-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest.cpp
More file actions
241 lines (199 loc) · 8.24 KB
/
Copy pathtest.cpp
File metadata and controls
241 lines (199 loc) · 8.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#include <stdio.h>
#include <jsoncpp/json/json.h>
#include <fstream>
#include <iostream>
#include <math.h>
#include "convolution.h"
#include "logging.h"
#define TESTS_2D 6 // MAX: 6
#define TESTS_3D 7 // MAX: 7
#define TESTS_MAXPOOL 3 // MAX: 3
#define TESTS_FULLCONN 2 // MAX: 2
#define MAX_ERR 0.01 // value for the max error between any expected and calcualted convolution value
static bool run_test_conv(const char* f_name, const int padding);
static bool run_test_maxpool(const char* f_name);
static bool run_test_fullconn(const char* f_name);
int main(){
system("python3 generate_tests.py"); // runs the py file to generate the test cases
// test cases for 2d convolution
if(TESTS_2D){
const char* f_names_2d[] = {"keys/test_conv_0.json", "keys/test_conv_1.json", "keys/test_conv_2.json",
"keys/test_conv_3.json", "keys/test_conv_4.json", "keys/test_conv_5.json"};
LOG_BLUE("Running test cases for 2d convolution: \n");
for (int i = 0; i < TESTS_2D; i++) {
if( run_test_conv(f_names_2d[i], 0)) {
LOG_GREEN("Test %02d Passed: %s\n", i, f_names_2d[i]);
}
else{
LOG_RED("Test %02d Failed: %s\n", i, f_names_2d[i]);
}
}
}
// test cases for 3d convolution
if (TESTS_3D) {
LOG_BLUE("Running test cases for 3d convolution: \n");
const char* f_names_3d[] = {"keys/test_conv3D_0.json", "keys/test_conv3D_1.json", "keys/test_conv3D_2.json",
"keys/test_conv3D_3.json", "keys/test_conv3D_4.json", "keys/test_conv3D_5.json",
"keys/test_conv3D_6.json"};
for (int i = 0; i < TESTS_3D; i++) {
bool success = (i < 6) ? run_test_conv(f_names_3d[i], 0) : run_test_conv(f_names_3d[i], 0); // meant for changing padding in the future
if( success ) {
LOG_GREEN("Test %02d Passed: %s\n", i, f_names_3d[i]);
}
else{
LOG_RED("Test %02d Failed: %s\n", i, f_names_3d[i]);
}
}
}
// test cases for max pooling
if(TESTS_MAXPOOL) {
LOG_BLUE("Running test cases for max pooling: \n");
const char* f_names_maxpool[] = {"keys/test_maxpool_0.json", "keys/test_maxpool_alexnet_1.json", "keys/test_maxpool_alexnet_3.json"};
for (int i = 0; i < TESTS_MAXPOOL; i++) {
if( run_test_maxpool(f_names_maxpool[i])) {
LOG_GREEN("Test %02d Passed: %s\n", i, f_names_maxpool[i]);
}
else{
LOG_RED("Test %02d Failed: %s\n", i, f_names_maxpool[i]);
}
}
}
// test cases for fully connected layer
if(TESTS_FULLCONN){
LOG_BLUE("Running test cases for fully connected: \n");
const char* f_names_fullconn[] = {"keys/test_fullconn_0.json", "keys/test_fullconn_1.json"};
for (int i = 0; i < TESTS_FULLCONN; i++) {
if( run_test_fullconn(f_names_fullconn[i])) {
LOG_GREEN("Test %02d Passed: %s\n", i, f_names_fullconn[i]);
}
else{
LOG_RED("Test %02d Failed: %s\n", i, f_names_fullconn[i]);
}
}
}
return 0;
}
static Layer* json_to_layer(Json::Value mat){
int c = mat["shape"][0].asInt();
int m = mat["shape"][1].asInt();
int n = mat["shape"][2].asInt();
// write each value fron the JSON obj to the Layer struct
// printf("(c, m, n) == (%d, %d, %d)\n", c, m, n);
Layer* layer = make_layer(m, n, c);
for(int chan = 0; chan < c; chan++){
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
set_weight(mat["data"][chan][i][j].asDouble(), layer, chan, i, j);
}
}
}
return layer;
}
static bool is_valid_err(Layer* a, Layer* b, double err){
// finds the % difference between all the expected and calculated values
// if any of them are > MAX_ERR, function reutrns false
double w1, w2, diff;
bool is_same = (a->m == b->m) && (a->n == b->n) && (a->c == b->c);
for(int chan = 0; is_same && chan < a->c; chan++){
for(int i = 0; is_same && i < a->m; i++){
for(int j = 0; is_same && j < a->n; j++){
w1 = get_weight(a, chan, i, j);
w2 = get_weight(b, chan, i, j);
diff = fabs(w1 - w2) / fabs(w1);
is_same &= (diff < err);
}
}
}
return is_same;
}
static bool run_test_fullconn(const char* f_name){
// reads JSON file and stores it
Json::Value data;
std::ifstream data_file(f_name, std::ifstream::binary);
data_file >> data;
data_file.close();
// read from JSON and convert to layer structure
Layer* mat = json_to_layer(data["matrix"]);
DBG_PRINT_LAYER_SML(mat, 0);
DBG_PRINT_ARR_SML(mat->weights, mat->m * mat->n * mat->c);
Layer* w_and_b = json_to_layer(data["w_and_b"]);
DBG_PRINT_LAYER_SML(w_and_b, 0);
Layer* fullconn_key = json_to_layer(data["output"]);
Layer* fullconn_calc = make_layer(w_and_b->n / 2, 1, 1);
make_fully_connected(mat, w_and_b, fullconn_calc);
DBG_PRINTF("\n");
DBG_PRINTF("\nkey fully connected: \n");
DBG_PRINT_LAYER_SML(fullconn_key, 0);
DBG_PRINTF("calculated fully connected: \n");
DBG_PRINT_LAYER_SML(fullconn_calc, 0);
// calculate the error between the calculation and the key
bool is_same = is_valid_err(fullconn_key, fullconn_calc, MAX_ERR);
// mem cleanup
destroy_layer(w_and_b);
destroy_layer(mat);
destroy_layer(fullconn_key);
destroy_layer(fullconn_calc);
return is_same;
}
static bool run_test_maxpool(const char* f_name){
// reads JSON file and stores it
Json::Value data;
std::ifstream data_file(f_name, std::ifstream::binary);
data_file >> data;
data_file.close();
// read from JSON and convert to layer structure
Layer* mat = json_to_layer(data["matrix"]);
DBG_PRINT_LAYER_SML(mat, 0);
int window_size_m = data["pool"]["shape"][0].asInt();
int window_size_n = data["pool"]["shape"][0].asInt();
int stride = data["pool"]["stride"].asInt();
Layer* pool_key = json_to_layer(data["output"]);
Layer* pool_calc = make_layer((mat->m - window_size_m) / stride + 1,
(mat->n - window_size_n) / stride + 1,
mat->c);
make_max_pooling(mat, window_size_m, window_size_n, stride, pool_calc);
DBG_PRINTF("\n");
DBG_PRINTF("\nkey pool: \n");
DBG_PRINT_LAYER_SML(pool_key, 0);
DBG_PRINTF("calculated pool: \n");
DBG_PRINT_LAYER_SML(pool_calc, 0);
// calculate the error between the calculation and the key
bool is_same = is_valid_err(pool_key, pool_calc, MAX_ERR);
// mem cleanup
destroy_layer(mat);
destroy_layer(pool_key);
destroy_layer(pool_calc);
return is_same;
}
static bool run_test_conv(const char* f_name, const int padding){
// reads JSON file and stores it
Json::Value data;
std::ifstream data_file(f_name, std::ifstream::binary);
data_file >> data;
data_file.close();
// read from JSON and convert to layer structure
Layer* mat = json_to_layer(data["matrix"]);
DBG_PRINT_LAYER_SML(mat, 0);
Layer* ker = json_to_layer(data["kernel"]);
DBG_PRINT_LAYER_SML(ker, 0);
DBG_PRINTF("(%d, %d, %d)\n", ker->c, ker->m, ker->n);
Layer* conv_key = json_to_layer(data["convolution"]);
Layer* conv_calc = make_layer(mat->m - ker->m + 1 + 2 * padding,
mat->n - ker->n + 1 + 2 * padding,
mat->c - ker->c + 1);
make_convolution(mat, ker, padding, conv_calc);
DBG_PRINTF("\n");
DBG_PRINTF("\nkey convolution: \n");
DBG_PRINT_LAYER_SML(conv_key, 0);
DBG_PRINTF("calculated convolution: \n");
DBG_PRINT_LAYER_SML(conv_calc, 0);
DBG_PRINTF("(%d, %d, %d)\n", conv_calc->c, conv_calc->m, conv_calc->n);
// calculate the error between the calculation and the key
bool is_same = is_valid_err(conv_key, conv_calc, MAX_ERR);
// mem cleanup
destroy_layer(ker);
destroy_layer(mat);
destroy_layer(conv_key);
destroy_layer(conv_calc);
return is_same;
}