#include "crnn_layer.h" #include "convolutional_layer.h" #include "utils.h" #include "cuda.h" #include "blas.h" #include "gemm.h" #include #include #include #include static void increment_layer(layer *l, int steps) { int num = l->outputs*l->batch*steps; l->output += num; l->delta += num; l->x += num; l->x_norm += num; #ifdef GPU l->output_gpu += num; l->delta_gpu += num; l->x_gpu += num; l->x_norm_gpu += num; #endif } layer make_crnn_layer(int batch, int h, int w, int c, int hidden_filters, int output_filters, int steps, int size, int stride, int pad, ACTIVATION activation, int batch_normalize) { fprintf(stderr, "CRNN Layer: %d x %d x %d image, %d filters\n", h,w,c,output_filters); batch = batch / steps; layer l = { (LAYER_TYPE)0 }; l.batch = batch; l.type = CRNN; l.steps = steps; l.h = h; l.w = w; l.c = c; l.out_h = h; l.out_w = w; l.out_c = output_filters; l.inputs = h*w*c; l.hidden = h * w * hidden_filters; l.outputs = l.out_h * l.out_w * l.out_c; l.state = (float*)calloc(l.hidden * batch * (steps + 1), sizeof(float)); l.input_layer = (layer*)malloc(sizeof(layer)); *(l.input_layer) = make_convolutional_layer(batch, steps, h, w, c, hidden_filters, size, stride, pad, activation, batch_normalize, 0, 0, 0, 0, 0); l.input_layer->batch = batch; if (l.workspace_size < l.input_layer->workspace_size) l.workspace_size = l.input_layer->workspace_size; l.self_layer = (layer*)malloc(sizeof(layer)); *(l.self_layer) = make_convolutional_layer(batch, steps, h, w, hidden_filters, hidden_filters, size, stride, pad, activation, batch_normalize, 0, 0, 0, 0, 0); l.self_layer->batch = batch; if (l.workspace_size < l.self_layer->workspace_size) l.workspace_size = l.self_layer->workspace_size; l.output_layer = (layer*)malloc(sizeof(layer)); *(l.output_layer) = make_convolutional_layer(batch, steps, h, w, hidden_filters, output_filters, size, stride, pad, activation, batch_normalize, 0, 0, 0, 0, 0); l.output_layer->batch = batch; if (l.workspace_size < l.output_layer->workspace_size) l.workspace_size = l.output_layer->workspace_size; l.output = l.output_layer->output; l.delta = l.output_layer->delta; l.forward = forward_crnn_layer; l.backward = backward_crnn_layer; l.update = update_crnn_layer; #ifdef GPU l.forward_gpu = forward_crnn_layer_gpu; l.backward_gpu = backward_crnn_layer_gpu; l.update_gpu = update_crnn_layer_gpu; l.state_gpu = cuda_make_array(l.state, batch*l.hidden*(steps + 1)); l.output_gpu = l.output_layer->output_gpu; l.delta_gpu = l.output_layer->delta_gpu; #endif return l; } void update_crnn_layer(layer l, int batch, float learning_rate, float momentum, float decay) { update_convolutional_layer(*(l.input_layer), batch, learning_rate, momentum, decay); update_convolutional_layer(*(l.self_layer), batch, learning_rate, momentum, decay); update_convolutional_layer(*(l.output_layer), batch, learning_rate, momentum, decay); } void forward_crnn_layer(layer l, network_state state) { network_state s = {0}; s.train = state.train; s.workspace = state.workspace; int i; layer input_layer = *(l.input_layer); layer self_layer = *(l.self_layer); layer output_layer = *(l.output_layer); fill_cpu(l.outputs * l.batch * l.steps, 0, output_layer.delta, 1); fill_cpu(l.hidden * l.batch * l.steps, 0, self_layer.delta, 1); fill_cpu(l.hidden * l.batch * l.steps, 0, input_layer.delta, 1); if(state.train) fill_cpu(l.hidden * l.batch, 0, l.state, 1); for (i = 0; i < l.steps; ++i) { s.input = state.input; forward_convolutional_layer(input_layer, s); s.input = l.state; forward_convolutional_layer(self_layer, s); float *old_state = l.state; if(state.train) l.state += l.hidden*l.batch; if(l.shortcut){ copy_cpu(l.hidden * l.batch, old_state, 1, l.state, 1); }else{ fill_cpu(l.hidden * l.batch, 0, l.state, 1); } axpy_cpu(l.hidden * l.batch, 1, input_layer.output, 1, l.state, 1); axpy_cpu(l.hidden * l.batch, 1, self_layer.output, 1, l.state, 1); s.input = l.state; forward_convolutional_layer(output_layer, s); state.input += l.inputs*l.batch; increment_layer(&input_layer, 1); increment_layer(&self_layer, 1); increment_layer(&output_layer, 1); } } void backward_crnn_layer(layer l, network_state state) { network_state s = {0}; s.train = state.train; s.workspace = state.workspace; int i; layer input_layer = *(l.input_layer); layer self_layer = *(l.self_layer); layer output_layer = *(l.output_layer); increment_layer(&input_layer, l.steps-1); increment_layer(&self_layer, l.steps-1); increment_layer(&output_layer, l.steps-1); l.state += l.hidden*l.batch*l.steps; for (i = l.steps-1; i >= 0; --i) { copy_cpu(l.hidden * l.batch, input_layer.output, 1, l.state, 1); axpy_cpu(l.hidden * l.batch, 1, self_layer.output, 1, l.state, 1); s.input = l.state; s.delta = self_layer.delta; backward_convolutional_layer(output_layer, s); l.state -= l.hidden*l.batch; /* if(i > 0){ copy_cpu(l.hidden * l.batch, input_layer.output - l.hidden*l.batch, 1, l.state, 1); axpy_cpu(l.hidden * l.batch, 1, self_layer.output - l.hidden*l.batch, 1, l.state, 1); }else{ fill_cpu(l.hidden * l.batch, 0, l.state, 1); } */ s.input = l.state; s.delta = self_layer.delta - l.hidden*l.batch; if (i == 0) s.delta = 0; backward_convolutional_layer(self_layer, s); copy_cpu(l.hidden*l.batch, self_layer.delta, 1, input_layer.delta, 1); if (i > 0 && l.shortcut) axpy_cpu(l.hidden*l.batch, 1, self_layer.delta, 1, self_layer.delta - l.hidden*l.batch, 1); s.input = state.input + i*l.inputs*l.batch; if(state.delta) s.delta = state.delta + i*l.inputs*l.batch; else s.delta = 0; backward_convolutional_layer(input_layer, s); increment_layer(&input_layer, -1); increment_layer(&self_layer, -1); increment_layer(&output_layer, -1); } } #ifdef GPU void pull_crnn_layer(layer l) { pull_convolutional_layer(*(l.input_layer)); pull_convolutional_layer(*(l.self_layer)); pull_convolutional_layer(*(l.output_layer)); } void push_crnn_layer(layer l) { push_convolutional_layer(*(l.input_layer)); push_convolutional_layer(*(l.self_layer)); push_convolutional_layer(*(l.output_layer)); } void update_crnn_layer_gpu(layer l, int batch, float learning_rate, float momentum, float decay) { update_convolutional_layer_gpu(*(l.input_layer), batch, learning_rate, momentum, decay); update_convolutional_layer_gpu(*(l.self_layer), batch, learning_rate, momentum, decay); update_convolutional_layer_gpu(*(l.output_layer), batch, learning_rate, momentum, decay); } void forward_crnn_layer_gpu(layer l, network_state state) { network_state s = {0}; s.train = state.train; s.workspace = state.workspace; int i; layer input_layer = *(l.input_layer); layer self_layer = *(l.self_layer); layer output_layer = *(l.output_layer); /* #ifdef CUDNN_HALF // slow and bad s.index = state.index; s.net = state.net; cuda_convert_f32_to_f16(input_layer.weights_gpu, input_layer.c*input_layer.n*input_layer.size*input_layer.size, input_layer.weights_gpu16); cuda_convert_f32_to_f16(self_layer.weights_gpu, self_layer.c*self_layer.n*self_layer.size*self_layer.size, self_layer.weights_gpu16); cuda_convert_f32_to_f16(output_layer.weights_gpu, output_layer.c*output_layer.n*output_layer.size*output_layer.size, output_layer.weights_gpu16); #endif //CUDNN_HALF */ fill_ongpu(l.outputs * l.batch * l.steps, 0, output_layer.delta_gpu, 1); fill_ongpu(l.hidden * l.batch * l.steps, 0, self_layer.delta_gpu, 1); fill_ongpu(l.hidden * l.batch * l.steps, 0, input_layer.delta_gpu, 1); if(state.train) fill_ongpu(l.hidden * l.batch, 0, l.state_gpu, 1); for (i = 0; i < l.steps; ++i) { s.input = state.input; forward_convolutional_layer_gpu(input_layer, s); s.input = l.state_gpu; forward_convolutional_layer_gpu(self_layer, s); float *old_state = l.state_gpu; if(state.train) l.state_gpu += l.hidden*l.batch; if(l.shortcut){ copy_ongpu(l.hidden * l.batch, old_state, 1, l.state_gpu, 1); }else{ fill_ongpu(l.hidden * l.batch, 0, l.state_gpu, 1); } axpy_ongpu(l.hidden * l.batch, 1, input_layer.output_gpu, 1, l.state_gpu, 1); axpy_ongpu(l.hidden * l.batch, 1, self_layer.output_gpu, 1, l.state_gpu, 1); s.input = l.state_gpu; forward_convolutional_layer_gpu(output_layer, s); state.input += l.inputs*l.batch; increment_layer(&input_layer, 1); increment_layer(&self_layer, 1); increment_layer(&output_layer, 1); } } void backward_crnn_layer_gpu(layer l, network_state state) { network_state s = {0}; s.train = state.train; s.workspace = state.workspace; int i; layer input_layer = *(l.input_layer); layer self_layer = *(l.self_layer); layer output_layer = *(l.output_layer); increment_layer(&input_layer, l.steps - 1); increment_layer(&self_layer, l.steps - 1); increment_layer(&output_layer, l.steps - 1); l.state_gpu += l.hidden*l.batch*l.steps; for (i = l.steps-1; i >= 0; --i) { //copy_ongpu(l.hidden * l.batch, input_layer.output_gpu, 1, l.state_gpu, 1); // commented in RNN //axpy_ongpu(l.hidden * l.batch, 1, self_layer.output_gpu, 1, l.state_gpu, 1); // commented in RNN s.input = l.state_gpu; s.delta = self_layer.delta_gpu; backward_convolutional_layer_gpu(output_layer, s); l.state_gpu -= l.hidden*l.batch; copy_ongpu(l.hidden*l.batch, self_layer.delta_gpu, 1, input_layer.delta_gpu, 1); s.input = l.state_gpu; s.delta = self_layer.delta_gpu - l.hidden*l.batch; if (i == 0) s.delta = 0; backward_convolutional_layer_gpu(self_layer, s); if (i > 0 && l.shortcut) axpy_ongpu(l.hidden*l.batch, 1, self_layer.delta_gpu, 1, self_layer.delta_gpu - l.hidden*l.batch, 1); s.input = state.input + i*l.inputs*l.batch; if(state.delta) s.delta = state.delta + i*l.inputs*l.batch; else s.delta = 0; backward_convolutional_layer_gpu(input_layer, s); increment_layer(&input_layer, -1); increment_layer(&self_layer, -1); increment_layer(&output_layer, -1); } } #endif