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

基于CNN-RNN的OCR模型CTC训练损失为inf但验证损失正常的问题解决咨询

解决CTC训练损失为inf的问题:输入序列长度要求及代码修改

先解释「输入序列长度应略大于真实标签长度」的含义

咱们得从CTC损失的核心逻辑说起:CTC是用来做序列对齐的——模型输出的是一串时间步序列(比如T个时间步),每个时间步对应一个字符的概率,我们要把这T步的输出对齐到长度为L的真实标签序列(你的文本长度)。

这里有个硬约束:T必须大于等于L。因为CTC允许插入空白符来对齐,但如果你的模型输出时间步T比真实标签长度L还短,根本不可能完成对齐(总不能把短序列“拉长”去匹配长标签吧),这时候CTC的损失计算就会直接返回无穷大(inf)。

而说“略大于”,一是因为如果T刚好等于L,模型对齐的自由度极低,很难学到鲁棒的特征;二是你已经把所有标签填充到了9个字符,那必须保证T>9,这样所有样本的真实标签长度(都≤9)都能满足T>L的条件,不会出现计算异常。


你的代码问题分析及修改步骤

1. 先确认模型输出的时间步长是否达标

你的LSTM输出张量lstm的第二个维度就是时间步长T(也就是tf.shape(y_pred)[1]的值),这是关键的数值,必须大于9。

快速检查方法:在定义完LSTM层后加一行打印代码:

print("LSTM输出形状:", lstm.shape)

运行后看输出的第二个数值,比如如果是(None, 8, 256),那T=8,这就小于9,肯定会导致训练集中部分样本(真实标签长度≥8)的损失变inf,进而整个训练损失变成inf。

2. 调整模型结构,增大时间步长T

如果T≤9,你需要修改CNN特征提取部分,让输出的时间步长变大:

  • 减少池化操作:比如把池化层的strides从2改成1,或者直接去掉1-2个池化层——池化会压缩特征图的尺寸,减少池化就能保留更多时间步。
  • 调整卷积步长:卷积层的strides参数如果设为(1,1)(而不是(2,1)),可以避免特征图宽度(对应时间步)被过度压缩。
  • 调整输入图像尺寸:如果允许的话,适当增加输入图像的宽度(文本图像通常宽大于高,宽度直接对应时间步),这样CNN处理后得到的特征图宽度也会更大。

3. 修正CTC层的标签长度计算(可选但重要)

你现在的CTCLayer里,label_length是用tf.shape(y_true)[1](也就是填充后的9),但实际训练中,很多样本的真实标签长度是小于9的。虽然当前的inf问题主要是T不够,但如果后续T达标后还是有问题,建议传递真实的标签长度而非填充后的长度:

首先在数据准备阶段,为每个样本记录真实的标签长度(比如生成y_train_length数组),然后修改模型:

# 新增真实标签长度的输入层
label_length_input = layers.Input(shape=(1,), dtype="int64")

# 修改CTCLayer,接收真实标签长度
class CTCLayer(layers.Layer):
    def __init__(self, name=None):
        super().__init__(name=name)
        self.loss_fn = keras.backend.ctc_batch_cost
    def call(self, y_true, y_pred, label_length):
        batch_len = tf.cast(tf.shape(y_true)[0], dtype="int64")
        input_length = tf.cast(tf.shape(y_pred)[1], dtype="int64")
        input_length = input_length * tf.ones(shape=(batch_len, 1), dtype="int64")
        # 用真实标签长度代替填充后的长度
        loss = self.loss_fn(y_true, y_pred, input_length, label_length)
        self.add_loss(loss)
        return y_pred

# 重构模型
outputs = layers.Dense(l+1, activation='softmax',name='output')(lstm)
output = CTCLayer()(labels, outputs, label_length_input)
model = Model(inputs = [input_layer, labels, label_length_input], outputs=output)

# 训练时传入真实标签长度
model.fit([x_train, y_train, y_train_length], y_train, validation_split=0.2, epochs=100)

这一步能让CTC损失计算更准确,避免填充字符带来的无效对齐约束。

4. 排查训练数据的异常情况

最后可以检查一下训练集里是否存在真实标签长度大于T的样本——如果有,哪怕T>9,这些样本的损失还是会变成inf。这时候要么过滤掉这些样本,要么进一步增大T。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 15:32:40