/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ #include // Declares the operator #include #include #include #include #include #include using namespace ::testing; using exec_aten::ScalarType; using exec_aten::string_view; using exec_aten::Tensor; using torch::executor::testing::SupportedFeatures; using torch::executor::testing::TensorFactory; class OpGeluTest : public OperatorTest { protected: Tensor& op_gelu_out(const Tensor& self, string_view approximate, Tensor& out) { return torch::executor::aten::gelu_outf(context_, self, approximate, out); } // Common testing for gelu on two floating point Tensors. template void test_gelu_execution() { TensorFactory tf; const std::vector sizes = {3, 2}; Tensor in = tf.make( sizes, /*data=*/{-0.4775, 0.2948, -0.3984, 1.8690, -0.4048, -0.4848}); // Destination for the gelu. Tensor out = tf.zeros(sizes); // Run full gelu. op_gelu_out(in, "none", out); // Check that it matches the expected output. EXPECT_TENSOR_CLOSE( out, tf.make( sizes, /*data=*/ {-0.15113, 0.181575, -0.137515, 1.81141, -0.13877, -0.152183})); // Run tanh gelu appx. op_gelu_out(in, "tanh", out); // Check that it matches the expected output. EXPECT_TENSOR_CLOSE( out, tf.make( sizes, /*data=*/ {-0.151145, 0.181573, -0.137522, 1.8114, -0.138778, -0.152199})); } }; TEST_F(OpGeluTest, FloatTensors) { test_gelu_execution(); } TEST_F(OpGeluTest, DoubleTensors) { if (!SupportedFeatures::get()->op_gelu_dtype_double) { GTEST_SKIP(); } test_gelu_execution(); } TEST_F(OpGeluTest, UnhandledDtypeDies) { // gelu() doesn't handle Bool. TensorFactory tf; const std::vector sizes = {2, 2}; Tensor a = tf.make(sizes, /*data=*/{false, true, false, true}); // Destination for the gelu. Tensor out = tf.zeros(sizes); ET_EXPECT_KERNEL_FAILURE(context_, op_gelu_out(a, "none", out)); } // The output tensor may not have a dtype different from the inputs even if it // has the same shape. TEST_F(OpGeluTest, MismatchedOutputDtypeDies) { // Two different dtypes. This test uses two types with the same size to // demonstrate that the ScalarType itself matters, not the size of the // tensor elements. TensorFactory tf_float; TensorFactory tf_double; const std::vector sizes = {2, 2}; Tensor a = tf_float.ones(sizes); // Destination with a dtype different from the input. Tensor out = tf_double.zeros(sizes); // Running Gelu on an input into an output of a different dtype should kill // the program ET_EXPECT_KERNEL_FAILURE(context_, op_gelu_out(a, "none", out)); } TEST_F(OpGeluTest, InvalidAppxStringDies) { TensorFactory tf; Tensor a = tf.ones(/*sizes=*/{4}); // Destination for the gelu; matches the shape of the inputs. Tensor out = tf.zeros(/*sizes=*/{4}); // Running Gelu with an invalid appx method should kill the program. ET_EXPECT_KERNEL_FAILURE(context_, op_gelu_out(a, "foo", out)); } TEST_F(OpGeluTest, SimpleGeneratedCase) { TensorFactory tf; Tensor x = tf.make( {10, 10}, {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}); Tensor expected_result = tf.make( {10, 10}, {0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193, 0.8411920070648193}); Tensor out = tf.zeros({10, 10}); Tensor ret = op_gelu_out(x, "tanh", out); EXPECT_TENSOR_CLOSE(out, expected_result); } TEST_F(OpGeluTest, DynamicShapeUpperBoundSameAsExpected) { TensorFactory tf; Tensor x = tf.make( {3, 2}, {0.9769402146339417, 0.4728269577026367, 0.04416435956954956, 0.7145527601242065, 0.7109619975090027, 0.36388522386550903}); Tensor expected_result = tf.make( {3, 2}, {0.8162848949432373, 0.3223743438720703, 0.022860059514641762, 0.5448282957077026, 0.5413010716438293, 0.23361928761005402}); Tensor out = tf.zeros({3, 2}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND); Tensor ret = op_gelu_out(x, "tanh", out); EXPECT_TENSOR_CLOSE(out, expected_result); } TEST_F(OpGeluTest, DynamicShapeUpperBoundLargerThanExpected) { GTEST_SKIP() << "Dynamic shape not supported"; TensorFactory tf; Tensor x = tf.make( {3, 2}, {0.9769402146339417, 0.4728269577026367, 0.04416435956954956, 0.7145527601242065, 0.7109619975090027, 0.36388522386550903}); Tensor expected_result = tf.make( {3, 2}, {0.8162848949432373, 0.3223743438720703, 0.022860059514641762, 0.5448282957077026, 0.5413010716438293, 0.23361928761005402}); Tensor out = tf.zeros({10, 10}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND); Tensor ret = op_gelu_out(x, "tanh", out); EXPECT_TENSOR_CLOSE(out, expected_result); } TEST_F(OpGeluTest, DynamicShapeUnbound) { GTEST_SKIP() << "Dynamic shape not supported"; TensorFactory tf; Tensor x = tf.make( {3, 2}, {0.9769402146339417, 0.4728269577026367, 0.04416435956954956, 0.7145527601242065, 0.7109619975090027, 0.36388522386550903}); Tensor expected_result = tf.make( {3, 2}, {0.8162848949432373, 0.3223743438720703, 0.022860059514641762, 0.5448282957077026, 0.5413010716438293, 0.23361928761005402}); Tensor out = tf.zeros({1, 1}, torch::executor::TensorShapeDynamism::DYNAMIC_UNBOUND); Tensor ret = op_gelu_out(x, "tanh", out); EXPECT_TENSOR_CLOSE(out, expected_result); }