From 796e464d43274415603e6f27a4bb81b6c1ef8cf3 Mon Sep 17 00:00:00 2001 From: Joseph Redmon Date: Fri, 24 Jan 2014 14:49:02 -0800 Subject: [PATCH] Connected layers use matrices --- Makefile | 2 +- dog.jpg | Bin 44245 -> 22323 bytes src/connected_layer.c | 109 +++++++++++++++++++++++++++++------------- src/image.c | 1 + src/mini_blas.c | 80 +++++++++++++++++++++++++++++++ src/mini_blas.h | 10 ++++ src/tests.c | 84 ++++++++++++++++++++++++++++++-- 7 files changed, 249 insertions(+), 37 deletions(-) create mode 100644 src/mini_blas.c create mode 100644 src/mini_blas.h diff --git a/Makefile b/Makefile index 44c930f8..415c5226 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ endif LDFLAGS=`pkg-config --libs opencv` -lm VPATH=./src/ -OBJ=network.o image.o tests.o convolutional_layer.o connected_layer.o maxpool_layer.o activations.o list.o option_list.o parser.o utils.o data.o matrix.o softmax_layer.o +OBJ=network.o image.o tests.o convolutional_layer.o connected_layer.o maxpool_layer.o activations.o list.o option_list.o parser.o utils.o data.o matrix.o softmax_layer.o mini_blas.o all: cnn diff --git a/dog.jpg b/dog.jpg index 16d05ab17c401c39d9d841d931ddb92cd65796f4..3b9f7abdd8b2315e3fbb6f99e7db08004726428d 100644 GIT binary patch delta 22027 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 diff --git a/src/connected_layer.c b/src/connected_layer.c index 0344c71a..6871b2ee 100644 --- a/src/connected_layer.c +++ b/src/connected_layer.c @@ -1,5 +1,6 @@ #include "connected_layer.h" #include "utils.h" +#include "mini_blas.h" #include #include @@ -35,55 +36,99 @@ connected_layer *make_connected_layer(int inputs, int outputs, ACTIVATION activa return layer; } +void update_connected_layer(connected_layer layer, double step, double momentum, double decay) +{ + int i; + for(i = 0; i < layer.outputs; ++i){ + layer.bias_momentum[i] = step*(layer.bias_updates[i]) + momentum*layer.bias_momentum[i]; + layer.biases[i] += layer.bias_momentum[i]; + } + for(i = 0; i < layer.outputs*layer.inputs; ++i){ + layer.weight_momentum[i] = step*(layer.weight_updates[i] - decay*layer.weights[i]) + momentum*layer.weight_momentum[i]; + layer.weights[i] += layer.weight_momentum[i]; + } + memset(layer.bias_updates, 0, layer.outputs*sizeof(double)); + memset(layer.weight_updates, 0, layer.outputs*layer.inputs*sizeof(double)); +} + void forward_connected_layer(connected_layer layer, double *input) { - int i, j; + int i; + memcpy(layer.output, layer.biases, layer.outputs*sizeof(double)); + int m = 1; + int k = layer.inputs; + int n = layer.outputs; + double *a = input; + double *b = layer.weights; + double *c = layer.output; + gemm(0,0,m,n,k,1,a,k,b,n,1,c,n); for(i = 0; i < layer.outputs; ++i){ - layer.output[i] = layer.biases[i]; - for(j = 0; j < layer.inputs; ++j){ - layer.output[i] += input[j]*layer.weights[i*layer.inputs + j]; - } layer.output[i] = activate(layer.output[i], layer.activation); } } void learn_connected_layer(connected_layer layer, double *input) { - int i, j; + int i; for(i = 0; i < layer.outputs; ++i){ layer.delta[i] *= gradient(layer.output[i], layer.activation); layer.bias_updates[i] += layer.delta[i]; - for(j = 0; j < layer.inputs; ++j){ - layer.weight_updates[i*layer.inputs + j] += layer.delta[i]*input[j]; - } } -} - -void update_connected_layer(connected_layer layer, double step, double momentum, double decay) -{ - int i,j; - for(i = 0; i < layer.outputs; ++i){ - layer.bias_momentum[i] = step*(layer.bias_updates[i]) + momentum*layer.bias_momentum[i]; - layer.biases[i] += layer.bias_momentum[i]; - for(j = 0; j < layer.inputs; ++j){ - int index = i*layer.inputs+j; - layer.weight_momentum[index] = step*(layer.weight_updates[index] - decay*layer.weights[index]) + momentum*layer.weight_momentum[index]; - layer.weights[index] += layer.weight_momentum[index]; - } - } - memset(layer.bias_updates, 0, layer.outputs*sizeof(double)); - memset(layer.weight_updates, 0, layer.outputs*layer.inputs*sizeof(double)); + int m = layer.inputs; + int k = 1; + int n = layer.outputs; + double *a = input; + double *b = layer.delta; + double *c = layer.weight_updates; + gemm(0,0,m,n,k,1,a,k,b,n,1,c,n); } void backward_connected_layer(connected_layer layer, double *input, double *delta) { - int i, j; + memset(delta, 0, layer.inputs*sizeof(double)); - for(j = 0; j < layer.inputs; ++j){ - delta[j] = 0; - for(i = 0; i < layer.outputs; ++i){ - delta[j] += layer.delta[i]*layer.weights[i*layer.inputs + j]; - } - } + int m = layer.inputs; + int k = layer.outputs; + int n = 1; + + double *a = layer.weights; + double *b = layer.delta; + double *c = delta; + + gemm(0,0,m,n,k,1,a,k,b,n,1,c,n); } +/* + void forward_connected_layer(connected_layer layer, double *input) + { + int i, j; + for(i = 0; i < layer.outputs; ++i){ + layer.output[i] = layer.biases[i]; + for(j = 0; j < layer.inputs; ++j){ + layer.output[i] += input[j]*layer.weights[i*layer.inputs + j]; + } + layer.output[i] = activate(layer.output[i], layer.activation); + } + } + void learn_connected_layer(connected_layer layer, double *input) + { + int i, j; + for(i = 0; i < layer.outputs; ++i){ + layer.delta[i] *= gradient(layer.output[i], layer.activation); + layer.bias_updates[i] += layer.delta[i]; + for(j = 0; j < layer.inputs; ++j){ + layer.weight_updates[i*layer.inputs + j] += layer.delta[i]*input[j]; + } + } + } + void backward_connected_layer(connected_layer layer, double *input, double *delta) + { + int i, j; + for(j = 0; j < layer.inputs; ++j){ + delta[j] = 0; + for(i = 0; i < layer.outputs; ++i){ + delta[j] += layer.delta[i]*layer.weights[i*layer.inputs + j]; + } + } + } + */ diff --git a/src/image.c b/src/image.c index 74b88325..df8e1b8f 100644 --- a/src/image.c +++ b/src/image.c @@ -207,6 +207,7 @@ image make_random_image(int h, int w, int c) int i; for(i = 0; i < h*w*c; ++i){ out.data[i] = rand_normal(); + //out.data[i] = rand()%3; } return out; } diff --git a/src/mini_blas.c b/src/mini_blas.c new file mode 100644 index 00000000..b15ba8e6 --- /dev/null +++ b/src/mini_blas.c @@ -0,0 +1,80 @@ + +void gemm(int TA, int TB, int M, int N, int K, double ALPHA, + double *A, int lda, + double *B, int ldb, + double BETA, + double *C, int ldc) +{ + // Assume TA = TB = 0, beta = 1 LULZ + int i,j,k; + for(i = 0; i < M; ++i){ + for(k = 0; k < K; ++k){ + for(j = 0; j < N; ++j){ + C[i*ldc+j] += ALPHA*A[i*lda+k]*B[k*ldb+j]; + } + } + } +} + +void im2row(double *image, int h, int w, int c, int size, int stride, double *matrix) +{ + int i; + int mc = c; + int mw = (size*size); + int mh = ((h-size)/stride+1)*((w-size)/stride+1); + int msize = mc*mw*mh; + for(i = 0; i < msize; ++i){ + int channel = i/(mh*mw); + int block = (i%(mh*mw))/mw; + int position = i%mw; + int block_h = block/((w-size)/stride+1); + int block_w = block%((w-size)/stride+1); + int ph, pw, pc; + ph = position/size+block_h; + pw = position%size+block_w; + pc = channel; + matrix[i] = image[pc*h*w+ph*w+pw]; + } +} +void im2col(double *image, int h, int w, int c, int size, int stride, double *matrix) +{ + int b,p; + int blocks = ((h-size)/stride+1)*((w-size)/stride+1); + int pixels = (size*size*c); + for(b = 0; b < blocks; ++b){ + int block_h = b/((w-size)/stride+1); + int block_w = b%((w-size)/stride+1); + for(p = 0; p < pixels; ++p){ + int ph, pw, pc; + int position = p%(size*size); + pc = p/(size*size); + ph = position/size+block_h; + pw = position%size+block_w; + matrix[b+p*blocks] = image[pc*h*w+ph*w+pw]; + } + } +} + +//From Berkeley Vision's Caffe! +void im2col_cpu(double* data_im, const int channels, + const int height, const int width, const int ksize, const int stride, + double* data_col) + { + int c,h,w; + int height_col = (height - ksize) / stride + 1; + int width_col = (width - ksize) / stride + 1; + int channels_col = channels * ksize * ksize; + for ( c = 0; c < channels_col; ++c) { + int w_offset = c % ksize; + int h_offset = (c / ksize) % ksize; + int c_im = c / ksize / ksize; + for ( h = 0; h < height_col; ++h) { + for ( w = 0; w < width_col; ++w) { + data_col[(c * height_col + h) * width_col + w] = + data_im[(c_im * height + h * stride + h_offset) * width + + w * stride + w_offset]; + } + } + } +} + diff --git a/src/mini_blas.h b/src/mini_blas.h new file mode 100644 index 00000000..cdf3a86e --- /dev/null +++ b/src/mini_blas.h @@ -0,0 +1,10 @@ +void gemm(int TA, int TB, int M, int N, int K, double ALPHA, + double *A, int lda, + double *B, int ldb, + double BETA, + double *C, int ldc); +void im2row(double *image, int h, int w, int c, int size, int stride, double *matrix); +void im2col(double *image, int h, int w, int c, int size, int stride, double *matrix); +void im2col_cpu(double* data_im, const int channels, + const int height, const int width, const int ksize, const int stride, + double* data_col); diff --git a/src/tests.c b/src/tests.c index 2a50bacf..ce131e7f 100644 --- a/src/tests.c +++ b/src/tests.c @@ -7,6 +7,7 @@ #include "data.h" #include "matrix.h" #include "utils.h" +#include "mini_blas.h" #include #include @@ -28,6 +29,35 @@ void test_convolve() show_image_layers(edge, "Test Convolve"); } +void test_convolve_matrix() +{ + image dog = load_image("dog.jpg"); + printf("dog channels %d\n", dog.c); + + int size = 11; + int stride = 1; + int n = 40; + double *filters = make_random_image(size, size, dog.c*n).data; + + int mw = ((dog.h-size)/stride+1)*((dog.w-size)/stride+1); + int mh = (size*size*dog.c); + double *matrix = calloc(mh*mw, sizeof(double)); + + image edge = make_image((dog.h-size)/stride+1, (dog.w-size)/stride+1, n); + + + int i; + clock_t start = clock(), end; + for(i = 0; i < 1000; ++i){ + im2col_cpu(dog.data, dog.c, dog.h, dog.w, size, stride, matrix); + gemm(0,0,n,mw,mh,1,filters,mh,matrix,mw,1,edge.data,mw); + } + end = clock(); + printf("Convolutions: %lf seconds\n", (double)(end-start)/CLOCKS_PER_SEC); + show_image_layers(edge, "Test Convolve"); + cvWaitKey(0); +} + void test_color() { image dog = load_image("test_color.png"); @@ -199,7 +229,7 @@ void test_nist() { srand(444444); srand(888888); - network net = parse_network_cfg("nist.cfg"); + network net = parse_network_cfg("nist_basic.cfg"); data train = load_categorical_data_csv("mnist/mnist_train.csv", 0, 10); data test = load_categorical_data_csv("mnist/mnist_test.csv",0,10); normalize_data_rows(train); @@ -216,8 +246,8 @@ void test_nist() end = clock(); printf("Time: %lf seconds\n", (double)(end-start)/CLOCKS_PER_SEC); start=end; - visualize_network(net); - cvWaitKey(100); + //visualize_network(net); + //cvWaitKey(100); //lr /= 2; if(count%5 == 0 && 0){ double train_acc = network_accuracy(net, train); @@ -336,13 +366,59 @@ void test_split() printf("%d, %d, %d\n", train.X.rows, split[0].X.rows, split[1].X.rows); } +double *random_matrix(int rows, int cols) +{ + int i, j; + double *m = calloc(rows*cols, sizeof(double)); + for(i = 0; i < rows; ++i){ + for(j = 0; j < cols; ++j){ + m[i*cols+j] = (double)rand()/RAND_MAX; + } + } + return m; +} + +void test_blas() +{ + int m = 6025, n = 20, k = 11*11*3; + double *a = random_matrix(m,k); + double *b = random_matrix(k,n); + double *c = random_matrix(m,n); + int i; + for(i = 0; i<1000; ++i){ + gemm(0,0,m,n,k,1,a,k,b,n,1,c,n); + } +} + +void test_im2row() +{ + int h = 20; + int w = 20; + int c = 3; + int stride = 1; + int size = 11; + image test = make_random_image(h,w,c); + int mc = 1; + int mw = ((h-size)/stride+1)*((w-size)/stride+1); + int mh = (size*size*c); + int msize = mc*mw*mh; + double *matrix = calloc(msize, sizeof(double)); + int i; + for(i = 0; i < 1000; ++i){ + im2col_cpu(test.data, c, h, w, size, stride, matrix); + image render = double_to_image(mh, mw, mc, matrix); + } +} int main() { + //test_blas(); + test_convolve_matrix(); +// test_im2row(); //test_kernel_update(); //test_split(); //test_ensemble(); - test_nist(); + //test_nist(); //test_full(); //test_random_preprocess(); //test_random_classify();