在Fully Convolutional Networks(FCN)中,会用到Crop 层,他的主要作用是进行裁切。下面我们举一个例子来说明如何使用Crop 层。
Caffe中的数据是以 blobs形式存在的,blob是四维数据,即 (Batch size, number of Chennels, Height, Width)=(N, C, H, W)。---(0,1,2,3)
Crop层的输入(bottom blobs)有两个,让我们假设为A和B,输出(top)为C。
- A是要进行裁切的bottom,他的size是 (20,50,512,512)
- B是裁切的参考输入,他的size是(20,10,256,256)
- C是输出(top blob),由A裁切而来,那么他的size是(20,10,256,256)
在这个例子中,轴0的维度不变,我们只需要裁切blob的轴1,2,3,所以我们设置axis=1,代表我们将会裁切轴1和它之后的所有轴。
有两个裁切模式:
模式1---给出3个offsets,每个针对一个dimension,offset=(25,128,128)
- axis=1,offset=(25,128,128)
- crop operation: C = A[: , 25: 25+B.shape[1] , 128: 128+B.shape[2] , 128: 128+B.shape[3] ]
- 也就是说,对于A的轴1,对称裁切了25-35
- 对称裁切:offset = (Original_length - desired length ) / 2
模式2---给出1个offset,适用于三个dimension,offset=25
- 那么就相当于模式1 的 offset=(25,25,25)
axis=0,1,2,3分别表示为N,C,H,W。默认axis等于2,即默认从H开始裁剪(裁剪H和W)。Offset表示裁剪的大小
void CropLayer<Dtype>::crop_copy(const vector<Blob<Dtype>*>& bottom,// bottom[0]
const vector<Blob<Dtype>*>& top,
const vector<int>& offsets,
vector<int> indices,//初始化时都是0
int cur_dim,//默认从0开始
const Dtype* src_data,
Dtype* dest_data,
bool is_forward) {
if (cur_dim + 1 < top[0]->num_axes()) {
// We are not yet at the final dimension, call copy recursively
// 还没到最后一个维度,递归调用crop_copy()
for (int i = 0; i < top[0]->shape(cur_dim); ++i) {
indices[cur_dim] = i;
crop_copy(bottom, top, offsets, indices, cur_dim+1,
src_data, dest_data, is_forward);
}
} else {
// We are at the last dimensions, which is stored continously(连续) in memory
for (int i = 0; i < top[0]->shape(cur_dim); ++i) {
// prepare index vector reduced(red) and with offsets(off) 准备索引向量
std::vector<int> ind_red(cur_dim, 0); //顶层的偏移向量
std::vector<int> ind_off(cur_dim+1, 0);//底层的偏移向量
for (int j = 0; j < cur_dim; ++j) {//注意这里的cur_dim=3,因此j最大为2,ind_red[0]初始化时是0
ind_red[j] = indices[j];
ind_off[j] = indices[j] + offsets[j];
}
ind_off[cur_dim] = offsets[cur_dim];//ind_off最后一维
// do the copy 复制操作
if (is_forward) {
caffe_copy(top[0]->shape(cur_dim),
src_data + bottom[0]->offset(ind_off),
dest_data + top[0]->offset(ind_red));
} else {
// in the backwards pass the src_data is top_diff
// and the dest_data is bottom_diff
// 后向过程src_data是top_diff,dest_data是bottom_diff
caffe_copy(top[0]->shape(cur_dim),
src_data + top[0]->offset(ind_red),
dest_data + bottom[0]->offset(ind_off));
}
}
}
}
模式1的prototxt写法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
layer {
name:
"crop_layer"
type:
"Crop"
bottom:
"A"
bottom:
"B"
top:
"C"
crop_param {
axis: 1
offset: 25
offset: 128
offset: 128
}
}
|