Skip to content

Commit

Permalink
first commit of ResRNN project
Browse files Browse the repository at this point in the history
  • Loading branch information
xwolfs committed Jul 10, 2017
0 parents commit d6c5852
Show file tree
Hide file tree
Showing 28 changed files with 15,328 additions and 0 deletions.
13 changes: 13 additions & 0 deletions Circle-RNN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# ResRNN
Implementation of a two path ResRNN architecture (Circle-RNN was invented).

### This repository is an implementation of our IPMI 2017 paper:
Xue W., Nachum I.B., Pandey S., Warrington J., Leung S., Li S. (2017) Direct Estimation of Regional Wall Thicknesses via Residual Recurrent Neural Network. In: Information Processing in Medical Imaging. IPMI 2017. Lecture Notes in Computer Science, vol 10265. Springer.

https://link.springer.com/chapter/10.1007/978-3-319-59050-9_40 or https://arxiv.org/pdf/1705.09728.pdf

### ON Circle-RNN

In caffe.proto, add the following line to message RecurrentParameter {}

optional uint32 depth = 6 [default = 0];
5 changes: 5 additions & 0 deletions Circle-RNN.md~
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@


In caffe.proto, add the following line to message RecurrentParameter {}

optional uint32 depth = 6 [default = 0];
2 changes: 2 additions & 0 deletions Circle-RNN/Circle-RNN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Circle-RNN

271 changes: 271 additions & 0 deletions Circle-RNN/circle_lstm_layer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
#include <string>
#include <vector>

#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/filler.hpp"
#include "caffe/layer.hpp"
#include "caffe/layers/circle_lstm_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void CircleLSTMLayer<Dtype>::RecurrentInputBlobNames(vector<string>* names) const {
names->resize(2);
(*names)[0] = "h_0";
(*names)[1] = "c_0";
}

template <typename Dtype>
void CircleLSTMLayer<Dtype>::RecurrentOutputBlobNames(vector<string>* names) const {
names->resize(2);
int depth = this->layer_param_.recurrent_param().depth();
if (depth==0) {
depth = this->T_;
}
(*names)[0] = "h_" + format_int(depth*this->T_);
(*names)[1] = "c_T";
}

template <typename Dtype>
void CircleLSTMLayer<Dtype>::RecurrentInputShapes(vector<BlobShape>* shapes) const {
const int num_output = this->layer_param_.recurrent_param().num_output();
const int num_blobs = 2;
shapes->resize(num_blobs);
for (int i = 0; i < num_blobs; ++i) {
(*shapes)[i].Clear();
(*shapes)[i].add_dim(1); // change from a single timestep to all timestep @xwolfs 2016/10/25
(*shapes)[i].add_dim(this->N_);
(*shapes)[i].add_dim(num_output);
}
}

template <typename Dtype>
void CircleLSTMLayer<Dtype>::OutputBlobNames(vector<string>* names) const {
names->resize(1);
(*names)[0] = "h";
}

template <typename Dtype>
void CircleLSTMLayer<Dtype>::FillUnrolledNet(NetParameter* net_param) const {
const int num_output = this->layer_param_.recurrent_param().num_output();
CHECK_GT(num_output, 0) << "num_output must be positive";
const FillerParameter& weight_filler =
this->layer_param_.recurrent_param().weight_filler();
const FillerParameter& bias_filler =
this->layer_param_.recurrent_param().bias_filler();

// Add generic LayerParameter's (without bottoms/tops) of layer types we'll
// use to save redundant code.
LayerParameter hidden_param;
hidden_param.set_type("InnerProduct");
hidden_param.mutable_inner_product_param()->set_num_output(num_output * 4);
hidden_param.mutable_inner_product_param()->set_bias_term(false);
hidden_param.mutable_inner_product_param()->set_axis(2);
hidden_param.mutable_inner_product_param()->
mutable_weight_filler()->CopyFrom(weight_filler);

LayerParameter biased_hidden_param(hidden_param);
biased_hidden_param.mutable_inner_product_param()->set_bias_term(true);
biased_hidden_param.mutable_inner_product_param()->
mutable_bias_filler()->CopyFrom(bias_filler);

LayerParameter sum_param;
sum_param.set_type("Eltwise");
sum_param.mutable_eltwise_param()->set_operation(
EltwiseParameter_EltwiseOp_SUM);

LayerParameter scale_param;
scale_param.set_type("Scale");
scale_param.mutable_scale_param()->set_axis(0);

LayerParameter slice_param;
slice_param.set_type("Slice");
slice_param.mutable_slice_param()->set_axis(0);

LayerParameter split_param;
split_param.set_type("Split");

vector<BlobShape> input_shapes;
RecurrentInputShapes(&input_shapes);
CHECK_EQ(2, input_shapes.size());

LayerParameter* input_layer_param = net_param->add_layer();
input_layer_param->set_type("Input");
InputParameter* input_param = input_layer_param->mutable_input_param();

input_layer_param->add_top("c_0");
input_param->add_shape()->CopyFrom(input_shapes[0]);

input_layer_param->add_top("h_0");
input_param->add_shape()->CopyFrom(input_shapes[1]);

LayerParameter* cont_slice_param = net_param->add_layer();
cont_slice_param->CopyFrom(slice_param);
cont_slice_param->set_name("cont_slice");
cont_slice_param->add_bottom("cont");
cont_slice_param->mutable_slice_param()->set_axis(0);

// Add layer to transform all timesteps of x to the hidden state dimension.
// W_xc_x = W_xc * x + b_c
{
LayerParameter* x_transform_param = net_param->add_layer();
x_transform_param->CopyFrom(biased_hidden_param);
x_transform_param->set_name("x_transform");
x_transform_param->add_param()->set_name("W_xc");
x_transform_param->add_param()->set_name("b_c");
x_transform_param->add_bottom("x");
x_transform_param->add_top("W_xc_x");
x_transform_param->add_propagate_down(true);
}

if (this->static_input_) {
// Add layer to transform x_static to the gate dimension.
// W_xc_x_static = W_xc_static * x_static
LayerParameter* x_static_transform_param = net_param->add_layer();
x_static_transform_param->CopyFrom(hidden_param);
x_static_transform_param->mutable_inner_product_param()->set_axis(1);
x_static_transform_param->set_name("W_xc_x_static");
x_static_transform_param->add_param()->set_name("W_xc_static");
x_static_transform_param->add_bottom("x_static");
x_static_transform_param->add_top("W_xc_x_static_preshape");
x_static_transform_param->add_propagate_down(true);

LayerParameter* reshape_param = net_param->add_layer();
reshape_param->set_type("Reshape");
BlobShape* new_shape =
reshape_param->mutable_reshape_param()->mutable_shape();
new_shape->add_dim(1); // One timestep.
// Should infer this->N as the dimension so we can reshape on batch size.
new_shape->add_dim(-1);
new_shape->add_dim(
x_static_transform_param->inner_product_param().num_output());
reshape_param->set_name("W_xc_x_static_reshape");
reshape_param->add_bottom("W_xc_x_static_preshape");
reshape_param->add_top("W_xc_x_static");
}

LayerParameter* x_slice_param = net_param->add_layer();
x_slice_param->CopyFrom(slice_param);
x_slice_param->add_bottom("W_xc_x");
x_slice_param->set_name("W_xc_x_slice");

LayerParameter output_concat_layer;
output_concat_layer.set_name("h_concat");
output_concat_layer.set_type("Concat");
output_concat_layer.add_top("h");
output_concat_layer.mutable_concat_param()->set_axis(0);

for (int t = 1; t <= this->T_; ++t) {
string ts = format_int(t);
cont_slice_param->add_top("cont_" + ts);
x_slice_param->add_top("W_xc_x_" + ts);
}

int depth = this->layer_param_.recurrent_param().depth();
if (depth==0) {
depth = this->T_;
}
for (int t = 1; t <= depth*this->T_; ++t) {

int m = (t-1) % this->T_ + 1;
string ms = format_int(m);
string ts = format_int(t);
string tm1s = format_int(t - 1);

// Add layers to flush the hidden state when beginning a new
// sequence, as indicated by cont_t.
// h_conted_{t-1} := cont_t * h_{t-1}
//
// Normally, cont_t is binary (i.e., 0 or 1), so:
// h_conted_{t-1} := h_{t-1} if cont_t == 1
// 0 otherwise
{
LayerParameter* cont_h_param = net_param->add_layer();
cont_h_param->CopyFrom(scale_param);
cont_h_param->set_name("h_conted_" + tm1s);
cont_h_param->add_bottom("h_" + tm1s);
if (m == 1 && t >this->T_) {
cont_h_param->add_bottom("cont_2");
} else {
cont_h_param->add_bottom("cont_" + ms);
}
cont_h_param->add_top("h_conted_" + tm1s);
}

// Add layer to compute
// W_hc_h_{t-1} := W_hc * h_conted_{t-1}
{
LayerParameter* w_param = net_param->add_layer();
w_param->CopyFrom(hidden_param);
w_param->set_name("transform_" + ts);
w_param->add_param()->set_name("W_hc");
w_param->add_bottom("h_conted_" + tm1s);
w_param->add_top("W_hc_h_" + tm1s);
w_param->mutable_inner_product_param()->set_axis(2);
}

// Add the outputs of the linear transformations to compute the gate input.
// gate_input_t := W_hc * h_conted_{t-1} + W_xc * x_t + b_c
// = W_hc_h_{t-1} + W_xc_x_t + b_c
{
LayerParameter* input_sum_layer = net_param->add_layer();
input_sum_layer->CopyFrom(sum_param);
input_sum_layer->set_name("gate_input_" + ts);
input_sum_layer->add_bottom("W_hc_h_" + tm1s);
input_sum_layer->add_bottom("W_xc_x_" + ms);
if (this->static_input_) {
input_sum_layer->add_bottom("W_xc_x_static");
}
input_sum_layer->add_top("gate_input_" + ts);
}

// Add LSTMUnit layer to compute the cell & hidden vectors c_t and h_t.
// Inputs: c_{t-1}, gate_input_t = (i_t, f_t, o_t, g_t), cont_t
// Outputs: c_t, h_t
// [ i_t' ]
// [ f_t' ] := gate_input_t
// [ o_t' ]
// [ g_t' ]
// i_t := \sigmoid[i_t']
// f_t := \sigmoid[f_t']
// o_t := \sigmoid[o_t']
// g_t := \tanh[g_t']
// c_t := cont_t * (f_t .* c_{t-1}) + (i_t .* g_t)
// h_t := o_t .* \tanh[c_t]
{
LayerParameter* lstm_unit_param = net_param->add_layer();
lstm_unit_param->set_type("LSTMUnit");
lstm_unit_param->add_bottom("c_" + tm1s);
lstm_unit_param->add_bottom("gate_input_" + ts);
if (m == 1 && t >this->T_) {
lstm_unit_param->add_bottom("cont_2");
} else {
lstm_unit_param->add_bottom("cont_" + ms);
}
lstm_unit_param->add_top("c_" + ts);
lstm_unit_param->add_top("h_" + ts);
lstm_unit_param->set_name("unit_" + ts);
}

}
for (int t = 1; t <= this->T_; ++t)
{
output_concat_layer.add_bottom("h_" + format_int((depth-1)*this->T_+t));
}

{
LayerParameter* c_T_copy_param = net_param->add_layer();
c_T_copy_param->CopyFrom(split_param);
c_T_copy_param->add_bottom("c_" + format_int(depth*this->T_));
c_T_copy_param->add_top("c_T");
}
net_param->add_layer()->CopyFrom(output_concat_layer);
}

INSTANTIATE_CLASS(CircleLSTMLayer);
REGISTER_LAYER_CLASS(CircleLSTM);

} // namespace caffe

Loading

0 comments on commit d6c5852

Please sign in to comment.