Parsing, image loading, lots of stuff
13 files modified
16 files added
| | |
| | | opencv/ |
| | | convnet/ |
| | | decaf/ |
| | | submission/ |
| | | cnn |
| | | |
| | | # OS Generated # |
| | |
| | | CC=gcc |
| | | CFLAGS=-Wall `pkg-config --cflags opencv` -O3 -flto -ffast-math |
| | | CFLAGS=-Wall `pkg-config --cflags opencv` -O0 -g |
| | | CFLAGS=-Wall `pkg-config --cflags opencv` -O3 -ffast-math -flto -march=native |
| | | #CFLAGS=-Wall `pkg-config --cflags opencv` -O0 -g |
| | | 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 |
| | | 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 |
| | | |
| | | all: cnn |
| | | |
| New file |
| | |
| | | [conn] |
| | | input = 1690 |
| | | output = 20 |
| | | activation=relu |
| | | |
| | | [conn] |
| | | output = 1 |
| | | activation=relu |
| | |
| | | #include "connected_layer.h" |
| | | |
| | | #include <math.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | |
| | | connected_layer *make_connected_layer(int inputs, int outputs, ACTIVATION activator) |
| | | { |
| | | printf("Connected Layer: %d inputs, %d outputs\n", inputs, outputs); |
| | | int i; |
| | | connected_layer *layer = calloc(1, sizeof(connected_layer)); |
| | | layer->inputs = inputs; |
| | | layer->outputs = outputs; |
| | | |
| | | layer->output = calloc(outputs, sizeof(double*)); |
| | | layer->delta = calloc(outputs, sizeof(double*)); |
| | | |
| | | layer->weight_updates = calloc(inputs*outputs, sizeof(double)); |
| | | layer->weight_momentum = calloc(inputs*outputs, sizeof(double)); |
| | | layer->weights = calloc(inputs*outputs, sizeof(double)); |
| | | for(i = 0; i < inputs*outputs; ++i) |
| | | layer->weights[i] = .5 - (double)rand()/RAND_MAX; |
| | | layer->weights[i] = .01*(.5 - (double)rand()/RAND_MAX); |
| | | |
| | | layer->bias_updates = calloc(outputs, sizeof(double)); |
| | | layer->bias_momentum = calloc(outputs, sizeof(double)); |
| | | layer->biases = calloc(outputs, sizeof(double)); |
| | | for(i = 0; i < outputs; ++i) |
| | | layer->biases[i] = (double)rand()/RAND_MAX; |
| | | layer->biases[i] = 1; |
| | | |
| | | if(activator == SIGMOID){ |
| | | layer->activation = sigmoid_activation; |
| | |
| | | return layer; |
| | | } |
| | | |
| | | void run_connected_layer(double *input, connected_layer layer) |
| | | void forward_connected_layer(connected_layer layer, double *input) |
| | | { |
| | | int i, j; |
| | | for(i = 0; i < layer.outputs; ++i){ |
| | |
| | | } |
| | | } |
| | | |
| | | void learn_connected_layer(double *input, connected_layer layer) |
| | | void learn_connected_layer(connected_layer layer, double *input) |
| | | { |
| | | calculate_update_connected_layer(input, layer); |
| | | backpropagate_connected_layer(input, layer); |
| | | int i, j; |
| | | for(i = 0; i < layer.outputs; ++i){ |
| | | 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) |
| | | void update_connected_layer(connected_layer layer, double step, double momentum, double decay) |
| | | { |
| | | int i,j; |
| | | for(i = 0; i < layer.outputs; ++i){ |
| | | layer.biases[i] += step*layer.bias_updates[i]; |
| | | layer.bias_momentum[i] = step*(layer.bias_updates[i] - decay*layer.biases[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.weights[index] += step*layer.weight_updates[index]; |
| | | 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)); |
| | | } |
| | | |
| | | void calculate_update_connected_layer(double *input, connected_layer layer) |
| | | { |
| | | int i, j; |
| | | for(i = 0; i < layer.outputs; ++i){ |
| | | layer.bias_updates[i] += layer.output[i]; |
| | | for(j = 0; j < layer.inputs; ++j){ |
| | | layer.weight_updates[i*layer.inputs + j] += layer.output[i]*input[j]; |
| | | } |
| | | } |
| | | } |
| | | |
| | | void backpropagate_connected_layer(double *input, connected_layer layer) |
| | | void backward_connected_layer(connected_layer layer, double *input, double *delta) |
| | | { |
| | | int i, j; |
| | | |
| | | for(j = 0; j < layer.inputs; ++j){ |
| | | double grad = layer.gradient(input[j]); |
| | | input[j] = 0; |
| | | delta[j] = 0; |
| | | for(i = 0; i < layer.outputs; ++i){ |
| | | input[j] += layer.output[i]*layer.weights[i*layer.inputs + j]; |
| | | delta[j] += layer.delta[i]*layer.weights[i*layer.inputs + j]; |
| | | } |
| | | input[j] *= grad; |
| | | delta[j] *= grad; |
| | | } |
| | | } |
| | | |
| | |
| | | int outputs; |
| | | double *weights; |
| | | double *biases; |
| | | |
| | | double *weight_updates; |
| | | double *bias_updates; |
| | | |
| | | double *weight_momentum; |
| | | double *bias_momentum; |
| | | |
| | | double *output; |
| | | double *delta; |
| | | |
| | | double (* activation)(); |
| | | double (* gradient)(); |
| | |
| | | |
| | | connected_layer *make_connected_layer(int inputs, int outputs, ACTIVATION activator); |
| | | |
| | | void run_connected_layer(double *input, connected_layer layer); |
| | | void learn_connected_layer(double *input, connected_layer layer); |
| | | void update_connected_layer(connected_layer layer, double step); |
| | | void forward_connected_layer(connected_layer layer, double *input); |
| | | void backward_connected_layer(connected_layer layer, double *input, double *delta); |
| | | void learn_connected_layer(connected_layer layer, double *input); |
| | | void update_connected_layer(connected_layer layer, double step, double momentum, double decay); |
| | | |
| | | void backpropagate_connected_layer(double *input, connected_layer layer); |
| | | void calculate_update_connected_layer(double *input, connected_layer layer); |
| | | |
| | | #endif |
| | | |
| | |
| | | #include "convolutional_layer.h" |
| | | #include <stdio.h> |
| | | |
| | | double convolution_activation(double x) |
| | | image get_convolutional_image(convolutional_layer layer) |
| | | { |
| | | return x*(x>0); |
| | | int h = (layer.h-1)/layer.stride + 1; |
| | | int w = (layer.w-1)/layer.stride + 1; |
| | | int c = layer.n; |
| | | return double_to_image(h,w,c,layer.output); |
| | | } |
| | | |
| | | double convolution_gradient(double x) |
| | | image get_convolutional_delta(convolutional_layer layer) |
| | | { |
| | | return (x>=0); |
| | | int h = (layer.h-1)/layer.stride + 1; |
| | | int w = (layer.w-1)/layer.stride + 1; |
| | | int c = layer.n; |
| | | return double_to_image(h,w,c,layer.delta); |
| | | } |
| | | |
| | | convolutional_layer *make_convolutional_layer(int h, int w, int c, int n, int size, int stride) |
| | | convolutional_layer *make_convolutional_layer(int h, int w, int c, int n, int size, int stride, ACTIVATION activator) |
| | | { |
| | | printf("Convolutional Layer: %d x %d x %d image, %d filters\n", h,w,c,n); |
| | | int i; |
| | | convolutional_layer *layer = calloc(1, sizeof(convolutional_layer)); |
| | | layer->h = h; |
| | | layer->w = w; |
| | | layer->c = c; |
| | | layer->n = n; |
| | | layer->stride = stride; |
| | | layer->kernels = calloc(n, sizeof(image)); |
| | | layer->kernel_updates = calloc(n, sizeof(image)); |
| | | layer->biases = calloc(n, sizeof(double)); |
| | | layer->bias_updates = calloc(n, sizeof(double)); |
| | | for(i = 0; i < n; ++i){ |
| | | layer->biases[i] = .005; |
| | | layer->kernels[i] = make_random_kernel(size, c); |
| | | layer->kernel_updates[i] = make_random_kernel(size, c); |
| | | } |
| | | layer->output = make_image((h-1)/stride+1, (w-1)/stride+1, n); |
| | | layer->output = calloc(((h-1)/stride+1) * ((w-1)/stride+1) * n, sizeof(double)); |
| | | layer->delta = calloc(((h-1)/stride+1) * ((w-1)/stride+1) * n, sizeof(double)); |
| | | layer->upsampled = make_image(h,w,n); |
| | | |
| | | if(activator == SIGMOID){ |
| | | layer->activation = sigmoid_activation; |
| | | layer->gradient = sigmoid_gradient; |
| | | }else if(activator == RELU){ |
| | | layer->activation = relu_activation; |
| | | layer->gradient = relu_gradient; |
| | | }else if(activator == IDENTITY){ |
| | | layer->activation = identity_activation; |
| | | layer->gradient = identity_gradient; |
| | | } |
| | | return layer; |
| | | } |
| | | |
| | | void run_convolutional_layer(const image input, const convolutional_layer layer) |
| | | void forward_convolutional_layer(const convolutional_layer layer, double *in) |
| | | { |
| | | int i; |
| | | image input = double_to_image(layer.h, layer.w, layer.c, in); |
| | | image output = get_convolutional_image(layer); |
| | | int i,j; |
| | | for(i = 0; i < layer.n; ++i){ |
| | | convolve(input, layer.kernels[i], layer.stride, i, layer.output); |
| | | convolve(input, layer.kernels[i], layer.stride, i, output); |
| | | } |
| | | for(i = 0; i < layer.output.h*layer.output.w*layer.output.c; ++i){ |
| | | layer.output.data[i] = convolution_activation(layer.output.data[i]); |
| | | for(i = 0; i < output.c; ++i){ |
| | | for(j = 0; j < output.h*output.w; ++j){ |
| | | int index = i*output.h*output.w + j; |
| | | output.data[index] += layer.biases[i]; |
| | | output.data[index] = layer.activation(output.data[index]); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void backpropagate_convolutional_layer(image input, convolutional_layer layer) |
| | | void backward_convolutional_layer(convolutional_layer layer, double *input, double *delta) |
| | | { |
| | | int i; |
| | | zero_image(input); |
| | | |
| | | image in_image = double_to_image(layer.h, layer.w, layer.c, input); |
| | | image in_delta = double_to_image(layer.h, layer.w, layer.c, delta); |
| | | image out_delta = get_convolutional_delta(layer); |
| | | zero_image(in_delta); |
| | | |
| | | for(i = 0; i < layer.n; ++i){ |
| | | back_convolve(input, layer.kernels[i], layer.stride, i, layer.output); |
| | | back_convolve(in_delta, layer.kernels[i], layer.stride, i, out_delta); |
| | | } |
| | | for(i = 0; i < layer.h*layer.w*layer.c; ++i){ |
| | | in_delta.data[i] *= layer.gradient(in_image.data[i]); |
| | | } |
| | | } |
| | | |
| | | /* |
| | | void backpropagate_convolutional_layer_convolve(image input, convolutional_layer layer) |
| | | { |
| | | int i,j; |
| | |
| | | rotate_image(layer.kernels[i]); |
| | | } |
| | | } |
| | | */ |
| | | |
| | | void learn_convolutional_layer(image input, convolutional_layer layer) |
| | | void learn_convolutional_layer(convolutional_layer layer, double *input) |
| | | { |
| | | int i; |
| | | image in_image = double_to_image(layer.h, layer.w, layer.c, input); |
| | | image out_delta = get_convolutional_delta(layer); |
| | | for(i = 0; i < layer.n; ++i){ |
| | | kernel_update(input, layer.kernel_updates[i], layer.stride, i, layer.output); |
| | | kernel_update(in_image, layer.kernel_updates[i], layer.stride, i, out_delta); |
| | | layer.bias_updates[i] += avg_image_layer(out_delta, i); |
| | | } |
| | | image old_input = copy_image(input); |
| | | backpropagate_convolutional_layer(input, layer); |
| | | for(i = 0; i < input.h*input.w*input.c; ++i){ |
| | | input.data[i] *= convolution_gradient(old_input.data[i]); |
| | | } |
| | | free_image(old_input); |
| | | } |
| | | |
| | | void update_convolutional_layer(convolutional_layer layer, double step) |
| | | { |
| | | return; |
| | | int i,j; |
| | | for(i = 0; i < layer.n; ++i){ |
| | | layer.biases[i] += step*layer.bias_updates[i]; |
| | | layer.bias_updates[i] = 0; |
| | | int pixels = layer.kernels[i].h*layer.kernels[i].w*layer.kernels[i].c; |
| | | for(j = 0; j < pixels; ++j){ |
| | | layer.kernels[i].data[j] += step*layer.kernel_updates[i].data[j]; |
| | |
| | | } |
| | | } |
| | | |
| | | void visualize_convolutional_layer(convolutional_layer layer) |
| | | { |
| | | int i; |
| | | char buff[256]; |
| | | //image vis = make_image(layer.n*layer.size, layer.size*layer.kernels[0].c, 3); |
| | | for(i = 0; i < layer.n; ++i){ |
| | | image k = layer.kernels[i]; |
| | | sprintf(buff, "Kernel %d", i); |
| | | if(k.c <= 3) show_image(k, buff); |
| | | else show_image_layers(k, buff); |
| | | } |
| | | } |
| | | |
| | |
| | | #define CONVOLUTIONAL_LAYER_H |
| | | |
| | | #include "image.h" |
| | | #include "activations.h" |
| | | |
| | | typedef struct { |
| | | int h,w,c; |
| | | int n; |
| | | int stride; |
| | | image *kernels; |
| | | image *kernel_updates; |
| | | double *biases; |
| | | double *bias_updates; |
| | | image upsampled; |
| | | image output; |
| | | double *delta; |
| | | double *output; |
| | | |
| | | double (* activation)(); |
| | | double (* gradient)(); |
| | | } convolutional_layer; |
| | | |
| | | convolutional_layer *make_convolutional_layer(int h, int w, int c, int n, int size, int stride); |
| | | void run_convolutional_layer(const image input, const convolutional_layer layer); |
| | | void learn_convolutional_layer(image input, convolutional_layer layer); |
| | | convolutional_layer *make_convolutional_layer(int h, int w, int c, int n, int size, int stride, ACTIVATION activator); |
| | | void forward_convolutional_layer(const convolutional_layer layer, double *in); |
| | | void backward_convolutional_layer(convolutional_layer layer, double *input, double *delta); |
| | | void learn_convolutional_layer(convolutional_layer layer, double *input); |
| | | |
| | | void update_convolutional_layer(convolutional_layer layer, double step); |
| | | void backpropagate_convolutional_layer(image input, convolutional_layer layer); |
| | | |
| | | void backpropagate_convolutional_layer_convolve(image input, convolutional_layer layer); |
| | | void visualize_convolutional_layer(convolutional_layer layer); |
| | | |
| | | image get_convolutional_image(convolutional_layer layer); |
| | | image get_convolutional_delta(convolutional_layer layer); |
| | | |
| | | #endif |
| | | |
| New file |
| | |
| | | #include "data.h" |
| | | #include "list.h" |
| | | #include "utils.h" |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | |
| | | batch make_batch(int n, int k) |
| | | { |
| | | batch b; |
| | | b.n = n; |
| | | if(k < 3) k = 1; |
| | | b.images = calloc(n, sizeof(image)); |
| | | b.truth = calloc(n, sizeof(double *)); |
| | | int i; |
| | | for(i =0 ; i < n; ++i) b.truth[i] = calloc(k, sizeof(double)); |
| | | return b; |
| | | } |
| | | |
| | | list *get_paths(char *filename) |
| | | { |
| | | char *path; |
| | | FILE *file = fopen(filename, "r"); |
| | | list *lines = make_list(); |
| | | while((path=fgetl(file))){ |
| | | list_insert(lines, path); |
| | | } |
| | | fclose(file); |
| | | return lines; |
| | | } |
| | | |
| | | int get_truth(char *path) |
| | | { |
| | | if(strstr(path, "dog")) return 1; |
| | | return 0; |
| | | } |
| | | |
| | | batch load_list(list *paths) |
| | | { |
| | | char *path; |
| | | batch data = make_batch(paths->size, 2); |
| | | node *n = paths->front; |
| | | int i; |
| | | for(i = 0; i < data.n; ++i){ |
| | | path = (char *)n->val; |
| | | data.images[i] = load_image(path); |
| | | data.truth[i][0] = get_truth(path); |
| | | n = n->next; |
| | | } |
| | | return data; |
| | | } |
| | | |
| | | batch get_all_data(char *filename) |
| | | { |
| | | list *paths = get_paths(filename); |
| | | batch b = load_list(paths); |
| | | free_list_contents(paths); |
| | | free_list(paths); |
| | | return b; |
| | | } |
| | | |
| | | void free_batch(batch b) |
| | | { |
| | | int i; |
| | | for(i = 0; i < b.n; ++i){ |
| | | free_image(b.images[i]); |
| | | free(b.truth[i]); |
| | | } |
| | | free(b.images); |
| | | free(b.truth); |
| | | } |
| | | |
| | | batch get_batch(char *filename, int curr, int total) |
| | | { |
| | | list *plist = get_paths(filename); |
| | | char **paths = (char **)list_to_array(plist); |
| | | int i; |
| | | int start = curr*plist->size/total; |
| | | int end = (curr+1)*plist->size/total; |
| | | batch b = make_batch(end-start, 2); |
| | | for(i = start; i < end; ++i){ |
| | | b.images[i-start] = load_image(paths[i]); |
| | | b.truth[i-start][0] = get_truth(paths[i]); |
| | | } |
| | | free_list_contents(plist); |
| | | free_list(plist); |
| | | free(paths); |
| | | return b; |
| | | } |
| | | |
| | | batch random_batch(char *filename, int n) |
| | | { |
| | | list *plist = get_paths(filename); |
| | | char **paths = (char **)list_to_array(plist); |
| | | int i; |
| | | batch b = make_batch(n, 2); |
| | | for(i = 0; i < n; ++i){ |
| | | int index = rand()%plist->size; |
| | | b.images[i] = load_image(paths[index]); |
| | | normalize_image(b.images[i]); |
| | | b.truth[i][0] = get_truth(paths[index]); |
| | | } |
| | | free_list_contents(plist); |
| | | free_list(plist); |
| | | free(paths); |
| | | return b; |
| | | } |
| New file |
| | |
| | | #ifndef DATA_H |
| | | #define DATA_H |
| | | |
| | | #include "image.h" |
| | | |
| | | typedef struct{ |
| | | int n; |
| | | image *images; |
| | | double **truth; |
| | | } batch; |
| | | |
| | | batch get_all_data(char *filename); |
| | | batch random_batch(char *filename, int n); |
| | | batch get_batch(char *filename, int curr, int total); |
| | | void free_batch(batch b); |
| | | |
| | | |
| | | #endif |
| | |
| | | p.data[i+j*p.h*p.w] = (p.data[i+j*p.h*p.w] - min[j])/(max[j]-min[j]); |
| | | } |
| | | } |
| | | free(min); |
| | | free(max); |
| | | } |
| | | |
| | | double avg_image_layer(image m, int l) |
| | | { |
| | | int i; |
| | | double sum = 0; |
| | | for(i = 0; i < m.h*m.w; ++i){ |
| | | sum += m.data[l*m.h*m.w + i]; |
| | | } |
| | | return sum/(m.h*m.w); |
| | | } |
| | | |
| | | void threshold_image(image p, double t) |
| | |
| | | } |
| | | } |
| | | |
| | | image make_image(int h, int w, int c) |
| | | image make_empty_image(int h, int w, int c) |
| | | { |
| | | image out; |
| | | out.h = h; |
| | | out.w = w; |
| | | out.c = c; |
| | | return out; |
| | | } |
| | | |
| | | image make_image(int h, int w, int c) |
| | | { |
| | | image out = make_empty_image(h,w,c); |
| | | out.data = calloc(h*w*c, sizeof(double)); |
| | | return out; |
| | | } |
| | | |
| | | image double_to_image(int h, int w, int c, double *data) |
| | | { |
| | | image out = make_empty_image(h,w,c); |
| | | out.data = data; |
| | | return out; |
| | | } |
| | | |
| | | void zero_image(image m) |
| | | { |
| | | memset(m.data, 0, m.h*m.w*m.c*sizeof(double)); |
| | |
| | | image out = make_image(h,w,c); |
| | | int i; |
| | | for(i = 0; i < h*w*c; ++i){ |
| | | out.data[i] = .5-(double)rand()/RAND_MAX; |
| | | out.data[i] = (.5-(double)rand()/RAND_MAX); |
| | | } |
| | | return out; |
| | | } |
| | |
| | | void zero_image(image m); |
| | | void rotate_image(image m); |
| | | void subtract_image(image a, image b); |
| | | double avg_image_layer(image m, int l); |
| | | |
| | | void show_image(image p, char *name); |
| | | void show_image_layers(image p, char *name); |
| | | |
| | | image make_image(int h, int w, int c); |
| | | image make_empty_image(int h, int w, int c); |
| | | image make_random_image(int h, int w, int c); |
| | | image make_random_kernel(int size, int c); |
| | | image double_to_image(int h, int w, int c, double *data); |
| | | image copy_image(image p); |
| | | image load_image(char *filename); |
| | | |
| New file |
| | |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include "list.h" |
| | | |
| | | list *make_list() |
| | | { |
| | | list *l = malloc(sizeof(list)); |
| | | l->size = 0; |
| | | l->front = 0; |
| | | l->back = 0; |
| | | return l; |
| | | } |
| | | |
| | | void transfer_node(list *s, list *d, node *n) |
| | | { |
| | | node *prev, *next; |
| | | prev = n->prev; |
| | | next = n->next; |
| | | if(prev) prev->next = next; |
| | | if(next) next->prev = prev; |
| | | --s->size; |
| | | if(s->front == n) s->front = next; |
| | | if(s->back == n) s->back = prev; |
| | | } |
| | | |
| | | void *list_pop(list *l){ |
| | | if(!l->back) return 0; |
| | | node *b = l->back; |
| | | void *val = b->val; |
| | | l->back = b->prev; |
| | | if(l->back) l->back->next = 0; |
| | | free(b); |
| | | --l->size; |
| | | |
| | | return val; |
| | | } |
| | | |
| | | void list_insert(list *l, void *val) |
| | | { |
| | | node *new = malloc(sizeof(node)); |
| | | new->val = val; |
| | | new->next = 0; |
| | | |
| | | if(!l->back){ |
| | | l->front = new; |
| | | new->prev = 0; |
| | | }else{ |
| | | l->back->next = new; |
| | | new->prev = l->back; |
| | | } |
| | | l->back = new; |
| | | ++l->size; |
| | | } |
| | | |
| | | void free_node(node *n) |
| | | { |
| | | node *next; |
| | | while(n) { |
| | | next = n->next; |
| | | free(n); |
| | | n = next; |
| | | } |
| | | } |
| | | |
| | | void free_list(list *l) |
| | | { |
| | | free_node(l->front); |
| | | free(l); |
| | | } |
| | | |
| | | void free_list_contents(list *l) |
| | | { |
| | | node *n = l->front; |
| | | while(n){ |
| | | free(n->val); |
| | | n = n->next; |
| | | } |
| | | } |
| | | |
| | | void **list_to_array(list *l) |
| | | { |
| | | void **a = calloc(l->size, sizeof(void*)); |
| | | int count = 0; |
| | | node *n = l->front; |
| | | while(n){ |
| | | a[count++] = n->val; |
| | | n = n->next; |
| | | } |
| | | return a; |
| | | } |
| New file |
| | |
| | | #ifndef LIST_H |
| | | #define LIST_H |
| | | |
| | | typedef struct node{ |
| | | void *val; |
| | | struct node *next; |
| | | struct node *prev; |
| | | } node; |
| | | |
| | | typedef struct list{ |
| | | int size; |
| | | node *front; |
| | | node *back; |
| | | } list; |
| | | |
| | | list *make_list(); |
| | | int list_find(list *l, void *val); |
| | | |
| | | void list_insert(list *, void *); |
| | | |
| | | void **list_to_array(list *l); |
| | | |
| | | void free_list(list *l); |
| | | void free_list_contents(list *l); |
| | | |
| | | #endif |
| New file |
| | |
| | | #include "matrix.h" |
| | | #include "utils.h" |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <assert.h> |
| | | #include <math.h> |
| | | |
| | | void free_matrix(matrix m) |
| | | { |
| | | int i; |
| | | for(i = 0; i < m.rows; ++i) free(m.vals[i]); |
| | | free(m.vals); |
| | | } |
| | | |
| | | matrix make_matrix(int rows, int cols) |
| | | { |
| | | matrix m; |
| | | m.rows = rows; |
| | | m.cols = cols; |
| | | m.vals = calloc(m.rows, sizeof(double *)); |
| | | int i; |
| | | for(i = 0; i < m.rows; ++i) m.vals[i] = calloc(m.cols, sizeof(double)); |
| | | return m; |
| | | } |
| | | |
| | | matrix hold_out_matrix(matrix *m, int n) |
| | | { |
| | | int i; |
| | | matrix h; |
| | | h.rows = n; |
| | | h.cols = m->cols; |
| | | h.vals = calloc(h.rows, sizeof(double *)); |
| | | for(i = 0; i < n; ++i){ |
| | | int index = rand()%m->rows; |
| | | h.vals[i] = m->vals[index]; |
| | | m->vals[index] = m->vals[--(m->rows)]; |
| | | } |
| | | return h; |
| | | } |
| | | |
| | | double *pop_column(matrix *m, int c) |
| | | { |
| | | double *col = calloc(m->rows, sizeof(double)); |
| | | int i, j; |
| | | for(i = 0; i < m->rows; ++i){ |
| | | col[i] = m->vals[i][c]; |
| | | for(j = c; j < m->cols-1; ++j){ |
| | | m->vals[i][j] = m->vals[i][j+1]; |
| | | } |
| | | } |
| | | --m->cols; |
| | | return col; |
| | | } |
| | | |
| | | matrix csv_to_matrix(char *filename) |
| | | { |
| | | FILE *fp = fopen(filename, "r"); |
| | | if(!fp) file_error(filename); |
| | | |
| | | matrix m; |
| | | m.cols = -1; |
| | | |
| | | char *line; |
| | | |
| | | int n = 0; |
| | | int size = 1024; |
| | | m.vals = calloc(size, sizeof(double*)); |
| | | while((line = fgetl(fp))){ |
| | | if(m.cols == -1) m.cols = count_fields(line); |
| | | if(n == size){ |
| | | size *= 2; |
| | | m.vals = realloc(m.vals, size*sizeof(double*)); |
| | | } |
| | | m.vals[n] = parse_fields(line, m.cols); |
| | | free(line); |
| | | ++n; |
| | | } |
| | | m.vals = realloc(m.vals, n*sizeof(double*)); |
| | | m.rows = n; |
| | | return m; |
| | | } |
| | | |
| | | void print_matrix(matrix m) |
| | | { |
| | | int i, j; |
| | | printf("%d X %d Matrix:\n",m.rows, m.cols); |
| | | printf(" __"); |
| | | for(j = 0; j < 16*m.cols-1; ++j) printf(" "); |
| | | printf("__ \n"); |
| | | |
| | | printf("| "); |
| | | for(j = 0; j < 16*m.cols-1; ++j) printf(" "); |
| | | printf(" |\n"); |
| | | |
| | | for(i = 0; i < m.rows; ++i){ |
| | | printf("| "); |
| | | for(j = 0; j < m.cols; ++j){ |
| | | printf("%15.7f ", m.vals[i][j]); |
| | | } |
| | | printf(" |\n"); |
| | | } |
| | | printf("|__"); |
| | | for(j = 0; j < 16*m.cols-1; ++j) printf(" "); |
| | | printf("__|\n"); |
| | | } |
| New file |
| | |
| | | #ifndef MATRIX_H |
| | | #define MATRIX_H |
| | | typedef struct matrix{ |
| | | int rows, cols; |
| | | double **vals; |
| | | } matrix; |
| | | |
| | | matrix make_matrix(int rows, int cols); |
| | | void free_matrix(matrix m); |
| | | void print_matrix(matrix m); |
| | | |
| | | matrix csv_to_matrix(char *filename); |
| | | matrix hold_out_matrix(matrix *m, int n); |
| | | |
| | | double *pop_column(matrix *m, int c); |
| | | |
| | | #endif |
| | |
| | | #include "maxpool_layer.h" |
| | | #include <stdio.h> |
| | | |
| | | image get_maxpool_image(maxpool_layer layer) |
| | | { |
| | | int h = (layer.h-1)/layer.stride + 1; |
| | | int w = (layer.w-1)/layer.stride + 1; |
| | | int c = layer.c; |
| | | return double_to_image(h,w,c,layer.output); |
| | | } |
| | | |
| | | maxpool_layer *make_maxpool_layer(int h, int w, int c, int stride) |
| | | { |
| | | printf("Maxpool Layer: %d x %d x %d image, %d stride\n", h,w,c,stride); |
| | | maxpool_layer *layer = calloc(1, sizeof(maxpool_layer)); |
| | | layer->h = h; |
| | | layer->w = w; |
| | | layer->c = c; |
| | | layer->stride = stride; |
| | | layer->output = make_image((h-1)/stride+1, (w-1)/stride+1, c); |
| | | layer->output = calloc(((h-1)/stride+1) * ((w-1)/stride+1) * c, sizeof(double)); |
| | | layer->delta = calloc(((h-1)/stride+1) * ((w-1)/stride+1) * c, sizeof(double)); |
| | | return layer; |
| | | } |
| | | |
| | | void run_maxpool_layer(const image input, const maxpool_layer layer) |
| | | void forward_maxpool_layer(const maxpool_layer layer, double *in) |
| | | { |
| | | image input = double_to_image(layer.h, layer.w, layer.c, in); |
| | | image output = get_maxpool_image(layer); |
| | | int i,j,k; |
| | | for(i = 0; i < layer.output.h*layer.output.w*layer.output.c; ++i) layer.output.data[i] = -DBL_MAX; |
| | | for(i = 0; i < input.h; ++i){ |
| | | for(j = 0; j < input.w; ++j){ |
| | | for(k = 0; k < input.c; ++k){ |
| | | for(i = 0; i < output.h*output.w*output.c; ++i) output.data[i] = -DBL_MAX; |
| | | for(k = 0; k < input.c; ++k){ |
| | | for(i = 0; i < input.h; ++i){ |
| | | for(j = 0; j < input.w; ++j){ |
| | | double val = get_pixel(input, i, j, k); |
| | | double cur = get_pixel(layer.output, i/layer.stride, j/layer.stride, k); |
| | | if(val > cur) set_pixel(layer.output, i/layer.stride, j/layer.stride, k, val); |
| | | double cur = get_pixel(output, i/layer.stride, j/layer.stride, k); |
| | | if(val > cur) set_pixel(output, i/layer.stride, j/layer.stride, k, val); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | #include "image.h" |
| | | |
| | | typedef struct { |
| | | int h,w,c; |
| | | int stride; |
| | | image output; |
| | | double *delta; |
| | | double *output; |
| | | } maxpool_layer; |
| | | |
| | | image get_maxpool_image(maxpool_layer layer); |
| | | maxpool_layer *make_maxpool_layer(int h, int w, int c, int stride); |
| | | void run_maxpool_layer(const image input, const maxpool_layer layer); |
| | | void forward_maxpool_layer(const maxpool_layer layer, double *in); |
| | | |
| | | #endif |
| | | |
| | |
| | | #include <stdio.h> |
| | | #include "network.h" |
| | | #include "image.h" |
| | | #include "data.h" |
| | | |
| | | #include "connected_layer.h" |
| | | #include "convolutional_layer.h" |
| | |
| | | return net; |
| | | } |
| | | |
| | | void run_network(image input, network net) |
| | | void forward_network(network net, double *input) |
| | | { |
| | | int i; |
| | | double *input_d = input.data; |
| | | for(i = 0; i < net.n; ++i){ |
| | | if(net.types[i] == CONVOLUTIONAL){ |
| | | convolutional_layer layer = *(convolutional_layer *)net.layers[i]; |
| | | run_convolutional_layer(input, layer); |
| | | forward_convolutional_layer(layer, input); |
| | | input = layer.output; |
| | | input_d = layer.output.data; |
| | | } |
| | | else if(net.types[i] == CONNECTED){ |
| | | connected_layer layer = *(connected_layer *)net.layers[i]; |
| | | run_connected_layer(input_d, layer); |
| | | input_d = layer.output; |
| | | forward_connected_layer(layer, input); |
| | | input = layer.output; |
| | | } |
| | | else if(net.types[i] == MAXPOOL){ |
| | | maxpool_layer layer = *(maxpool_layer *)net.layers[i]; |
| | | run_maxpool_layer(input, layer); |
| | | forward_maxpool_layer(layer, input); |
| | | input = layer.output; |
| | | input_d = layer.output.data; |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | else if(net.types[i] == CONNECTED){ |
| | | connected_layer layer = *(connected_layer *)net.layers[i]; |
| | | update_connected_layer(layer, step); |
| | | update_connected_layer(layer, step, .3, 0); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void learn_network(image input, network net) |
| | | double *get_network_output_layer(network net, int i) |
| | | { |
| | | if(net.types[i] == CONVOLUTIONAL){ |
| | | convolutional_layer layer = *(convolutional_layer *)net.layers[i]; |
| | | return layer.output; |
| | | } else if(net.types[i] == MAXPOOL){ |
| | | maxpool_layer layer = *(maxpool_layer *)net.layers[i]; |
| | | return layer.output; |
| | | } else if(net.types[i] == CONNECTED){ |
| | | connected_layer layer = *(connected_layer *)net.layers[i]; |
| | | return layer.output; |
| | | } |
| | | return 0; |
| | | } |
| | | double *get_network_output(network net) |
| | | { |
| | | return get_network_output_layer(net, net.n-1); |
| | | } |
| | | |
| | | double *get_network_delta_layer(network net, int i) |
| | | { |
| | | if(net.types[i] == CONVOLUTIONAL){ |
| | | convolutional_layer layer = *(convolutional_layer *)net.layers[i]; |
| | | return layer.delta; |
| | | } else if(net.types[i] == MAXPOOL){ |
| | | maxpool_layer layer = *(maxpool_layer *)net.layers[i]; |
| | | return layer.delta; |
| | | } else if(net.types[i] == CONNECTED){ |
| | | connected_layer layer = *(connected_layer *)net.layers[i]; |
| | | return layer.delta; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | double *get_network_delta(network net) |
| | | { |
| | | return get_network_delta_layer(net, net.n-1); |
| | | } |
| | | |
| | | void learn_network(network net, double *input) |
| | | { |
| | | int i; |
| | | image prev; |
| | | double *prev_p; |
| | | double *prev_input; |
| | | double *prev_delta; |
| | | for(i = net.n-1; i >= 0; --i){ |
| | | if(i == 0){ |
| | | prev = input; |
| | | prev_p = prev.data; |
| | | } else if(net.types[i-1] == CONVOLUTIONAL){ |
| | | convolutional_layer layer = *(convolutional_layer *)net.layers[i-1]; |
| | | prev = layer.output; |
| | | prev_p = prev.data; |
| | | } else if(net.types[i-1] == MAXPOOL){ |
| | | maxpool_layer layer = *(maxpool_layer *)net.layers[i-1]; |
| | | prev = layer.output; |
| | | prev_p = prev.data; |
| | | } else if(net.types[i-1] == CONNECTED){ |
| | | connected_layer layer = *(connected_layer *)net.layers[i-1]; |
| | | prev_p = layer.output; |
| | | prev_input = input; |
| | | prev_delta = 0; |
| | | }else{ |
| | | prev_input = get_network_output_layer(net, i-1); |
| | | prev_delta = get_network_delta_layer(net, i-1); |
| | | } |
| | | |
| | | if(net.types[i] == CONVOLUTIONAL){ |
| | | convolutional_layer layer = *(convolutional_layer *)net.layers[i]; |
| | | learn_convolutional_layer(prev, layer); |
| | | learn_convolutional_layer(layer, prev_input); |
| | | if(i != 0) backward_convolutional_layer(layer, prev_input, prev_delta); |
| | | } |
| | | else if(net.types[i] == MAXPOOL){ |
| | | //maxpool_layer layer = *(maxpool_layer *)net.layers[i]; |
| | | } |
| | | else if(net.types[i] == CONNECTED){ |
| | | connected_layer layer = *(connected_layer *)net.layers[i]; |
| | | learn_connected_layer(prev_p, layer); |
| | | learn_connected_layer(layer, prev_input); |
| | | if(i != 0) backward_connected_layer(layer, prev_input, prev_delta); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | double *get_network_output_layer(network net, int i) |
| | | void train_network_batch(network net, batch b) |
| | | { |
| | | if(net.types[i] == CONVOLUTIONAL){ |
| | | convolutional_layer layer = *(convolutional_layer *)net.layers[i]; |
| | | return layer.output.data; |
| | | int i,j; |
| | | int k = get_network_output_size(net); |
| | | int correct = 0; |
| | | for(i = 0; i < b.n; ++i){ |
| | | forward_network(net, b.images[i].data); |
| | | image o = get_network_image(net); |
| | | double *output = get_network_output(net); |
| | | double *delta = get_network_delta(net); |
| | | for(j = 0; j < k; ++j){ |
| | | //printf("%f %f\n", b.truth[i][j], output[j]); |
| | | delta[j] = b.truth[i][j]-output[j]; |
| | | if(fabs(delta[j]) < .5) ++correct; |
| | | //printf("%f\n", output[j]); |
| | | } |
| | | learn_network(net, b.images[i].data); |
| | | update_network(net, .00001); |
| | | } |
| | | else if(net.types[i] == MAXPOOL){ |
| | | maxpool_layer layer = *(maxpool_layer *)net.layers[i]; |
| | | return layer.output.data; |
| | | } |
| | | else if(net.types[i] == CONNECTED){ |
| | | connected_layer layer = *(connected_layer *)net.layers[i]; |
| | | return layer.output; |
| | | } |
| | | return 0; |
| | | printf("Accuracy: %f\n", (double)correct/b.n); |
| | | } |
| | | |
| | | int get_network_output_size_layer(network net, int i) |
| | | { |
| | | if(net.types[i] == CONVOLUTIONAL){ |
| | | convolutional_layer layer = *(convolutional_layer *)net.layers[i]; |
| | | return layer.output.h*layer.output.w*layer.output.c; |
| | | image output = get_convolutional_image(layer); |
| | | return output.h*output.w*output.c; |
| | | } |
| | | else if(net.types[i] == MAXPOOL){ |
| | | maxpool_layer layer = *(maxpool_layer *)net.layers[i]; |
| | | return layer.output.h*layer.output.w*layer.output.c; |
| | | image output = get_maxpool_image(layer); |
| | | return output.h*output.w*output.c; |
| | | } |
| | | else if(net.types[i] == CONNECTED){ |
| | | connected_layer layer = *(connected_layer *)net.layers[i]; |
| | |
| | | return 0; |
| | | } |
| | | |
| | | double *get_network_output(network net) |
| | | int get_network_output_size(network net) |
| | | { |
| | | int i = net.n-1; |
| | | return get_network_output_layer(net, i); |
| | | return get_network_output_size_layer(net, i); |
| | | } |
| | | |
| | | image get_network_image_layer(network net, int i) |
| | | { |
| | | if(net.types[i] == CONVOLUTIONAL){ |
| | | convolutional_layer layer = *(convolutional_layer *)net.layers[i]; |
| | | return layer.output; |
| | | return get_convolutional_image(layer); |
| | | } |
| | | else if(net.types[i] == MAXPOOL){ |
| | | maxpool_layer layer = *(maxpool_layer *)net.layers[i]; |
| | | return layer.output; |
| | | return get_maxpool_image(layer); |
| | | } |
| | | return make_image(0,0,0); |
| | | } |
| | |
| | | { |
| | | int i; |
| | | for(i = net.n-1; i >= 0; --i){ |
| | | if(net.types[i] == CONVOLUTIONAL){ |
| | | convolutional_layer layer = *(convolutional_layer *)net.layers[i]; |
| | | return layer.output; |
| | | } |
| | | else if(net.types[i] == MAXPOOL){ |
| | | maxpool_layer layer = *(maxpool_layer *)net.layers[i]; |
| | | return layer.output; |
| | | } |
| | | image m = get_network_image_layer(net, i); |
| | | if(m.h != 0) return m; |
| | | } |
| | | return make_image(1,1,1); |
| | | } |
| | | |
| | | void visualize_network(network net) |
| | | { |
| | | int i; |
| | | for(i = 0; i < 1; ++i){ |
| | | if(net.types[i] == CONVOLUTIONAL){ |
| | | convolutional_layer layer = *(convolutional_layer *)net.layers[i]; |
| | | visualize_convolutional_layer(layer); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | #define NETWORK_H |
| | | |
| | | #include "image.h" |
| | | #include "data.h" |
| | | |
| | | typedef enum { |
| | | CONVOLUTIONAL, |
| | |
| | | } network; |
| | | |
| | | network make_network(int n); |
| | | void run_network(image input, network net); |
| | | void learn_network(image input, network net); |
| | | void forward_network(network net, double *input); |
| | | void learn_network(network net, double *input); |
| | | void update_network(network net, double step); |
| | | void train_network_batch(network net, batch b); |
| | | double *get_network_output(network net); |
| | | double *get_network_output_layer(network net, int i); |
| | | double *get_network_delta_layer(network net, int i); |
| | | double *get_network_delta(network net); |
| | | int get_network_output_size_layer(network net, int i); |
| | | int get_network_output_size(network net); |
| | | image get_network_image(network net); |
| | | image get_network_image_layer(network net, int i); |
| | | |
| New file |
| | |
| | | #include <stdlib.h> |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | #include "option_list.h" |
| | | |
| | | typedef struct{ |
| | | char *key; |
| | | char *val; |
| | | int used; |
| | | } kvp; |
| | | |
| | | void option_insert(list *l, char *key, char *val) |
| | | { |
| | | kvp *p = malloc(sizeof(kvp)); |
| | | p->key = key; |
| | | p->val = val; |
| | | p->used = 0; |
| | | list_insert(l, p); |
| | | } |
| | | |
| | | void option_unused(list *l) |
| | | { |
| | | node *n = l->front; |
| | | while(n){ |
| | | kvp *p = (kvp *)n->val; |
| | | if(!p->used){ |
| | | fprintf(stderr, "Unused field: '%s = %s'\n", p->key, p->val); |
| | | } |
| | | n = n->next; |
| | | } |
| | | } |
| | | |
| | | char *option_find(list *l, char *key) |
| | | { |
| | | node *n = l->front; |
| | | while(n){ |
| | | kvp *p = (kvp *)n->val; |
| | | if(strcmp(p->key, key) == 0){ |
| | | p->used = 1; |
| | | return p->val; |
| | | } |
| | | n = n->next; |
| | | } |
| | | return 0; |
| | | } |
| | | char *option_find_str(list *l, char *key, char *def) |
| | | { |
| | | char *v = option_find(l, key); |
| | | if(v) return v; |
| | | fprintf(stderr, "%s: Using default '%s'\n", key, def); |
| | | return def; |
| | | } |
| | | |
| | | int option_find_int(list *l, char *key, int def) |
| | | { |
| | | char *v = option_find(l, key); |
| | | if(v) return atoi(v); |
| | | fprintf(stderr, "%s: Using default '%d'\n", key, def); |
| | | return def; |
| | | } |
| | | |
| | | double option_find_double(list *l, char *key, double def) |
| | | { |
| | | char *v = option_find(l, key); |
| | | if(v) return atof(v); |
| | | fprintf(stderr, "%s: Using default '%lf'\n", key, def); |
| | | return def; |
| | | } |
| New file |
| | |
| | | #ifndef OPTION_LIST_H |
| | | #define OPTION_LIST_H |
| | | #include "list.h" |
| | | |
| | | void option_insert(list *l, char *key, char *val); |
| | | char *option_find(list *l, char *key); |
| | | char *option_find_str(list *l, char *key, char *def); |
| | | int option_find_int(list *l, char *key, int def); |
| | | double option_find_double(list *l, char *key, double def); |
| | | void option_unused(list *l); |
| | | |
| | | #endif |
| New file |
| | |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | #include <stdlib.h> |
| | | |
| | | #include "parser.h" |
| | | #include "activations.h" |
| | | #include "convolutional_layer.h" |
| | | #include "connected_layer.h" |
| | | #include "maxpool_layer.h" |
| | | #include "list.h" |
| | | #include "option_list.h" |
| | | #include "utils.h" |
| | | |
| | | typedef struct{ |
| | | char *type; |
| | | list *options; |
| | | }section; |
| | | |
| | | int is_convolutional(section *s); |
| | | int is_connected(section *s); |
| | | int is_maxpool(section *s); |
| | | list *read_cfg(char *filename); |
| | | |
| | | |
| | | network parse_network_cfg(char *filename) |
| | | { |
| | | list *sections = read_cfg(filename); |
| | | network net = make_network(sections->size); |
| | | |
| | | node *n = sections->front; |
| | | int count = 0; |
| | | while(n){ |
| | | section *s = (section *)n->val; |
| | | list *options = s->options; |
| | | if(is_convolutional(s)){ |
| | | int h,w,c; |
| | | int n = option_find_int(options, "filters",1); |
| | | int size = option_find_int(options, "size",1); |
| | | int stride = option_find_int(options, "stride",1); |
| | | char *activation_s = option_find_str(options, "activation", "sigmoid"); |
| | | ACTIVATION activation = get_activation(activation_s); |
| | | if(count == 0){ |
| | | h = option_find_int(options, "height",1); |
| | | w = option_find_int(options, "width",1); |
| | | c = option_find_int(options, "channels",1); |
| | | }else{ |
| | | image m = get_network_image_layer(net, count-1); |
| | | h = m.h; |
| | | w = m.w; |
| | | c = m.c; |
| | | if(h == 0) error("Layer before convolutional layer must output image."); |
| | | } |
| | | convolutional_layer *layer = make_convolutional_layer(h,w,c,n,size,stride, activation); |
| | | net.types[count] = CONVOLUTIONAL; |
| | | net.layers[count] = layer; |
| | | option_unused(options); |
| | | } |
| | | else if(is_connected(s)){ |
| | | int input; |
| | | int output = option_find_int(options, "output",1); |
| | | char *activation_s = option_find_str(options, "activation", "sigmoid"); |
| | | ACTIVATION activation = get_activation(activation_s); |
| | | if(count == 0){ |
| | | input = option_find_int(options, "input",1); |
| | | }else{ |
| | | input = get_network_output_size_layer(net, count-1); |
| | | } |
| | | connected_layer *layer = make_connected_layer(input, output, activation); |
| | | net.types[count] = CONNECTED; |
| | | net.layers[count] = layer; |
| | | option_unused(options); |
| | | }else if(is_maxpool(s)){ |
| | | int h,w,c; |
| | | int stride = option_find_int(options, "stride",1); |
| | | //char *activation_s = option_find_str(options, "activation", "sigmoid"); |
| | | if(count == 0){ |
| | | h = option_find_int(options, "height",1); |
| | | w = option_find_int(options, "width",1); |
| | | c = option_find_int(options, "channels",1); |
| | | }else{ |
| | | image m = get_network_image_layer(net, count-1); |
| | | h = m.h; |
| | | w = m.w; |
| | | c = m.c; |
| | | if(h == 0) error("Layer before convolutional layer must output image."); |
| | | } |
| | | maxpool_layer *layer = make_maxpool_layer(h,w,c,stride); |
| | | net.types[count] = MAXPOOL; |
| | | net.layers[count] = layer; |
| | | option_unused(options); |
| | | }else{ |
| | | fprintf(stderr, "Type not recognized: %s\n", s->type); |
| | | } |
| | | ++count; |
| | | n = n->next; |
| | | } |
| | | return net; |
| | | } |
| | | |
| | | int is_convolutional(section *s) |
| | | { |
| | | return (strcmp(s->type, "[conv]")==0 |
| | | || strcmp(s->type, "[convolutional]")==0); |
| | | } |
| | | int is_connected(section *s) |
| | | { |
| | | return (strcmp(s->type, "[conn]")==0 |
| | | || strcmp(s->type, "[connected]")==0); |
| | | } |
| | | int is_maxpool(section *s) |
| | | { |
| | | return (strcmp(s->type, "[max]")==0 |
| | | || strcmp(s->type, "[maxpool]")==0); |
| | | } |
| | | |
| | | int read_option(char *s, list *options) |
| | | { |
| | | int i; |
| | | int len = strlen(s); |
| | | char *val = 0; |
| | | for(i = 0; i < len; ++i){ |
| | | if(s[i] == '='){ |
| | | s[i] = '\0'; |
| | | val = s+i+1; |
| | | break; |
| | | } |
| | | } |
| | | if(i == len-1) return 0; |
| | | char *key = s; |
| | | option_insert(options, key, val); |
| | | return 1; |
| | | } |
| | | |
| | | list *read_cfg(char *filename) |
| | | { |
| | | FILE *file = fopen(filename, "r"); |
| | | if(file == 0) file_error(filename); |
| | | char *line; |
| | | int nu = 0; |
| | | list *sections = make_list(); |
| | | section *current = 0; |
| | | while((line=fgetl(file)) != 0){ |
| | | ++ nu; |
| | | strip(line); |
| | | switch(line[0]){ |
| | | case '[': |
| | | current = malloc(sizeof(section)); |
| | | list_insert(sections, current); |
| | | current->options = make_list(); |
| | | current->type = line; |
| | | break; |
| | | case '\0': |
| | | case '#': |
| | | case ';': |
| | | free(line); |
| | | break; |
| | | default: |
| | | if(!read_option(line, current->options)){ |
| | | printf("Config file error line %d, could parse: %s\n", nu, line); |
| | | free(line); |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | fclose(file); |
| | | return sections; |
| | | } |
| | | |
| New file |
| | |
| | | #ifndef PARSER_H |
| | | #define PARSER_H |
| | | #include "network.h" |
| | | |
| | | network parse_network_cfg(char *filename); |
| | | |
| | | #endif |
| | |
| | | #include "network.h" |
| | | #include "image.h" |
| | | #include "parser.h" |
| | | #include "data.h" |
| | | #include "matrix.h" |
| | | |
| | | #include <time.h> |
| | | #include <stdlib.h> |
| | |
| | | int n = 3; |
| | | int stride = 1; |
| | | int size = 3; |
| | | convolutional_layer layer = *make_convolutional_layer(dog.h, dog.w, dog.c, n, size, stride); |
| | | convolutional_layer layer = *make_convolutional_layer(dog.h, dog.w, dog.c, n, size, stride, RELU); |
| | | char buff[256]; |
| | | for(i = 0; i < n; ++i) { |
| | | sprintf(buff, "Kernel %d", i); |
| | | show_image(layer.kernels[i], buff); |
| | | } |
| | | run_convolutional_layer(dog, layer); |
| | | forward_convolutional_layer(layer, dog.data); |
| | | |
| | | maxpool_layer mlayer = *make_maxpool_layer(layer.output.h, layer.output.w, layer.output.c, 2); |
| | | run_maxpool_layer(layer.output,mlayer); |
| | | image output = get_convolutional_image(layer); |
| | | maxpool_layer mlayer = *make_maxpool_layer(output.h, output.w, output.c, 2); |
| | | forward_maxpool_layer(mlayer, layer.output); |
| | | |
| | | show_image_layers(mlayer.output, "Test Maxpool Layer"); |
| | | show_image_layers(get_maxpool_image(mlayer), "Test Maxpool Layer"); |
| | | } |
| | | |
| | | void test_load() |
| | |
| | | show_image(random, "Test Rotate Random"); |
| | | } |
| | | |
| | | void test_network() |
| | | { |
| | | network net; |
| | | net.n = 11; |
| | | net.layers = calloc(net.n, sizeof(void *)); |
| | | net.types = calloc(net.n, sizeof(LAYER_TYPE)); |
| | | net.types[0] = CONVOLUTIONAL; |
| | | net.types[1] = MAXPOOL; |
| | | net.types[2] = CONVOLUTIONAL; |
| | | net.types[3] = MAXPOOL; |
| | | net.types[4] = CONVOLUTIONAL; |
| | | net.types[5] = CONVOLUTIONAL; |
| | | net.types[6] = CONVOLUTIONAL; |
| | | net.types[7] = MAXPOOL; |
| | | net.types[8] = CONNECTED; |
| | | net.types[9] = CONNECTED; |
| | | net.types[10] = CONNECTED; |
| | | |
| | | image dog = load_image("test_hinton.jpg"); |
| | | |
| | | int n = 48; |
| | | int stride = 4; |
| | | int size = 11; |
| | | convolutional_layer cl = *make_convolutional_layer(dog.h, dog.w, dog.c, n, size, stride); |
| | | maxpool_layer ml = *make_maxpool_layer(cl.output.h, cl.output.w, cl.output.c, 2); |
| | | |
| | | n = 128; |
| | | size = 5; |
| | | stride = 1; |
| | | convolutional_layer cl2 = *make_convolutional_layer(ml.output.h, ml.output.w, ml.output.c, n, size, stride); |
| | | maxpool_layer ml2 = *make_maxpool_layer(cl2.output.h, cl2.output.w, cl2.output.c, 2); |
| | | |
| | | n = 192; |
| | | size = 3; |
| | | convolutional_layer cl3 = *make_convolutional_layer(ml2.output.h, ml2.output.w, ml2.output.c, n, size, stride); |
| | | convolutional_layer cl4 = *make_convolutional_layer(cl3.output.h, cl3.output.w, cl3.output.c, n, size, stride); |
| | | n = 128; |
| | | convolutional_layer cl5 = *make_convolutional_layer(cl4.output.h, cl4.output.w, cl4.output.c, n, size, stride); |
| | | maxpool_layer ml3 = *make_maxpool_layer(cl5.output.h, cl5.output.w, cl5.output.c, 4); |
| | | connected_layer nl = *make_connected_layer(ml3.output.h*ml3.output.w*ml3.output.c, 4096, RELU); |
| | | connected_layer nl2 = *make_connected_layer(4096, 4096, RELU); |
| | | connected_layer nl3 = *make_connected_layer(4096, 1000, RELU); |
| | | |
| | | net.layers[0] = &cl; |
| | | net.layers[1] = &ml; |
| | | net.layers[2] = &cl2; |
| | | net.layers[3] = &ml2; |
| | | net.layers[4] = &cl3; |
| | | net.layers[5] = &cl4; |
| | | net.layers[6] = &cl5; |
| | | net.layers[7] = &ml3; |
| | | net.layers[8] = &nl; |
| | | net.layers[9] = &nl2; |
| | | net.layers[10] = &nl3; |
| | | |
| | | int i; |
| | | clock_t start = clock(), end; |
| | | for(i = 0; i < 10; ++i){ |
| | | run_network(dog, net); |
| | | rotate_image(dog); |
| | | } |
| | | end = clock(); |
| | | printf("Ran %lf second per iteration\n", (double)(end-start)/CLOCKS_PER_SEC/10); |
| | | |
| | | show_image_layers(get_network_image(net), "Test Network Layer"); |
| | | } |
| | | |
| | | void test_backpropagate() |
| | | { |
| | | int n = 3; |
| | | int size = 4; |
| | | int stride = 10; |
| | | image dog = load_image("dog.jpg"); |
| | | show_image(dog, "Test Backpropagate Input"); |
| | | image dog_copy = copy_image(dog); |
| | | convolutional_layer cl = *make_convolutional_layer(dog.h, dog.w, dog.c, n, size, stride); |
| | | run_convolutional_layer(dog, cl); |
| | | show_image(cl.output, "Test Backpropagate Output"); |
| | | int i; |
| | | clock_t start = clock(), end; |
| | | for(i = 0; i < 100; ++i){ |
| | | backpropagate_convolutional_layer(dog_copy, cl); |
| | | } |
| | | end = clock(); |
| | | printf("Backpropagate: %lf seconds\n", (double)(end-start)/CLOCKS_PER_SEC); |
| | | start = clock(); |
| | | for(i = 0; i < 100; ++i){ |
| | | backpropagate_convolutional_layer_convolve(dog, cl); |
| | | } |
| | | end = clock(); |
| | | printf("Backpropagate Using Convolutions: %lf seconds\n", (double)(end-start)/CLOCKS_PER_SEC); |
| | | show_image(dog_copy, "Test Backpropagate 1"); |
| | | show_image(dog, "Test Backpropagate 2"); |
| | | subtract_image(dog, dog_copy); |
| | | show_image(dog, "Test Backpropagate Difference"); |
| | | } |
| | | |
| | | void test_ann() |
| | | { |
| | | network net; |
| | | net.n = 3; |
| | | net.layers = calloc(net.n, sizeof(void *)); |
| | | net.types = calloc(net.n, sizeof(LAYER_TYPE)); |
| | | net.types[0] = CONNECTED; |
| | | net.types[1] = CONNECTED; |
| | | net.types[2] = CONNECTED; |
| | | |
| | | connected_layer nl = *make_connected_layer(1, 20, RELU); |
| | | connected_layer nl2 = *make_connected_layer(20, 20, RELU); |
| | | connected_layer nl3 = *make_connected_layer(20, 1, RELU); |
| | | |
| | | net.layers[0] = &nl; |
| | | net.layers[1] = &nl2; |
| | | net.layers[2] = &nl3; |
| | | |
| | | image t = make_image(1,1,1); |
| | | int count = 0; |
| | | |
| | | double avgerr = 0; |
| | | while(1){ |
| | | double v = ((double)rand()/RAND_MAX); |
| | | double truth = v*v; |
| | | set_pixel(t,0,0,0,v); |
| | | run_network(t, net); |
| | | double *out = get_network_output(net); |
| | | double err = pow((out[0]-truth),2.); |
| | | avgerr = .99 * avgerr + .01 * err; |
| | | //if(++count % 100000 == 0) printf("%f\n", avgerr); |
| | | if(++count % 100000 == 0) printf("%f %f :%f AVG %f \n", truth, out[0], err, avgerr); |
| | | out[0] = truth - out[0]; |
| | | learn_network(t, net); |
| | | update_network(net, .001); |
| | | } |
| | | |
| | | } |
| | | |
| | | void test_parser() |
| | | { |
| | | network net = parse_network_cfg("test.cfg"); |
| | | image t = make_image(1,1,1); |
| | | network net = parse_network_cfg("test_parser.cfg"); |
| | | double input[1]; |
| | | int count = 0; |
| | | |
| | | double avgerr = 0; |
| | | while(1){ |
| | | double v = ((double)rand()/RAND_MAX); |
| | | double truth = v*v; |
| | | set_pixel(t,0,0,0,v); |
| | | run_network(t, net); |
| | | input[0] = v; |
| | | forward_network(net, input); |
| | | double *out = get_network_output(net); |
| | | double *delta = get_network_delta(net); |
| | | double err = pow((out[0]-truth),2.); |
| | | avgerr = .99 * avgerr + .01 * err; |
| | | //if(++count % 100000 == 0) printf("%f\n", avgerr); |
| | | if(++count % 100000 == 0) printf("%f %f :%f AVG %f \n", truth, out[0], err, avgerr); |
| | | out[0] = truth - out[0]; |
| | | learn_network(t, net); |
| | | if(++count % 1000000 == 0) printf("%f %f :%f AVG %f \n", truth, out[0], err, avgerr); |
| | | delta[0] = truth - out[0]; |
| | | learn_network(net, input); |
| | | update_network(net, .001); |
| | | } |
| | | } |
| | | |
| | | void test_data() |
| | | { |
| | | batch train = random_batch("train_paths.txt", 101); |
| | | show_image(train.images[0], "Test Data Loading"); |
| | | show_image(train.images[100], "Test Data Loading"); |
| | | show_image(train.images[10], "Test Data Loading"); |
| | | free_batch(train); |
| | | } |
| | | |
| | | void test_train() |
| | | { |
| | | network net = parse_network_cfg("test.cfg"); |
| | | srand(0); |
| | | //visualize_network(net); |
| | | int i = 1000; |
| | | //while(1){ |
| | | while(i > 0){ |
| | | batch train = random_batch("train_paths.txt", 100); |
| | | train_network_batch(net, train); |
| | | //show_image_layers(get_network_image(net), "hey"); |
| | | //visualize_network(net); |
| | | //cvWaitKey(0); |
| | | free_batch(train); |
| | | --i; |
| | | } |
| | | //} |
| | | } |
| | | |
| | | double error_network(network net, matrix m, double *truth) |
| | | { |
| | | int i; |
| | | int correct = 0; |
| | | for(i = 0; i < m.rows; ++i){ |
| | | forward_network(net, m.vals[i]); |
| | | double *out = get_network_output(net); |
| | | double err = truth[i] - out[0]; |
| | | if(fabs(err) < .5) ++correct; |
| | | } |
| | | return (double)correct/m.rows; |
| | | } |
| | | |
| | | void classify_random_filters() |
| | | { |
| | | network net = parse_network_cfg("random_filter_finish.cfg"); |
| | | matrix m = csv_to_matrix("train.csv"); |
| | | matrix ho = hold_out_matrix(&m, 2500); |
| | | double *truth = pop_column(&m, 0); |
| | | double *ho_truth = pop_column(&ho, 0); |
| | | int i; |
| | | clock_t start = clock(), end; |
| | | int count = 0; |
| | | while(++count <= 300){ |
| | | for(i = 0; i < m.rows; ++i){ |
| | | int index = rand()%m.rows; |
| | | //image p = double_to_image(1690,1,1,m.vals[index]); |
| | | //normalize_image(p); |
| | | forward_network(net, m.vals[index]); |
| | | double *out = get_network_output(net); |
| | | double *delta = get_network_delta(net); |
| | | //printf("%f\n", out[0]); |
| | | delta[0] = truth[index] - out[0]; |
| | | // printf("%f\n", delta[0]); |
| | | //printf("%f %f\n", truth[index], out[0]); |
| | | learn_network(net, m.vals[index]); |
| | | update_network(net, .000005); |
| | | } |
| | | double test_acc = error_network(net, m, truth); |
| | | double valid_acc = error_network(net, ho, ho_truth); |
| | | printf("%f, %f\n", test_acc, valid_acc); |
| | | fprintf(stderr, "%5d: %f Valid: %f\n",count, test_acc, valid_acc); |
| | | //if(valid_acc > .70) break; |
| | | } |
| | | end = clock(); |
| | | FILE *fp = fopen("submission/out.txt", "w"); |
| | | matrix test = csv_to_matrix("test.csv"); |
| | | truth = pop_column(&test, 0); |
| | | for(i = 0; i < test.rows; ++i){ |
| | | forward_network(net, test.vals[i]); |
| | | double *out = get_network_output(net); |
| | | if(fabs(out[0]) < .5) fprintf(fp, "0\n"); |
| | | else fprintf(fp, "1\n"); |
| | | } |
| | | fclose(fp); |
| | | printf("Neural Net Learning: %lf seconds\n", (double)(end-start)/CLOCKS_PER_SEC); |
| | | } |
| | | |
| | | void test_random_filters() |
| | | { |
| | | FILE *file = fopen("test.csv", "w"); |
| | | int i,j,k; |
| | | srand(0); |
| | | network net = parse_network_cfg("test_random_filter.cfg"); |
| | | for(i = 0; i < 100; ++i){ |
| | | printf("%d\n", i); |
| | | batch part = get_batch("test_paths.txt", i, 100); |
| | | for(j = 0; j < part.n; ++j){ |
| | | forward_network(net, part.images[j].data); |
| | | double *out = get_network_output(net); |
| | | fprintf(file, "%f", part.truth[j][0]); |
| | | for(k = 0; k < get_network_output_size(net); ++k){ |
| | | fprintf(file, ",%f", out[k]); |
| | | } |
| | | fprintf(file, "\n"); |
| | | } |
| | | free_batch(part); |
| | | } |
| | | } |
| | | |
| | | int main() |
| | | { |
| | | test_parser(); |
| | | //classify_random_filters(); |
| | | //test_random_filters(); |
| | | test_train(); |
| | | //test_parser(); |
| | | //test_backpropagate(); |
| | | //test_ann(); |
| | | //test_convolve(); |
| New file |
| | |
| | | #include "utils.h" |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <math.h> |
| | | |
| | | void error(char *s) |
| | | { |
| | | fprintf(stderr, "Error: %s\n", s); |
| | | exit(0); |
| | | } |
| | | |
| | | void malloc_error() |
| | | { |
| | | fprintf(stderr, "Malloc error\n"); |
| | | exit(-1); |
| | | } |
| | | |
| | | void file_error(char *s) |
| | | { |
| | | fprintf(stderr, "Couldn't open file: %s\n", s); |
| | | exit(0); |
| | | } |
| | | |
| | | list *split_str(char *s, char delim) |
| | | { |
| | | int i; |
| | | int len = strlen(s); |
| | | list *l = make_list(); |
| | | list_insert(l, s); |
| | | for(i = 0; i < len; ++i){ |
| | | if(s[i] == delim){ |
| | | s[i] = '\0'; |
| | | list_insert(l, &(s[i+1])); |
| | | } |
| | | } |
| | | return l; |
| | | } |
| | | |
| | | void strip(char *s) |
| | | { |
| | | int i; |
| | | int len = strlen(s); |
| | | int offset = 0; |
| | | for(i = 0; i < len; ++i){ |
| | | char c = s[i]; |
| | | if(c==' '||c=='\t'||c=='\n') ++offset; |
| | | else s[i-offset] = c; |
| | | } |
| | | s[len-offset] = '\0'; |
| | | } |
| | | |
| | | void strip_char(char *s, char bad) |
| | | { |
| | | int i; |
| | | int len = strlen(s); |
| | | int offset = 0; |
| | | for(i = 0; i < len; ++i){ |
| | | char c = s[i]; |
| | | if(c==bad) ++offset; |
| | | else s[i-offset] = c; |
| | | } |
| | | s[len-offset] = '\0'; |
| | | } |
| | | |
| | | char *fgetl(FILE *fp) |
| | | { |
| | | if(feof(fp)) return 0; |
| | | int size = 512; |
| | | char *line = malloc(size*sizeof(char)); |
| | | if(!fgets(line, size, fp)){ |
| | | free(line); |
| | | return 0; |
| | | } |
| | | |
| | | int curr = strlen(line); |
| | | |
| | | while(line[curr-1]!='\n'){ |
| | | size *= 2; |
| | | line = realloc(line, size*sizeof(char)); |
| | | if(!line) malloc_error(); |
| | | fgets(&line[curr], size-curr, fp); |
| | | curr = strlen(line); |
| | | } |
| | | line[curr-1] = '\0'; |
| | | |
| | | return line; |
| | | } |
| | | |
| | | char *copy_string(char *s) |
| | | { |
| | | char *copy = malloc(strlen(s)+1); |
| | | strncpy(copy, s, strlen(s)+1); |
| | | return copy; |
| | | } |
| | | |
| | | list *parse_csv_line(char *line) |
| | | { |
| | | list *l = make_list(); |
| | | char *c, *p; |
| | | int in = 0; |
| | | for(c = line, p = line; *c != '\0'; ++c){ |
| | | if(*c == '"') in = !in; |
| | | else if(*c == ',' && !in){ |
| | | *c = '\0'; |
| | | list_insert(l, copy_string(p)); |
| | | p = c+1; |
| | | } |
| | | } |
| | | list_insert(l, copy_string(p)); |
| | | return l; |
| | | } |
| | | |
| | | int count_fields(char *line) |
| | | { |
| | | int count = 0; |
| | | int done = 0; |
| | | char *c; |
| | | for(c = line; !done; ++c){ |
| | | done = (*c == '\0'); |
| | | if(*c == ',' || done) ++count; |
| | | } |
| | | return count; |
| | | } |
| | | |
| | | double *parse_fields(char *line, int n) |
| | | { |
| | | double *field = calloc(n, sizeof(double)); |
| | | char *c, *p, *end; |
| | | int count = 0; |
| | | int done = 0; |
| | | for(c = line, p = line; !done; ++c){ |
| | | done = (*c == '\0'); |
| | | if(*c == ',' || done){ |
| | | *c = '\0'; |
| | | field[count] = strtod(p, &end); |
| | | if(p == c) field[count] = nan(""); |
| | | if(end != c && (end != c-1 || *end != '\r')) field[count] = nan(""); //DOS file formats! |
| | | p = c+1; |
| | | ++count; |
| | | } |
| | | } |
| | | return field; |
| | | } |
| | | |
| | | |
| | | |
| New file |
| | |
| | | #ifndef UTILS_H |
| | | #define UTILS_H |
| | | #include <stdio.h> |
| | | #include "list.h" |
| | | |
| | | void error(char *s); |
| | | void malloc_error(); |
| | | void file_error(char *s); |
| | | void strip(char *s); |
| | | void strip_char(char *s, char bad); |
| | | list *split_str(char *s, char delim); |
| | | char *fgetl(FILE *fp); |
| | | list *parse_csv_line(char *line); |
| | | char *copy_string(char *s); |
| | | int count_fields(char *line); |
| | | double *parse_fields(char *line, int n); |
| | | #endif |
| | | |
| New file |
| | |
| | | [conv] |
| | | width=200 |
| | | height=200 |
| | | channels=3 |
| | | filters=10 |
| | | size=3 |
| | | stride=2 |
| | | activation=relu |
| | | |
| | | [maxpool] |
| | | stride=2 |
| | | |
| | | [conv] |
| | | filters=10 |
| | | size=10 |
| | | stride=2 |
| | | activation=relu |
| | | |
| | | [maxpool] |
| | | stride=2 |
| | | |
| | | [conv] |
| | | filters=10 |
| | | size=10 |
| | | stride=2 |
| | | activation=relu |
| | | |
| | | [maxpool] |
| | | stride=2 |
| | | |
| | | [conn] |
| | | output = 10 |
| | | activation=relu |
| | | |
| | | [conn] |
| | | output = 1 |
| | | activation=relu |
| New file |
| | |
| | | [conn] |
| | | input=1 |
| | | output = 20 |
| | | activation=sigmoid |
| | | |
| | | [conn] |
| | | output = 1 |
| | | activation=sigmoid |
| New file |
| | |
| | | [conv] |
| | | width=200 |
| | | height=200 |
| | | channels=3 |
| | | filters=10 |
| | | size=15 |
| | | stride=2 |
| | | activation=relu |
| | | |
| | | [maxpool] |
| | | stride=2 |
| | | |
| | | [conv] |
| | | filters=10 |
| | | size=5 |
| | | stride=1 |
| | | activation=relu |
| | | |
| | | [maxpool] |
| | | stride=2 |
| | | |
| | | [conv] |
| | | filters=10 |
| | | size=3 |
| | | stride=1 |
| | | activation=relu |
| | | |
| | | [maxpool] |
| | | stride=2 |