1 // Tencent is pleased to support the open source community by making ncnn available.
2 //
3 // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
4 //
5 // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
7 //
8 // https://opensource.org/licenses/BSD-3-Clause
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
14 
15 #include "layer/innerproduct.h"
16 #include "testutil.h"
17 
test_innerproduct(const ncnn::Mat & a,int outch,int bias)18 static int test_innerproduct(const ncnn::Mat& a, int outch, int bias)
19 {
20     ncnn::ParamDict pd;
21     pd.set(0, outch); // num_output
22     pd.set(1, bias);  // bias_term
23     pd.set(2, outch * a.w * a.h * a.c);
24 
25     int activation_type = RAND() % 6; // 0 1 2 3 4 5
26     ncnn::Mat activation_params(2);
27     activation_params[0] = RandomFloat(-1, 0); // alpha
28     activation_params[1] = RandomFloat(0, 1);  // beta
29     pd.set(9, activation_type);
30     pd.set(10, activation_params);
31 
32     std::vector<ncnn::Mat> weights(bias ? 2 : 1);
33     weights[0] = RandomMat(outch * a.w * a.h * a.c);
34     if (bias)
35         weights[1] = RandomMat(outch);
36 
37     int ret = test_layer<ncnn::InnerProduct>("InnerProduct", pd, weights, a);
38     if (ret != 0)
39     {
40         fprintf(stderr, "test_innerproduct failed a.dims=%d a=(%d %d %d) outch=%d bias=%d act=%d actparams=[%f,%f]\n", a.dims, a.w, a.h, a.c, outch, bias, activation_type, activation_params[0], activation_params[1]);
41     }
42 
43     return ret;
44 }
45 
test_innerproduct_0()46 static int test_innerproduct_0()
47 {
48     return 0
49            || test_innerproduct(RandomMat(1, 3, 1), 1, 1)
50            || test_innerproduct(RandomMat(3, 2, 2), 2, 0)
51            || test_innerproduct(RandomMat(9, 3, 8), 7, 1)
52            || test_innerproduct(RandomMat(2, 2, 8), 8, 0)
53            || test_innerproduct(RandomMat(4, 3, 15), 8, 1)
54            || test_innerproduct(RandomMat(6, 2, 16), 16, 0)
55            || test_innerproduct(RandomMat(6, 2, 16), 7, 1)
56            || test_innerproduct(RandomMat(6, 2, 5), 16, 1);
57 }
58 
test_innerproduct_1()59 static int test_innerproduct_1()
60 {
61     return 0
62            || test_innerproduct(RandomMat(1, 1), 1, 1)
63            || test_innerproduct(RandomMat(3, 2), 2, 0)
64            || test_innerproduct(RandomMat(9, 8), 7, 1)
65            || test_innerproduct(RandomMat(2, 8), 8, 0)
66            || test_innerproduct(RandomMat(4, 15), 8, 1)
67            || test_innerproduct(RandomMat(6, 16), 16, 0)
68            || test_innerproduct(RandomMat(6, 16), 7, 1)
69            || test_innerproduct(RandomMat(6, 5), 16, 1);
70 }
71 
test_innerproduct_2()72 static int test_innerproduct_2()
73 {
74     return 0
75            || test_innerproduct(RandomMat(1), 1, 1)
76            || test_innerproduct(RandomMat(2), 2, 0)
77            || test_innerproduct(RandomMat(8), 7, 1)
78            || test_innerproduct(RandomMat(8), 8, 0)
79            || test_innerproduct(RandomMat(15), 8, 1)
80            || test_innerproduct(RandomMat(15), 15, 1)
81            || test_innerproduct(RandomMat(16), 16, 0)
82            || test_innerproduct(RandomMat(16), 7, 1)
83            || test_innerproduct(RandomMat(5), 16, 0)
84            || test_innerproduct(RandomMat(32), 16, 1)
85            || test_innerproduct(RandomMat(12), 16, 0)
86            || test_innerproduct(RandomMat(16), 12, 1)
87            || test_innerproduct(RandomMat(24), 32, 1);
88 }
89 
90 #if NCNN_INT8
test_innerproduct_int8(const ncnn::Mat & a,int outch,int bias)91 static int test_innerproduct_int8(const ncnn::Mat& a, int outch, int bias)
92 {
93     ncnn::ParamDict pd;
94     pd.set(0, outch); // num_output
95     pd.set(1, bias);  // bias_term
96     pd.set(2, outch * a.w * a.h * a.c);
97     pd.set(8, 1); // int8_scale_term
98 
99     int activation_type = RAND() % 6; // 0 1 2 3 4 5
100     ncnn::Mat activation_params(2);
101     activation_params[0] = RandomFloat(-1, 0); // alpha
102     activation_params[1] = RandomFloat(0, 1);  // beta
103     pd.set(9, activation_type);
104     pd.set(10, activation_params);
105 
106     std::vector<ncnn::Mat> weights(bias ? 4 : 3);
107     const int k = a.w * a.h * a.c;
108     weights[0] = RandomMat(outch * k);
109     ncnn::Mat weight_scales = scales_mat(weights[0], outch, k, k);
110     ncnn::Mat input_scales = scales_mat(a, 1, k, k);
111 
112     if (bias)
113     {
114         weights[1] = RandomMat(outch);
115         weights[2] = weight_scales;
116         weights[3] = input_scales;
117     }
118     else
119     {
120         weights[1] = weight_scales;
121         weights[2] = input_scales;
122     }
123 
124     int flag = TEST_LAYER_DISABLE_GPU_TESTING;
125     int ret = test_layer<ncnn::InnerProduct>("InnerProduct", pd, weights, a, 0.001f, 0, flag);
126     if (ret != 0)
127     {
128         fprintf(stderr, "test_innerproduct_int8 failed a.dims=%d a=(%d %d %d) outch=%d bias=%d act=%d actparams=[%f,%f]\n", a.dims, a.w, a.h, a.c, outch, bias, activation_type, activation_params[0], activation_params[1]);
129     }
130 
131     return ret;
132 }
133 
test_innerproduct_3()134 static int test_innerproduct_3()
135 {
136     return 0
137            || test_innerproduct_int8(RandomMat(1, 3, 1), 1, 1)
138            || test_innerproduct_int8(RandomMat(3, 2, 2), 2, 1)
139            || test_innerproduct_int8(RandomMat(5, 3, 3), 3, 1)
140            || test_innerproduct_int8(RandomMat(7, 2, 3), 12, 1)
141            || test_innerproduct_int8(RandomMat(9, 3, 4), 4, 1)
142            || test_innerproduct_int8(RandomMat(2, 2, 7), 7, 1)
143            || test_innerproduct_int8(RandomMat(4, 3, 8), 3, 1)
144            || test_innerproduct_int8(RandomMat(6, 2, 8), 8, 1)
145            || test_innerproduct_int8(RandomMat(8, 3, 15), 15, 1)
146            || test_innerproduct_int8(RandomMat(7, 2, 16), 4, 1)
147            || test_innerproduct_int8(RandomMat(6, 3, 16), 16, 1);
148 }
149 #endif // NCNN_INT8
150 
test_innerproduct_gemm(const ncnn::Mat & a,int outch,int bias)151 static int test_innerproduct_gemm(const ncnn::Mat& a, int outch, int bias)
152 {
153     ncnn::ParamDict pd;
154     pd.set(0, outch);
155     pd.set(1, bias);
156     pd.set(2, outch * a.w);
157 
158     int activation_type = RAND() % 6;
159     ncnn::Mat activation_params(2);
160     activation_params[0] = RandomFloat(-1, 0);
161     activation_params[1] = RandomFloat(0, 1);
162     pd.set(9, activation_type);
163     pd.set(10, activation_params);
164 
165     std::vector<ncnn::Mat> weights(bias ? 2 : 1);
166     weights[0] = RandomMat(outch * a.w);
167     if (bias)
168         weights[1] = RandomMat(outch);
169 
170     int ret = test_layer<ncnn::InnerProduct>("InnerProduct", pd, weights, a);
171     if (ret != 0)
172     {
173         fprintf(stderr, "test_innerproduct_gemm failed a.dims=%d a=(%d %d %d) outch=%d bias=%d act=%d actparams=[%f,%f]\n", a.dims, a.w, a.h, a.c, outch, bias, activation_type, activation_params[0], activation_params[1]);
174     }
175 
176     return ret;
177 }
178 
test_innerproduct_4()179 static int test_innerproduct_4()
180 {
181     return 0
182            || test_innerproduct_gemm(RandomMat(1, 5), 1, 1)
183            || test_innerproduct_gemm(RandomMat(3, 2), 2, 0)
184            || test_innerproduct_gemm(RandomMat(9, 8), 7, 1)
185            || test_innerproduct_gemm(RandomMat(2, 8), 8, 0)
186            || test_innerproduct_gemm(RandomMat(13, 12), 8, 1)
187            || test_innerproduct_gemm(RandomMat(16, 12), 16, 0)
188            || test_innerproduct_gemm(RandomMat(11, 24), 8, 0)
189            || test_innerproduct_gemm(RandomMat(13, 24), 12, 1)
190            || test_innerproduct_gemm(RandomMat(15, 12), 20, 1)
191            || test_innerproduct_gemm(RandomMat(16, 12), 11, 1)
192            || test_innerproduct_gemm(RandomMat(19, 16), 16, 1)
193            || test_innerproduct_gemm(RandomMat(14, 15), 8, 1)
194            || test_innerproduct_gemm(RandomMat(17, 15), 12, 1)
195            || test_innerproduct_gemm(RandomMat(12, 16), 7, 1);
196 }
197 
198 #if NCNN_INT8
test_innerproduct_gemm_int8(const ncnn::Mat & a,int outch,int bias)199 static int test_innerproduct_gemm_int8(const ncnn::Mat& a, int outch, int bias)
200 {
201     ncnn::ParamDict pd;
202     pd.set(0, outch);
203     pd.set(1, bias);
204     pd.set(2, outch * a.w);
205     pd.set(8, 1); // int8_scale_term
206 
207     std::vector<ncnn::Mat> weights(bias ? 4 : 3);
208     const int k = a.w;
209     weights[0] = RandomMat(outch * k);
210     ncnn::Mat weight_scales = scales_mat(weights[0], outch, k, k);
211     ncnn::Mat input_scales = scales_mat(a, 1, k, k);
212 
213     if (bias)
214     {
215         weights[1] = RandomMat(outch);
216         weights[2] = weight_scales;
217         weights[3] = input_scales;
218     }
219     else
220     {
221         weights[1] = weight_scales;
222         weights[2] = input_scales;
223     }
224 
225     int flag = TEST_LAYER_DISABLE_GPU_TESTING;
226     int ret = test_layer<ncnn::InnerProduct>("InnerProduct", pd, weights, a, 0.001f, 0, flag);
227     if (ret != 0)
228     {
229         fprintf(stderr, "test_innerproduct_gemm_int8 failed a.dims=%d a=(%d %d %d) outch=%d bias=%d\n", a.dims, a.w, a.h, a.c, outch, bias);
230     }
231 
232     return ret;
233 }
234 
test_innerproduct_5()235 static int test_innerproduct_5()
236 {
237     return 0
238            || test_innerproduct_gemm_int8(RandomMat(1, 5), 1, 1)
239            || test_innerproduct_gemm_int8(RandomMat(3, 2), 2, 0)
240            || test_innerproduct_gemm_int8(RandomMat(9, 8), 7, 1)
241            || test_innerproduct_gemm_int8(RandomMat(2, 8), 8, 0)
242            || test_innerproduct_gemm_int8(RandomMat(13, 12), 8, 1)
243            || test_innerproduct_gemm_int8(RandomMat(16, 12), 16, 0)
244            || test_innerproduct_gemm_int8(RandomMat(4, 15), 8, 1)
245            || test_innerproduct_gemm_int8(RandomMat(6, 16), 16, 0)
246            || test_innerproduct_gemm_int8(RandomMat(12, 16), 7, 1);
247 }
248 #endif // NCNN_INT8
249 
main()250 int main()
251 {
252     SRAND(7767517);
253 
254 #if NCNN_INT8
255     return 0
256            || test_innerproduct_0()
257            || test_innerproduct_1()
258            || test_innerproduct_2()
259            || test_innerproduct_3()
260            || test_innerproduct_4()
261            || test_innerproduct_5();
262 #else
263     return 0
264            || test_innerproduct_0()
265            || test_innerproduct_1()
266            || test_innerproduct_2()
267            || test_innerproduct_4();
268 #endif
269 }
270