You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ResNet残差块1x1卷积适配Add层张量形状的原理问询

问题背景

假设我有一组形状为(None, 188, 1)的加速度计时序数据,需要完成分类任务,尝试自行实现ResNet模型,对应实现代码如下:

def residual_block(inputs, filters, kernel_size, shortcut):

    out = tf.keras.layers.Conv1D(filters=filters, kernel_size=kernel_size,
                                 strides=1, padding='causal')(inputs)
    out = tf.keras.layers.ReLU()(out)
    out = tf.keras.layers.Conv1D(filters=filters, kernel_size=kernel_size,
                                 strides=1, padding='causal')(out)
    if shortcut:
        out = tf.keras.layers.Conv1D(1, 1, padding="causal")(out)
    out = tf.keras.layers.add([inputs, out])
    out = tf.keras.layers.ReLU()(out)
    out = tf.keras.layers.MaxPool1D()(out)

    return out

def resnet_model(n_timesteps, n_features, n_classes):
    filters_1 = 16
    kernel_size_1 = 10

    filters_2 = 32
    kernel_size_2 = 10
    # head 1
    input1 = tf.keras.layers.Input(shape=(n_timesteps, n_features))
    res_block1_1 = residual_block(input1, filters_1, kernel_size_1, shortcut=False)
    res_block1_2 = residual_block(res_block1_1, filters_2, kernel_size_2, shortcut=True)
    flatten1 = tf.keras.layers.Flatten()(res_block1_2)

    dense1 = tf.keras.layers.Dense(512, activation='relu')(flatten1)
    drop1 = tf.keras.layers.Dropout(0.3)(dense1)
    dense2 = tf.keras.layers.Dense(128, activation="relu")(drop1)
    drop2 = tf.keras.layers.Dropout(0.3)(dense2)
    outputs = tf.keras.layers.Dense(n_classes, activation="softmax")(drop2)

    model = tf.keras.Model(inputs=[input1, input2, input3],
                           outputs=outputs)
    model.compile(loss='categorical_crossentropy',
                  optimizer=tf.keras.optimizers.Adam(),
                  metrics=['accuracy'])
    return model

最初仅使用单个残差块时模型运行无异常,加入第二个残差块后出现报错。梳理数据流向可知:

  • 第一个残差块的Add层接收的两个输入形状分别为:来自原始输入的(None, 188, 1)、来自卷积分支的(None, 188, 16),相加操作可正常执行
  • 第二个残差块的Add层触发形状不匹配错误,接收的两个输入分别为:来自前序MaxPooling层的(None, 94, 16)、来自卷积分支的(None, 94, 8)

尝试加入1x1 Convolution修复该问题,但不理解修复逻辑:根据ResNet设计原理,残差相加要求Add层的两个输入形状完全一致,因此通常使用1x1卷积做维度适配,但当前代码中的1x1卷积处理后得到的张量形状为(None, 94, 1),依然和shortcut分支传入的(None, 94, 16)形状不匹配。

核心疑问:当前代码中的1x1卷积是如何解决形状不匹配问题的?1x1卷积和Add层配合实现残差连接的正确逻辑是什么?

问题解答

首先直接给结论:你代码里写的1x1卷积根本没有正确解决形状不匹配问题,第一个残差块能跑通完全是依赖TensorFlow的广播机制误打误撞生效,属于不符合ResNet设计规范的错误实现。

第一个残差块能运行的本质原因

你观察到第一个块的原始输入形状是(None,188,1)、卷积分支输出形状是(None,188,16)还能相加,不是代码写对了,是广播机制自动把最后一维长度为1的张量复制16次,和16通道的张量对齐后完成计算。这种操作完全破坏了残差连接的语义,相当于把单通道输入强行复制到所有通道做相加,和ResNet的残差设计逻辑没有关系。

当前1x1卷积的逻辑错误

残差连接用1x1卷积做形状适配的核心规则是:必须保证送入Add层的两个张量在所有维度上长度完全相等,1x1卷积的作用是调整通道数,通常加在shortcut直连分支上,输出通道数要和卷积分支的最终输出通道数完全匹配;如果卷积步长导致时间步长度变化,还要给1x1卷积设相同步长对齐时间步维度。
你现在的实现把1x1卷积加在了卷积分支上,还硬编码输出通道为1,相当于把卷积分支的通道数压回1,再靠广播机制和shortcut分支的16通道张量相加,本质和第一个块的错误逻辑完全一致,只是把适配方向反过来了,根本不是正确的维度适配。另外你提到第二个块卷积分支输出是(None,94,8)也不符合预期——你两层Conv1D都设了32个滤波器,正常输出通道应该是32,这个数值偏差说明代码还有其他隐藏的运行问题。

正确的残差块1x1卷积适配写法

1x1卷积要放在shortcut路径上,仅当输入和卷积分支输出形状不匹配时启用,输出通道数和卷积分支通道数保持一致,修正后的残差块参考代码如下:

def residual_block(inputs, filters, kernel_size, need_shortcut_conv):
    # 主卷积分支
    out = tf.keras.layers.Conv1D(filters=filters, kernel_size=kernel_size,
                                 strides=1, padding='causal')(inputs)
    out = tf.keras.layers.ReLU()(out)
    out = tf.keras.layers.Conv1D(filters=filters, kernel_size=kernel_size,
                                 strides=1, padding='causal')(out)
    # shortcut分支:形状不匹配时用1x1卷积对齐
    if need_shortcut_conv:
        shortcut = tf.keras.layers.Conv1D(filters=filters, kernel_size=1, padding="causal")(inputs)
    else:
        shortcut = inputs
    # 两个分支形状完全对齐后再相加
    out = tf.keras.layers.add([shortcut, out])
    out = tf.keras.layers.ReLU()(out)
    out = tf.keras.layers.MaxPool1D()(out)
    return out

另外你现有代码还有两个会直接导致运行报错的低级问题:

  • 模型构造时Model的输入参数写了[input1, input2, input3],但你只定义了input1这一个输入层,运行时会直接抛出input2未定义的错误
  • 你把MaxPool层放在残差相加操作之后,每经过一个块时间步长度就会减半,如果后续残差块用步长大于1的卷积做下采样,还要在shortcut的1x1卷积上设置对应步长,保证时间步维度也完全对齐,不能依赖广播机制凑运行结果。

内容的提问来源于stack exchange,提问作者DPM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 21:03:38