Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion onnxruntime/core/providers/cpu/rnn/rnn.cc
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ Status RNN<float>::Compute(OpKernelContext* ctx) const {

for (int direction = 0; direction < num_directions; direction++) {
auto activation_func = GetFuncByName<float>(activations_[direction], "Tanh");
const auto& activation = activation_funcs_.Entries()[direction];
bool isReverse = direction_ == "reverse" || direction == 1;

if (B != nullptr) {
Expand Down Expand Up @@ -279,7 +280,7 @@ Status RNN<float>::Compute(OpKernelContext* ctx) const {
// apply activation
ApplyActivationToBatches<float>(sequence_lens, h_prev, Y_buffer_data_current_frame,
time_step, batch_size, hidden_size_,
activation_alpha_[direction], activation_beta_[direction], clip_, activation_func);
activation.alpha, activation.beta, clip_, activation_func);
} // close sequence loop

if (Y_h)
Expand Down
13 changes: 6 additions & 7 deletions onnxruntime/core/providers/cpu/rnn/rnn.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "core/common/exceptions.h"
#include "core/framework/op_kernel.h"
#include "core/providers/cpu/mlas_backend_kernel_selector_config_utils.h"
#include "core/providers/cpu/rnn/rnn_helpers.h"

namespace onnxruntime {
template <typename T>
Expand All @@ -24,8 +25,8 @@ class RNN : public OpKernel {
ORT_ENFORCE(allowed_directions.find(direction_) != allowed_directions.end());
const int num_directions = direction_ == "bidirectional" ? 2 : 1;

activation_alpha_ = info.GetAttrsOrDefault("activation_alpha", std::vector<float>(num_directions, 0.0F));
activation_beta_ = info.GetAttrsOrDefault("activation_beta", std::vector<float>(num_directions, 0.0F));
const auto activation_alpha = info.GetAttrsOrDefault<float>("activation_alpha");
const auto activation_beta = info.GetAttrsOrDefault<float>("activation_beta");
ORT_ENFORCE(info.GetAttrs("activations", activations_).IsOK());
// TODO: is it optional or not?
ORT_ENFORCE(info.GetAttr("hidden_size", &hidden_size_).IsOK());
Expand All @@ -42,6 +43,8 @@ class RNN : public OpKernel {
"RNN op: Invalid activation attribute - ", activations_[direction]);
}

activation_funcs_ = rnn::detail::ActivationFuncs(activations_, activation_alpha, activation_beta);

ORT_ENFORCE(layout_ == 0,
"Batchwise recurrent operations (layout == 1) are not supported. If you need support create a github issue with justification.");

Expand All @@ -51,11 +54,7 @@ class RNN : public OpKernel {
Status Compute(OpKernelContext* context) const override;

private:
// optional, default values tied to the activation function
std::vector<float> activation_alpha_;

// optional, default values tied to the activation function
std::vector<float> activation_beta_;
rnn::detail::ActivationFuncs activation_funcs_;

// optional, default = "Tanh"
std::vector<std::string> activations_;
Expand Down
66 changes: 66 additions & 0 deletions onnxruntime/test/providers/cpu/rnn/rnn_op_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,72 @@ TEST(RNNTest, RNN_with_invalid_activation_load_failure) {
{kCudaExecutionProvider, kTensorrtExecutionProvider});
}

namespace {
void RunRnnActivationParametersTest(const std::vector<std::string>& activations,
bool add_activation_alpha,
const std::vector<float>& activation_alpha,
bool add_activation_beta,
const std::vector<float>& activation_beta,
const std::vector<float>& expected_output) {
auto cpu = DefaultCpuExecutionProvider();
if (!cpu) {
GTEST_SKIP() << "CPU EP not available in this build.";
}

OpTester test("RNN");
const int64_t num_directions = static_cast<int64_t>(activations.size());
int64_t input_size = 1, hidden_size = 1, seq_length = 1, batch_size = 1;

test.AddAttribute("activations", activations);
test.AddAttribute("direction", num_directions == 2 ? "bidirectional" : "forward");
test.AddAttribute("hidden_size", hidden_size);
if (add_activation_alpha) {
test.AddAttribute<std::vector<float>>("activation_alpha", activation_alpha);
}
if (add_activation_beta) {
test.AddAttribute<std::vector<float>>("activation_beta", activation_beta);
}

std::vector<int64_t> X_dims = {seq_length, batch_size, input_size};
std::vector<float> X_data{1.F};
test.AddInput<float>("X", X_dims, X_data);

std::vector<int64_t> W_dims = {num_directions, hidden_size, input_size};
std::vector<float> W_data(static_cast<size_t>(num_directions), -1.F);
test.AddInput<float>("W", W_dims, W_data);

std::vector<int64_t> R_dims = {num_directions, hidden_size, hidden_size};
std::vector<float> R_data(static_cast<size_t>(num_directions), 0.F);
test.AddInput<float>("R", R_dims, R_data);

std::vector<int64_t> Y_dims = {seq_length, num_directions, batch_size, hidden_size};
test.AddOutput<float>("Y", Y_dims, expected_output);

std::vector<int64_t> Y_h_dims{num_directions, batch_size, hidden_size};
test.AddOutput<float>("Y_h", Y_h_dims, expected_output);

test.ConfigEp(std::move(cpu)).RunWithConfig();
}
} // namespace

TEST(RNNTest, RNN_mixed_activations_consume_only_required_alpha_beta) {
RunRnnActivationParametersTest({"HardSigmoid", "Tanh"}, true, {0.2F}, true, {0.5F},
{0.3F, -0.7615942F});
}

TEST(RNNTest, RNN_empty_activation_parameters_use_activation_defaults) {
RunRnnActivationParametersTest({"HardSigmoid"}, true, {}, true, {}, {0.3F});
}

TEST(RNNTest, RNN_missing_activation_alpha_uses_activation_default) {
RunRnnActivationParametersTest({"LeakyRelu"}, false, {}, false, {}, {-0.01F});
}

TEST(RNNTest, RNN_extra_activation_parameter_entries_are_ignored) {
RunRnnActivationParametersTest({"HardSigmoid", "HardSigmoid"}, true, {0.1F, 0.2F, 0.3F},
true, {0.5F, 0.6F, 0.7F}, {0.4F, 0.4F});
}

// Test that seq_length == 0 produces zero-filled Y and Y_h without crashing.
TEST(RNNTest, RNN_seq_length_zero) {
auto cpu = DefaultCpuExecutionProvider();
Expand Down
Loading