一、目标
本文主要完成除带随机失活dropout shortcut)以外的模型。
在这里插入图片描述

二、关键代码
(1)constant scaling
与原始残差块的差别在于,将输出从y=f(x)+x变成了y=0.5[f(x)+x]。
如图Fig.2(b)所示,设置\lambda=0.5,即h(xl)=0.5xl,对于残差函数F有两种处理方式,一种是不加缩放系数,另一种是残差函数F以1-\lambda为系数进行缩放。试验结果表明,第一种方式的模型无法很好的收敛,第二种方式的模型能够收敛,但在最终的测试集上的分类错误率大于原始的模型。

class ResidualBlock(nn.Module):
    def __init__(self, channels):
        super(ResidualBlock, self).__init__()
        self.channels = channels
        self.conv1 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)

    def forward(self, x):
        y = F.relu(self.conv1(x))
        y = self.conv2(y)
        return 0.5*F.relu(x + y)

在这里插入图片描述
在这里插入图片描述

(2)conv shortcut
将输出y=f(x)+x中的x经过一个1*1的卷积层。
在shortcut部分使用1×1卷积,效果远不如原始网络,证明了1×1卷积依然阻碍了信号的传递过程。

class ResidualBlock(nn.Module):
    def __init__(self, channels):
        super(ResidualBlock, self).__init__()
        self.channels = channels
        self.conv1 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.conv3 = nn.Conv2d(channels, channels, kernel_size=1)
    def forward(self, x):
        y = F.relu(self.conv1(x))
        y = self.conv2(y)
        z = self.conv3(x)+y
        return F.relu(z)

在这里插入图片描述在这里插入图片描述

(3)shortcut-only gating
在卷积后,多加了一个sigmoid层,变为线性输出,再用1去减去结果。
如图Fig.2(d)所示,这种方式不再对残差部分进行处理,而是只对shortcut部分乘以1-g(x),bg的取值依然很关键,当bg为0时,1-g(x)的期望是0.5,最终网络的误差为12.86%。如果设置bg为-6,那么1-g(x)很接近1,网络接近于恒等映射,取得的6.91%的误差耶很接近原始网络。

class ResidualBlock(nn.Module):
    def __init__(self, channels):
        super(ResidualBlock, self).__init__()
        self.channels = channels
        self.conv1 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.conv3 = nn.Conv2d(channels, channels, kernel_size=1)
        self.sigmoid = torch.nn.Sigmoid()
    def forward(self, x):
        y = F.relu(self.conv1(x))
        y = self.conv2(y)
        con = 1-(self.sigmoid(self.conv3(x)))
        z = con*x
        return F.relu(z+y)

在这里插入图片描述
在这里插入图片描述

(4)exclusive gating
如图Fig.2©所示,考虑一个gating函数,g(x)通过1×1的卷积实现。对于残差函数F部分乘以系数g(x),shortcut部分乘以系数1-g(x),实验发现偏置项bg的初始化非常重要,最好的情况是bg=-6是在测试集上得到了8.70%的误差,依然不如原始网络。

exclusive gating的影响有两个方面:当1-g(x)接近于1,g(x)就接近于0,在这种情况下shortcut约等于恒等映射,有助于信号的传递过程,但此时的g(x)接近于0,这抑制了残差函数的作用。为了进一步分析在shortcutbu部分的gating作用,作者进一步设计了shortcut-only gating的方式

class ResidualBlock(nn.Module):
    def __init__(self, channels):
        super(ResidualBlock, self).__init__()
        self.channels = channels
        self.conv1 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.conv3 = nn.Conv2d(channels, channels, kernel_size=1)
        self.sigmoid = torch.nn.Sigmoid()
    def forward(self, x):
        y = F.relu(self.conv1(x))
        y = self.conv2(y)
        con = 1-(self.sigmoid(self.conv3(x)))
        z = con*x
        y = y*con
        return F.relu(z+y)

在这里插入图片描述

在这里插入图片描述

三、后续安排
继续学习BN,随机失活等神经网络中的常用层,然后再精读这篇论文,看以下其他方向的研究。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐