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

语义分割CNN训练报错:deconv2/biases含NaN及protobuf超限问题

解决TensorFlow语义分割训练中的NaN与Protobuf超限问题

针对你遇到的两个核心训练错误,结合你的硬件环境(4GB显存GTX960M、TensorFlow 1.4)和模型场景,以下是针对性的解决方案:


问题1:float16导致的Nan in summary histogram错误

根本原因

float16的数值范围(±65504)远小于float32(±3.4e38),在模型训练的梯度更新、权重初始化(tf.truncated_normal生成的数值可能在float16下精度丢失)或ReLU激活后的数值处理中,极易出现数值溢出/下溢,进而产生NaN,反映在summary直方图中。

解决方案

不要直接将整个模型输出强制转为float16,而是采用手动混合精度训练适配TF1.4:

  1. 模型内部计算保持float32,仅在显存存储时用float16:
    # 修改conv_layer和deconv_layer的返回值,去掉强制转float16
    # 改为仅在最终输出时转float16
    def conv_layer(...):
        # ... 原有代码 ...
        return activation  # 保留float32
    def deconv_layer(...):
        # ... 原有代码 ...
        return activation  # 保留float32
    # 模型最终输出转float16
    def semantic_seg_model(...):
        # ... 原有代码 ...
        return tf.cast(deconv, dtype=tf.float16)
    
  2. 优化权重初始化方式:
    替换tf.truncated_normal为更稳定的初始化器,避免初始权重过大导致激活值溢出:
    filter_tensor = tf.variance_scaling_initializer(scale=2.0)(
        [kernel_size[0], kernel_size[1], input_shape[3], filters]
    )
    
  3. 添加激活值裁剪:
    用tf.nn.relu6代替tf.nn.relu,限制激活值范围,防止float16下溢出:
    activation = tf.nn.relu6(conv2d + bias)
    

问题2:Protobuf超过2GB限制错误

根本原因

你设置的tf.summary.image('input', features, batch_size)会一次性写入1000张28x28x3的图像到summary,再加上所有层的权重、偏置、激活值的直方图,summary文件体积会迅速膨胀,超过Protobuf的2GB单文件限制。即使调小batch size,23万+的总样本量累计写入后仍会触发问题。

解决方案

  1. 大幅削减summary写入量:
    • 限制图像summary的输出数量:将max_outputs从batch_size改为10,每次仅写入少量样本:
      tf.summary.image('input', features, max_outputs=10)
      
    • 关闭不必要的直方图:仅保留权重的直方图,去掉偏置和激活值的统计,减少summary体积:
      # 在conv_layer和deconv_layer中,仅保留以下代码
      tf.summary.histogram("weights", filter)
      # 移除tf.summary.histogram("biases", bias)和tf.summary.histogram("activations", activation)
      
  2. 间隔写入summary:
    不要每个epoch都写入summary,每隔10个epoch写一次:
    for epoch in range(epochs):
        # ... 训练代码 ...
        if epoch % 10 == 0:
            s = sess.run(merged_summary)
            writer.add_summary(s, epoch)
    
  3. 改用更高效的数据管道:
    替换旧的tf.train.slice_input_producer队列API为tf.data.Dataset,降低显存占用和数据处理开销:
    dataset = tf.data.Dataset.from_tensor_slices((features, labels))
    dataset = dataset.batch(256, drop_remainder=True)  # 调小batch size到256
    dataset = dataset.prefetch(tf.data.experimental.AUTOTUNE)
    iterator = dataset.make_initializable_iterator()
    image_batch, label_batch = iterator.get_next()
    
    # 训练时初始化迭代器
    sess.run(iterator.initializer)
    

针对你的硬件的额外优化

由于GTX960M只有4GB显存,TF1.4显存优化能力有限,建议:

  1. 保持简化后的模型结构(小滤波器尺寸、少滤波器数量),避免显存过载
  2. 调整学习率:你之前设置的1e-50过小,模型根本无法更新,改为1e-4并添加学习率衰减:
    global_step = tf.Variable(0, trainable=False)
    learning_rate = tf.train.exponential_decay(
        1e-4, global_step, 1000, 0.96, staircase=True
    )
    optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost, global_step=global_step)
    
  3. 关闭设备日志输出:config.log_device_placement = True会增加显存占用,改为False

验证步骤

  1. 先禁用所有非必要的summary,仅保留损失和精度的标量统计
  2. 应用混合精度训练调整
  3. 调小batch size到256,设置合理的学习率
  4. 启动训练,观察是否还出现NaN或Protobuf错误

如果仍有问题,检查输入数据是否存在NaN/异常值,提前对图像块做归一化(如除以255转成0-1范围),避免数值过大导致的计算异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:10:05