/home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/histogram.tests.c
Line | Count | Source |
1 | | #include "case.h" |
2 | | #include "ccv_case.h" |
3 | | #include "ccv_nnc_case.h" |
4 | | #include <ccv.h> |
5 | | #include <nnc/ccv_nnc.h> |
6 | | #include <nnc/ccv_nnc_easy.h> |
7 | | #include "3rdparty/dsfmt/dSFMT.h" |
8 | | |
9 | | TEST_SETUP() |
10 | | { |
11 | | ccv_nnc_init(); |
12 | | } |
13 | | |
14 | | TEST_CASE("logarithmic histogram v.s. bins histogram") |
15 | 1 | { |
16 | 1 | ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 3000, 2000), 0); |
17 | 1 | ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 774 * 2), 0); |
18 | 1 | double v = 1e-12; |
19 | 1 | int i; |
20 | 775 | for (i = 0; v < 1e20; i++, v *= 1.1774 ) |
21 | 774 | { |
22 | 774 | h->data.f32[i + 774] = v; |
23 | 774 | h->data.f32[774 - i - 1] = -v; |
24 | 774 | } |
25 | 1 | dsfmt_t dsfmt; |
26 | 1 | dsfmt_init_gen_rand(&dsfmt, 1); |
27 | 6.00M | for (i = 0; i < 3000 * 2000; i++6.00M ) |
28 | 6.00M | a->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2000 - 1000; |
29 | 1 | a->data.f32[0] = NAN; |
30 | 1 | a->data.f32[1] = -FLT_MAX; |
31 | 1 | a->data.f32[2] = FLT_MAX; |
32 | 1 | a->data.f32[3] = 0; |
33 | 1 | a->data.f32[4] = 1e-20; |
34 | 1 | a->data.f32[5] = -1e-20; |
35 | 1 | a->data.f32[6] = 1e20 - 1e18; |
36 | 1 | a->data.f32[7] = -1e20 + 1e18; |
37 | 1 | ccv_nnc_tensor_t* const bl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 775 * 2), 0); |
38 | 1 | ccv_nnc_tensor_t* const bb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 775 * 2), 0); |
39 | 1 | ccv_nnc_tensor_t* const sl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0); |
40 | 1 | ccv_nnc_tensor_t* const sb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0); |
41 | 1 | ccv_nnc_cmd_exec(CMD_HISTOGRAM_LOG(), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(bl, sl), 0); |
42 | 1 | ccv_nnc_cmd_exec(CMD_HISTOGRAM_BINS(), ccv_nnc_no_hint, 0, TENSOR_LIST(a, h), TENSOR_LIST(bb, sb), 0); |
43 | 1.55k | for (i = 0; i < 775 * 2; i++1.55k ) |
44 | 1.55k | { |
45 | 1.55k | const int sum = bb->data.i32[i] + bl->data.i32[i]; |
46 | 1.55k | const float tol = sum > 10 ? fabsf((float)(bl->data.i32[i] - bb->data.i32[i])) / (float)sum232 : abs(bl->data.i32[i] - bb->data.i32[i])1.31k ; |
47 | 1.55k | REQUIRE(tol < 0.1, "should be smaller than tolerance for bl->data.i32[%d](%d), bb->data.i32[%d](%d)", i, bl->data.i32[i], i, bb->data.i32[i]); |
48 | 1.55k | } |
49 | 1 | REQUIRE_EQ(sl->data.f32[0], -FLT_MAX, "should be equal to the minimal"); |
50 | 1 | REQUIRE_EQ(sl->data.f32[1], FLT_MAX, "should be equal to the maximal"); |
51 | 1 | REQUIRE(isnan(sl->data.f32[2]), "sum is nan"); |
52 | 1 | REQUIRE(isnan(sl->data.f32[3]), "sum of squares is nan"); |
53 | 1 | REQUIRE_EQ(bb->data.i32[0], 1, "should have 1 smaller than minimal value"); |
54 | 1 | REQUIRE_EQ(bb->data.i32[774 * 2], 1, "should have 1 larger than maximal value"); |
55 | 1 | REQUIRE_EQ(bb->data.i32[775 * 2 - 1], 1, "should have 1 nan"); |
56 | 1 | REQUIRE_EQ(bb->data.i32[774 * 2 - 1], 1, "should have 1 in the range (1e20 / 1.1, 1e20)"); |
57 | 1 | REQUIRE_EQ(bb->data.i32[1], 1, "should have 1 in the range (-1e20, -1e20 / 1.1)"); |
58 | 1 | REQUIRE_EQ(bb->data.i32[774], 3, "should have 3 in the range (-1e-12, 1e-12)"); |
59 | 1 | REQUIRE_EQ(bl->data.i32[0], 1, "should have 1 smaller than minimal value"); |
60 | 1 | REQUIRE_EQ(bl->data.i32[774 * 2], 1, "should have 1 larger than maximal value"); |
61 | 1 | REQUIRE_EQ(bl->data.i32[775 * 2 - 1], 1, "should have 1 nan"); |
62 | 1 | REQUIRE_EQ(bl->data.i32[774 * 2 - 1], 1, "should have 1 in the range (1e20 / 1.1, 1e20)"); |
63 | 1 | REQUIRE_EQ(bl->data.i32[1], 1, "should have 1 in the range (-1e20, -1e20 / 1.1)"); |
64 | 1 | REQUIRE_EQ(bl->data.i32[774], 3, "should have 3 in the range (-1e-12, 1e-12)"); |
65 | 1 | REQUIRE_TENSOR_EQ(sl, sb, "computed stats should be equal"); |
66 | 1 | ccv_nnc_tensor_free(a); |
67 | 1 | ccv_nnc_tensor_free(h); |
68 | 1 | ccv_nnc_tensor_free(bl); |
69 | 1 | ccv_nnc_tensor_free(bb); |
70 | 1 | ccv_nnc_tensor_free(sl); |
71 | 1 | ccv_nnc_tensor_free(sb); |
72 | 1 | } |
73 | | |
74 | | TEST_CASE("even histogram v.s. bins histogram") |
75 | 1 | { |
76 | 1 | ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 3000, 2000), 0); |
77 | 1 | ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 201), 0); |
78 | 1 | int i; |
79 | 202 | for (i = 0; i < 201; i++201 ) |
80 | 201 | { |
81 | 201 | h->data.f32[i] = (i - 100) * 10; |
82 | 201 | } |
83 | 1 | dsfmt_t dsfmt; |
84 | 1 | dsfmt_init_gen_rand(&dsfmt, 1); |
85 | 6.00M | for (i = 0; i < 3000 * 2000; i++6.00M ) |
86 | 6.00M | a->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2000 - 1000; |
87 | 1 | a->data.f32[0] = NAN; |
88 | 1 | a->data.f32[1] = -FLT_MAX; |
89 | 1 | a->data.f32[2] = FLT_MAX; |
90 | 1 | a->data.f32[3] = 0; |
91 | 1 | a->data.f32[4] = 1e-20; |
92 | 1 | a->data.f32[5] = -1e-20; |
93 | 1 | a->data.f32[6] = 1e20 - 1e18; |
94 | 1 | a->data.f32[7] = -1e20 + 1e18; |
95 | 1 | ccv_nnc_tensor_t* const bl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 203), 0); |
96 | 1 | ccv_nnc_tensor_t* const bb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 203), 0); |
97 | 1 | ccv_nnc_tensor_t* const sl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0); |
98 | 1 | ccv_nnc_tensor_t* const sb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0); |
99 | 1 | ccv_nnc_cmd_exec(CMD_HISTOGRAM_EVEN(200, -1000, 1000), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(bl, sl), 0); |
100 | 1 | ccv_nnc_cmd_exec(CMD_HISTOGRAM_BINS(), ccv_nnc_no_hint, 0, TENSOR_LIST(a, h), TENSOR_LIST(bb, sb), 0); |
101 | 204 | for (i = 0; i < 203; i++203 ) |
102 | 203 | { |
103 | 203 | const int diff = abs(bb->data.i32[i] - bl->data.i32[i]); |
104 | 203 | REQUIRE(diff < 5, "differences should be smaller than 5 for bl->data.i32[%d](%d), bb->data.i32[%d](%d)", i, bl->data.i32[i], i, bb->data.i32[i]); |
105 | 203 | } |
106 | 1 | REQUIRE_EQ(sl->data.f32[0], -FLT_MAX, "should be equal to the minimal"); |
107 | 1 | REQUIRE_EQ(sl->data.f32[1], FLT_MAX, "should be equal to the maximal"); |
108 | 1 | REQUIRE(isnan(sl->data.f32[2]), "sum is nan"); |
109 | 1 | REQUIRE(isnan(sl->data.f32[3]), "sum of squares is nan"); |
110 | 1 | REQUIRE_EQ(bb->data.i32[0], 2, "should have 2 smaller than minimal value"); |
111 | 1 | REQUIRE_EQ(bb->data.i32[201], 2, "should have 2 larger than maximal value"); |
112 | 1 | REQUIRE_EQ(bb->data.i32[202], 1, "should have 1 nan"); |
113 | 1 | REQUIRE_EQ(bl->data.i32[0], 2, "should have 2 smaller than minimal value"); |
114 | 1 | REQUIRE_EQ(bl->data.i32[201], 2, "should have 2 larger than maximal value"); |
115 | 1 | REQUIRE_EQ(bl->data.i32[202], 1, "should have 1 nan"); |
116 | 1 | REQUIRE_TENSOR_EQ(sl, sb, "computed stats should be equal"); |
117 | 1 | ccv_nnc_tensor_free(a); |
118 | 1 | ccv_nnc_tensor_free(h); |
119 | 1 | ccv_nnc_tensor_free(bl); |
120 | 1 | ccv_nnc_tensor_free(bb); |
121 | 1 | ccv_nnc_tensor_free(sl); |
122 | 1 | ccv_nnc_tensor_free(sb); |
123 | 1 | } |
124 | | |
125 | | TEST_CASE("logarithmic histogram v.s. bins histogram on tensor view") |
126 | 1 | { |
127 | 1 | ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 30, 100, 20, 100), 0); |
128 | 1 | ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 774 * 2), 0); |
129 | 1 | double v = 1e-12; |
130 | 1 | int i; |
131 | 775 | for (i = 0; v < 1e20; i++, v *= 1.1774 ) |
132 | 774 | { |
133 | 774 | h->data.f32[i + 774] = v; |
134 | 774 | h->data.f32[774 - i - 1] = -v; |
135 | 774 | } |
136 | 1 | dsfmt_t dsfmt; |
137 | 1 | dsfmt_init_gen_rand(&dsfmt, 1); |
138 | 6.00M | for (i = 0; i < 3000 * 2000; i++6.00M ) |
139 | 6.00M | a->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2000 - 1000; |
140 | 1 | ccv_nnc_tensor_view_t* const av = ccv_nnc_tensor_view_new(a, CPU_TENSOR_NCHW(32F, 30, 20, 20, 40), DIM_ALLOC(0, 10, 0, 20), DIM_ALLOC(100 * 20 * 100, 20 * 100, 100, 1)); |
141 | | // All these skipped. |
142 | 1 | a->data.f32[0] = NAN; |
143 | 1 | a->data.f32[1] = -FLT_MAX; |
144 | 1 | a->data.f32[2] = FLT_MAX; |
145 | 1 | a->data.f32[3] = 0; |
146 | 1 | a->data.f32[4] = 1e-20; |
147 | 1 | a->data.f32[5] = -1e-20; |
148 | 1 | a->data.f32[6] = 1e20 - 1e18; |
149 | 1 | a->data.f32[7] = -1e20 + 1e18; |
150 | 1 | ccv_nnc_tensor_t* const bl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 775 * 2), 0); |
151 | 1 | ccv_nnc_tensor_t* const bb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 775 * 2), 0); |
152 | 1 | ccv_nnc_tensor_t* const sl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0); |
153 | 1 | ccv_nnc_tensor_t* const sb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0); |
154 | 1 | ccv_nnc_cmd_exec(CMD_HISTOGRAM_LOG(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av), TENSOR_LIST(bl, sl), 0); |
155 | 1 | ccv_nnc_cmd_exec(CMD_HISTOGRAM_BINS(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av, h), TENSOR_LIST(bb, sb), 0); |
156 | 1.55k | for (i = 0; i < 775 * 2; i++1.55k ) |
157 | 1.55k | { |
158 | 1.55k | const int sum = bb->data.i32[i] + bl->data.i32[i]; |
159 | 1.55k | const float tol = sum > 10 ? fabsf((float)(bl->data.i32[i] - bb->data.i32[i])) / (float)sum174 : abs(bl->data.i32[i] - bb->data.i32[i])1.37k ; |
160 | 1.55k | REQUIRE(tol < 0.1, "should be smaller than tolerance for bl->data.i32[%d](%d), bb->data.i32[%d](%d)", i, bl->data.i32[i], i, bb->data.i32[i]); |
161 | 1.55k | } |
162 | 1 | REQUIRE(sl->data.f32[0] < -990, "minimal should be close to the edge"); |
163 | 1 | REQUIRE(sl->data.f32[1] > 990, "maximal should be close to the edge"); |
164 | 1 | REQUIRE(sl->data.f32[2] / (float)ccv_nnc_tensor_count(av->info) < 1, "sum should be close to 0"); |
165 | 1 | REQUIRE_EQ_WITH_TOLERANCE(sl->data.f32[3] / (float)ccv_nnc_tensor_count(av->info), 2000 * 2000 / 12, 1e3, "sum of squares should be close to its expected value in uniform distribution"); |
166 | 1 | REQUIRE_EQ(bb->data.i32[0], 0, "should've skipped all manual numbers"); |
167 | 1 | REQUIRE_EQ(bb->data.i32[774 * 2], 0, "should've skipped all manual numbers"); |
168 | 1 | REQUIRE_EQ(bb->data.i32[775 * 2 - 1], 0, "should've skipped all manual numbers"); |
169 | 1 | REQUIRE_EQ(bb->data.i32[774 * 2 - 1], 0, "should've skipped all manual numbers"); |
170 | 1 | REQUIRE_EQ(bb->data.i32[1], 0, "should've skipped all manual numbers"); |
171 | 1 | REQUIRE_EQ(bb->data.i32[774], 0, "should've skipped all manual numbers"); |
172 | 1 | REQUIRE_EQ(bl->data.i32[0], 0, "should've skipped all manual numbers"); |
173 | 1 | REQUIRE_EQ(bl->data.i32[774 * 2], 0, "should've skipped all manual numbers"); |
174 | 1 | REQUIRE_EQ(bl->data.i32[775 * 2 - 1], 0, "should've skipped all manual numbers"); |
175 | 1 | REQUIRE_EQ(bl->data.i32[774 * 2 - 1], 0, "should've skipped all manual numbers"); |
176 | 1 | REQUIRE_EQ(bl->data.i32[1], 0, "should've skipped all manual numbers"); |
177 | 1 | REQUIRE_EQ(bl->data.i32[774], 0, "should've skipped all manual numbers"); |
178 | 1 | REQUIRE_TENSOR_EQ(sl, sb, "computed stats should be equal"); |
179 | 1 | ccv_nnc_tensor_free(a); |
180 | 1 | ccv_nnc_tensor_view_free(av); |
181 | 1 | ccv_nnc_tensor_free(h); |
182 | 1 | ccv_nnc_tensor_free(bl); |
183 | 1 | ccv_nnc_tensor_free(bb); |
184 | 1 | ccv_nnc_tensor_free(sl); |
185 | 1 | ccv_nnc_tensor_free(sb); |
186 | 1 | } |
187 | | |
188 | | TEST_CASE("even histogram v.s. bins histogram on tensor view") |
189 | 1 | { |
190 | 1 | ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 30, 100, 20, 100), 0); |
191 | 1 | ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 201), 0); |
192 | 1 | int i; |
193 | 202 | for (i = 0; i < 201; i++201 ) |
194 | 201 | { |
195 | 201 | h->data.f32[i] = (i - 100) * 10; |
196 | 201 | } |
197 | 1 | dsfmt_t dsfmt; |
198 | 1 | dsfmt_init_gen_rand(&dsfmt, 1); |
199 | 6.00M | for (i = 0; i < 3000 * 2000; i++6.00M ) |
200 | 6.00M | a->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2000 - 1000; |
201 | 1 | ccv_nnc_tensor_view_t* const av = ccv_nnc_tensor_view_new(a, CPU_TENSOR_NCHW(32F, 30, 20, 20, 40), DIM_ALLOC(0, 10, 0, 20), DIM_ALLOC(100 * 20 * 100, 20 * 100, 100, 1)); |
202 | 1 | a->data.f32[0] = NAN; |
203 | 1 | a->data.f32[1] = -FLT_MAX; |
204 | 1 | a->data.f32[2] = FLT_MAX; |
205 | 1 | a->data.f32[3] = 0; |
206 | 1 | a->data.f32[4] = 1e-20; |
207 | 1 | a->data.f32[5] = -1e-20; |
208 | 1 | a->data.f32[6] = 1e20 - 1e18; |
209 | 1 | a->data.f32[7] = -1e20 + 1e18; |
210 | 1 | ccv_nnc_tensor_t* const bl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 203), 0); |
211 | 1 | ccv_nnc_tensor_t* const bb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32S, 203), 0); |
212 | 1 | ccv_nnc_tensor_t* const sl = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0); |
213 | 1 | ccv_nnc_tensor_t* const sb = ccv_nnc_tensor_new(0, CPU_TENSOR_NCHW(32F, 4), 0); |
214 | 1 | ccv_nnc_cmd_exec(CMD_HISTOGRAM_EVEN(200, -1000, 1000), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av), TENSOR_LIST(bl, sl), 0); |
215 | 1 | ccv_nnc_cmd_exec(CMD_HISTOGRAM_BINS(), ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)av, h), TENSOR_LIST(bb, sb), 0); |
216 | 204 | for (i = 0; i < 203; i++203 ) |
217 | 203 | { |
218 | 203 | const int diff = abs(bb->data.i32[i] - bl->data.i32[i]); |
219 | 203 | REQUIRE(diff < 5, "differences should be smaller than 5 for bl->data.i32[%d](%d), bb->data.i32[%d](%d)", i, bl->data.i32[i], i, bb->data.i32[i]); |
220 | 203 | } |
221 | 1 | REQUIRE(sl->data.f32[0] < -990, "minimal should be close to the edge"); |
222 | 1 | REQUIRE(sl->data.f32[1] > 990, "maximal should be close to the edge"); |
223 | 1 | REQUIRE(sl->data.f32[2] / (float)ccv_nnc_tensor_count(av->info) < 1, "sum should be close to 0"); |
224 | 1 | REQUIRE_EQ_WITH_TOLERANCE(sl->data.f32[3] / (float)ccv_nnc_tensor_count(av->info), 2000 * 2000 / 12, 1e3, "sum of squares should be close to its expected value in uniform distribution"); |
225 | 1 | REQUIRE_EQ(bb->data.i32[0], 0, "should've skipped all manual numbers"); |
226 | 1 | REQUIRE_EQ(bb->data.i32[201], 0, "should've skipped all manual numbers"); |
227 | 1 | REQUIRE_EQ(bb->data.i32[202], 0, "should've skipped all manual numbers"); |
228 | 1 | REQUIRE_EQ(bl->data.i32[0], 0, "should've skipped all manual numbers"); |
229 | 1 | REQUIRE_EQ(bl->data.i32[201], 0, "should've skipped all manual numbers"); |
230 | 1 | REQUIRE_EQ(bl->data.i32[202], 0, "should've skipped all manual numbers"); |
231 | 1 | REQUIRE_TENSOR_EQ(sl, sb, "computed stats should be equal"); |
232 | 1 | ccv_nnc_tensor_free(a); |
233 | 1 | ccv_nnc_tensor_view_free(av); |
234 | 1 | ccv_nnc_tensor_free(h); |
235 | 1 | ccv_nnc_tensor_free(bl); |
236 | 1 | ccv_nnc_tensor_free(bb); |
237 | 1 | ccv_nnc_tensor_free(sl); |
238 | 1 | ccv_nnc_tensor_free(sb); |
239 | 1 | } |
240 | | |
241 | | #include "case_main.h" |