1 /* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #include <math.h>
16 #include <stdint.h>
17
18 #include <vector>
19
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 #include "tensorflow/lite/kernels/internal/test_util.h"
23 #include "tensorflow/lite/kernels/test_util.h"
24 #include "tensorflow/lite/schema/schema_generated.h"
25
26 namespace tflite {
27 namespace {
28
29 using ::testing::ElementsAre;
30 using ::testing::ElementsAreArray;
31
32 template <typename T>
33 class PowOpModel : public SingleOpModel {
34 public:
PowOpModel(const TensorData & input1,const TensorData & input2,const TensorData & output)35 PowOpModel(const TensorData& input1, const TensorData& input2,
36 const TensorData& output) {
37 input1_ = AddInput(input1);
38 input2_ = AddInput(input2);
39 output_ = AddOutput(output);
40 SetBuiltinOp(BuiltinOperator_POW, BuiltinOptions_PowOptions,
41 CreatePowOptions(builder_).Union());
42 BuildInterpreter({GetShape(input1_), GetShape(input2_)});
43 }
44
input1()45 int input1() { return input1_; }
input2()46 int input2() { return input2_; }
47
GetOutput()48 std::vector<T> GetOutput() { return ExtractVector<T>(output_); }
GetOutputShape()49 std::vector<int> GetOutputShape() { return GetTensorShape(output_); }
50
51 private:
52 int input1_;
53 int input2_;
54 int output_;
55 };
56
TEST(PowOpModel,Simple)57 TEST(PowOpModel, Simple) {
58 PowOpModel<int32_t> model({TensorType_INT32, {1, 2, 2, 1}},
59 {TensorType_INT32, {1, 2, 2, 1}},
60 {TensorType_INT32, {}});
61 model.PopulateTensor<int32_t>(model.input1(), {12, 2, 7, 8});
62 model.PopulateTensor<int32_t>(model.input2(), {1, 2, 3, 1});
63 ASSERT_EQ(model.Invoke(), kTfLiteOk);
64 EXPECT_THAT(model.GetOutputShape(), ElementsAre(1, 2, 2, 1));
65 EXPECT_THAT(model.GetOutput(), ElementsAre(12, 4, 343, 8));
66 }
67
TEST(PowOpModel,NegativeAndZeroValue)68 TEST(PowOpModel, NegativeAndZeroValue) {
69 PowOpModel<int32_t> model({TensorType_INT32, {1, 2, 2, 1}},
70 {TensorType_INT32, {1, 2, 2, 1}},
71 {TensorType_INT32, {}});
72 model.PopulateTensor<int32_t>(model.input1(), {0, 2, -7, 8});
73 model.PopulateTensor<int32_t>(model.input2(), {1, 2, 3, 0});
74 ASSERT_EQ(model.Invoke(), kTfLiteOk);
75 EXPECT_THAT(model.GetOutputShape(), ElementsAre(1, 2, 2, 1));
76 EXPECT_THAT(model.GetOutput(), ElementsAre(0, 4, -343, 1));
77 }
78
TEST(PowOpModel,Float)79 TEST(PowOpModel, Float) {
80 PowOpModel<float> model({TensorType_FLOAT32, {1, 2, 2, 1}},
81 {TensorType_FLOAT32, {1, 2, 2, 1}},
82 {TensorType_FLOAT32, {}});
83 model.PopulateTensor<float>(model.input1(), {0.3, 0.4, 0.7, 5.8});
84 model.PopulateTensor<float>(model.input2(), {0.5, 2.7, 3.1, 3.2});
85 ASSERT_EQ(model.Invoke(), kTfLiteOk);
86 EXPECT_THAT(model.GetOutputShape(), ElementsAre(1, 2, 2, 1));
87 EXPECT_THAT(model.GetOutput(),
88 ElementsAreArray(ArrayFloatNear(
89 {0.5477226, 0.08424846, 0.33098164, 277.313}, 1e-3)));
90 }
91
TEST(PowOpModel,NegativeFloatTest)92 TEST(PowOpModel, NegativeFloatTest) {
93 PowOpModel<float> model({TensorType_FLOAT32, {1, 2, 2, 1}},
94 {TensorType_FLOAT32, {1, 2, 2, 1}},
95 {TensorType_FLOAT32, {}});
96 model.PopulateTensor<float>(model.input1(), {0.3, 0.4, 0.7, 5.8});
97 model.PopulateTensor<float>(model.input2(), {0.5, -2.7, 3.1, -3.2});
98 ASSERT_EQ(model.Invoke(), kTfLiteOk);
99 EXPECT_THAT(model.GetOutputShape(), ElementsAre(1, 2, 2, 1));
100 EXPECT_THAT(model.GetOutput(),
101 ElementsAreArray(ArrayFloatNear(
102 {0.5477226, 11.869653, 0.33098164, 0.003606}, 1e-3)));
103 }
104
TEST(PowOpModel,BroadcastTest)105 TEST(PowOpModel, BroadcastTest) {
106 PowOpModel<int32_t> model({TensorType_INT32, {1, 2, 2, 1}},
107 {TensorType_INT32, {1}}, {TensorType_INT32, {}});
108 model.PopulateTensor<int32_t>(model.input1(), {12, 2, 7, 8});
109 model.PopulateTensor<int32_t>(model.input2(), {4});
110 ASSERT_EQ(model.Invoke(), kTfLiteOk);
111 EXPECT_THAT(model.GetOutputShape(), ElementsAre(1, 2, 2, 1));
112 EXPECT_THAT(model.GetOutput(), ElementsAre(20736, 16, 2401, 4096));
113 }
114
TEST(PowOpModel,BroadcastFloatTest)115 TEST(PowOpModel, BroadcastFloatTest) {
116 PowOpModel<float> model({TensorType_FLOAT32, {1, 2, 2, 1}},
117 {TensorType_FLOAT32, {1}}, {TensorType_FLOAT32, {}});
118 model.PopulateTensor<float>(model.input1(), {12, 2, 7, 8});
119 model.PopulateTensor<float>(model.input2(), {4});
120 ASSERT_EQ(model.Invoke(), kTfLiteOk);
121 EXPECT_THAT(model.GetOutputShape(), ElementsAre(1, 2, 2, 1));
122 EXPECT_THAT(model.GetOutput(), ElementsAre(20736, 16, 2401, 4096));
123 }
124
125 template <typename T>
CalculateTrueResults(const std::vector<T> & input_data,T exponent,int flat_size,std::vector<T> * output_data)126 void CalculateTrueResults(const std::vector<T>& input_data, T exponent,
127 int flat_size, std::vector<T>* output_data) {
128 for (int i = 0; i < flat_size; ++i) {
129 output_data->at(i) = std::pow(input_data[i], exponent);
130 }
131 }
132
TEST(PowOpModel,FloatSingleIntegerExponentTest)133 TEST(PowOpModel, FloatSingleIntegerExponentTest) {
134 PowOpModel<float> model({TensorType_FLOAT32, {1, 2, 2, 1}},
135 {TensorType_FLOAT32, {1}}, {TensorType_FLOAT32, {}});
136 const int input_size = 1 * 2 * 2 * 1;
137 for (int i = 1; i < 20; ++i) {
138 std::vector<float> input_data(input_size);
139 for (int index = 0; index < input_size; ++index) {
140 // For exponent is float case, if base < 0, we will result in nan, so
141 // we only populate positive base.
142 input_data[index] = UniformRandomFloat(0, 1.5);
143 }
144 model.PopulateTensor<float>(model.input1(), input_data);
145 float exponent = static_cast<float>(i);
146 // Random deviate exponent, e.g., 1.99999 or 2.00001.
147 exponent += UniformRandomInt(-1, 1) * 1e-5;
148 model.PopulateTensor<float>(model.input2(), {exponent});
149 ASSERT_EQ(model.Invoke(), kTfLiteOk);
150 EXPECT_THAT(model.GetOutputShape(), ElementsAre(1, 2, 2, 1));
151 std::vector<float> output_data(input_size);
152 CalculateTrueResults(input_data, exponent, input_size, &output_data);
153 EXPECT_THAT(model.GetOutput(),
154 ElementsAreArray(ArrayFloatNear(output_data, 1e-2)));
155 }
156 }
157
TEST(PowOpModel,IntSingleIntegerExponentTest)158 TEST(PowOpModel, IntSingleIntegerExponentTest) {
159 PowOpModel<int32_t> model({TensorType_INT32, {1, 2, 2, 1}},
160 {TensorType_INT32, {1}}, {TensorType_INT32, {}});
161 const int input_size = 1 * 2 * 2 * 1;
162 for (int i = 1; i < 20; ++i) {
163 std::vector<int32_t> input_data(input_size);
164 for (int index = 0; index < input_size; ++index) {
165 input_data[index] = UniformRandomInt(-2, -2);
166 }
167 model.PopulateTensor<int32_t>(model.input1(), input_data);
168 int exponent = i;
169 model.PopulateTensor<int32_t>(model.input2(), {exponent});
170 ASSERT_EQ(model.Invoke(), kTfLiteOk);
171 EXPECT_THAT(model.GetOutputShape(), ElementsAre(1, 2, 2, 1));
172 std::vector<int32_t> output_data(input_size);
173 CalculateTrueResults(input_data, exponent, input_size, &output_data);
174 EXPECT_THAT(model.GetOutput(), ElementsAreArray(output_data));
175 }
176 }
177
178 } // namespace
179 } // namespace tflite
180