-
Notifications
You must be signed in to change notification settings - Fork 0
/
train_test_conv_net.cpp
271 lines (243 loc) · 9.97 KB
/
train_test_conv_net.cpp
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#include <emmintrin.h>
#include <math.h>
#include <sys/time.h>
#include <stdint.h>
#include <stdio.h>
#include <random>
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "static_image.h"
#include "dataloaders/cifar_loader.h"
#include "conv_net_params.h"
timeval t1, t2;
extern "C" {
#include "halide_conv_net.h"
}
void train(cv::Mat &trainX, cv::Mat &trainY, double reg, double learning_rate,
double momentum, double learning_rate_decay, int num_epochs);
int main(int argc, char **argv) {
// Load the data
cv::Mat trainX, testX;
cv::Mat trainY, testY;
trainX = cv::Mat::zeros(1024 * 3, 50000, CV_64FC1);
testX = cv::Mat::zeros(1024 * 3, 10000, CV_64FC1);
trainY = cv::Mat::zeros(1, 50000, CV_8UC1);
testX = cv::Mat::zeros(1, 10000, CV_8UC1);
read_CIFAR10(trainX, testX, trainY, testY, "./dataloaders");
// Compute mean of the data
cv::Mat mean_image = cv::Mat::zeros(1024 * 3, 1, CV_64FC1);
for(int i = 0; i < trainX.size[0]; i++)
for(int n = 0; n < trainX.size[1]; n++)
mean_image.at<double>(i, 0) += trainX.at<double>(i, n)/trainX.size[1];
// Subtract mean from data
for(int i = 0; i < trainX.size[0]; i++)
for(int n = 0; n < trainX.size[1]; n++)
trainX.at<double>(i, n) -= mean_image.at<double>(i, 0);
#ifdef SHOW_MEAN
// Create window
cv::namedWindow( "Mean Image" , cv::WINDOW_NORMAL );
cv::Mat mean_show = cv::Mat::zeros(32, 32, CV_8UC3);
for(int c = 0; c < 3; c++)
for(int i = 0; i < 32; i++)
for(int j = 0; j < 32; j++)
// The color channesl seem to be flipped
mean_show.at<cv::Vec3b>(i, j)[2-c] =
(unsigned char) mean_image.at<double>(c*32*32 + i*32 + j, 0);
for(;;) {
int c;
c = cv::waitKey(10);
if( (char)c == 27 )
{ break; }
imshow( "Mean Image", mean_show);
}
#endif
train(trainX, trainY, 0.001, 1e-4, 0.9, 0.95, 1);
return 0;
}
void train(cv::Mat &trainX, cv::Mat &trainY, double reg, double learning_rate,
double momentum, double learning_rate_decay, int num_epochs) {
// Training using stochaistic gradient descent
int num_validation = 1000;
int num_samples = trainX.size[1] - num_validation;
int iterations_per_epoch = num_samples/N;
int num_iterartions = num_epochs * iterations_per_epoch;
int epoch = 0;
std::default_random_engine generator;
std::uniform_int_distribution<int> dist_uni(0, num_samples - 1);
std::normal_distribution<double> dist_norm(0.0, 1.0);
// Declare inputs of the network. All the constants N, H and C are
// declared in the two_layer_net_params.h
// TODO make class for the two layer net and move all network
// specific code into the class. The trainer can then be independent
// of the model.
Image<double> data(32, 32, 3, N);
Image<unsigned char> labels(N);
Image<double> conv_W(f_W, f_H, CH, N_f);
Image<double> conv_W_cache(f_W, f_H, CH, N_f);
Image<double> conv_b(N_f);
Image<double> conv_b_cache(N_f);
Image<double> fc_W(8192, C);
Image<double> fc_W_cache(8192, C);
Image<double> fc_b(C);
Image<double> fc_b_cache(C);
// Initialize the weights
for ( int f = 0; f < N_f; f++) {
conv_b(f) = (double) 0;
conv_b_cache(f) = (double) 0;
for ( int c = 0; c < CH; c++)
for ( int h = 0; h < f_H; h++)
for ( int w = 0; w < f_W; w++) {
conv_W(w, h, c, f) = 0.00001 * dist_norm(generator);
conv_W_cache(w, h, c, f) = (double) 0;
}
}
for( int i = 0; i < C; i++) {
fc_b(i) = (double) 0;
fc_b_cache(i) = (double) 0;
for ( int j = 0; j < 8192; j++) {
fc_W(j, i) = 0.00001 * dist_norm(generator);
fc_W_cache(j, i) = (double) 0;
}
}
for (int it = 0; it < num_iterartions; it++) {
std::vector<int> indices;
// Collect batch size number of sample indices
// Sampling with replacement
for (int n = 0; n < N; n++) {
indices.push_back(dist_uni(generator));
}
// Load the data for the corresponding indices into Halide
// structures
for(int n = 0; n < N; n++) {
labels(n) = trainY.at<unsigned char>(0, indices[n]);
for(int c = 0; c < CH; c++)
for(int h = 0; h < D_H; h++)
for(int w = 0; w < D_W; w++)
data(w, h, c, n) = trainX.at<double>(D_W*D_H*c + h * D_W + w, indices[n]);
}
// Compute the loss and gradients
Image<double> probs(C, N), loss(1);
Image<double> dWconv(f_W, f_H, CH, N_f);
Image<double> dWfc(8192, C);
Image<double> dconv_b(N_f);
Image<double> dfc_b(C);
gettimeofday(&t1, NULL);
halide_conv_net(data, labels, conv_W, fc_W, conv_b, fc_b, reg,
probs, loss, dWconv, dWfc, dconv_b, dfc_b);
//halide_conv_net(data, labels, conv_W, fc_W, conv_b, fc_b, reg,
// probs, loss);
gettimeofday(&t2, NULL);
#ifdef SHOW_TIME
float time = (t2.tv_sec - t1.tv_sec) + (t2.tv_usec - t1.tv_usec) / 1000000.0f;
printf("Iteration %d time: %f\n", it, time);
#endif
// Update the weights
for( int i = 0; i < C; i++) {
// fc_b(i) += -learning_rate * dfc_b(i);
fc_b_cache(i) = momentum * fc_b_cache(i) - learning_rate * dfc_b(i);
fc_b(i) += fc_b_cache(i);
for ( int j = 0; j < 8192; j++) {
//fc_W(j, i) += -learning_rate * dWfc(j, i);
fc_W_cache(j, i) = momentum * fc_W_cache(j, i) -
learning_rate * dWfc(j, i);
fc_W(j, i) += fc_W_cache(j, i);
}
}
for ( int f = 0; f < N_f; f++) {
conv_b_cache(f) = momentum * conv_b_cache(f) -
learning_rate * dconv_b(f);
conv_b(f) += conv_b_cache(f);
for ( int c = 0; c < CH; c++)
for ( int h = 0; h < f_H; h++)
for ( int w = 0; w < f_W; w++) {
conv_W_cache(w, h, c, f) =
momentum * conv_W_cache(w, h, c, f) -
learning_rate * dWconv(w, h, c, f);
conv_W(w, h, c, f) += conv_W_cache(w, h, c, f);
}
}
// Periodically check training and validation accuracy
if (it%100 == 0) {
int train_correct = 0;
int val_correct = 0;
for(int n = 0; n < N; n++){
int max_prob_label = 0;
for(int c = 0; c < C; c++){
if(probs(c, n) > probs(max_prob_label, n))
max_prob_label = c;
}
if(max_prob_label == labels(n))
train_correct++;
}
Image<double> val_data(32, 32, 3, num_validation);
Image<unsigned char> val_labels(num_validation);
Image<double> val_probs(C, num_validation);
for(int n = 0; n < num_validation; n++) {
val_labels(n) = trainY.at<unsigned char>(0, num_samples + n);
for(int c = 0; c < CH; c++)
for(int h = 0; h < D_H; h++)
for(int w = 0; w < D_W; w++)
val_data(w, h, c, n) =
trainX.at<double>(D_W*D_H*c + h * D_W + w,
num_samples + n);
}
halide_conv_net(val_data, val_labels, conv_W, fc_W, conv_b, fc_b, reg,
val_probs, loss, dWconv, dWfc, dconv_b, dfc_b);
for(int n = 0; n < num_validation; n++){
int max_prob_label = 0;
for(int c = 0; c < C; c++){
if(val_probs(c, n) > val_probs(max_prob_label, n))
max_prob_label = c;
}
if(max_prob_label == val_labels(n))
val_correct++;
}
printf("Validation accuracy: %lf, Training accuracy: %lf, Loss: %lf\n",
((double)val_correct)/num_validation, ((double)train_correct)/N,
loss(0));
}
bool epoch_end = (it + 1) % iterations_per_epoch == 0;
if (it > 0 && epoch_end) {
learning_rate *= learning_rate_decay;
epoch += 1;
}
}
#ifdef SHOW_WEIGHTS
// Create window
cv::namedWindow( "Weights" , cv::WINDOW_NORMAL );
int sep = 1;
int grid_size = std::ceil(std::sqrt(N_f));
cv::Mat filter_show = cv::Mat::zeros(grid_size * (f_W + sep) -1,
grid_size * (f_H + sep) -1, CV_64FC3);
for(int n = 0; n < N_f; n++) {
int grid_loc_x = n/grid_size;
int grid_loc_y = n%grid_size;
double min_val = conv_W(0, 0, 0, n);
double max_val = conv_W(0, 0, 0, n);
for(int c = 0; c < CH; c++)
for(int i = 0; i < f_H; i++)
for(int j = 0; j < f_W; j++) {
if (conv_W(i, j, c, n) > max_val)
max_val = conv_W(i, j, c, n);
if (conv_W(i, j, c, n) < min_val)
min_val = conv_W(i, j, c, n);
}
for(int c = 0; c < CH; c++)
for(int i = 0; i < f_H; i++)
for(int j = 0; j < f_W; j++) {
// The color channesl seem to be flipped
double normalized = (conv_W(i, j, c, n) - min_val)/(max_val - min_val);
filter_show.at<cv::Vec3d>(grid_loc_x*(f_W + sep) + i,
grid_loc_y*(f_H +sep) + j)[2-c] = normalized;
}
}
for(;;) {
int c;
c = cv::waitKey(10);
if( (char)c == 27 )
{ break; }
imshow( "Weights", filter_show);
}
#endif
}