Mapped unidirectional gru & unit test

Signed-off-by: Chen Xin <jack.chen@verisilicon.com>
This commit is contained in:
Chen Xin 2022-08-30 18:43:53 +08:00 committed by Sven
parent 58395cf7a7
commit f6121140b0
4 changed files with 274 additions and 1 deletions

View File

@ -0,0 +1,84 @@
/****************************************************************************
*
* Copyright (c) 2022 Vivante Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TIM_VX_OPS_UNIDIRECTIONAL_SEQUENCE_GRU_H_
#define TIM_VX_OPS_UNIDIRECTIONAL_SEQUENCE_GRU_H_
#include <array>
#include "tim/vx/direct_map_op.h"
#include "vsi_nn_pub.h"
namespace tim {
namespace vx {
namespace ops {
/**
* ## UnidirectionalSequenceGRU
*
* - num_units : dimensionality of the output space.
* - activation : Activation function to use.
* - recurrent_activation : Activation function to use for the recurrent step.
* - reset_after : whether to apply reset gate after or before matrix multiplication.
* False = "before", True = "after".
* - return_sequences : Whether to return the last output in the output sequence,
* or the full sequence. Default: False.
* - time_major : If True, the inputs and outputs will be in shape [feature, batch, timesteps],
* in the False case, it will be [feature, timesteps, batch].
*/
class UnidirectionalSequenceGRU : public DirectMapOp {
public:
enum ActivationType {
kNONE = 0,
kRELU = 1,
kRELU6 = 3,
kTANH = 4,
kSIGMOID = 6,
kHARDSIGMOID = 31, /* temporary use 31 */
};
UnidirectionalSequenceGRU(
Graph* graph, uint32_t num_units,
ActivationType activation = ActivationType::kTANH,
ActivationType recurrent_activation = ActivationType::kSIGMOID,
vsi_bool reset_after = TRUE,
vsi_bool return_sequences = FALSE, /*False: only return last state*/
vsi_bool time_major = TRUE);
std::shared_ptr<Operation> Clone(
std::shared_ptr<Graph>& graph) const override;
protected:
const uint32_t num_units_;
const ActivationType activation_;
const ActivationType recurrent_activation_;
const int32_t reset_after_;
const int32_t return_sequences_;
const int32_t time_major_;
};
} // namespace ops
} // namespace vx
} // namespace tim
#endif /* TIM_VX_OPS_UNIDIRECTIONAL_SEQUENCE_GRU_H_ */

View File

@ -112,7 +112,7 @@ GroupedConv1d|GROUPED_CONV1D|Mapped|[tf.keras.layers.Conv1D](https://tensorflow.
|ROI_Align|ROI_ALIGN|Mapped|[ANEURALNETWORKS_ROI_ALIGN](https://developer.android.com/ndk/reference/group/neural-networks#group___neural_networks_1ggaabbe492c60331b13038e39d4207940e0a2848b39dd4bfba78f2438fda0d9397a4)
|TopK|TOPK|Mapped (limited support)|[tf.math.top_k](https://tensorflow.google.cn/api_docs/python/tf/math/top_k)
|GRUCell|GRUCELL_OVXLIB|Mapped|[tf.keras.layers.GRUCell](https://tensorflow.google.cn/api_docs/python/tf/keras/layers/GRUCell?hl=en)
|UnidirectionalSequenceGRU|GRU_OVXLIB|Planned 22Q3|[tf.keras.layers.GRU](https://tensorflow.google.cn/api_docs/python/tf/keras/layers/GRUCell?hl=en)
|UnidirectionalSequenceGRU|GRU_OVXLIB|Mapped|[tf.keras.layers.GRU](https://tensorflow.google.cn/api_docs/python/tf/keras/layers/GRUCell?hl=en)
|UnidirectionalSequenceRNN|UNIDIRECTIONAL_SEQUENCE_RNN|Planned 22Q3|[ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_RNN](https://developer.android.com/ndk/reference/group/neural-networks#group___neural_networks_1ggaabbe492c60331b13038e39d4207940e0ae11aa1d461d2abaa117f6ee2cb503dd8)
|BidirectionalSequenceRNN|BIDIRECTIONAL_SEQUENCE_RNN|Planned 22Q3|[ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_RNN](https://developer.android.com/ndk/reference/group/neural-networks#group___neural_networks_1ggaabbe492c60331b13038e39d4207940e0a487fc5ae247de828f13e62b99f259f3c)
|BidirectionalSequenceLSTM|BIDIRECTIONAL_SEQUENCE_LSTM|Mapped|[ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_LSTM](https://developer.android.com/ndk/reference/group/neural-networks#group___neural_networks_1ggaabbe492c60331b13038e39d4207940e0a492a71cb7aa50b9a1a834a3cb269d778)

View File

@ -0,0 +1,60 @@
/****************************************************************************
*
* Copyright (c) 2022 Vivante Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#include "tim/vx/ops/unidirectional_sequence_gru.h"
#include "direct_map_op_impl.h"
#include "type_utils.h"
#include "vsi_nn_pub.h"
namespace tim {
namespace vx {
namespace ops {
UnidirectionalSequenceGRU::UnidirectionalSequenceGRU(
Graph* graph, uint32_t num_units, ActivationType activation,
ActivationType recurrent_activation, vsi_bool reset_after,
vsi_bool return_sequences, vsi_bool time_major)
: DirectMapOp(graph, VSI_NN_OP_GRU),
num_units_(num_units),
activation_(activation),
recurrent_activation_(recurrent_activation),
reset_after_(reset_after),
return_sequences_(return_sequences),
time_major_(time_major) {
this->impl()->node()->nn_param.gru.num_units = num_units;
this->impl()->node()->nn_param.gru.activation = activation;
this->impl()->node()->nn_param.gru.recurrent_activation = recurrent_activation;
this->impl()->node()->nn_param.gru.reset_after = reset_after;
this->impl()->node()->nn_param.gru.return_sequences = return_sequences;
this->impl()->node()->nn_param.gru.time_major = time_major;
}
std::shared_ptr<Operation> UnidirectionalSequenceGRU::Clone(
std::shared_ptr<Graph>& graph) const {
return graph->CreateOperation<UnidirectionalSequenceGRU>(
this->num_units_, this->activation_, this->recurrent_activation_,
this->reset_after_, this->return_sequences_, this->time_major_);
}
} // namespace ops
} // namespace vx
} // namespace tim

View File

@ -0,0 +1,129 @@
/****************************************************************************
*
* Copyright (c) 2022 Vivante Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#include "tim/vx/context.h"
#include "tim/vx/graph.h"
#include "tim/vx/ops/unidirectional_sequence_gru.h"
#include "gtest/gtest.h"
#include "test_utils.h"
std::shared_ptr<tim::vx::Tensor> make_empty_tensor(
std::shared_ptr<tim::vx::Graph> graph, const tim::vx::ShapeType& shape,
const tim::vx::TensorAttribute& role);
TEST(UnidirectionalSequenceGRU, unit_3) {
auto ctx = tim::vx::Context::Create();
auto graph = ctx->CreateGraph();
const int timesteps = 1;
const int batchs = 2;
const int feature = 4;
const int num_units = 2;
tim::vx::ShapeType in_shape({feature, batchs, timesteps});
tim::vx::ShapeType hstate_shape({num_units, batchs});
tim::vx::ShapeType out_shape({num_units, batchs, timesteps});
tim::vx::TensorSpec input_spec(tim::vx::DataType::FLOAT32, in_shape,
tim::vx::TensorAttribute::INPUT);
tim::vx::TensorSpec output_spec(tim::vx::DataType::FLOAT32, out_shape,
tim::vx::TensorAttribute::OUTPUT);
tim::vx::TensorSpec hstate_spec(tim::vx::DataType::FLOAT32, hstate_shape,
tim::vx::TensorAttribute::INPUT);
tim::vx::TensorSpec kernel_i_spec(tim::vx::DataType::FLOAT32,
tim::vx::ShapeType({feature, num_units}),
tim::vx::TensorAttribute::CONSTANT);
tim::vx::TensorSpec kernel_r_spec(tim::vx::DataType::FLOAT32,
tim::vx::ShapeType({num_units, num_units}),
tim::vx::TensorAttribute::CONSTANT);
std::vector<float> kernel_i2z = {-0.1201707124710083, 0.051147401332855225,
-0.02161085605621338, 0.2582472562789917,
-0.7641150951385498, 0.27272117137908936,
0.4013441801071167, -0.43467071652412415};
std::vector<float> kernel_i2r = {-0.34522661566734314, 0.11888366937637329,
0.6542353630065918, 0.6331415176391602,
-0.2489457130432129, -0.47332942485809326,
-0.7532100081443787, 0.46069061756134033};
std::vector<float> kernel_i2h = {
-0.0012096166610717773, -0.05206263065338135, -0.418102502822876,
-0.20800292491912842, -0.5549647808074951, -0.1337134838104248,
0.14222955703735352, -0.21347862482070923};
std::vector<float> kernel_r2z = {-0.49559473991394043, -0.10428445041179657,
0.39165210723876953, 0.38152191042900085};
std::vector<float> kernel_r2r = {0.03387263044714928, -0.39444485306739807,
0.4542817771434784, -0.4098765254020691};
std::vector<float> kernel_r2h = {-0.5441233515739441, -0.35663682222366333,
-0.3120974004268646, 0.6267299056053162};
auto input_tensor = graph->CreateTensor(input_spec);
auto hstate_tensor = graph->CreateTensor(hstate_spec);
auto output_tensor = graph->CreateTensor(output_spec);
auto hstate_out = graph->CreateTensor(
hstate_spec.SetAttribute(tim::vx::TensorAttribute::OUTPUT));
auto kernel_i2z_tensor =
graph->CreateTensor(kernel_i_spec, kernel_i2z.data());
auto kernel_i2r_tensor =
graph->CreateTensor(kernel_i_spec, kernel_i2r.data());
auto kernel_i2h_tensor =
graph->CreateTensor(kernel_i_spec, kernel_i2h.data());
auto kernel_r2z_tensor =
graph->CreateTensor(kernel_r_spec, kernel_r2z.data());
auto kernel_r2r_tensor =
graph->CreateTensor(kernel_r_spec, kernel_r2r.data());
auto kernel_r2h_tensor =
graph->CreateTensor(kernel_r_spec, kernel_r2h.data());
std::vector<float> in_data = {1, 2, 3, 4, 1, 2, 3, 4};
std::vector<float> hstate = {0, 0};
std::vector<float> golden = {-0.2719525, -0.5766771, -0.2719525, -0.5766771};
EXPECT_TRUE(
input_tensor->CopyDataToTensor(in_data.data(), in_data.size() * 4));
EXPECT_TRUE(
hstate_tensor->CopyDataToTensor(hstate.data(), hstate.size() * 4));
auto op =
graph->CreateOperation<tim::vx::ops::UnidirectionalSequenceGRU>(num_units);
(*op)
.BindInputs({
input_tensor,
hstate_tensor, //h_state
kernel_i2z_tensor, //KERNEL_I2
kernel_i2r_tensor, //KERNEL_I2
kernel_i2h_tensor, //KERNEL_I2
kernel_r2z_tensor, //KERNEL_R2
kernel_r2r_tensor, //KERNEL_R2
kernel_r2h_tensor, //KERNEL_R2
})
.BindOutputs({output_tensor, hstate_out});
EXPECT_TRUE(graph->Compile());
EXPECT_TRUE(graph->Run());
std::vector<float> output(golden.size());
EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data()));
EXPECT_TRUE(ArraysMatch(golden, output, 1e-5f));
}