mirror of
https://github.com/pjreddie/darknet.git
synced 2023-08-10 21:13:14 +03:00
Working?
This commit is contained in:
parent
2db9fbef2b
commit
0d6bb5d44d
7
Makefile
7
Makefile
@ -1,10 +1,11 @@
|
|||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-Wall `pkg-config --cflags opencv` -O3 -ffast-math -flto -march=native
|
COMMON=-Wall `pkg-config --cflags opencv` -isystem /usr/local/Cellar/opencv/2.4.6.1/include/opencv -isystem /usr/local/Cellar/opencv/2.4.6.1/include
|
||||||
#CFLAGS=-Wall `pkg-config --cflags opencv` -O0 -g
|
CFLAGS= $(COMMON) -O3 -ffast-math -flto
|
||||||
|
#CFLAGS= $(COMMON) -O0 -g
|
||||||
LDFLAGS=`pkg-config --libs opencv` -lm
|
LDFLAGS=`pkg-config --libs opencv` -lm
|
||||||
VPATH=./src/
|
VPATH=./src/
|
||||||
|
|
||||||
OBJ=network.o image.o tests.o convolutional_layer.o connected_layer.o maxpool_layer.o activations.o list.o option_list.o parser.o utils.o data.o matrix.o
|
OBJ=network.o image.o tests.o convolutional_layer.o connected_layer.o maxpool_layer.o activations.o list.o option_list.o parser.o utils.o data.o matrix.o softmax_layer.o
|
||||||
|
|
||||||
all: cnn
|
all: cnn
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[conn]
|
[conn]
|
||||||
input=1690
|
input=1690
|
||||||
output = 20
|
output = 10
|
||||||
activation=relu
|
activation=relu
|
||||||
|
|
||||||
[conn]
|
[conn]
|
9
convolutional.cfg
Normal file
9
convolutional.cfg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[conv]
|
||||||
|
width=200
|
||||||
|
height=200
|
||||||
|
channels=3
|
||||||
|
filters=10
|
||||||
|
size=15
|
||||||
|
stride=16
|
||||||
|
activation=relu
|
||||||
|
|
21
full.cfg
Normal file
21
full.cfg
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[conv]
|
||||||
|
width=64
|
||||||
|
height=64
|
||||||
|
channels=3
|
||||||
|
filters=10
|
||||||
|
size=11
|
||||||
|
stride=2
|
||||||
|
activation=ramp
|
||||||
|
|
||||||
|
[maxpool]
|
||||||
|
stride=2
|
||||||
|
|
||||||
|
[conn]
|
||||||
|
output = 100
|
||||||
|
activation=ramp
|
||||||
|
|
||||||
|
[conn]
|
||||||
|
output = 2
|
||||||
|
activation=ramp
|
||||||
|
|
||||||
|
[softmax]
|
35
nist.cfg
Normal file
35
nist.cfg
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
[conv]
|
||||||
|
width=28
|
||||||
|
height=28
|
||||||
|
channels=1
|
||||||
|
filters=4
|
||||||
|
size=5
|
||||||
|
stride=1
|
||||||
|
activation=ramp
|
||||||
|
|
||||||
|
[maxpool]
|
||||||
|
stride=2
|
||||||
|
|
||||||
|
[conv]
|
||||||
|
filters=12
|
||||||
|
size=5
|
||||||
|
stride=1
|
||||||
|
activation=ramp
|
||||||
|
|
||||||
|
[maxpool]
|
||||||
|
stride=2
|
||||||
|
|
||||||
|
[conv]
|
||||||
|
filters=10
|
||||||
|
size=3
|
||||||
|
stride=1
|
||||||
|
activation=ramp
|
||||||
|
|
||||||
|
[maxpool]
|
||||||
|
stride=2
|
||||||
|
|
||||||
|
[conn]
|
||||||
|
output = 10
|
||||||
|
activation=ramp
|
||||||
|
|
||||||
|
[softmax]
|
10
nist_basic.cfg
Normal file
10
nist_basic.cfg
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[conn]
|
||||||
|
input=784
|
||||||
|
output = 100
|
||||||
|
activation=ramp
|
||||||
|
|
||||||
|
[conn]
|
||||||
|
output = 10
|
||||||
|
activation=ramp
|
||||||
|
|
||||||
|
[softmax]
|
@ -9,10 +9,38 @@ ACTIVATION get_activation(char *s)
|
|||||||
if (strcmp(s, "sigmoid")==0) return SIGMOID;
|
if (strcmp(s, "sigmoid")==0) return SIGMOID;
|
||||||
if (strcmp(s, "relu")==0) return RELU;
|
if (strcmp(s, "relu")==0) return RELU;
|
||||||
if (strcmp(s, "identity")==0) return IDENTITY;
|
if (strcmp(s, "identity")==0) return IDENTITY;
|
||||||
|
if (strcmp(s, "ramp")==0) return RAMP;
|
||||||
fprintf(stderr, "Couldn't find activation function %s, going with ReLU\n", s);
|
fprintf(stderr, "Couldn't find activation function %s, going with ReLU\n", s);
|
||||||
return RELU;
|
return RELU;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double activate(double x, ACTIVATION a){
|
||||||
|
switch(a){
|
||||||
|
case IDENTITY:
|
||||||
|
return x;
|
||||||
|
case SIGMOID:
|
||||||
|
return 1./(1.+exp(-x));
|
||||||
|
case RELU:
|
||||||
|
return x*(x>0);
|
||||||
|
case RAMP:
|
||||||
|
return x*(x>0) + .1*x;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
double gradient(double x, ACTIVATION a){
|
||||||
|
switch(a){
|
||||||
|
case IDENTITY:
|
||||||
|
return 1;
|
||||||
|
case SIGMOID:
|
||||||
|
return (1.-x)*x;
|
||||||
|
case RELU:
|
||||||
|
return (x>0);
|
||||||
|
case RAMP:
|
||||||
|
return (x>0) + .1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
double identity_activation(double x)
|
double identity_activation(double x)
|
||||||
{
|
{
|
||||||
return x;
|
return x;
|
||||||
@ -28,7 +56,7 @@ double relu_activation(double x)
|
|||||||
}
|
}
|
||||||
double relu_gradient(double x)
|
double relu_gradient(double x)
|
||||||
{
|
{
|
||||||
return (x>=0);
|
return (x>0);
|
||||||
}
|
}
|
||||||
|
|
||||||
double sigmoid_activation(double x)
|
double sigmoid_activation(double x)
|
||||||
|
@ -2,16 +2,13 @@
|
|||||||
#define ACTIVATIONS_H
|
#define ACTIVATIONS_H
|
||||||
|
|
||||||
typedef enum{
|
typedef enum{
|
||||||
SIGMOID, RELU, IDENTITY
|
SIGMOID, RELU, IDENTITY, RAMP
|
||||||
}ACTIVATION;
|
}ACTIVATION;
|
||||||
|
|
||||||
ACTIVATION get_activation(char *s);
|
ACTIVATION get_activation(char *s);
|
||||||
double relu_activation(double x);
|
|
||||||
double relu_gradient(double x);
|
double activate(double x, ACTIVATION a);
|
||||||
double sigmoid_activation(double x);
|
double gradient(double x, ACTIVATION a);
|
||||||
double sigmoid_gradient(double x);
|
|
||||||
double identity_activation(double x);
|
|
||||||
double identity_gradient(double x);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
#include "connected_layer.h"
|
#include "connected_layer.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
connected_layer *make_connected_layer(int inputs, int outputs, ACTIVATION activator)
|
connected_layer *make_connected_layer(int inputs, int outputs, ACTIVATION activation)
|
||||||
{
|
{
|
||||||
printf("Connected Layer: %d inputs, %d outputs\n", inputs, outputs);
|
printf("Connected Layer: %d inputs, %d outputs\n", inputs, outputs);
|
||||||
int i;
|
int i;
|
||||||
@ -19,26 +20,18 @@ connected_layer *make_connected_layer(int inputs, int outputs, ACTIVATION activa
|
|||||||
layer->weight_updates = calloc(inputs*outputs, sizeof(double));
|
layer->weight_updates = calloc(inputs*outputs, sizeof(double));
|
||||||
layer->weight_momentum = calloc(inputs*outputs, sizeof(double));
|
layer->weight_momentum = calloc(inputs*outputs, sizeof(double));
|
||||||
layer->weights = calloc(inputs*outputs, sizeof(double));
|
layer->weights = calloc(inputs*outputs, sizeof(double));
|
||||||
|
double scale = 2./inputs;
|
||||||
for(i = 0; i < inputs*outputs; ++i)
|
for(i = 0; i < inputs*outputs; ++i)
|
||||||
layer->weights[i] = .01*(.5 - (double)rand()/RAND_MAX);
|
layer->weights[i] = rand_normal()*scale;
|
||||||
|
|
||||||
layer->bias_updates = calloc(outputs, sizeof(double));
|
layer->bias_updates = calloc(outputs, sizeof(double));
|
||||||
layer->bias_momentum = calloc(outputs, sizeof(double));
|
layer->bias_momentum = calloc(outputs, sizeof(double));
|
||||||
layer->biases = calloc(outputs, sizeof(double));
|
layer->biases = calloc(outputs, sizeof(double));
|
||||||
for(i = 0; i < outputs; ++i)
|
for(i = 0; i < outputs; ++i)
|
||||||
|
//layer->biases[i] = rand_normal()*scale + scale;
|
||||||
layer->biases[i] = 1;
|
layer->biases[i] = 1;
|
||||||
|
|
||||||
if(activator == SIGMOID){
|
layer->activation = activation;
|
||||||
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;
|
return layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +43,7 @@ void forward_connected_layer(connected_layer layer, double *input)
|
|||||||
for(j = 0; j < layer.inputs; ++j){
|
for(j = 0; j < layer.inputs; ++j){
|
||||||
layer.output[i] += input[j]*layer.weights[i*layer.inputs + j];
|
layer.output[i] += input[j]*layer.weights[i*layer.inputs + j];
|
||||||
}
|
}
|
||||||
layer.output[i] = layer.activation(layer.output[i]);
|
layer.output[i] = activate(layer.output[i], layer.activation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +51,7 @@ void learn_connected_layer(connected_layer layer, double *input)
|
|||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
for(i = 0; i < layer.outputs; ++i){
|
for(i = 0; i < layer.outputs; ++i){
|
||||||
|
layer.delta[i] *= gradient(layer.output[i], layer.activation);
|
||||||
layer.bias_updates[i] += layer.delta[i];
|
layer.bias_updates[i] += layer.delta[i];
|
||||||
for(j = 0; j < layer.inputs; ++j){
|
for(j = 0; j < layer.inputs; ++j){
|
||||||
layer.weight_updates[i*layer.inputs + j] += layer.delta[i]*input[j];
|
layer.weight_updates[i*layer.inputs + j] += layer.delta[i]*input[j];
|
||||||
@ -69,12 +63,13 @@ void update_connected_layer(connected_layer layer, double step, double momentum,
|
|||||||
{
|
{
|
||||||
int i,j;
|
int i,j;
|
||||||
for(i = 0; i < layer.outputs; ++i){
|
for(i = 0; i < layer.outputs; ++i){
|
||||||
layer.bias_momentum[i] = step*(layer.bias_updates[i] - decay*layer.biases[i]) + momentum*layer.bias_momentum[i];
|
layer.bias_momentum[i] = step*(layer.bias_updates[i]) + momentum*layer.bias_momentum[i];
|
||||||
layer.biases[i] += layer.bias_momentum[i];
|
layer.biases[i] += layer.bias_momentum[i];
|
||||||
for(j = 0; j < layer.inputs; ++j){
|
for(j = 0; j < layer.inputs; ++j){
|
||||||
int index = i*layer.inputs+j;
|
int index = i*layer.inputs+j;
|
||||||
layer.weight_momentum[index] = step*(layer.weight_updates[index] - decay*layer.weights[index]) + momentum*layer.weight_momentum[index];
|
layer.weight_momentum[index] = step*(layer.weight_updates[index] - decay*layer.weights[index]) + momentum*layer.weight_momentum[index];
|
||||||
layer.weights[index] += layer.weight_momentum[index];
|
layer.weights[index] += layer.weight_momentum[index];
|
||||||
|
//layer.weights[index] = constrain(layer.weights[index], 100.);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memset(layer.bias_updates, 0, layer.outputs*sizeof(double));
|
memset(layer.bias_updates, 0, layer.outputs*sizeof(double));
|
||||||
@ -86,12 +81,10 @@ void backward_connected_layer(connected_layer layer, double *input, double *delt
|
|||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
for(j = 0; j < layer.inputs; ++j){
|
for(j = 0; j < layer.inputs; ++j){
|
||||||
double grad = layer.gradient(input[j]);
|
|
||||||
delta[j] = 0;
|
delta[j] = 0;
|
||||||
for(i = 0; i < layer.outputs; ++i){
|
for(i = 0; i < layer.outputs; ++i){
|
||||||
delta[j] += layer.delta[i]*layer.weights[i*layer.inputs + j];
|
delta[j] += layer.delta[i]*layer.weights[i*layer.inputs + j];
|
||||||
}
|
}
|
||||||
delta[j] *= grad;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,11 +18,11 @@ typedef struct{
|
|||||||
double *output;
|
double *output;
|
||||||
double *delta;
|
double *delta;
|
||||||
|
|
||||||
double (* activation)();
|
ACTIVATION activation;
|
||||||
double (* gradient)();
|
|
||||||
} connected_layer;
|
} connected_layer;
|
||||||
|
|
||||||
connected_layer *make_connected_layer(int inputs, int outputs, ACTIVATION activator);
|
connected_layer *make_connected_layer(int inputs, int outputs, ACTIVATION activation);
|
||||||
|
|
||||||
void forward_connected_layer(connected_layer layer, double *input);
|
void forward_connected_layer(connected_layer layer, double *input);
|
||||||
void backward_connected_layer(connected_layer layer, double *input, double *delta);
|
void backward_connected_layer(connected_layer layer, double *input, double *delta);
|
||||||
|
@ -1,55 +1,74 @@
|
|||||||
#include "convolutional_layer.h"
|
#include "convolutional_layer.h"
|
||||||
|
#include "utils.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
image get_convolutional_image(convolutional_layer layer)
|
image get_convolutional_image(convolutional_layer layer)
|
||||||
{
|
{
|
||||||
int h = (layer.h-1)/layer.stride + 1;
|
int h,w,c;
|
||||||
int w = (layer.w-1)/layer.stride + 1;
|
if(layer.edge){
|
||||||
int c = layer.n;
|
h = (layer.h-1)/layer.stride + 1;
|
||||||
|
w = (layer.w-1)/layer.stride + 1;
|
||||||
|
}else{
|
||||||
|
h = (layer.h - layer.size)/layer.stride+1;
|
||||||
|
w = (layer.h - layer.size)/layer.stride+1;
|
||||||
|
}
|
||||||
|
c = layer.n;
|
||||||
return double_to_image(h,w,c,layer.output);
|
return double_to_image(h,w,c,layer.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
image get_convolutional_delta(convolutional_layer layer)
|
image get_convolutional_delta(convolutional_layer layer)
|
||||||
{
|
{
|
||||||
int h = (layer.h-1)/layer.stride + 1;
|
int h,w,c;
|
||||||
int w = (layer.w-1)/layer.stride + 1;
|
if(layer.edge){
|
||||||
int c = layer.n;
|
h = (layer.h-1)/layer.stride + 1;
|
||||||
|
w = (layer.w-1)/layer.stride + 1;
|
||||||
|
}else{
|
||||||
|
h = (layer.h - layer.size)/layer.stride+1;
|
||||||
|
w = (layer.h - layer.size)/layer.stride+1;
|
||||||
|
}
|
||||||
|
c = layer.n;
|
||||||
return double_to_image(h,w,c,layer.delta);
|
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, ACTIVATION activator)
|
convolutional_layer *make_convolutional_layer(int h, int w, int c, int n, int size, int stride, ACTIVATION activation)
|
||||||
{
|
{
|
||||||
printf("Convolutional Layer: %d x %d x %d image, %d filters\n", h,w,c,n);
|
|
||||||
int i;
|
int i;
|
||||||
|
int out_h,out_w;
|
||||||
convolutional_layer *layer = calloc(1, sizeof(convolutional_layer));
|
convolutional_layer *layer = calloc(1, sizeof(convolutional_layer));
|
||||||
layer->h = h;
|
layer->h = h;
|
||||||
layer->w = w;
|
layer->w = w;
|
||||||
layer->c = c;
|
layer->c = c;
|
||||||
layer->n = n;
|
layer->n = n;
|
||||||
|
layer->edge = 0;
|
||||||
layer->stride = stride;
|
layer->stride = stride;
|
||||||
layer->kernels = calloc(n, sizeof(image));
|
layer->kernels = calloc(n, sizeof(image));
|
||||||
layer->kernel_updates = calloc(n, sizeof(image));
|
layer->kernel_updates = calloc(n, sizeof(image));
|
||||||
|
layer->kernel_momentum = calloc(n, sizeof(image));
|
||||||
layer->biases = calloc(n, sizeof(double));
|
layer->biases = calloc(n, sizeof(double));
|
||||||
layer->bias_updates = calloc(n, sizeof(double));
|
layer->bias_updates = calloc(n, sizeof(double));
|
||||||
|
layer->bias_momentum = calloc(n, sizeof(double));
|
||||||
|
double scale = 20./(size*size*c);
|
||||||
for(i = 0; i < n; ++i){
|
for(i = 0; i < n; ++i){
|
||||||
layer->biases[i] = .005;
|
//layer->biases[i] = rand_normal()*scale + scale;
|
||||||
layer->kernels[i] = make_random_kernel(size, c);
|
layer->biases[i] = 1;
|
||||||
layer->kernel_updates[i] = make_random_kernel(size, c);
|
layer->kernels[i] = make_random_kernel(size, c, scale);
|
||||||
|
layer->kernel_updates[i] = make_random_kernel(size, c, 0);
|
||||||
|
layer->kernel_momentum[i] = make_random_kernel(size, c, 0);
|
||||||
}
|
}
|
||||||
layer->output = calloc(((h-1)/stride+1) * ((w-1)/stride+1) * n, sizeof(double));
|
layer->size = 2*(size/2)+1;
|
||||||
layer->delta = calloc(((h-1)/stride+1) * ((w-1)/stride+1) * n, sizeof(double));
|
if(layer->edge){
|
||||||
|
out_h = (layer->h-1)/layer->stride + 1;
|
||||||
|
out_w = (layer->w-1)/layer->stride + 1;
|
||||||
|
}else{
|
||||||
|
out_h = (layer->h - layer->size)/layer->stride+1;
|
||||||
|
out_w = (layer->h - layer->size)/layer->stride+1;
|
||||||
|
}
|
||||||
|
printf("Convolutional Layer: %d x %d x %d image, %d filters -> %d x %d x %d image\n", h,w,c,n, out_h, out_w, n);
|
||||||
|
layer->output = calloc(out_h * out_w * n, sizeof(double));
|
||||||
|
layer->delta = calloc(out_h * out_w * n, sizeof(double));
|
||||||
layer->upsampled = make_image(h,w,n);
|
layer->upsampled = make_image(h,w,n);
|
||||||
|
layer->activation = activation;
|
||||||
|
|
||||||
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;
|
return layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,13 +78,13 @@ void forward_convolutional_layer(const convolutional_layer layer, double *in)
|
|||||||
image output = get_convolutional_image(layer);
|
image output = get_convolutional_image(layer);
|
||||||
int i,j;
|
int i,j;
|
||||||
for(i = 0; i < layer.n; ++i){
|
for(i = 0; i < layer.n; ++i){
|
||||||
convolve(input, layer.kernels[i], layer.stride, i, output);
|
convolve(input, layer.kernels[i], layer.stride, i, output, layer.edge);
|
||||||
}
|
}
|
||||||
for(i = 0; i < output.c; ++i){
|
for(i = 0; i < output.c; ++i){
|
||||||
for(j = 0; j < output.h*output.w; ++j){
|
for(j = 0; j < output.h*output.w; ++j){
|
||||||
int index = i*output.h*output.w + j;
|
int index = i*output.h*output.w + j;
|
||||||
output.data[index] += layer.biases[i];
|
output.data[index] += layer.biases[i];
|
||||||
output.data[index] = layer.activation(output.data[index]);
|
output.data[index] = activate(output.data[index], layer.activation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,32 +93,29 @@ void backward_convolutional_layer(convolutional_layer layer, double *input, doub
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
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 in_delta = double_to_image(layer.h, layer.w, layer.c, delta);
|
||||||
image out_delta = get_convolutional_delta(layer);
|
image out_delta = get_convolutional_delta(layer);
|
||||||
zero_image(in_delta);
|
zero_image(in_delta);
|
||||||
|
|
||||||
for(i = 0; i < layer.n; ++i){
|
for(i = 0; i < layer.n; ++i){
|
||||||
back_convolve(in_delta, layer.kernels[i], layer.stride, i, out_delta);
|
back_convolve(in_delta, layer.kernels[i], layer.stride, i, out_delta, layer.edge);
|
||||||
}
|
|
||||||
for(i = 0; i < layer.h*layer.w*layer.c; ++i){
|
|
||||||
in_delta.data[i] *= layer.gradient(in_image.data[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void backward_convolutional_layer2(convolutional_layer layer, double *input, double *delta)
|
||||||
void backpropagate_convolutional_layer_convolve(image input, convolutional_layer layer)
|
|
||||||
{
|
{
|
||||||
|
image in_delta = double_to_image(layer.h, layer.w, layer.c, delta);
|
||||||
|
image out_delta = get_convolutional_delta(layer);
|
||||||
int i,j;
|
int i,j;
|
||||||
for(i = 0; i < layer.n; ++i){
|
for(i = 0; i < layer.n; ++i){
|
||||||
rotate_image(layer.kernels[i]);
|
rotate_image(layer.kernels[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
zero_image(input);
|
zero_image(in_delta);
|
||||||
upsample_image(layer.output, layer.stride, layer.upsampled);
|
upsample_image(out_delta, layer.stride, layer.upsampled);
|
||||||
for(j = 0; j < input.c; ++j){
|
for(j = 0; j < in_delta.c; ++j){
|
||||||
for(i = 0; i < layer.n; ++i){
|
for(i = 0; i < layer.n; ++i){
|
||||||
two_d_convolve(layer.upsampled, i, layer.kernels[i], j, 1, input, j);
|
two_d_convolve(layer.upsampled, i, layer.kernels[i], j, 1, in_delta, j, layer.edge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,34 +123,99 @@ void backpropagate_convolutional_layer_convolve(image input, convolutional_layer
|
|||||||
rotate_image(layer.kernels[i]);
|
rotate_image(layer.kernels[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
void learn_convolutional_layer(convolutional_layer layer, double *input)
|
void learn_convolutional_layer(convolutional_layer layer, double *input)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
image in_image = double_to_image(layer.h, layer.w, layer.c, input);
|
image in_image = double_to_image(layer.h, layer.w, layer.c, input);
|
||||||
image out_delta = get_convolutional_delta(layer);
|
image out_delta = get_convolutional_delta(layer);
|
||||||
|
image out_image = get_convolutional_image(layer);
|
||||||
|
for(i = 0; i < out_image.h*out_image.w*out_image.c; ++i){
|
||||||
|
out_delta.data[i] *= gradient(out_image.data[i], layer.activation);
|
||||||
|
}
|
||||||
for(i = 0; i < layer.n; ++i){
|
for(i = 0; i < layer.n; ++i){
|
||||||
kernel_update(in_image, layer.kernel_updates[i], layer.stride, i, out_delta);
|
kernel_update(in_image, layer.kernel_updates[i], layer.stride, i, out_delta, layer.edge);
|
||||||
layer.bias_updates[i] += avg_image_layer(out_delta, i);
|
layer.bias_updates[i] += avg_image_layer(out_delta, i);
|
||||||
|
//printf("%30.20lf\n", layer.bias_updates[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_convolutional_layer(convolutional_layer layer, double step)
|
void update_convolutional_layer(convolutional_layer layer, double step, double momentum, double decay)
|
||||||
{
|
{
|
||||||
return;
|
//step = .01;
|
||||||
int i,j;
|
int i,j;
|
||||||
for(i = 0; i < layer.n; ++i){
|
for(i = 0; i < layer.n; ++i){
|
||||||
layer.biases[i] += step*layer.bias_updates[i];
|
layer.bias_momentum[i] = step*(layer.bias_updates[i])
|
||||||
|
+ momentum*layer.bias_momentum[i];
|
||||||
|
layer.biases[i] += layer.bias_momentum[i];
|
||||||
|
//layer.biases[i] = constrain(layer.biases[i],1.);
|
||||||
layer.bias_updates[i] = 0;
|
layer.bias_updates[i] = 0;
|
||||||
int pixels = layer.kernels[i].h*layer.kernels[i].w*layer.kernels[i].c;
|
int pixels = layer.kernels[i].h*layer.kernels[i].w*layer.kernels[i].c;
|
||||||
for(j = 0; j < pixels; ++j){
|
for(j = 0; j < pixels; ++j){
|
||||||
layer.kernels[i].data[j] += step*layer.kernel_updates[i].data[j];
|
layer.kernel_momentum[i].data[j] = step*(layer.kernel_updates[i].data[j] - decay*layer.kernels[i].data[j])
|
||||||
|
+ momentum*layer.kernel_momentum[i].data[j];
|
||||||
|
layer.kernels[i].data[j] += layer.kernel_momentum[i].data[j];
|
||||||
|
//layer.kernels[i].data[j] = constrain(layer.kernels[i].data[j], 1.);
|
||||||
}
|
}
|
||||||
zero_image(layer.kernel_updates[i]);
|
zero_image(layer.kernel_updates[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void visualize_convolutional_filters(convolutional_layer layer, char *window)
|
||||||
|
{
|
||||||
|
int color = 1;
|
||||||
|
int border = 1;
|
||||||
|
int h,w,c;
|
||||||
|
int size = layer.size;
|
||||||
|
h = size;
|
||||||
|
w = (size + border) * layer.n - border;
|
||||||
|
c = layer.kernels[0].c;
|
||||||
|
if(c != 3 || !color){
|
||||||
|
h = (h+border)*c - border;
|
||||||
|
c = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
image filters = make_image(h,w,c);
|
||||||
|
int i,j;
|
||||||
|
for(i = 0; i < layer.n; ++i){
|
||||||
|
int w_offset = i*(size+border);
|
||||||
|
image k = layer.kernels[i];
|
||||||
|
image copy = copy_image(k);
|
||||||
|
/*
|
||||||
|
printf("Kernel %d - Bias: %f, Channels:",i,layer.biases[i]);
|
||||||
|
for(j = 0; j < k.c; ++j){
|
||||||
|
double a = avg_image_layer(k, j);
|
||||||
|
printf("%f, ", a);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
*/
|
||||||
|
normalize_image(copy);
|
||||||
|
for(j = 0; j < k.c; ++j){
|
||||||
|
set_pixel(copy,0,0,j,layer.biases[i]);
|
||||||
|
}
|
||||||
|
if(c == 3 && color){
|
||||||
|
embed_image(copy, filters, 0, w_offset);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
for(j = 0; j < k.c; ++j){
|
||||||
|
int h_offset = j*(size+border);
|
||||||
|
image layer = get_image_layer(k, j);
|
||||||
|
embed_image(layer, filters, h_offset, w_offset);
|
||||||
|
free_image(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free_image(copy);
|
||||||
|
}
|
||||||
|
image delta = get_convolutional_delta(layer);
|
||||||
|
image dc = collapse_image_layers(delta, 1);
|
||||||
|
char buff[256];
|
||||||
|
sprintf(buff, "%s: Delta", window);
|
||||||
|
show_image(dc, buff);
|
||||||
|
free_image(dc);
|
||||||
|
show_image(filters, window);
|
||||||
|
free_image(filters);
|
||||||
|
}
|
||||||
|
|
||||||
void visualize_convolutional_layer(convolutional_layer layer)
|
void visualize_convolutional_layer(convolutional_layer layer)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -7,27 +7,31 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
int h,w,c;
|
int h,w,c;
|
||||||
int n;
|
int n;
|
||||||
|
int size;
|
||||||
int stride;
|
int stride;
|
||||||
image *kernels;
|
image *kernels;
|
||||||
image *kernel_updates;
|
image *kernel_updates;
|
||||||
|
image *kernel_momentum;
|
||||||
double *biases;
|
double *biases;
|
||||||
double *bias_updates;
|
double *bias_updates;
|
||||||
|
double *bias_momentum;
|
||||||
image upsampled;
|
image upsampled;
|
||||||
double *delta;
|
double *delta;
|
||||||
double *output;
|
double *output;
|
||||||
|
|
||||||
double (* activation)();
|
ACTIVATION activation;
|
||||||
double (* gradient)();
|
int edge;
|
||||||
} convolutional_layer;
|
} convolutional_layer;
|
||||||
|
|
||||||
convolutional_layer *make_convolutional_layer(int h, int w, int c, int n, int size, int stride, ACTIVATION activator);
|
convolutional_layer *make_convolutional_layer(int h, int w, int c, int n, int size, int stride, ACTIVATION activation);
|
||||||
void forward_convolutional_layer(const convolutional_layer layer, double *in);
|
void forward_convolutional_layer(const convolutional_layer layer, double *in);
|
||||||
void backward_convolutional_layer(convolutional_layer layer, double *input, double *delta);
|
void backward_convolutional_layer(convolutional_layer layer, double *input, double *delta);
|
||||||
void learn_convolutional_layer(convolutional_layer layer, double *input);
|
void learn_convolutional_layer(convolutional_layer layer, double *input);
|
||||||
|
|
||||||
void update_convolutional_layer(convolutional_layer layer, double step);
|
void update_convolutional_layer(convolutional_layer layer, double step, double momentum, double decay);
|
||||||
|
|
||||||
void backpropagate_convolutional_layer_convolve(image input, convolutional_layer layer);
|
void backpropagate_convolutional_layer_convolve(image input, convolutional_layer layer);
|
||||||
|
void visualize_convolutional_filters(convolutional_layer layer, char *window);
|
||||||
void visualize_convolutional_layer(convolutional_layer layer);
|
void visualize_convolutional_layer(convolutional_layer layer);
|
||||||
|
|
||||||
image get_convolutional_image(convolutional_layer layer);
|
image get_convolutional_image(convolutional_layer layer);
|
||||||
|
31
src/data.c
31
src/data.c
@ -30,13 +30,18 @@ list *get_paths(char *filename)
|
|||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_truth(char *path)
|
void fill_truth(char *path, char **labels, int k, double *truth)
|
||||||
{
|
{
|
||||||
if(strstr(path, "dog")) return 1;
|
int i;
|
||||||
return 0;
|
memset(truth, 0, k*sizeof(double));
|
||||||
|
for(i = 0; i < k; ++i){
|
||||||
|
if(strstr(path, labels[i])){
|
||||||
|
truth[i] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
batch load_list(list *paths)
|
batch load_list(list *paths, char **labels, int k)
|
||||||
{
|
{
|
||||||
char *path;
|
char *path;
|
||||||
batch data = make_batch(paths->size, 2);
|
batch data = make_batch(paths->size, 2);
|
||||||
@ -45,16 +50,16 @@ batch load_list(list *paths)
|
|||||||
for(i = 0; i < data.n; ++i){
|
for(i = 0; i < data.n; ++i){
|
||||||
path = (char *)n->val;
|
path = (char *)n->val;
|
||||||
data.images[i] = load_image(path);
|
data.images[i] = load_image(path);
|
||||||
data.truth[i][0] = get_truth(path);
|
fill_truth(path, labels, k, data.truth[i]);
|
||||||
n = n->next;
|
n = n->next;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
batch get_all_data(char *filename)
|
batch get_all_data(char *filename, char **labels, int k)
|
||||||
{
|
{
|
||||||
list *paths = get_paths(filename);
|
list *paths = get_paths(filename);
|
||||||
batch b = load_list(paths);
|
batch b = load_list(paths, labels, k);
|
||||||
free_list_contents(paths);
|
free_list_contents(paths);
|
||||||
free_list(paths);
|
free_list(paths);
|
||||||
return b;
|
return b;
|
||||||
@ -71,7 +76,7 @@ void free_batch(batch b)
|
|||||||
free(b.truth);
|
free(b.truth);
|
||||||
}
|
}
|
||||||
|
|
||||||
batch get_batch(char *filename, int curr, int total)
|
batch get_batch(char *filename, int curr, int total, char **labels, int k)
|
||||||
{
|
{
|
||||||
list *plist = get_paths(filename);
|
list *plist = get_paths(filename);
|
||||||
char **paths = (char **)list_to_array(plist);
|
char **paths = (char **)list_to_array(plist);
|
||||||
@ -81,7 +86,7 @@ batch get_batch(char *filename, int curr, int total)
|
|||||||
batch b = make_batch(end-start, 2);
|
batch b = make_batch(end-start, 2);
|
||||||
for(i = start; i < end; ++i){
|
for(i = start; i < end; ++i){
|
||||||
b.images[i-start] = load_image(paths[i]);
|
b.images[i-start] = load_image(paths[i]);
|
||||||
b.truth[i-start][0] = get_truth(paths[i]);
|
fill_truth(paths[i], labels, k, b.truth[i-start]);
|
||||||
}
|
}
|
||||||
free_list_contents(plist);
|
free_list_contents(plist);
|
||||||
free_list(plist);
|
free_list(plist);
|
||||||
@ -89,7 +94,7 @@ batch get_batch(char *filename, int curr, int total)
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
batch random_batch(char *filename, int n)
|
batch random_batch(char *filename, int n, char **labels, int k)
|
||||||
{
|
{
|
||||||
list *plist = get_paths(filename);
|
list *plist = get_paths(filename);
|
||||||
char **paths = (char **)list_to_array(plist);
|
char **paths = (char **)list_to_array(plist);
|
||||||
@ -98,8 +103,10 @@ batch random_batch(char *filename, int n)
|
|||||||
for(i = 0; i < n; ++i){
|
for(i = 0; i < n; ++i){
|
||||||
int index = rand()%plist->size;
|
int index = rand()%plist->size;
|
||||||
b.images[i] = load_image(paths[index]);
|
b.images[i] = load_image(paths[index]);
|
||||||
normalize_image(b.images[i]);
|
//scale_image(b.images[i], 1./255.);
|
||||||
b.truth[i][0] = get_truth(paths[index]);
|
z_normalize_image(b.images[i]);
|
||||||
|
fill_truth(paths[index], labels, k, b.truth[i]);
|
||||||
|
//print_image(b.images[i]);
|
||||||
}
|
}
|
||||||
free_list_contents(plist);
|
free_list_contents(plist);
|
||||||
free_list(plist);
|
free_list(plist);
|
||||||
|
@ -9,9 +9,9 @@ typedef struct{
|
|||||||
double **truth;
|
double **truth;
|
||||||
} batch;
|
} batch;
|
||||||
|
|
||||||
batch get_all_data(char *filename);
|
batch get_all_data(char *filename, char **labels, int k);
|
||||||
batch random_batch(char *filename, int n);
|
batch random_batch(char *filename, int n, char **labels, int k);
|
||||||
batch get_batch(char *filename, int curr, int total);
|
batch get_batch(char *filename, int curr, int total, char **labels, int k);
|
||||||
void free_batch(batch b);
|
void free_batch(batch b);
|
||||||
|
|
||||||
|
|
||||||
|
148
src/image.c
148
src/image.c
@ -1,4 +1,5 @@
|
|||||||
#include "image.h"
|
#include "image.h"
|
||||||
|
#include "utils.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int windows = 0;
|
int windows = 0;
|
||||||
@ -9,6 +10,39 @@ void subtract_image(image a, image b)
|
|||||||
for(i = 0; i < a.h*a.w*a.c; ++i) a.data[i] -= b.data[i];
|
for(i = 0; i < a.h*a.w*a.c; ++i) a.data[i] -= b.data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void embed_image(image source, image dest, int h, int w)
|
||||||
|
{
|
||||||
|
int i,j,k;
|
||||||
|
for(k = 0; k < source.c; ++k){
|
||||||
|
for(i = 0; i < source.h; ++i){
|
||||||
|
for(j = 0; j < source.w; ++j){
|
||||||
|
double val = get_pixel(source, i,j,k);
|
||||||
|
set_pixel(dest, h+i, w+j, k, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image collapse_image_layers(image source, int border)
|
||||||
|
{
|
||||||
|
int h = source.h;
|
||||||
|
h = (h+border)*source.c - border;
|
||||||
|
image dest = make_image(h, source.w, 1);
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < source.c; ++i){
|
||||||
|
image layer = get_image_layer(source, i);
|
||||||
|
int h_offset = i*(source.h+border);
|
||||||
|
embed_image(layer, dest, h_offset, 0);
|
||||||
|
free_image(layer);
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void z_normalize_image(image p)
|
||||||
|
{
|
||||||
|
normalize_array(p.data, p.h*p.w*p.c);
|
||||||
|
}
|
||||||
|
|
||||||
void normalize_image(image p)
|
void normalize_image(image p)
|
||||||
{
|
{
|
||||||
double *min = calloc(p.c, sizeof(double));
|
double *min = calloc(p.c, sizeof(double));
|
||||||
@ -24,7 +58,7 @@ void normalize_image(image p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(i = 0; i < p.c; ++i){
|
for(i = 0; i < p.c; ++i){
|
||||||
if(max[i] - min[i] < .00001){
|
if(max[i] - min[i] < .000000001){
|
||||||
min[i] = 0;
|
min[i] = 0;
|
||||||
max[i] = 1;
|
max[i] = 1;
|
||||||
}
|
}
|
||||||
@ -71,12 +105,13 @@ void show_image(image p, char *name)
|
|||||||
normalize_image(copy);
|
normalize_image(copy);
|
||||||
|
|
||||||
char buff[256];
|
char buff[256];
|
||||||
sprintf(buff, "%s (%d)", name, windows);
|
//sprintf(buff, "%s (%d)", name, windows);
|
||||||
|
sprintf(buff, "%s", name);
|
||||||
|
|
||||||
IplImage *disp = cvCreateImage(cvSize(p.w,p.h), IPL_DEPTH_8U, p.c);
|
IplImage *disp = cvCreateImage(cvSize(p.w,p.h), IPL_DEPTH_8U, p.c);
|
||||||
int step = disp->widthStep;
|
int step = disp->widthStep;
|
||||||
cvNamedWindow(buff, CV_WINDOW_AUTOSIZE);
|
cvNamedWindow(buff, CV_WINDOW_AUTOSIZE);
|
||||||
cvMoveWindow(buff, 100*(windows%10) + 200*(windows/10), 100*(windows%10));
|
//cvMoveWindow(buff, 100*(windows%10) + 200*(windows/10), 100*(windows%10));
|
||||||
++windows;
|
++windows;
|
||||||
for(i = 0; i < p.h; ++i){
|
for(i = 0; i < p.h; ++i){
|
||||||
for(j = 0; j < p.w; ++j){
|
for(j = 0; j < p.w; ++j){
|
||||||
@ -85,9 +120,16 @@ void show_image(image p, char *name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(disp->height < 100 || disp->width < 100){
|
free_image(copy);
|
||||||
|
if(disp->height < 500 || disp->width < 500){
|
||||||
|
int w = 1500;
|
||||||
|
int h = w*p.h/p.w;
|
||||||
|
if(h > 1000){
|
||||||
|
h = 1000;
|
||||||
|
w = h*p.w/p.h;
|
||||||
|
}
|
||||||
IplImage *buffer = disp;
|
IplImage *buffer = disp;
|
||||||
disp = cvCreateImage(cvSize(100,100*p.h/p.w), buffer->depth, buffer->nChannels);
|
disp = cvCreateImage(cvSize(w, h), buffer->depth, buffer->nChannels);
|
||||||
cvResize(buffer, disp, CV_INTER_NN);
|
cvResize(buffer, disp, CV_INTER_NN);
|
||||||
cvReleaseImage(&buffer);
|
cvReleaseImage(&buffer);
|
||||||
}
|
}
|
||||||
@ -107,6 +149,13 @@ void show_image_layers(image p, char *name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void show_image_collapsed(image p, char *name)
|
||||||
|
{
|
||||||
|
image c = collapse_image_layers(p, 1);
|
||||||
|
show_image(c, name);
|
||||||
|
free_image(c);
|
||||||
|
}
|
||||||
|
|
||||||
image make_empty_image(int h, int w, int c)
|
image make_empty_image(int h, int w, int c)
|
||||||
{
|
{
|
||||||
image out;
|
image out;
|
||||||
@ -157,16 +206,29 @@ image make_random_image(int h, int w, int c)
|
|||||||
image out = make_image(h,w,c);
|
image out = make_image(h,w,c);
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < h*w*c; ++i){
|
for(i = 0; i < h*w*c; ++i){
|
||||||
out.data[i] = (.5-(double)rand()/RAND_MAX);
|
out.data[i] = rand_normal();
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
image make_random_kernel(int size, int c)
|
void add_scalar_image(image m, double s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < m.h*m.w*m.c; ++i) m.data[i] += s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scale_image(image m, double s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < m.h*m.w*m.c; ++i) m.data[i] *= s;
|
||||||
|
}
|
||||||
|
|
||||||
|
image make_random_kernel(int size, int c, double scale)
|
||||||
{
|
{
|
||||||
int pad;
|
int pad;
|
||||||
if((pad=(size%2==0))) ++size;
|
if((pad=(size%2==0))) ++size;
|
||||||
image out = make_random_image(size,size,c);
|
image out = make_random_image(size,size,c);
|
||||||
|
scale_image(out, scale);
|
||||||
int i,k;
|
int i,k;
|
||||||
if(pad){
|
if(pad){
|
||||||
for(k = 0; k < out.c; ++k){
|
for(k = 0; k < out.c; ++k){
|
||||||
@ -250,18 +312,29 @@ void add_pixel_extend(image m, int x, int y, int c, double val)
|
|||||||
add_pixel(m, x, y, c, val);
|
add_pixel(m, x, y, c, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void two_d_convolve(image m, int mc, image kernel, int kc, int stride, image out, int oc)
|
void two_d_convolve(image m, int mc, image kernel, int kc, int stride, image out, int oc, int edge)
|
||||||
{
|
{
|
||||||
int x,y,i,j;
|
int x,y,i,j;
|
||||||
for(x = 0; x < m.h; x += stride){
|
int xstart, xend, ystart, yend;
|
||||||
for(y = 0; y < m.w; y += stride){
|
if(edge){
|
||||||
|
xstart = ystart = 0;
|
||||||
|
xend = m.h;
|
||||||
|
yend = m.w;
|
||||||
|
}else{
|
||||||
|
xstart = kernel.h/2;
|
||||||
|
ystart = kernel.w/2;
|
||||||
|
xend = m.h-kernel.h/2;
|
||||||
|
yend = m.w - kernel.w/2;
|
||||||
|
}
|
||||||
|
for(x = xstart; x < xend; x += stride){
|
||||||
|
for(y = ystart; y < yend; y += stride){
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
for(i = 0; i < kernel.h; ++i){
|
for(i = 0; i < kernel.h; ++i){
|
||||||
for(j = 0; j < kernel.w; ++j){
|
for(j = 0; j < kernel.w; ++j){
|
||||||
sum += get_pixel(kernel, i, j, kc)*get_pixel_extend(m, x+i-kernel.h/2, y+j-kernel.w/2, mc);
|
sum += get_pixel(kernel, i, j, kc)*get_pixel_extend(m, x+i-kernel.h/2, y+j-kernel.w/2, mc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
add_pixel(out, x/stride, y/stride, oc, sum);
|
add_pixel(out, (x-xstart)/stride, (y-ystart)/stride, oc, sum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,13 +353,13 @@ double single_convolve(image m, image kernel, int x, int y)
|
|||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void convolve(image m, image kernel, int stride, int channel, image out)
|
void convolve(image m, image kernel, int stride, int channel, image out, int edge)
|
||||||
{
|
{
|
||||||
assert(m.c == kernel.c);
|
assert(m.c == kernel.c);
|
||||||
int i;
|
int i;
|
||||||
zero_channel(out, channel);
|
zero_channel(out, channel);
|
||||||
for(i = 0; i < m.c; ++i){
|
for(i = 0; i < m.c; ++i){
|
||||||
two_d_convolve(m, i, kernel, i, stride, out, channel);
|
two_d_convolve(m, i, kernel, i, stride, out, channel, edge);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
int j;
|
int j;
|
||||||
@ -326,20 +399,32 @@ void single_update(image m, image update, int x, int y, double error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void kernel_update(image m, image update, int stride, int channel, image out)
|
void kernel_update(image m, image update, int stride, int channel, image out, int edge)
|
||||||
{
|
{
|
||||||
assert(m.c == update.c);
|
assert(m.c == update.c);
|
||||||
zero_image(update);
|
zero_image(update);
|
||||||
int i, j;
|
int i, j, istart, jstart, iend, jend;
|
||||||
for(i = 0; i < m.h; i += stride){
|
if(edge){
|
||||||
for(j = 0; j < m.w; j += stride){
|
istart = jstart = 0;
|
||||||
double error = get_pixel(out, i/stride, j/stride, channel);
|
iend = m.h;
|
||||||
|
jend = m.w;
|
||||||
|
}else{
|
||||||
|
istart = update.h/2;
|
||||||
|
jstart = update.w/2;
|
||||||
|
iend = m.h-update.h/2;
|
||||||
|
jend = m.w - update.w/2;
|
||||||
|
}
|
||||||
|
for(i = istart; i < iend; i += stride){
|
||||||
|
for(j = jstart; j < jend; j += stride){
|
||||||
|
double error = get_pixel(out, (i-istart)/stride, (j-jstart)/stride, channel);
|
||||||
single_update(m, update, i, j, error);
|
single_update(m, update, i, j, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
for(i = 0; i < update.h*update.w*update.c; ++i){
|
for(i = 0; i < update.h*update.w*update.c; ++i){
|
||||||
update.data[i] /= (m.h/stride)*(m.w/stride);
|
update.data[i] /= (m.h/stride)*(m.w/stride);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void single_back_convolve(image m, image kernel, int x, int y, double val)
|
void single_back_convolve(image m, image kernel, int x, int y, double val)
|
||||||
@ -355,18 +440,35 @@ void single_back_convolve(image m, image kernel, int x, int y, double val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void back_convolve(image m, image kernel, int stride, int channel, image out)
|
void back_convolve(image m, image kernel, int stride, int channel, image out, int edge)
|
||||||
{
|
{
|
||||||
assert(m.c == kernel.c);
|
assert(m.c == kernel.c);
|
||||||
int i, j;
|
int i, j, istart, jstart, iend, jend;
|
||||||
for(i = 0; i < m.h; i += stride){
|
if(edge){
|
||||||
for(j = 0; j < m.w; j += stride){
|
istart = jstart = 0;
|
||||||
double val = get_pixel(out, i/stride, j/stride, channel);
|
iend = m.h;
|
||||||
|
jend = m.w;
|
||||||
|
}else{
|
||||||
|
istart = kernel.h/2;
|
||||||
|
jstart = kernel.w/2;
|
||||||
|
iend = m.h-kernel.h/2;
|
||||||
|
jend = m.w - kernel.w/2;
|
||||||
|
}
|
||||||
|
for(i = istart; i < iend; i += stride){
|
||||||
|
for(j = jstart; j < jend; j += stride){
|
||||||
|
double val = get_pixel(out, (i-istart)/stride, (j-jstart)/stride, channel);
|
||||||
single_back_convolve(m, kernel, i, j, val);
|
single_back_convolve(m, kernel, i, j, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_image(image m)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i =0 ; i < m.h*m.w*m.c; ++i) printf("%lf, ", m.data[i]);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
void free_image(image m)
|
void free_image(image m)
|
||||||
{
|
{
|
||||||
free(m.data);
|
free(m.data);
|
||||||
|
17
src/image.h
17
src/image.h
@ -10,20 +10,27 @@ typedef struct {
|
|||||||
double *data;
|
double *data;
|
||||||
} image;
|
} image;
|
||||||
|
|
||||||
|
void scale_image(image m, double s);
|
||||||
|
void add_scalar_image(image m, double s);
|
||||||
void normalize_image(image p);
|
void normalize_image(image p);
|
||||||
|
void z_normalize_image(image p);
|
||||||
void threshold_image(image p, double t);
|
void threshold_image(image p, double t);
|
||||||
void zero_image(image m);
|
void zero_image(image m);
|
||||||
void rotate_image(image m);
|
void rotate_image(image m);
|
||||||
void subtract_image(image a, image b);
|
void subtract_image(image a, image b);
|
||||||
double avg_image_layer(image m, int l);
|
double avg_image_layer(image m, int l);
|
||||||
|
void embed_image(image source, image dest, int h, int w);
|
||||||
|
image collapse_image_layers(image source, int border);
|
||||||
|
|
||||||
void show_image(image p, char *name);
|
void show_image(image p, char *name);
|
||||||
void show_image_layers(image p, char *name);
|
void show_image_layers(image p, char *name);
|
||||||
|
void show_image_collapsed(image p, char *name);
|
||||||
|
void print_image(image m);
|
||||||
|
|
||||||
image make_image(int h, int w, int c);
|
image make_image(int h, int w, int c);
|
||||||
image make_empty_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_image(int h, int w, int c);
|
||||||
image make_random_kernel(int size, int c);
|
image make_random_kernel(int size, int c, double scale);
|
||||||
image double_to_image(int h, int w, int c, double *data);
|
image double_to_image(int h, int w, int c, double *data);
|
||||||
image copy_image(image p);
|
image copy_image(image p);
|
||||||
image load_image(char *filename);
|
image load_image(char *filename);
|
||||||
@ -35,11 +42,11 @@ void set_pixel(image m, int x, int y, int c, double val);
|
|||||||
|
|
||||||
image get_image_layer(image m, int l);
|
image get_image_layer(image m, int l);
|
||||||
|
|
||||||
void two_d_convolve(image m, int mc, image kernel, int kc, int stride, image out, int oc);
|
void two_d_convolve(image m, int mc, image kernel, int kc, int stride, image out, int oc, int edge);
|
||||||
void upsample_image(image m, int stride, image out);
|
void upsample_image(image m, int stride, image out);
|
||||||
void convolve(image m, image kernel, int stride, int channel, image out);
|
void convolve(image m, image kernel, int stride, int channel, image out, int edge);
|
||||||
void back_convolve(image m, image kernel, int stride, int channel, image out);
|
void back_convolve(image m, image kernel, int stride, int channel, image out, int edge);
|
||||||
void kernel_update(image m, image update, int stride, int channel, image out);
|
void kernel_update(image m, image update, int stride, int channel, image out, int edge);
|
||||||
|
|
||||||
void free_image(image m);
|
void free_image(image m);
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,6 +9,14 @@ image get_maxpool_image(maxpool_layer layer)
|
|||||||
return double_to_image(h,w,c,layer.output);
|
return double_to_image(h,w,c,layer.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
image get_maxpool_delta(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.delta);
|
||||||
|
}
|
||||||
|
|
||||||
maxpool_layer *make_maxpool_layer(int h, int w, int c, int stride)
|
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);
|
printf("Maxpool Layer: %d x %d x %d image, %d stride\n", h,w,c,stride);
|
||||||
@ -39,3 +47,25 @@ void forward_maxpool_layer(const maxpool_layer layer, double *in)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void backward_maxpool_layer(const maxpool_layer layer, double *in, double *delta)
|
||||||
|
{
|
||||||
|
image input = double_to_image(layer.h, layer.w, layer.c, in);
|
||||||
|
image input_delta = double_to_image(layer.h, layer.w, layer.c, delta);
|
||||||
|
image output_delta = get_maxpool_delta(layer);
|
||||||
|
image output = get_maxpool_image(layer);
|
||||||
|
int i,j,k;
|
||||||
|
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(output, i/layer.stride, j/layer.stride, k);
|
||||||
|
double d = get_pixel(output_delta, i/layer.stride, j/layer.stride, k);
|
||||||
|
if(val == cur) {
|
||||||
|
set_pixel(input_delta, i, j, k, d);
|
||||||
|
}
|
||||||
|
else set_pixel(input_delta, i, j, k, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ typedef struct {
|
|||||||
image get_maxpool_image(maxpool_layer layer);
|
image get_maxpool_image(maxpool_layer layer);
|
||||||
maxpool_layer *make_maxpool_layer(int h, int w, int c, int stride);
|
maxpool_layer *make_maxpool_layer(int h, int w, int c, int stride);
|
||||||
void forward_maxpool_layer(const maxpool_layer layer, double *in);
|
void forward_maxpool_layer(const maxpool_layer layer, double *in);
|
||||||
|
void backward_maxpool_layer(const maxpool_layer layer, double *in, double *delta);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
100
src/network.c
100
src/network.c
@ -2,10 +2,12 @@
|
|||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#include "connected_layer.h"
|
#include "connected_layer.h"
|
||||||
#include "convolutional_layer.h"
|
#include "convolutional_layer.h"
|
||||||
#include "maxpool_layer.h"
|
#include "maxpool_layer.h"
|
||||||
|
#include "softmax_layer.h"
|
||||||
|
|
||||||
network make_network(int n)
|
network make_network(int n)
|
||||||
{
|
{
|
||||||
@ -30,6 +32,11 @@ void forward_network(network net, double *input)
|
|||||||
forward_connected_layer(layer, input);
|
forward_connected_layer(layer, input);
|
||||||
input = layer.output;
|
input = layer.output;
|
||||||
}
|
}
|
||||||
|
else if(net.types[i] == SOFTMAX){
|
||||||
|
softmax_layer layer = *(softmax_layer *)net.layers[i];
|
||||||
|
forward_softmax_layer(layer, input);
|
||||||
|
input = layer.output;
|
||||||
|
}
|
||||||
else if(net.types[i] == MAXPOOL){
|
else if(net.types[i] == MAXPOOL){
|
||||||
maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
||||||
forward_maxpool_layer(layer, input);
|
forward_maxpool_layer(layer, input);
|
||||||
@ -44,14 +51,17 @@ void update_network(network net, double step)
|
|||||||
for(i = 0; i < net.n; ++i){
|
for(i = 0; i < net.n; ++i){
|
||||||
if(net.types[i] == CONVOLUTIONAL){
|
if(net.types[i] == CONVOLUTIONAL){
|
||||||
convolutional_layer layer = *(convolutional_layer *)net.layers[i];
|
convolutional_layer layer = *(convolutional_layer *)net.layers[i];
|
||||||
update_convolutional_layer(layer, step);
|
update_convolutional_layer(layer, step, 0.9, .01);
|
||||||
}
|
}
|
||||||
else if(net.types[i] == MAXPOOL){
|
else if(net.types[i] == MAXPOOL){
|
||||||
//maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
//maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
||||||
}
|
}
|
||||||
|
else if(net.types[i] == SOFTMAX){
|
||||||
|
//maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
||||||
|
}
|
||||||
else if(net.types[i] == CONNECTED){
|
else if(net.types[i] == CONNECTED){
|
||||||
connected_layer layer = *(connected_layer *)net.layers[i];
|
connected_layer layer = *(connected_layer *)net.layers[i];
|
||||||
update_connected_layer(layer, step, .3, 0);
|
update_connected_layer(layer, step, .9, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,6 +74,9 @@ double *get_network_output_layer(network net, int i)
|
|||||||
} else if(net.types[i] == MAXPOOL){
|
} else if(net.types[i] == MAXPOOL){
|
||||||
maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
||||||
return layer.output;
|
return layer.output;
|
||||||
|
} else if(net.types[i] == SOFTMAX){
|
||||||
|
softmax_layer layer = *(softmax_layer *)net.layers[i];
|
||||||
|
return layer.output;
|
||||||
} else if(net.types[i] == CONNECTED){
|
} else if(net.types[i] == CONNECTED){
|
||||||
connected_layer layer = *(connected_layer *)net.layers[i];
|
connected_layer layer = *(connected_layer *)net.layers[i];
|
||||||
return layer.output;
|
return layer.output;
|
||||||
@ -83,6 +96,9 @@ double *get_network_delta_layer(network net, int i)
|
|||||||
} else if(net.types[i] == MAXPOOL){
|
} else if(net.types[i] == MAXPOOL){
|
||||||
maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
||||||
return layer.delta;
|
return layer.delta;
|
||||||
|
} else if(net.types[i] == SOFTMAX){
|
||||||
|
softmax_layer layer = *(softmax_layer *)net.layers[i];
|
||||||
|
return layer.delta;
|
||||||
} else if(net.types[i] == CONNECTED){
|
} else if(net.types[i] == CONNECTED){
|
||||||
connected_layer layer = *(connected_layer *)net.layers[i];
|
connected_layer layer = *(connected_layer *)net.layers[i];
|
||||||
return layer.delta;
|
return layer.delta;
|
||||||
@ -114,7 +130,12 @@ void learn_network(network net, double *input)
|
|||||||
if(i != 0) backward_convolutional_layer(layer, prev_input, prev_delta);
|
if(i != 0) backward_convolutional_layer(layer, prev_input, prev_delta);
|
||||||
}
|
}
|
||||||
else if(net.types[i] == MAXPOOL){
|
else if(net.types[i] == MAXPOOL){
|
||||||
//maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
||||||
|
if(i != 0) backward_maxpool_layer(layer, prev_input, prev_delta);
|
||||||
|
}
|
||||||
|
else if(net.types[i] == SOFTMAX){
|
||||||
|
softmax_layer layer = *(softmax_layer *)net.layers[i];
|
||||||
|
if(i != 0) backward_softmax_layer(layer, prev_input, prev_delta);
|
||||||
}
|
}
|
||||||
else if(net.types[i] == CONNECTED){
|
else if(net.types[i] == CONNECTED){
|
||||||
connected_layer layer = *(connected_layer *)net.layers[i];
|
connected_layer layer = *(connected_layer *)net.layers[i];
|
||||||
@ -130,19 +151,33 @@ void train_network_batch(network net, batch b)
|
|||||||
int k = get_network_output_size(net);
|
int k = get_network_output_size(net);
|
||||||
int correct = 0;
|
int correct = 0;
|
||||||
for(i = 0; i < b.n; ++i){
|
for(i = 0; i < b.n; ++i){
|
||||||
|
show_image(b.images[i], "Input");
|
||||||
forward_network(net, b.images[i].data);
|
forward_network(net, b.images[i].data);
|
||||||
image o = get_network_image(net);
|
image o = get_network_image(net);
|
||||||
|
if(o.h) show_image_collapsed(o, "Output");
|
||||||
double *output = get_network_output(net);
|
double *output = get_network_output(net);
|
||||||
double *delta = get_network_delta(net);
|
double *delta = get_network_delta(net);
|
||||||
|
int max_k = 0;
|
||||||
|
double max = 0;
|
||||||
for(j = 0; j < k; ++j){
|
for(j = 0; j < k; ++j){
|
||||||
//printf("%f %f\n", b.truth[i][j], output[j]);
|
|
||||||
delta[j] = b.truth[i][j]-output[j];
|
delta[j] = b.truth[i][j]-output[j];
|
||||||
if(fabs(delta[j]) < .5) ++correct;
|
if(output[j] > max) {
|
||||||
//printf("%f\n", output[j]);
|
max = output[j];
|
||||||
|
max_k = j;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if(b.truth[i][max_k]) ++correct;
|
||||||
|
printf("%f\n", (double)correct/(i+1));
|
||||||
learn_network(net, b.images[i].data);
|
learn_network(net, b.images[i].data);
|
||||||
update_network(net, .00001);
|
update_network(net, .001);
|
||||||
|
if(i%100 == 0){
|
||||||
|
visualize_network(net);
|
||||||
|
cvWaitKey(100);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
visualize_network(net);
|
||||||
|
print_network(net);
|
||||||
|
cvWaitKey(100);
|
||||||
printf("Accuracy: %f\n", (double)correct/b.n);
|
printf("Accuracy: %f\n", (double)correct/b.n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,6 +197,10 @@ int get_network_output_size_layer(network net, int i)
|
|||||||
connected_layer layer = *(connected_layer *)net.layers[i];
|
connected_layer layer = *(connected_layer *)net.layers[i];
|
||||||
return layer.outputs;
|
return layer.outputs;
|
||||||
}
|
}
|
||||||
|
else if(net.types[i] == SOFTMAX){
|
||||||
|
softmax_layer layer = *(softmax_layer *)net.layers[i];
|
||||||
|
return layer.inputs;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +220,7 @@ image get_network_image_layer(network net, int i)
|
|||||||
maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
||||||
return get_maxpool_image(layer);
|
return get_maxpool_image(layer);
|
||||||
}
|
}
|
||||||
return make_image(0,0,0);
|
return make_empty_image(0,0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
image get_network_image(network net)
|
image get_network_image(network net)
|
||||||
@ -191,17 +230,56 @@ image get_network_image(network net)
|
|||||||
image m = get_network_image_layer(net, i);
|
image m = get_network_image_layer(net, i);
|
||||||
if(m.h != 0) return m;
|
if(m.h != 0) return m;
|
||||||
}
|
}
|
||||||
return make_image(1,1,1);
|
return make_empty_image(0,0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visualize_network(network net)
|
void visualize_network(network net)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < 1; ++i){
|
char buff[256];
|
||||||
|
for(i = 0; i < net.n; ++i){
|
||||||
|
sprintf(buff, "Layer %d", i);
|
||||||
if(net.types[i] == CONVOLUTIONAL){
|
if(net.types[i] == CONVOLUTIONAL){
|
||||||
convolutional_layer layer = *(convolutional_layer *)net.layers[i];
|
convolutional_layer layer = *(convolutional_layer *)net.layers[i];
|
||||||
visualize_convolutional_layer(layer);
|
visualize_convolutional_filters(layer, buff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_network(network net)
|
||||||
|
{
|
||||||
|
int i,j;
|
||||||
|
for(i = 0; i < net.n; ++i){
|
||||||
|
double *output;
|
||||||
|
int n = 0;
|
||||||
|
if(net.types[i] == CONVOLUTIONAL){
|
||||||
|
convolutional_layer layer = *(convolutional_layer *)net.layers[i];
|
||||||
|
output = layer.output;
|
||||||
|
image m = get_convolutional_image(layer);
|
||||||
|
n = m.h*m.w*m.c;
|
||||||
|
}
|
||||||
|
else if(net.types[i] == MAXPOOL){
|
||||||
|
maxpool_layer layer = *(maxpool_layer *)net.layers[i];
|
||||||
|
output = layer.output;
|
||||||
|
image m = get_maxpool_image(layer);
|
||||||
|
n = m.h*m.w*m.c;
|
||||||
|
}
|
||||||
|
else if(net.types[i] == CONNECTED){
|
||||||
|
connected_layer layer = *(connected_layer *)net.layers[i];
|
||||||
|
output = layer.output;
|
||||||
|
n = layer.outputs;
|
||||||
|
}
|
||||||
|
else if(net.types[i] == SOFTMAX){
|
||||||
|
softmax_layer layer = *(softmax_layer *)net.layers[i];
|
||||||
|
output = layer.output;
|
||||||
|
n = layer.inputs;
|
||||||
|
}
|
||||||
|
double mean = mean_array(output, n);
|
||||||
|
double vari = variance_array(output, n);
|
||||||
|
printf("Layer %d - Mean: %f, Variance: %f\n",i,mean, vari);
|
||||||
|
if(n > 100) n = 100;
|
||||||
|
for(j = 0; j < n; ++j) printf("%f, ", output[j]);
|
||||||
|
if(n == 100)printf(".....\n");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
CONVOLUTIONAL,
|
CONVOLUTIONAL,
|
||||||
CONNECTED,
|
CONNECTED,
|
||||||
MAXPOOL
|
MAXPOOL,
|
||||||
|
SOFTMAX
|
||||||
} LAYER_TYPE;
|
} LAYER_TYPE;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -30,6 +31,8 @@ int get_network_output_size_layer(network net, int i);
|
|||||||
int get_network_output_size(network net);
|
int get_network_output_size(network net);
|
||||||
image get_network_image(network net);
|
image get_network_image(network net);
|
||||||
image get_network_image_layer(network net, int i);
|
image get_network_image_layer(network net, int i);
|
||||||
|
void print_network(network net);
|
||||||
|
void visualize_network(network net);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
19
src/parser.c
19
src/parser.c
@ -7,6 +7,7 @@
|
|||||||
#include "convolutional_layer.h"
|
#include "convolutional_layer.h"
|
||||||
#include "connected_layer.h"
|
#include "connected_layer.h"
|
||||||
#include "maxpool_layer.h"
|
#include "maxpool_layer.h"
|
||||||
|
#include "softmax_layer.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "option_list.h"
|
#include "option_list.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
@ -19,6 +20,7 @@ typedef struct{
|
|||||||
int is_convolutional(section *s);
|
int is_convolutional(section *s);
|
||||||
int is_connected(section *s);
|
int is_connected(section *s);
|
||||||
int is_maxpool(section *s);
|
int is_maxpool(section *s);
|
||||||
|
int is_softmax(section *s);
|
||||||
list *read_cfg(char *filename);
|
list *read_cfg(char *filename);
|
||||||
|
|
||||||
|
|
||||||
@ -69,6 +71,17 @@ network parse_network_cfg(char *filename)
|
|||||||
net.types[count] = CONNECTED;
|
net.types[count] = CONNECTED;
|
||||||
net.layers[count] = layer;
|
net.layers[count] = layer;
|
||||||
option_unused(options);
|
option_unused(options);
|
||||||
|
}else if(is_softmax(s)){
|
||||||
|
int input;
|
||||||
|
if(count == 0){
|
||||||
|
input = option_find_int(options, "input",1);
|
||||||
|
}else{
|
||||||
|
input = get_network_output_size_layer(net, count-1);
|
||||||
|
}
|
||||||
|
softmax_layer *layer = make_softmax_layer(input);
|
||||||
|
net.types[count] = SOFTMAX;
|
||||||
|
net.layers[count] = layer;
|
||||||
|
option_unused(options);
|
||||||
}else if(is_maxpool(s)){
|
}else if(is_maxpool(s)){
|
||||||
int h,w,c;
|
int h,w,c;
|
||||||
int stride = option_find_int(options, "stride",1);
|
int stride = option_find_int(options, "stride",1);
|
||||||
@ -113,6 +126,12 @@ int is_maxpool(section *s)
|
|||||||
|| strcmp(s->type, "[maxpool]")==0);
|
|| strcmp(s->type, "[maxpool]")==0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int is_softmax(section *s)
|
||||||
|
{
|
||||||
|
return (strcmp(s->type, "[soft]")==0
|
||||||
|
|| strcmp(s->type, "[softmax]")==0);
|
||||||
|
}
|
||||||
|
|
||||||
int read_option(char *s, list *options)
|
int read_option(char *s, list *options)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
35
src/softmax_layer.c
Normal file
35
src/softmax_layer.c
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include "softmax_layer.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
softmax_layer *make_softmax_layer(int inputs)
|
||||||
|
{
|
||||||
|
printf("Softmax Layer: %d inputs\n", inputs);
|
||||||
|
softmax_layer *layer = calloc(1, sizeof(softmax_layer));
|
||||||
|
layer->inputs = inputs;
|
||||||
|
layer->output = calloc(inputs, sizeof(double));
|
||||||
|
layer->delta = calloc(inputs, sizeof(double));
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void forward_softmax_layer(const softmax_layer layer, double *input)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double sum = 0;
|
||||||
|
for(i = 0; i < layer.inputs; ++i){
|
||||||
|
sum += exp(input[i]);
|
||||||
|
}
|
||||||
|
for(i = 0; i < layer.inputs; ++i){
|
||||||
|
layer.output[i] = exp(input[i])/sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backward_softmax_layer(const softmax_layer layer, double *input, double *delta)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < layer.inputs; ++i){
|
||||||
|
delta[i] = layer.delta[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
14
src/softmax_layer.h
Normal file
14
src/softmax_layer.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef SOFTMAX_LAYER_H
|
||||||
|
#define SOFTMAX_LAYER_H
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int inputs;
|
||||||
|
double *delta;
|
||||||
|
double *output;
|
||||||
|
} softmax_layer;
|
||||||
|
|
||||||
|
softmax_layer *make_softmax_layer(int inputs);
|
||||||
|
void forward_softmax_layer(const softmax_layer layer, double *input);
|
||||||
|
void backward_softmax_layer(const softmax_layer layer, double *input, double *delta);
|
||||||
|
|
||||||
|
#endif
|
185
src/tests.c
185
src/tests.c
@ -6,6 +6,7 @@
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include "matrix.h"
|
#include "matrix.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -21,7 +22,7 @@ void test_convolve()
|
|||||||
int i;
|
int i;
|
||||||
clock_t start = clock(), end;
|
clock_t start = clock(), end;
|
||||||
for(i = 0; i < 1000; ++i){
|
for(i = 0; i < 1000; ++i){
|
||||||
convolve(dog, kernel, 1, 0, edge);
|
convolve(dog, kernel, 1, 0, edge, 1);
|
||||||
}
|
}
|
||||||
end = clock();
|
end = clock();
|
||||||
printf("Convolutions: %lf seconds\n", (double)(end-start)/CLOCKS_PER_SEC);
|
printf("Convolutions: %lf seconds\n", (double)(end-start)/CLOCKS_PER_SEC);
|
||||||
@ -57,6 +58,61 @@ void test_convolutional_layer()
|
|||||||
show_image_layers(get_maxpool_image(mlayer), "Test Maxpool Layer");
|
show_image_layers(get_maxpool_image(mlayer), "Test Maxpool Layer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void verify_convolutional_layer()
|
||||||
|
{
|
||||||
|
srand(0);
|
||||||
|
int i;
|
||||||
|
int n = 1;
|
||||||
|
int stride = 1;
|
||||||
|
int size = 3;
|
||||||
|
double eps = .00000001;
|
||||||
|
image test = make_random_image(5,5, 1);
|
||||||
|
convolutional_layer layer = *make_convolutional_layer(test.h,test.w,test.c, n, size, stride, RELU);
|
||||||
|
image out = get_convolutional_image(layer);
|
||||||
|
double **jacobian = calloc(test.h*test.w*test.c, sizeof(double));
|
||||||
|
|
||||||
|
forward_convolutional_layer(layer, test.data);
|
||||||
|
image base = copy_image(out);
|
||||||
|
|
||||||
|
for(i = 0; i < test.h*test.w*test.c; ++i){
|
||||||
|
test.data[i] += eps;
|
||||||
|
forward_convolutional_layer(layer, test.data);
|
||||||
|
image partial = copy_image(out);
|
||||||
|
subtract_image(partial, base);
|
||||||
|
scale_image(partial, 1/eps);
|
||||||
|
jacobian[i] = partial.data;
|
||||||
|
test.data[i] -= eps;
|
||||||
|
}
|
||||||
|
double **jacobian2 = calloc(out.h*out.w*out.c, sizeof(double));
|
||||||
|
image in_delta = make_image(test.h, test.w, test.c);
|
||||||
|
image out_delta = get_convolutional_delta(layer);
|
||||||
|
for(i = 0; i < out.h*out.w*out.c; ++i){
|
||||||
|
out_delta.data[i] = 1;
|
||||||
|
backward_convolutional_layer2(layer, test.data, in_delta.data);
|
||||||
|
image partial = copy_image(in_delta);
|
||||||
|
jacobian2[i] = partial.data;
|
||||||
|
out_delta.data[i] = 0;
|
||||||
|
}
|
||||||
|
int j;
|
||||||
|
double *j1 = calloc(test.h*test.w*test.c*out.h*out.w*out.c, sizeof(double));
|
||||||
|
double *j2 = calloc(test.h*test.w*test.c*out.h*out.w*out.c, sizeof(double));
|
||||||
|
for(i = 0; i < test.h*test.w*test.c; ++i){
|
||||||
|
for(j =0 ; j < out.h*out.w*out.c; ++j){
|
||||||
|
j1[i*out.h*out.w*out.c + j] = jacobian[i][j];
|
||||||
|
j2[i*out.h*out.w*out.c + j] = jacobian2[j][i];
|
||||||
|
printf("%f %f\n", jacobian[i][j], jacobian2[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
image mj1 = double_to_image(test.w*test.h*test.c, out.w*out.h*out.c, 1, j1);
|
||||||
|
image mj2 = double_to_image(test.w*test.h*test.c, out.w*out.h*out.c, 1, j2);
|
||||||
|
printf("%f %f\n", avg_image_layer(mj1,0), avg_image_layer(mj2,0));
|
||||||
|
show_image(mj1, "forward jacobian");
|
||||||
|
show_image(mj2, "backward jacobian");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void test_load()
|
void test_load()
|
||||||
{
|
{
|
||||||
image dog = load_image("dog.jpg");
|
image dog = load_image("dog.jpg");
|
||||||
@ -119,30 +175,26 @@ void test_parser()
|
|||||||
|
|
||||||
void test_data()
|
void test_data()
|
||||||
{
|
{
|
||||||
batch train = random_batch("train_paths.txt", 101);
|
char *labels[] = {"cat","dog"};
|
||||||
|
batch train = random_batch("train_paths.txt", 101,labels, 2);
|
||||||
show_image(train.images[0], "Test Data Loading");
|
show_image(train.images[0], "Test Data Loading");
|
||||||
show_image(train.images[100], "Test Data Loading");
|
show_image(train.images[100], "Test Data Loading");
|
||||||
show_image(train.images[10], "Test Data Loading");
|
show_image(train.images[10], "Test Data Loading");
|
||||||
free_batch(train);
|
free_batch(train);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_train()
|
void test_full()
|
||||||
{
|
{
|
||||||
network net = parse_network_cfg("test.cfg");
|
network net = parse_network_cfg("full.cfg");
|
||||||
srand(0);
|
srand(0);
|
||||||
//visualize_network(net);
|
int i = 0;
|
||||||
int i = 1000;
|
char *labels[] = {"cat","dog"};
|
||||||
//while(1){
|
while(i++ < 1000 || 1){
|
||||||
while(i > 0){
|
batch train = random_batch("train_paths.txt", 1000, labels, 2);
|
||||||
batch train = random_batch("train_paths.txt", 100);
|
|
||||||
train_network_batch(net, train);
|
train_network_batch(net, train);
|
||||||
//show_image_layers(get_network_image(net), "hey");
|
|
||||||
//visualize_network(net);
|
|
||||||
//cvWaitKey(0);
|
|
||||||
free_batch(train);
|
free_batch(train);
|
||||||
--i;
|
printf("Round %d\n", i);
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double error_network(network net, matrix m, double *truth)
|
double error_network(network net, matrix m, double *truth)
|
||||||
@ -158,9 +210,90 @@ double error_network(network net, matrix m, double *truth)
|
|||||||
return (double)correct/m.rows;
|
return (double)correct/m.rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
void classify_random_filters()
|
double **one_hot(double *a, int n, int k)
|
||||||
{
|
{
|
||||||
network net = parse_network_cfg("random_filter_finish.cfg");
|
int i;
|
||||||
|
double **t = calloc(n, sizeof(double*));
|
||||||
|
for(i = 0; i < n; ++i){
|
||||||
|
t[i] = calloc(k, sizeof(double));
|
||||||
|
int index = (int)a[i];
|
||||||
|
t[i][index] = 1;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_nist()
|
||||||
|
{
|
||||||
|
network net = parse_network_cfg("nist.cfg");
|
||||||
|
matrix m = csv_to_matrix("images/nist_train.csv");
|
||||||
|
matrix ho = hold_out_matrix(&m, 3000);
|
||||||
|
double *truth_1d = pop_column(&m, 0);
|
||||||
|
double **truth = one_hot(truth_1d, m.rows, 10);
|
||||||
|
double *ho_truth_1d = pop_column(&ho, 0);
|
||||||
|
double **ho_truth = one_hot(ho_truth_1d, ho.rows, 10);
|
||||||
|
int i,j;
|
||||||
|
clock_t start = clock(), end;
|
||||||
|
int count = 0;
|
||||||
|
double lr = .0001;
|
||||||
|
while(++count <= 3000000){
|
||||||
|
//lr *= .99;
|
||||||
|
int index = 0;
|
||||||
|
int correct = 0;
|
||||||
|
for(i = 0; i < 1000; ++i){
|
||||||
|
index = rand()%m.rows;
|
||||||
|
normalize_array(m.vals[index], 28*28);
|
||||||
|
forward_network(net, m.vals[index]);
|
||||||
|
double *out = get_network_output(net);
|
||||||
|
double *delta = get_network_delta(net);
|
||||||
|
int max_i = 0;
|
||||||
|
double max = out[0];
|
||||||
|
for(j = 0; j < 10; ++j){
|
||||||
|
delta[j] = truth[index][j]-out[j];
|
||||||
|
if(out[j] > max){
|
||||||
|
max = out[j];
|
||||||
|
max_i = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(truth[index][max_i]) ++correct;
|
||||||
|
learn_network(net, m.vals[index]);
|
||||||
|
update_network(net, lr);
|
||||||
|
}
|
||||||
|
print_network(net);
|
||||||
|
image input = double_to_image(28,28,1, m.vals[index]);
|
||||||
|
show_image(input, "Input");
|
||||||
|
image o = get_network_image(net);
|
||||||
|
show_image_collapsed(o, "Output");
|
||||||
|
visualize_network(net);
|
||||||
|
cvWaitKey(100);
|
||||||
|
//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 %f\n",count, (double)correct/1000, lr);
|
||||||
|
//if(valid_acc > .70) break;
|
||||||
|
}
|
||||||
|
end = clock();
|
||||||
|
printf("Neural Net Learning: %lf seconds\n", (double)(end-start)/CLOCKS_PER_SEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_kernel_update()
|
||||||
|
{
|
||||||
|
srand(0);
|
||||||
|
double delta[] = {.1};
|
||||||
|
double input[] = {.3, .5, .3, .5, .5, .5, .5, .0, .5};
|
||||||
|
double kernel[] = {1,2,3,4,5,6,7,8,9};
|
||||||
|
convolutional_layer layer = *make_convolutional_layer(3, 3, 1, 1, 3, 1, IDENTITY);
|
||||||
|
layer.kernels[0].data = kernel;
|
||||||
|
layer.delta = delta;
|
||||||
|
learn_convolutional_layer(layer, input);
|
||||||
|
print_image(layer.kernels[0]);
|
||||||
|
print_image(get_convolutional_delta(layer));
|
||||||
|
print_image(layer.kernel_updates[0]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_random_classify()
|
||||||
|
{
|
||||||
|
network net = parse_network_cfg("connected.cfg");
|
||||||
matrix m = csv_to_matrix("train.csv");
|
matrix m = csv_to_matrix("train.csv");
|
||||||
matrix ho = hold_out_matrix(&m, 2500);
|
matrix ho = hold_out_matrix(&m, 2500);
|
||||||
double *truth = pop_column(&m, 0);
|
double *truth = pop_column(&m, 0);
|
||||||
@ -181,7 +314,7 @@ void classify_random_filters()
|
|||||||
// printf("%f\n", delta[0]);
|
// printf("%f\n", delta[0]);
|
||||||
//printf("%f %f\n", truth[index], out[0]);
|
//printf("%f %f\n", truth[index], out[0]);
|
||||||
learn_network(net, m.vals[index]);
|
learn_network(net, m.vals[index]);
|
||||||
update_network(net, .000005);
|
update_network(net, .00001);
|
||||||
}
|
}
|
||||||
double test_acc = error_network(net, m, truth);
|
double test_acc = error_network(net, m, truth);
|
||||||
double valid_acc = error_network(net, ho, ho_truth);
|
double valid_acc = error_network(net, ho, ho_truth);
|
||||||
@ -203,15 +336,16 @@ void classify_random_filters()
|
|||||||
printf("Neural Net Learning: %lf seconds\n", (double)(end-start)/CLOCKS_PER_SEC);
|
printf("Neural Net Learning: %lf seconds\n", (double)(end-start)/CLOCKS_PER_SEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_random_filters()
|
void test_random_preprocess()
|
||||||
{
|
{
|
||||||
FILE *file = fopen("test.csv", "w");
|
FILE *file = fopen("train.csv", "w");
|
||||||
|
char *labels[] = {"cat","dog"};
|
||||||
int i,j,k;
|
int i,j,k;
|
||||||
srand(0);
|
srand(0);
|
||||||
network net = parse_network_cfg("test_random_filter.cfg");
|
network net = parse_network_cfg("convolutional.cfg");
|
||||||
for(i = 0; i < 100; ++i){
|
for(i = 0; i < 100; ++i){
|
||||||
printf("%d\n", i);
|
printf("%d\n", i);
|
||||||
batch part = get_batch("test_paths.txt", i, 100);
|
batch part = get_batch("train_paths.txt", i, 100, labels, 2);
|
||||||
for(j = 0; j < part.n; ++j){
|
for(j = 0; j < part.n; ++j){
|
||||||
forward_network(net, part.images[j].data);
|
forward_network(net, part.images[j].data);
|
||||||
double *out = get_network_output(net);
|
double *out = get_network_output(net);
|
||||||
@ -227,9 +361,11 @@ void test_random_filters()
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
//classify_random_filters();
|
//test_kernel_update();
|
||||||
//test_random_filters();
|
//test_nist();
|
||||||
test_train();
|
test_full();
|
||||||
|
//test_random_preprocess();
|
||||||
|
//test_random_classify();
|
||||||
//test_parser();
|
//test_parser();
|
||||||
//test_backpropagate();
|
//test_backpropagate();
|
||||||
//test_ann();
|
//test_ann();
|
||||||
@ -239,6 +375,7 @@ int main()
|
|||||||
//test_load();
|
//test_load();
|
||||||
//test_network();
|
//test_network();
|
||||||
//test_convolutional_layer();
|
//test_convolutional_layer();
|
||||||
|
//verify_convolutional_layer();
|
||||||
//test_color();
|
//test_color();
|
||||||
cvWaitKey(0);
|
cvWaitKey(0);
|
||||||
return 0;
|
return 0;
|
||||||
|
42
src/utils.c
42
src/utils.c
@ -143,5 +143,47 @@ double *parse_fields(char *line, int n)
|
|||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double mean_array(double *a, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double sum = 0;
|
||||||
|
for(i = 0; i < n; ++i) sum += a[i];
|
||||||
|
return sum/n;
|
||||||
|
}
|
||||||
|
|
||||||
|
double variance_array(double *a, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double sum = 0;
|
||||||
|
double mean = mean_array(a, n);
|
||||||
|
for(i = 0; i < n; ++i) sum += (a[i] - mean)*(a[i]-mean);
|
||||||
|
double variance = sum/n;
|
||||||
|
return variance;
|
||||||
|
}
|
||||||
|
|
||||||
|
double constrain(double a, double max)
|
||||||
|
{
|
||||||
|
if(a > abs(max)) return abs(max);
|
||||||
|
if(a < -abs(max)) return -abs(max);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void normalize_array(double *a, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double mu = mean_array(a,n);
|
||||||
|
double sigma = sqrt(variance_array(a,n));
|
||||||
|
for(i = 0; i < n; ++i){
|
||||||
|
a[i] = (a[i] - mu)/sigma;
|
||||||
|
}
|
||||||
|
mu = mean_array(a,n);
|
||||||
|
sigma = sqrt(variance_array(a,n));
|
||||||
|
}
|
||||||
|
|
||||||
|
double rand_normal()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double sum= 0;
|
||||||
|
for(i = 0; i < 12; ++i) sum += (double)rand()/RAND_MAX;
|
||||||
|
return sum-6.;
|
||||||
|
}
|
||||||
|
@ -14,5 +14,10 @@ list *parse_csv_line(char *line);
|
|||||||
char *copy_string(char *s);
|
char *copy_string(char *s);
|
||||||
int count_fields(char *line);
|
int count_fields(char *line);
|
||||||
double *parse_fields(char *line, int n);
|
double *parse_fields(char *line, int n);
|
||||||
|
void normalize_array(double *a, int n);
|
||||||
|
double constrain(double a, double max);
|
||||||
|
double rand_normal();
|
||||||
|
double mean_array(double *a, int n);
|
||||||
|
double variance_array(double *a, int n);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
36
test.cfg
36
test.cfg
@ -3,30 +3,30 @@ width=200
|
|||||||
height=200
|
height=200
|
||||||
channels=3
|
channels=3
|
||||||
filters=10
|
filters=10
|
||||||
size=3
|
size=15
|
||||||
stride=2
|
stride=16
|
||||||
activation=relu
|
activation=relu
|
||||||
|
|
||||||
[maxpool]
|
#[maxpool]
|
||||||
stride=2
|
#stride=2
|
||||||
|
|
||||||
[conv]
|
#[conv]
|
||||||
filters=10
|
#filters=10
|
||||||
size=10
|
#size=10
|
||||||
stride=2
|
#stride=4
|
||||||
activation=relu
|
#activation=relu
|
||||||
|
|
||||||
[maxpool]
|
#[maxpool]
|
||||||
stride=2
|
#stride=2
|
||||||
|
|
||||||
[conv]
|
#[conv]
|
||||||
filters=10
|
#filters=10
|
||||||
size=10
|
#size=10
|
||||||
stride=2
|
#stride=4
|
||||||
activation=relu
|
#activation=relu
|
||||||
|
|
||||||
[maxpool]
|
#[maxpool]
|
||||||
stride=2
|
#stride=2
|
||||||
|
|
||||||
[conn]
|
[conn]
|
||||||
output = 10
|
output = 10
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
[conn]
|
|
||||||
input=1
|
|
||||||
output = 20
|
|
||||||
activation=sigmoid
|
|
||||||
|
|
||||||
[conn]
|
|
||||||
output = 1
|
|
||||||
activation=sigmoid
|
|
@ -1,29 +0,0 @@
|
|||||||
[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