分割网络FCN

 

 

原作者源码地址[32s, caffe]:https://github.com/shelhamer/fcn.berkeleyvision.org/blob/master/voc-fcn32s/net.py

(

基本忠于原作的翻译地址[32s, pytorch]:https://github.com/wkentaro/pytorch-fcn/blob/master/torchfcn/models/fcn32s.py

)

这里说原作的几个点。

 

结构

 

caffe源码

def fcn(split):
    n = caffe.NetSpec()
    pydata_params = dict(split=split, mean=(104.00699, 116.66877, 122.67892),
            seed=1337)
    if split == 'train':
        pydata_params['sbdd_dir'] = '../data/sbdd/dataset'
        pylayer = 'SBDDSegDataLayer'
    else:
        pydata_params['voc_dir'] = '../data/pascal/VOC2011'
        pylayer = 'VOCSegDataLayer'
    n.data, n.label = L.Python(module='voc_layers', layer=pylayer,
            ntop=2, param_str=str(pydata_params))

    # the base net
    n.conv1_1, n.relu1_1 = conv_relu(n.data, 64, pad=100)
    n.conv1_2, n.relu1_2 = conv_relu(n.relu1_1, 64)
    n.pool1 = max_pool(n.relu1_2)

    n.conv2_1, n.relu2_1 = conv_relu(n.pool1, 128)
    n.conv2_2, n.relu2_2 = conv_relu(n.relu2_1, 128)
    n.pool2 = max_pool(n.relu2_2)

    n.conv3_1, n.relu3_1 = conv_relu(n.pool2, 256)
    n.conv3_2, n.relu3_2 = conv_relu(n.relu3_1, 256)
    n.conv3_3, n.relu3_3 = conv_relu(n.relu3_2, 256)
    n.pool3 = max_pool(n.relu3_3)

    n.conv4_1, n.relu4_1 = conv_relu(n.pool3, 512)
    n.conv4_2, n.relu4_2 = conv_relu(n.relu4_1, 512)
    n.conv4_3, n.relu4_3 = conv_relu(n.relu4_2, 512)
    n.pool4 = max_pool(n.relu4_3)

    n.conv5_1, n.relu5_1 = conv_relu(n.pool4, 512)   # out shape=(13, 13)
    n.conv5_2, n.relu5_2 = conv_relu(n.relu5_1, 512)
    n.conv5_3, n.relu5_3 = conv_relu(n.relu5_2, 512)
    n.pool5 = max_pool(n.relu5_3)

    # fully conv
    n.fc6, n.relu6 = conv_relu(n.pool5, 4096, ks=7, pad=0) # out shape=(7, 7)
    n.drop6 = L.Dropout(n.relu6, dropout_ratio=0.5, in_place=True)

    n.fc7, n.relu7 = conv_relu(n.drop6, 4096, ks=1, pad=0)  # out shape=(7, 7)
    n.drop7 = L.Dropout(n.relu7, dropout_ratio=0.5, in_place=True)

    n.score_fr = L.Convolution(n.drop7, num_output=21, kernel_size=1, pad=0,
        param=[dict(lr_mult=1, decay_mult=1), dict(lr_mult=2, decay_mult=0)])
    n.upscore = L.Deconvolution(n.score_fr,
        convolution_param=dict(num_output=21, kernel_size=64, stride=32,
            bias_term=False),
        param=[dict(lr_mult=0)])
    n.score = crop(n.upscore, n.data) # crop size to n.data
    n.loss = L.SoftmaxWithLoss(n.score, n.label,
            loss_param=dict(normalize=False, ignore_label=255))

    return n.to_proto()

 

容易疑惑的点

一些trick在后来都不再使用了。

到底是从哪里开始上采样的?

是像很多复现的论文那样,从conv5后开始上采样32倍得到原图224吗?

不是的。原作是从fc7开始上采样。

那么fc7难道不是feature map=1*1了吗?怎么上采样到224?

不是的。由于前面有padding=100,因此conv5的输出是13×13。fc6后是7×7,这个7×7里面,只有4×4的感受野对应原来的224图像,剩下的3是padding带来的。fc7只增加非线性,输出保持了7×7,但是这个7×7里面,应该学习到了原图224的特征。然后在此基础上作插值32倍。

 

为什么在Conv1设置pad=100?

为了应对小图片的情况。

在不做pad的情况下,当输入224的图片时,经过5个conv后输出是7×7,和fc6的kernel 7×7卷积,仍然有1个像素的输出。但是如果输入图片小于224时,conv之后输出小于7×7,都没有fc6的7×7的kernel大,因此fc6卷积后,就一个像素都没有了。因此,原作者使用了简单粗暴的方法,直接在conv前pad 100,保证小图片经过网络后也有输出。

回答:vgg16运行到pool5缩小了32倍,h0为输入图像大小,h6为输入到fc6的feature map大小,经过7x7卷积大小为:h6-7+1=h6-6=(h0/32)-6=(h0-6*32)/32=(h-192)/32,如果h0<192则报错(因为此时h6的输出将小于卷积核7*7的大小),因此FCN采用了一个简单的方法,直接在第一层卷积增加了一个100的padding,即增加100*2=200来解决这个问题。

 

第6层fc6的ks=7

FCN设计之初,这个kernel=7是为了替代全连接层的,即对于输入是7×7,kernel也是个7×7,conv就可以代替全连接了。同时当输入更大时,conv也可以适应。

但是等到后来为了解决小图片输入的问题增加了padding=100后,输入到fc6的feature map已经不是7×7了,而是13×13了,这里的ks=7也就没有了原来全连接的作用。

那为什么conv5使用3个kernel=3的卷积代替kernel=7的卷积,而fc6却不把这个kernel=7也换成3个kernel=3呢?应该是作者并没有进一步把注意力重新放在这里。当用kernel=7代替fully connection后,已经是重大突破了。并没有来第二轮重新检查这个地方是不是再可以改进。

 

转置卷积Deconvolution的参数kernel_size=64

为什么不用kernel=N,stride=N实现准确的上采样N倍。这个涉及到FCN的训练和权重初始化等更复杂的问题。
FCN的网络由分类网络和上采样网络两部分组成,其中分类网络权重采用预训练权重,上采样网络权重使用双线性插值初始化,kernel=2N是和双线性插值初始化相关的。64的kernel,双线性插值后就是32了。

 

crop

因为前面padding了100,所以此处要截掉多余的部分,使输出和原输入的size大小一致。

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值