【Pytorch】Identity Mappings in Deep Residual Networks经典论文模型复现(1)
一、目标本文主要完成除带随机失活(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为系数进行缩放。试验
一、目标
本文主要完成除带随机失活(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,随机失活等神经网络中的常用层,然后再精读这篇论文,看以下其他方向的研究。
更多推荐
所有评论(0)