本文主要是介绍Mxnet (17): 残差网络(ResNet),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
理论上添加新的层会导致误差降低,但是实践中,添加过多的层后训练误差往往不降反升。即使利用批量归一化带来的数值稳定性使训练深层模型更加容易,该问题仍然存在。针对这一问题,何恺明等人提出了残差网络(ResNet)
1 残差块
结合下图理解残差,输入为 x ,假设我们希望学出的理想映射为 f(x) 。
- 左侧, 虚线框中的部分必须直接学习映射 f ( x ) f(x) f(x) 。
- 右侧, 虚线框中的部分则需要拟合出有关恒等映射的残差映射 f ( x ) − x f(x)−x f(x)−x。
我们只需将图中右图虚线框内上方的加权运算(如仿射)的权重和偏差参数学成0,那么 f(x) 即为恒等映射。实际中,当理想映射 f(x) 极接近于恒等映射时,残差映射也易于捕捉恒等映射的细微波动。
右图也是ResNet的基础块,即残差块(residual block)。在残差块中,输入可通过跨层的数据线路更快地向前传播。残差映射在实际中往往更容易优化。
ResNet沿用了VGG全 3 × 3 3×3 3×3卷积层的设计。残差块里首先有2个有相同输出通道数的 3 × 3 3×3 3×3卷积层。每个卷积层后接一个批量归一化层和ReLU激活函数。这种设计要求两个卷积层的输出必须与输入具有相同的形状,以便可以将它们相加。如果要更改通道数,则需要引入其他 1 × 1 1×1 1×1卷积层将输入转换为所需的形状以进行加法运算
class Residual(nn.Block): def __init__(self, num_channels, use_1x1conv=False, strides=1, **kwargs):super().__init__(**kwargs)self.conv1 = nn.Conv2D(num_channels, kernel_size=3, padding=1,strides=strides)self.conv2 = nn.Conv2D(num_channels, kernel_size=3, padding=1)if use_1x1conv:self.conv3 = nn.Conv2D(num_channels, kernel_size=1,strides=strides)else:self.conv3 = Noneself.bn1 = nn.BatchNorm()self.bn2 = nn.BatchNorm()def forward(self, X):Y = npx.relu(self.bn1(self.conv1(X)))Y = self.bn2(self.conv2(Y))if self.conv3:X = self.conv3(X)return npx.relu(Y + X)
- 看一下输入和输出具有相同形状的情况。
block = Residual(3)
block.initialize()
X = np.random.uniform(size=(4, 3, 6, 6))
block(X).shape# (4, 3, 6, 6)
- 还可以选择在增加输出通道数量的同时将输出高度和宽度减半。
blk = Residual(6, use_1x1conv=True, strides=
这篇关于Mxnet (17): 残差网络(ResNet)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!