目录
一、问题
二、思考分析
🍨 本文为[🔗365天深度学习训练营]内部限免文章(版权归 *K同学啊* 所有)
🍖 作者:[K同学啊]
查看j6周代码,思考解决问题。
一、问题
📌你需要解决的疑问:这个代码是否有错?对错与否都请给出你的思考
📌打卡要求:请查找相关资料、逐步推理模型、详细写下你的思考过程
在Resnext网络中 定义残差单元块中,如果conv_shortcut=False,那么执行“x=Add()…”语句时,通道数不一致的,为什么不会报错呢?
代码:
# 定义残差单元
def block(x, filters, strides=1, groups=32, conv_shortcut=True):
if conv_shortcut:
shortcut = Conv2D(filters * 2, kernel_size=(1, 1), strides=strides, padding='same', use_bias=False)(x)
# epsilon为BN公式中防止分母为零的值
shortcut = BatchNormalization(epsilon=1.001e-5)(shortcut)
else:
# identity_shortcut
shortcut = x
# 三层卷积层
x = Conv2D(filters=filters, kernel_size=(1, 1), strides=1, padding='same', use_bias=False)(x)
x = BatchNormalization(epsilon=1.001e-5)(x)
x = ReLU()(x)
# 计算每组的通道数
g_channels = int(filters / groups)
# 进行分组卷积
x = grouped_convolution_block(x, strides, groups, g_channels)
x = Conv2D(filters=filters * 2, kernel_size=(1, 1), strides=1, padding='same', use_bias=False)(x)
x = BatchNormalization(epsilon=1.001e-5)(x)
x = Add()([x, shortcut])
x = ReLU()(x)
return x
# 堆叠残差单元
def stack(x, filters, blocks, strides, groups=32):
# 每个stack的第一个block的残差连接都需要使用1*1卷积升维
x = block(x, filters, strides=strides, groups=groups)
for i in range(blocks):
x = block(x, filters, groups=groups, conv_shortcut=False)
return x
二、思考分析
在ResNext网络中,如果在定义残差单元块时,将conv_shortcut参数设置为False,表示使用identity_shortcut而不是Conv2D层作为快捷连接。
对于定义残差单元block模块,Add()是x和shortcut相加,x通道数是filter*2。对于shortcut,conv_shortcut为True则是filters*2,否则是原始输入通道数。
最后对于堆叠残差模块stack,第二次调用block时,conv_shortcut参数是False,使用的是identity_shortcut,这种情况下,快捷连接将直接传递输入x给块的最后一层。因此,在执行“x=Add()…”语句时,快捷连接的通道数与该层的通道数不一致。
但是,由于Add()层在通道数不同时会自动对快捷连接进行零填充,所以不会出现尺寸不匹配的错误。此外,这种零填充不会对训练产生任何影响,因为填充的值不会接收任何梯度更新。
总之,Add 层具有自动广播机制,可以在计算时自动扩展较小张量的形状以匹配较大张量的形状,因此即使通道数不一致也不会报错。
广播机制是指在进行张量运算时,系统会自动对两个张量进行扩展,使它们的形状相同,然后再进行运算。这样,即使两个张量的形状不同,也可以将它们相加或相乘。这种机制可以简化代码,提高效率。