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

Python中CNN的ResNet34编码器出现IndexError的原因及修复方案

问题原因与修复方案

为什么会出现IndexError?

你遇到的IndexError: list index out of range本质是ResNet34的残差块结构和你复用的ResNet50版res_blk函数不兼容:

  • 原res_blk是为ResNet50的Bottleneck瓶颈结构写的:它需要3层卷积(1x1、3x3、1x1),所以调用时要传长度为3的ch(通道数列表)和ksize(卷积核尺寸列表),比如[64,64,256]和[1,3,1]。
  • 但ResNet34用的是BasicBlock基础残差块,只有2层3x3卷积,你传入的ch是[64,64](长度为2),但函数里依然尝试访问ch[2](第三层卷积的通道数),自然就触发索引越界了。

修复方法:适配ResNet34的BasicBlock修改res_blk

既然目标是实现ResNet34编码器,我们需要把res_blk改成两层卷积的基础残差块结构,同时修正通道数的获取逻辑(原代码ch_in = l.get_shape().as_list()拿到的是整个张量形状,应该只取通道维度)。

修改后的res_blk代码:

def res_blk(name, l, ch, ksize, count, strides=1, freeze=False):
    # TensorPack默认NCHW格式,通道数在shape的第1位
    ch_in = l.get_shape().as_list()[1]
    with tf.variable_scope(name):
        for i in range(count):
            with tf.variable_scope('block' + str(i)):
                x = l if i == 0 else BNReLU('preact', l)
                # ResNet34 BasicBlock:两层3x3卷积
                x = Conv2D('conv1', x, ch[0], ksize[0], 
                           strides=strides if i == 0 else 1, 
                           activation=BNReLU)
                x = Conv2D('conv2', x, ch[1], ksize[1], activation=tf.identity)
                # Shortcut逻辑:步长≠1或输入输出通道不同时,用1x1卷积调整
                if (strides != 1 or ch_in != ch[1]) and i == 0:
                    l = Conv2D('convshortcut', l, ch[1], 1, strides=strides)
                x = tf.stop_gradient(x) if freeze else x
                l = l + x
                l = BNReLU('bnlast', l)
    return l

然后你的encoder函数可以保持原调用参数不变(因为现在res_blk已经支持两层残差块的参数了):

def encoder(i, freeze):
    d1 = Conv2D('conv0', i, 64, 7, padding='valid', strides=1, activation=BNReLU)
    d1 = res_blk('group0', d1, [64, 64], [3, 3], 3, strides=1, freeze=freeze)
    d2 = res_blk('group1', d1, [128, 128], [3, 3], 4, strides=2, freeze=freeze)
    d2 = tf.stop_gradient(d2) if freeze else d2
    d3 = res_blk('group2', d2, [256, 256], [3, 3], 6, strides=2, freeze=freeze)
    d3 = tf.stop_gradient(d3) if freeze else d3
    d4 = res_blk('group3', d3, [512, 512], [3, 3], 3, strides=2, freeze=freeze)
    d4 = tf.stop_gradient(d4) if freeze else d4
    d4 = Conv2D('conv_bot', d4, 1024, 1, padding='same')
    return [d1, d2, d3, d4]

额外提示

  • ResNet34和ResNet50的核心差异就是残差块:
    • ResNet34:BasicBlock(2个3x3卷积,通道数一致)
    • ResNet50+:Bottleneck(1x1压缩通道→3x3卷积→1x1恢复通道,减少计算量)
  • 如果你坚持不想修改res_blk,也可以强行按Bottleneck格式传参数(比如[64,64,64]),但这会违背ResNet34的设计,增加不必要的计算,不推荐这么做。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 15:42:36