I have a requirement to implement the forward computing of deconv layer in the 3D filter manner.
Here, by '3D filter manner', I mean convolution like the Gaussian filter in CV. In the contrast, the caffe implements the deconv in the gemm + col2im manner.
I find a similar question here. The guy wrote the code according the introduction in tranposed conv.
He/She does not open the source code. So I finished my own one:
template <typename DataType> int deconv_cpu(
DataType *src, DataType *dst, DataType *para, DataType *bias,
int in_width, int in_height, int in_channel,
int out_width, int out_height, int out_channel,
int ks, int padding = 0, int step = 1) { // step indicates the stride
int col, row, ch_o, ch_i, x, y;
int r = (ks - 1) / 2; //radius;
DataType result;
DataType *output;
DataType *filter;
DataType *input;
int sim_width, sim_height, sim_pad, width_border, height_border;
sim_width = in_width * step - step + 1;
sim_height = in_height * step - step + 1;
sim_pad = ks - padding - 1;
width_border = sim_pad == 0 ? r : 0;
height_border = sim_pad == 0 ? r : 0;
for (row = height_border; row < (sim_height - height_border); row++)
for (col = width_border; col < (sim_width - width_border); col++)
{
for (ch_o = 0; ch_o < out_channel; ch_o++)
{
output = dst + ch_o * out_width * out_height;
result = 0;
for (ch_i = 0; ch_i < in_channel; ch_i++)
{
filter = para + ks * ks * (in_channel * ch_o + ch_i);
//filter = para + ks*ks * (out_channel * ch_i + ch_o);
input = src + ch_i * in_width * in_height;
for (x = -r; x <= r; x++)
{
for (y = -r; y <= r; y++)
{
if ((row + x) >= 0 && (col + y) >= 0 && (row + x) < sim_height && (col + y) < sim_width)
{
if ( (row + x) % step != 0 || (col + y) % step != 0) continue;
result += input[(row + x) / step * in_width + (col + y) / step] * filter[(x + r) * ks + (y + r)];
}
}
}
}
if (bias != NULL) result = result + bias[ch_o];
output[(row - height_border) * out_width + (col - width_border)] = result;
}
}
return 0;
}
I compare the result with the caffe's one:
const caffe::vector<caffe::shared_ptr<caffe::Blob<float> > > blobs = layers[i]->blobs();
float *filter = blobs[0]->mutable_cpu_data();
float *bias = blobs[1]->mutable_cpu_data();
caffe::shared_ptr<caffe::Blob<float> > blob;
blob = caffe_net->blob_by_name(np.bottom(0));
deconv_cpu(blob->mutable_cpu_data(), dst, filter, bias, width1,
height1, c1, width2, height2, c2, ks, pad, stride);
blob = caffe_net->blob_by_name(np.top(0));
if(compare(dst, blob->mutable_cpu_data()) == 0) printf("match\n");
else printf("do not match\n");
However, the code does not give the same result with the caffe's implementation.
Do anyone know what is wrong? Or any advises or comment on the code?
This issue is finally fixed by change the filter index: filter[(r-x) * ks + (r-y)]