Transpose Convolution Initializa

2018-12-08  本文已影响0人  是许嘉晨

第一篇博客首先感谢我的女朋友姜旭艳小姐的大力支持 😊


在语义分割问题中经常出现的操作就是反卷积,目的是将图片从较小的分辨率放大到更大的分辨率。反卷积层的参数初始化在训练过程中有很大的作用,如果采用随机初始化可能导致训练时间更长或者是效果不好,所以往往采用的是bilinear kernel初始化。

bilinear kernel实现代码

def upsample_filt(size):
    """
    size: Size of the filter
    """
    factor = (size + 1) 
    if size % 2 == 1:
        center = factor - 1
    else:
        center = factor - 0.5 

    og = np.ogrid[:size, :size]

    return (1 - abs(og[0] - center) / factor) * (1 - abs(og[1] - center) / factor)
# 以 size = 4 为例

factor = 5
center = 1.5
og = 
[array([[0],
       [1],
       [2],
       [3]]), array([[0, 1, 2, 3]])]

abs(og[0] - center) = 
[[ 1.5]
 [ 0.5]
 [ 0.5]
 [ 1.5]]

# 显然 abs(og[0] - center) 表示的是图像上每一个像素点到中心点(center)的距离
# 然后再利用核长度 factor 进行归一化
# 之所以 factor = size + 1 是因为将中心点也考虑进来了 所以总共有 size + 1 个像素
# 然后 (1 - abs(og[0] - center) / factor) 表示的就是在x轴方向上每个像素点的权重
# 距离越远权重越小
# 最后将x和y轴上的值相乘得到整个图像上每个像素点的权重

1 - abs(og[0] - center) / factor) * (1 - abs(og[1] - center) / factor = 
[[ 0.0625  0.1875  0.1875  0.0625]
 [ 0.1875  0.5625  0.5625  0.1875]
 [ 0.1875  0.5625  0.5625  0.1875]
 [ 0.0625  0.1875  0.1875  0.0625]]

在反卷积核中卷积核是一个四维变量[in_channels, out_channels, H, W],所以需要将卷积核的每一层都用上述的双线性插值核来赋值。
因此完整的初始化代码为

def bilinear_kernel(in_channels, out_channels, kernel_size):
    '''
    return a bilinear filter tensor
    '''
    factor = (kernel_size + 1) // 2
    if kernel_size % 2 == 1:
        center = factor - 1
    else:
        center = factor - 0.5
    og = np.ogrid[:kernel_size, :kernel_size]
    filt = (1 - abs(og[0] - center) / factor) * (1 - abs(og[1] - center) / factor)

    # 上半部分是生成一层双线性插值核
    # 下面是拉伸
    weight = np.zeros((in_channels, out_channels, kernel_size, kernel_size), dtype='float32')
    # 赋值到每一层
    weight[range(in_channels), range(out_channels), :, :] = filt 
    return torch.from_numpy(weight)

conv_trans = nn.ConvTranspose2d(3, 3, 4, 2, 1)
# 将其定义为 bilinear kernel
conv_trans.weight.data = bilinear_kernel(3, 3, 4)
上一篇下一篇

猜你喜欢

热点阅读