mirror of
https://github.com/pjreddie/darknet.git
synced 2023-08-10 21:13:14 +03:00
Parsing, image loading, lots of stuff
This commit is contained in:
parent
d7286c2732
commit
2db9fbef2b
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,6 +5,7 @@ images/
|
||||
opencv/
|
||||
convnet/
|
||||
decaf/
|
||||
submission/
|
||||
cnn
|
||||
|
||||
# OS Generated #
|
||||
|
6
Makefile
6
Makefile
@ -1,10 +1,10 @@
|
||||
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
|
||||
|
||||
|
8
random_filter_finish.cfg
Normal file
8
random_filter_finish.cfg
Normal file
@ -0,0 +1,8 @@
|
||||
[conn]
|
||||
input = 1690
|
||||
output = 20
|
||||
activation=relu
|
||||
|
||||
[conn]
|
||||
output = 1
|
||||
activation=relu
|
@ -1,27 +1,32 @@
|
||||
#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;
|
||||
@ -37,7 +42,7 @@ connected_layer *make_connected_layer(int inputs, int outputs, ACTIVATION activa
|
||||
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){
|
||||
@ -49,48 +54,44 @@ void run_connected_layer(double *input, connected_layer layer)
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,15 @@ typedef struct{
|
||||
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)();
|
||||
@ -18,12 +24,11 @@ typedef struct{
|
||||
|
||||
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
|
||||
|
||||
|
@ -1,52 +1,93 @@
|
||||
#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;
|
||||
@ -66,25 +107,26 @@ void backpropagate_convolutional_layer_convolve(image input, convolutional_layer
|
||||
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];
|
||||
@ -93,3 +135,16 @@ void update_convolutional_layer(convolutional_layer layer, double step)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,22 +2,36 @@
|
||||
#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
|
||||
|
||||
|
108
src/data.c
Normal file
108
src/data.c
Normal file
@ -0,0 +1,108 @@
|
||||
#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;
|
||||
}
|
18
src/data.h
Normal file
18
src/data.h
Normal file
@ -0,0 +1,18 @@
|
||||
#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
|
29
src/image.c
29
src/image.c
@ -34,6 +34,18 @@ void normalize_image(image p)
|
||||
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)
|
||||
@ -95,16 +107,29 @@ 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 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));
|
||||
@ -132,7 +157,7 @@ image make_random_image(int h, int w, int c)
|
||||
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;
|
||||
}
|
||||
|
@ -15,13 +15,16 @@ void threshold_image(image p, double t);
|
||||
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);
|
||||
|
||||
|
90
src/list.c
Normal file
90
src/list.c
Normal file
@ -0,0 +1,90 @@
|
||||
#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;
|
||||
}
|
26
src/list.h
Normal file
26
src/list.h
Normal file
@ -0,0 +1,26 @@
|
||||
#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
|
106
src/matrix.c
Normal file
106
src/matrix.c
Normal file
@ -0,0 +1,106 @@
|
||||
#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");
|
||||
}
|
17
src/matrix.h
Normal file
17
src/matrix.h
Normal file
@ -0,0 +1,17 @@
|
||||
#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
|
@ -1,24 +1,41 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,12 +4,15 @@
|
||||
#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
|
||||
|
||||
|
154
src/network.c
154
src/network.c
@ -1,5 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include "network.h"
|
||||
#include "image.h"
|
||||
#include "data.h"
|
||||
|
||||
#include "connected_layer.h"
|
||||
#include "convolutional_layer.h"
|
||||
@ -14,27 +16,24 @@ network make_network(int n)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -52,74 +51,112 @@ void update_network(network net, double step)
|
||||
}
|
||||
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];
|
||||
@ -128,21 +165,21 @@ int get_network_output_size_layer(network net, int 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);
|
||||
}
|
||||
@ -151,15 +188,20 @@ image get_network_image(network net)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#define NETWORK_H
|
||||
|
||||
#include "image.h"
|
||||
#include "data.h"
|
||||
|
||||
typedef enum {
|
||||
CONVOLUTIONAL,
|
||||
@ -17,12 +18,16 @@ typedef struct {
|
||||
} 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);
|
||||
|
||||
|
68
src/option_list.c
Normal file
68
src/option_list.c
Normal file
@ -0,0 +1,68 @@
|
||||
#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;
|
||||
}
|
12
src/option_list.h
Normal file
12
src/option_list.h
Normal file
@ -0,0 +1,12 @@
|
||||
#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
|
168
src/parser.c
Normal file
168
src/parser.c
Normal file
@ -0,0 +1,168 @@
|
||||
#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;
|
||||
}
|
||||
|
7
src/parser.h
Normal file
7
src/parser.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef PARSER_H
|
||||
#define PARSER_H
|
||||
#include "network.h"
|
||||
|
||||
network parse_network_cfg(char *filename);
|
||||
|
||||
#endif
|
277
src/tests.c
277
src/tests.c
@ -4,6 +4,8 @@
|
||||
#include "network.h"
|
||||
#include "image.h"
|
||||
#include "parser.h"
|
||||
#include "data.h"
|
||||
#include "matrix.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
@ -40,18 +42,19 @@ void test_convolutional_layer()
|
||||
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()
|
||||
@ -90,168 +93,144 @@ void test_rotate()
|
||||
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();
|
||||
|
147
src/utils.c
Normal file
147
src/utils.c
Normal file
@ -0,0 +1,147 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
|
18
src/utils.h
Normal file
18
src/utils.h
Normal file
@ -0,0 +1,18 @@
|
||||
#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
|
||||
|
37
test.cfg
Normal file
37
test.cfg
Normal file
@ -0,0 +1,37 @@
|
||||
[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
|
8
test_parser.cfg
Normal file
8
test_parser.cfg
Normal file
@ -0,0 +1,8 @@
|
||||
[conn]
|
||||
input=1
|
||||
output = 20
|
||||
activation=sigmoid
|
||||
|
||||
[conn]
|
||||
output = 1
|
||||
activation=sigmoid
|
29
test_random_filter.cfg
Normal file
29
test_random_filter.cfg
Normal file
@ -0,0 +1,29 @@
|
||||
[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
|
Loading…
Reference in New Issue
Block a user