Hyunjun

simple_convnet_cpp 코드 추가

...@@ -26,5 +26,17 @@ test하는 부분만 골라내기 위해 python test 코드를 추가(test.py), simple_convnet ...@@ -26,5 +26,17 @@ test하는 부분만 골라내기 위해 python test 코드를 추가(test.py), simple_convnet
26 7. python test 폴더 추가 26 7. python test 폴더 추가
27 python test 폴더에는 test에 필요하지 않은 train 부분을 삭제함 27 python test 폴더에는 test에 필요하지 않은 train 부분을 삭제함
28 28
29 -8. make_img_py 추가
30 -이미지를 불러와 (32,32,3)의 크기로 resize한 후 input.txt에 저장함
...\ No newline at end of file ...\ No newline at end of file
29 +
30 +8. make_img.py 추가
31 +이미지를 불러와 (32,32,3)의 크기로 resize한 후 input.txt에 저장함
32 +
33 +
34 +9. simple_convnet_cpp 코드 추가
35 + 1) layers.hpp : Convolution, ReLu, Normalization, Pooling, DW_Conv등 각 layer가 구현
36 + 2) SimpleConvNet.hpp : 딥러닝 모델이 구현
37 + 3) input.txt : make_img.py코드로 만든 이미지를 (32,32,3)의 크기로 만들어 txt파일로 저장
38 + 4) pred.txt : 1개의 이미지만 넣으면 예측이 되지않아 dummy를 같이 읽어서 처리함. 출력은 되지않음
39 + 5) params.txt : 속도향상을 위해 params.pkl파일을 params.txt로 변환
40 + 6) main.cpp
41 + *c++ 컴파일러 버전 11이상
42 + *프로젝트 생성 시 sdl 검사 체크 해제
...\ No newline at end of file ...\ No newline at end of file
......
1 +#ifndef LAYERS_
2 +#define LAYERS_
3 +#include<vector>
4 +#include<cmath>
5 +// 3D Matrix
6 +struct Mat {
7 + int dim, row, col;
8 + std::vector< double > mat;
9 + Mat(int dim, int row, int col, std::vector< double > v) : dim(dim), row(row), col(col), mat(v) {};
10 +};
11 +
12 +// Mat 일차원으로 계산 + dimension 변수
13 +class Layer {
14 +public:
15 + virtual std::vector<Mat> forward(std::vector<Mat> &x) { return std::vector<Mat>(); }
16 +};
17 +
18 +// padding
19 +class Convolution : public Layer {
20 +private:
21 + std::vector<Mat> W;
22 + int stride, pad;
23 +public:
24 + Convolution() {};
25 + ~Convolution() {};
26 + Convolution(std::vector<Mat> W, int stride=1, int pad=0) : W(W), stride(stride), pad(pad) {};
27 +
28 + // Each image x conv with each w
29 + virtual std::vector<Mat> forward(std::vector<Mat> &x) {
30 + std::vector< Mat > out;
31 + int n, nw;
32 + for (n = 0; n < x.size(); n++) {
33 + std::vector<double>rev;
34 + for (nw = 0; nw < W.size(); nw++) {
35 + auto e = Convolution_(x[n], W[nw]);
36 + rev.insert(rev.end(), e.begin(), e.end());
37 + }
38 + int out_r = (x[n].row + 2 * pad - W[0].row) / stride + 1;
39 + int out_c = (x[n].col + 2 * pad - W[0].col) / stride + 1;
40 + out.push_back(Mat(nw, out_r, out_c, rev));
41 + }
42 + return out;
43 + }
44 +
45 + // Convolution x and W (both are 3-D Mat)
46 + std::vector<double> Convolution_(const Mat& x,const Mat& w) {
47 + std::vector<double> ret;
48 + int ndim = x.dim - w.dim + 1;
49 + for (int d = 0; d < x.dim - w.dim + 1; d++) {
50 + for (int r = -pad; r < x.row - w.row + 1 + pad; r++) {
51 + for (int c = -pad; c < x.col - w.col +1 +pad; c++) {
52 + ret.push_back(Convolution_(x, w, d, r, c));
53 + }
54 + }
55 + }
56 + return ret;
57 + }
58 +
59 + double Convolution_(const Mat& x, const Mat& w, int d, int r,int c) {
60 + double ret = 0, xx=0;
61 + int ds = w.col * w.row, rs = w.col;
62 + int dxs = x.col * x.row, rxs = x.col;
63 + for (int dd = 0; dd < w.dim; dd++) {
64 + for (int rr = 0; rr < w.row; rr++) {
65 + for (int cc = 0; cc < w.col; cc++) {
66 + if ((pad > 0) && (r + rr < 0 || c + cc < 0 || r + rr >= x.row || c + cc >= x.col))
67 + xx = 0;
68 + else
69 + xx = x.mat[(d + dd)*(dxs)+(r + rr)*rxs + (c + cc)];
70 + ret += xx * w.mat[dd*(ds)+rr*(rs)+cc];
71 + }
72 + }
73 + }
74 + return ret;
75 + }
76 +};
77 +
78 +// Depthwise Conv
79 +class DW_Convolution : public Layer {
80 +private:
81 + std::vector<Mat> W;
82 + int stride, pad;
83 +public:
84 + DW_Convolution() {};
85 + ~DW_Convolution() {};
86 + DW_Convolution(std::vector<Mat> W, int stride=1, int pad=0) : W(W), stride(stride), pad(pad) {};
87 +
88 + virtual std::vector<Mat> forward(std::vector<Mat> &x) {
89 + std::vector<Mat> out;
90 + int n, d;
91 + for (n = 0; n < x.size(); n++) {
92 + // Each dimension Conv with each filter
93 + std::vector<double> rev;
94 + for (d = 0; d < x[n].dim; d++) {
95 + std::vector<double> e = Convolution_(x[n], W[d], d);
96 + rev.insert(rev.end(), e.begin(), e.end());
97 + }
98 + int out_r = (x[n].row + 2 * pad - W[0].row) / stride + 1;
99 + int out_c = (x[n].col + 2 * pad - W[0].col) / stride + 1;
100 + out.push_back(Mat(d, out_r, out_c, rev));
101 + }
102 + return out;
103 + }
104 +
105 + std::vector<double> Convolution_(const Mat& x, const Mat& w, int d) {
106 + std::vector<double> out;
107 + int dd = d * x.col * x.row;
108 + for (int r = -pad; r < x.row - w.row + 1 + pad; r++) { // r+=stride
109 + for (int c = -pad; c < x.col - w.col + 1 + pad; c++) {
110 + out.push_back(Convolution_(x, w, dd, r, c));
111 + }
112 + }
113 + return out;
114 + }
115 +
116 + double Convolution_(const Mat& x, const Mat& w, int dd, int r, int c) {
117 + double ret = 0, xx=0;
118 + for (int rr = 0; rr < w.row; rr++) {
119 + for (int cc = 0; cc < w.col; cc++) {
120 + if ((pad > 0) && (r + rr < 0 || c + cc < 0 || r + rr >= x.row || c + cc >= x.col))
121 + xx = 0;
122 + else
123 + xx = x.mat[dd + (r + rr)*x.col + (c+cc)];
124 + ret += xx * w.mat[rr*w.col + cc];
125 + }
126 + }
127 + return ret;
128 + }
129 +};
130 +
131 +// n개의 이미지 같은 위치의 Row, col 값을 Normalization
132 +class LightNormalization : public Layer{
133 +public:
134 + virtual std::vector<Mat> forward(std::vector<Mat>& x) {
135 + std::vector<Mat> out;
136 + int dim = x[0].dim, row = x[0].row, col = x[0].col, nx = x.size();
137 + int ds = row*col;
138 + for (int d = 0; d < dim; d++) {
139 + double mu = 0, var=0, std, tmp; // mu : mean of x img each dim
140 + for (int r = 0; r < row; r++)
141 + for (int c = 0; c < col; c++)
142 + for (int n = 0; n < nx; n++)
143 + mu += x[n].mat[d*ds + r*col + c];
144 +
145 + mu = mu / (double)(row*col*nx);
146 +
147 + for (int r = 0; r < row; r++)
148 + for (int c = 0; c < col; c++)
149 + for (int n = 0; n < nx; n++) {
150 + tmp = x[n].mat[d*ds + r*col + c] - mu;
151 + var += (tmp*tmp);
152 + }
153 +
154 + var = var / (double)(row*col*nx);
155 + std = sqrt(var+10e-7);
156 + for (int r = 0; r < row; r++)
157 + for (int c = 0; c < col; c++)
158 + for (int n = 0; n < nx; n++)
159 + x[n].mat[d*ds + r*col + c] = (x[n].mat[d*ds + r*col + c] - mu) / std;
160 + }
161 + return x;
162 + }
163 +};
164 +
165 +class Relu : public Layer {
166 +public:
167 + virtual std::vector<Mat> forward(std::vector<Mat> &x) {
168 + int nx = x.size(), nm = x[0].dim * x[0].row * x[0].col;
169 + for (int n = 0; n < nx; n++)
170 + for (int i = 0; i < nm; i++)
171 + if (x[n].mat[i] < 0)
172 + x[n].mat[i] = 0;
173 + return x;
174 + }
175 +};
176 +
177 +class Pooling : public Layer{
178 +private:
179 + int pool_h, pool_w, stride, pad;
180 +public:
181 + Pooling() { pad = 0; };
182 + ~Pooling() {};
183 + Pooling(int pool_h, int pool_w, int stride=1, int pad=0) :pool_h(pool_h), pool_w(pool_w), stride(stride), pad(pad) {};
184 +
185 + virtual std::vector<Mat> forward(std::vector<Mat>& x) {
186 + std::vector<Mat> out;
187 + int n, d, nx = x.size();
188 + for (n = 0; n < nx; n++) {
189 + std::vector<double> rev;
190 + for (d = 0; d < x[n].dim; d++) {
191 + std::vector<double> e = MaxPooling_(x[n], d);
192 + rev.insert(rev.end(), e.begin(), e.end());
193 + }
194 + int out_h = (x[n].row + 2 * pad - pool_h) / stride + 1;
195 + int out_w = (x[n].col + 2 * pad - pool_w) / stride + 1;
196 + out.push_back(Mat(d, out_h, out_w, rev));
197 + }
198 + return out;
199 + }
200 +
201 + // Pooling each image
202 + std::vector<double> MaxPooling_(Mat& x, int d) {
203 + std::vector<double> out;
204 + int row = x.row, col = x.col;
205 + int dd = d * col * row;
206 + for (int r = -pad; r < row - pool_h + 1 + pad; r+=stride) {
207 + for (int c = -pad; c < col - pool_w + 1 + pad; c+=stride) {
208 + out.push_back(MaxPooling_(x, dd, r, c));
209 + }
210 + }
211 + return out;
212 + }
213 +
214 + // Pooling pool_w * pool_h
215 + double MaxPooling_(Mat& x, int dd, int r, int c) {
216 + double ret = 0, xx = 0;
217 + for (int rr = 0; rr < pool_h; rr++) {
218 + for (int cc = 0; cc < pool_w; cc++) {
219 + if ((pad > 0) && (r + rr < 0 || c + cc < 0 || r + rr >= x.row || c + cc >= x.col))
220 + xx = 0;
221 + else
222 + xx = x.mat[dd + (r + rr)*x.col + (c + cc)];
223 + if(ret < xx)
224 + ret = xx;
225 + }
226 + }
227 + return ret;
228 + }
229 +};
230 +
231 +class Affine : public Layer{
232 +private:
233 + std::vector<Mat> W;
234 +public:
235 + Affine() {}
236 + ~Affine() {}
237 + Affine(std::vector<Mat>& W) : W(W){}
238 +
239 + virtual std::vector<Mat> forward(std::vector<Mat>& x) {
240 + std::vector<Mat> out;
241 + int nx = x.size();
242 + for (int n = 0; n < nx; n++) {
243 + Mat e = Dot_(x[n]);
244 + out.push_back(e);
245 + }
246 + return out;
247 + }
248 +
249 + Mat Dot_(const Mat& x) {
250 + int dim = W[0].dim, row = W[0].row, col = W[0].col, nw = W.size();
251 + int size = dim*row*col;
252 + std::vector<double> ret(col);
253 +
254 + for (int c = 0; c < col; c++) {
255 + for (int n = 0; n < nw; n++) {
256 + ret[c] += W[n].mat[c] * x.mat[n];
257 + }
258 +
259 + }
260 + return Mat(col, 1, 1, ret);
261 + }
262 +};
263 +#endif
1 +#ifndef SIMPLECONV_
2 +#define SIMPLECONV_
3 +#include"Layers.hpp"
4 +#include<iostream>
5 +#include<cstdio>
6 +#include<string.h>
7 +#include<stdlib.h>
8 +struct input_dim {
9 + int d1, d2, d3;
10 + input_dim(int d1, int d2, int d3) :d1(d1), d2(d2), d3(d3) {};
11 +};
12 +
13 +struct conv_param {
14 + int fn1, fn2, fn3;
15 + int filtersize, pad, stride;
16 + conv_param(int ftnum1, int ftnum2, int ftnum3, int ftsize, int pad, int stride) :fn1(ftnum1),
17 + fn2(ftnum2), fn3(ftnum3), filtersize(ftsize), pad(pad), stride(stride) {};
18 +};
19 +
20 +class SimpleConvNet {
21 +private:
22 + std::vector< Layer* > layers;
23 +
24 + std::vector<Mat> W[7]; // weights
25 + std::vector<int> shape[7]; // shape of each weights
26 +public:
27 + SimpleConvNet() {}
28 + ~SimpleConvNet() {}
29 + SimpleConvNet(input_dim id, conv_param cp, int hidden_size=512, int output_size=10, bool pretrained=true) {
30 + if (pretrained)
31 + load_trained("params.txt");
32 +
33 + layers.push_back(new Convolution(W[0], 1, 1));
34 + layers.push_back(new LightNormalization());
35 + layers.push_back(new Relu());
36 + layers.push_back(new Pooling(2, 2, 2));
37 +
38 + layers.push_back(new Convolution(W[1], 1, 0));
39 + layers.push_back(new LightNormalization());
40 + layers.push_back(new Relu());
41 +
42 + layers.push_back(new DW_Convolution(W[2], 1, 1));
43 + layers.push_back(new LightNormalization());
44 + layers.push_back(new Relu());
45 + layers.push_back(new Pooling(2, 2, 2));
46 +
47 + layers.push_back(new Convolution(W[3], 1, 0));
48 + layers.push_back(new LightNormalization());
49 + layers.push_back(new Relu());
50 +
51 + layers.push_back(new DW_Convolution(W[4], 1, 1));
52 + layers.push_back(new LightNormalization());
53 + layers.push_back(new Relu());
54 + layers.push_back(new Pooling(2, 2, 2));
55 +
56 + layers.push_back(new Affine(W[5]));
57 + layers.push_back(new LightNormalization());
58 + layers.push_back(new Relu());
59 +
60 + layers.push_back(new Affine(W[6]));
61 + }
62 +
63 + std::vector< Mat > predict(std::vector<Mat>& x) {
64 + for (int i = 0; i < layers.size(); i++) {
65 + x = layers[i]->forward(x);
66 + }
67 + return x;
68 + }
69 +
70 + double accuracy(std::vector< std::vector< unsigned char > > x, std::vector< int > ans, int batch_size=100) {
71 + return 1.0;
72 + }
73 +
74 + std::vector<int> argmax(std::vector< Mat >& x) {
75 + std::vector<int> pred;
76 + for (int n = 0; n < x.size(); n++) {
77 + int pid = 0, pos;
78 + double pval = -1e9;
79 + for (int i = 0; i < x[n].mat.size(); i++) {
80 + if (pval < x[n].mat[i]) {
81 + pval = x[n].mat[i];
82 + pid = i;
83 + }
84 + }
85 + pred.push_back(pid);
86 + }
87 + return pred;
88 + }
89 +
90 + void load_trained(const char* filename="params.txt") {
91 + FILE *f = fopen(filename, "r");
92 + if (f == NULL) {
93 + printf("File not found\n");
94 + exit(1);
95 + }
96 + char line[10] = { 0 };
97 + int keynum;
98 + while (fscanf(f, "%s", line)==1) {
99 + char s[4][10] = { 0 };
100 + keynum = line[1] - '0' - 1;
101 +
102 + // get shape
103 + fscanf(f, "%s", s[0]);
104 + fscanf(f, "%s", s[1]);
105 + if (s[1][strlen(s[1]) - 1] != '\"') {
106 + fscanf(f, "%s", s[2]);
107 + fscanf(f, "%s", s[3]);
108 + }
109 +
110 + // nw = number of weights : shape[0]
111 + // size = input size of W[key]
112 + int size = 1, nw=0;
113 + for (int i = 0; i < 4; i++) {
114 + int val = 0;
115 + for (int j = 0; j < strlen(s[i]); j++) {
116 + if ('0' <= s[i][j] && s[i][j] <= '9') {
117 + val = 10 * val + (s[i][j] - '0');
118 + }
119 + }
120 + if (val) {
121 + shape[keynum].push_back(val);
122 + size *= val;
123 + if (nw == 0)
124 + nw = val;
125 + }
126 + }
127 + // Read data of W[key]
128 + int fsize = size / nw;
129 + double *mm = new double[fsize];
130 + for (int i = 0; i < size; i++) {
131 + fscanf(f, "%lf", &mm[i%fsize]);
132 + if (i%fsize == fsize - 1) {
133 + if(shape[keynum].size() == 2)
134 + W[keynum].push_back(Mat(1, 1, shape[keynum][1], std::vector<double>(mm, mm + fsize)));
135 + else if(shape[keynum].size() == 4)
136 + W[keynum].push_back(Mat(shape[keynum][1], shape[keynum][2],
137 + shape[keynum][3], std::vector<double>(mm, mm + fsize)));
138 + }
139 + }
140 + }
141 + printf("Trained weights loading done\n");
142 + }
143 +};
144 +#endif
This diff is collapsed. Click to expand it.
1 +#include"Layers.hpp"
2 +#include"SimpleConvNet.hpp"
3 +using namespace std;
4 +int main() {
5 +
6 + input_dim id = { 3, 32, 32 };
7 + conv_param cp = { 32,32,64, 3,1,1 };
8 + SimpleConvNet SCN(id, cp);
9 +
10 + freopen("input.txt", "r", stdin);
11 + vector<Mat> X;
12 + int nx = 1, dim = 3, row = 32, col = 32;
13 + double tmp;
14 + for (int i = 0; i < nx; i++) {
15 + vector<double> rev;
16 + for (int d = 0; d < dim; d++) {
17 + for (int r = 0; r < row; r++) {
18 + for (int c = 0; c < col; c++) {
19 + scanf("%lf", &tmp);
20 + rev.push_back(tmp);
21 + }
22 + }
23 + }
24 + X.push_back(Mat(dim, row, col, rev));
25 + }
26 + freopen("pred.txt", "r", stdin);
27 + nx = 2, dim = 3, row = 32, col = 32;
28 + for (int i = 0; i < nx; i++) {
29 + vector<double> rev;
30 + for (int d = 0; d < dim; d++) {
31 + for (int r = 0; r < row; r++) {
32 + for (int c = 0; c < col; c++) {
33 + scanf("%lf", &tmp);
34 + rev.push_back(tmp);
35 + }
36 + }
37 + }
38 + X.push_back(Mat(dim, row, col, rev));
39 + }
40 +
41 + auto x = SCN.predict(X);
42 +
43 + auto pred = SCN.argmax(x);
44 +
45 + int num = 0, pd;
46 +
47 + printf("predict : %d ", pred[0]);
48 + return 0;
49 +}
...\ No newline at end of file ...\ No newline at end of file
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.