@@ -23,12 +23,13 @@ using executorch::aten::ArrayRef;
23
23
using executorch::aten::Scalar;
24
24
using executorch::aten::ScalarType;
25
25
using executorch::aten::Tensor;
26
+ using executorch::aten::optional;
26
27
using torch::executor::testing::TensorFactory;
27
28
28
29
class OpLinearOutTest : public OperatorTest {
29
30
protected:
30
- Tensor& op_linear_out (const Tensor& self, const Tensor& mat2, Tensor& out) {
31
- return torch::executor::aten::linear_outf (context_, self, mat2, {} , out);
31
+ Tensor& op_linear_out (const Tensor& self, const Tensor& mat2, const optional<Tensor>& bias, Tensor& out) {
32
+ return torch::executor::aten::linear_outf (context_, self, mat2, bias , out);
32
33
}
33
34
34
35
template <class CTYPE , executorch::aten::ScalarType DTYPE>
@@ -47,14 +48,18 @@ class OpLinearOutTest : public OperatorTest {
47
48
Tensor x = tf.full ({3 , 32 }, 2 );
48
49
Tensor y = tf.full ({5 , 32 }, 3 );
49
50
50
- // Output shape should be (3, 5)
51
- Tensor out = tf.zeros ({3 , 5 });
52
-
53
- op_linear_out (x, y, out);
54
-
55
- Tensor expected = tf.full ({3 , 5 }, 192 );
56
-
57
- EXPECT_TENSOR_EQ (out, expected);
51
+ // without bias
52
+ Tensor out_no_bias = tf.zeros ({3 , 5 });
53
+ op_linear_out (x, y, {}, out_no_bias);
54
+ Tensor expected_no_bias = tf.full ({3 , 5 }, 192 );
55
+ EXPECT_TENSOR_EQ (out_no_bias, expected_no_bias);
56
+
57
+ // with bias
58
+ Tensor bias = tf.full ({5 }, 1 );
59
+ Tensor out_with_bias = tf.zeros ({3 , 5 });
60
+ op_linear_out (x, y, bias, out_with_bias);
61
+ Tensor expected_with_bias = tf.full ({3 , 5 }, 193 );
62
+ EXPECT_TENSOR_EQ (out_with_bias, expected_with_bias);
58
63
}
59
64
};
60
65
@@ -66,13 +71,15 @@ TEST_F(OpLinearOutTest, OutputDim) {
66
71
Tensor y = tf.ones ({5 , 4 });
67
72
Tensor out = tf.zeros ({3 , 5 });
68
73
69
- Tensor ret = op_linear_out (x, y, out);
74
+ Tensor bias = tf.ones ({5 });
75
+
76
+ Tensor ret = op_linear_out (x, y, bias, out);
70
77
71
78
// Should always return the provided out Tensor.
72
79
EXPECT_TENSOR_EQ (ret, out);
73
80
74
- // Expected tensor, filled with 4 .
75
- Tensor expected = tf.full ({3 , 5 }, 4 );
81
+ // Expected tensor, filled with 5 .
82
+ Tensor expected = tf.full ({3 , 5 }, 5 );
76
83
77
84
EXPECT_TENSOR_EQ (out, expected);
78
85
}
@@ -94,44 +101,47 @@ TEST_F(OpLinearOutTest, EmptyInputWithEmptyOutTensorPasses) {
94
101
// Empty input matrices
95
102
Tensor x = tf.make ({0 , 3 }, {});
96
103
Tensor y = tf.make ({0 , 3 }, {});
104
+ Tensor bias = tf.make ({0 }, {});
97
105
98
106
// Output matrix is also empty
99
107
Tensor out = tf.make ({0 , 0 }, {});
100
108
101
109
Tensor expected = tf.make ({0 , 0 }, {});
102
110
103
- EXPECT_TENSOR_EQ (op_linear_out (x, y, out), expected);
111
+ EXPECT_TENSOR_EQ (op_linear_out (x, y, bias, out), expected);
104
112
}
105
113
106
114
TEST_F (OpLinearOutTest, InfinityTensorPasses) {
107
115
TensorFactory<ScalarType::Float> tff;
108
116
109
117
Tensor x = tff.full ({3 , 4 }, std::numeric_limits<float >::infinity ());
110
118
Tensor y = tff.full ({5 , 4 }, 3 );
119
+ Tensor bias = tff.full ({5 }, 1 );
111
120
112
121
// Output shape should be (3, 5)
113
122
Tensor out = tff.zeros ({3 , 5 });
114
123
115
124
Tensor expected = tff.full ({3 , 5 }, std::numeric_limits<float >::infinity ());
116
125
117
- EXPECT_TENSOR_EQ (op_linear_out (x, y, out), expected);
126
+ EXPECT_TENSOR_EQ (op_linear_out (x, y, bias, out), expected);
118
127
}
119
128
120
129
TEST_F (OpLinearOutTest, MismatchedDimensionsDies) {
121
130
TensorFactory<ScalarType::Int> tf;
122
131
123
132
Tensor x = tf.full ({2 , 2 }, 3 );
133
+ Tensor bias = tf.full ({2 }, 1 );
124
134
125
135
Tensor wrong_y = tf.full ({1 , 3 }, 1 );
126
136
Tensor right_y = tf.full ({2 , 2 }, 1 );
127
137
128
138
// Make an empty out tensor and demonstrate that it's empty.
129
139
Tensor out = tf.full ({2 , 2 }, 0 );
130
140
131
- Tensor expected = tf.full ({2 , 2 }, 6 );
132
- ET_EXPECT_KERNEL_FAILURE (context_, op_linear_out (x, wrong_y, out));
141
+ Tensor expected = tf.full ({2 , 2 }, 7 );
142
+ ET_EXPECT_KERNEL_FAILURE (context_, op_linear_out (x, wrong_y, bias, out));
133
143
134
- EXPECT_TENSOR_EQ (op_linear_out (x, right_y, out), expected);
144
+ EXPECT_TENSOR_EQ (op_linear_out (x, right_y, bias, out), expected);
135
145
}
136
146
137
147
TEST_F (OpLinearOutTest, MismatchedDimensionSizeDies) {
@@ -140,6 +150,7 @@ TEST_F(OpLinearOutTest, MismatchedDimensionSizeDies) {
140
150
}
141
151
TensorFactory<ScalarType::Int> tf;
142
152
Tensor x = tf.full ({2 , 2 }, 3 );
153
+ Tensor bias = tf.full ({2 }, 1 );
143
154
144
155
// wrong_y has incompatible dim
145
156
Tensor wrong_y = tf.full ({2 , 2 , 2 }, 1 );
@@ -149,8 +160,8 @@ TEST_F(OpLinearOutTest, MismatchedDimensionSizeDies) {
149
160
Tensor right_out = tf.ones ({2 , 2 });
150
161
Tensor wrong_out = tf.ones ({2 , 2 , 3 });
151
162
152
- ET_EXPECT_KERNEL_FAILURE (context_, op_linear_out (x, right_y, wrong_out));
153
- ET_EXPECT_KERNEL_FAILURE (context_, op_linear_out (x, wrong_y, right_out));
163
+ ET_EXPECT_KERNEL_FAILURE (context_, op_linear_out (x, right_y, bias, wrong_out));
164
+ ET_EXPECT_KERNEL_FAILURE (context_, op_linear_out (x, wrong_y, bias, right_out));
154
165
}
155
166
156
167
TEST_F (OpLinearOutTest, WrongOutShapeDies) {
@@ -161,14 +172,15 @@ TEST_F(OpLinearOutTest, WrongOutShapeDies) {
161
172
Tensor x = tf.ones ({10 , 3 });
162
173
163
174
Tensor y = tf.ones ({4 , 3 });
175
+ Tensor bias = tf.ones ({4 });
164
176
165
177
// wrong_out has incompatible shape
166
178
Tensor right_out = tf.ones ({10 , 4 });
167
179
Tensor wrong_out = tf.ones ({7 , 5 });
168
180
169
- ET_EXPECT_KERNEL_FAILURE (context_, op_linear_out (x, y, wrong_out));
181
+ ET_EXPECT_KERNEL_FAILURE (context_, op_linear_out (x, y, bias, wrong_out));
170
182
171
- EXPECT_TENSOR_EQ (op_linear_out (x, y, right_out), tf.full ({10 , 4 }, 3 ));
183
+ EXPECT_TENSOR_EQ (op_linear_out (x, y, bias, right_out), tf.full ({10 , 4 }, 4 ));
172
184
}
173
185
174
186
TEST_F (OpLinearOutTest, DynamicShapeUpperBoundSameAsExpected) {
@@ -192,24 +204,25 @@ TEST_F(OpLinearOutTest, DynamicShapeUpperBoundSameAsExpected) {
192
204
0.09420186281204224 ,
193
205
0.9070476293563843 ,
194
206
0.9310881495475769 });
207
+ Tensor bias = tf.ones ({4 });
195
208
Tensor expected_result = tf.make (
196
209
{3 , 4 },
197
- {0 .2506277561187744 ,
198
- 0 .15225356817245483 ,
199
- 0 .18952149152755737 ,
200
- 0 .48189279437065125 ,
201
- 0 .976661741733551 ,
202
- 0 .480360746383667 ,
203
- 0 .8310978412628174 ,
204
- 1 .6718982458114624 ,
205
- 0 .703657865524292 ,
206
- 0 .2534688115119934 ,
207
- 0 .6746801733970642 ,
208
- 1 .0356627702713013 });
210
+ {1 .2506277561187744 ,
211
+ 1 .15225356817245483 ,
212
+ 1 .18952149152755737 ,
213
+ 1 .48189279437065125 ,
214
+ 1 .976661741733551 ,
215
+ 1 .480360746383667 ,
216
+ 1 .8310978412628174 ,
217
+ 2 .6718982458114624 ,
218
+ 1 .703657865524292 ,
219
+ 1 .2534688115119934 ,
220
+ 1 .6746801733970642 ,
221
+ 2 .0356627702713013 });
209
222
210
223
Tensor out =
211
224
tf.zeros ({3 , 4 }, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
212
- Tensor ret = op_linear_out (x, y, out);
225
+ Tensor ret = op_linear_out (x, y, bias, out);
213
226
EXPECT_TENSOR_CLOSE (out, expected_result);
214
227
}
215
228
@@ -234,24 +247,25 @@ TEST_F(OpLinearOutTest, DynamicShapeUpperBoundLargerThanExpected) {
234
247
0.09420186281204224 ,
235
248
0.9070476293563843 ,
236
249
0.9310881495475769 });
250
+ Tensor bias = tf.ones ({4 });
237
251
Tensor expected_result = tf.make (
238
252
{3 , 4 },
239
- {0 .2506277561187744 ,
240
- 0 .15225356817245483 ,
241
- 0 .18952149152755737 ,
242
- 0 .48189279437065125 ,
243
- 0 .976661741733551 ,
244
- 0 .480360746383667 ,
245
- 0 .8310978412628174 ,
246
- 1 .6718982458114624 ,
247
- 0 .703657865524292 ,
248
- 0 .2534688115119934 ,
249
- 0 .6746801733970642 ,
250
- 1 .0356627702713013 });
253
+ {1 .2506277561187744 ,
254
+ 1 .15225356817245483 ,
255
+ 1 .18952149152755737 ,
256
+ 1 .48189279437065125 ,
257
+ 1 .976661741733551 ,
258
+ 1 .480360746383667 ,
259
+ 1 .8310978412628174 ,
260
+ 2 .6718982458114624 ,
261
+ 1 .703657865524292 ,
262
+ 1 .2534688115119934 ,
263
+ 1 .6746801733970642 ,
264
+ 2 .0356627702713013 });
251
265
252
266
Tensor out =
253
267
tf.zeros ({10 , 10 }, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
254
- Tensor ret = op_linear_out (x, y, out);
268
+ Tensor ret = op_linear_out (x, y, bias, out);
255
269
EXPECT_TENSOR_CLOSE (out, expected_result);
256
270
}
257
271
@@ -277,24 +291,25 @@ TEST_F(OpLinearOutTest, DynamicShapeUnbound) {
277
291
0.09420186281204224 ,
278
292
0.9070476293563843 ,
279
293
0.9310881495475769 });
294
+ Tensor bias = tf.ones ({4 });
280
295
Tensor expected_result = tf.make (
281
296
{3 , 4 },
282
- {0 .2506277561187744 ,
283
- 0 .15225356817245483 ,
284
- 0 .18952149152755737 ,
285
- 0 .48189279437065125 ,
286
- 0 .976661741733551 ,
287
- 0 .480360746383667 ,
288
- 0 .8310978412628174 ,
289
- 1 .6718982458114624 ,
290
- 0 .703657865524292 ,
291
- 0 .2534688115119934 ,
292
- 0 .6746801733970642 ,
293
- 1 .0356627702713013 });
297
+ {1 .2506277561187744 ,
298
+ 1 .15225356817245483 ,
299
+ 1 .18952149152755737 ,
300
+ 1 .48189279437065125 ,
301
+ 1 .976661741733551 ,
302
+ 1 .480360746383667 ,
303
+ 1 .8310978412628174 ,
304
+ 2 .6718982458114624 ,
305
+ 1 .703657865524292 ,
306
+ 1 .2534688115119934 ,
307
+ 1 .6746801733970642 ,
308
+ 2 .0356627702713013 });
294
309
295
310
Tensor out =
296
311
tf.zeros ({1 , 1 }, torch::executor::TensorShapeDynamism::DYNAMIC_UNBOUND);
297
- Tensor ret = op_linear_out (x, y, out);
312
+ Tensor ret = op_linear_out (x, y, bias, out);
298
313
EXPECT_TENSOR_CLOSE (out, expected_result);
299
314
}
300
315
0 commit comments