如何对验证码中的每个字母/数字使用交叉熵损失函数?

数据挖掘 神经网络 张量流 损失函数
2022-03-14 05:30:10

我正在尝试使用 TensorFlow 中的简单全连接神经网络开发验证码求解器。所有验证码都有 5 个数字/字母,每个字符可以是数字 0-9 或字母 AZ。它们看起来都是这样的:

验证码1 验证码2 验证码3 验证码4 验证码5

每个验证码都有一个这样的标签,例如:“AB4D1”。我取这些标签,将它们拆分 ['A', 'B', '4', 'D', '1'],将每个字符转换为 0 到 35 之间的数字(26 个字母和 10 个数字)并转换每一个都指向一个热表示 [0, 0, 0, 1, 0,..]。然后,我将验证码中所有字母的 one-hot 数组连接起来,因此我最终为每个图像提供了一个 5*36 长度的数组。(该数组有 5 个 1,其余为 0)

现在我想知道使用什么损失函数。我尝试了均方误差,但由于某种原因根本不起作用。现在我正在尝试使用交叉熵(首先使用softmax),但据我了解,我需要将它分别应用于每个字母,然后将每个字母的损失相加,因为softmax需要专有类别。

我尝试拆分模型输出和标签:

split_logits = tf.split(logits, num_or_size_splits=5, axis=1)
split_train_labels = tf.split(tf_train_labels, num_or_size_splits=5, axis=1)

这很有效。现在我只是将每个字母的交叉熵损失加在一起。

loss = 
tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits_v2(labels=split_train_labels[0], logits=split_logits[0])) +
tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits_v2(labels=split_train_labels[1], logits=split_logits[1])) +
tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits_v2(labels=split_train_labels[2], logits=split_logits[2])) +
tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits_v2(labels=split_train_labels[3], logits=split_logits[3])) +
tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits_v2(labels=split_train_labels[4], logits=split_logits[4])) 

但这是我有问题的地方。只要我在那里只有第一个(0th)数字/字母的行,它就可以很好地工作(但显然只学会识别第一个字母)。一旦我为另一个字母添加术语,或者只添加一个其他字母而不是第一个字母,网络在训练开始后立即停滞不前,并且永远不会提高到高于随机的性能。

我不知道如何解决这个问题。我认为问题出在我的损失函数或网络结构中。

问题是除了第一个之外的所有字母由于不同的字体大小/宽度而在它们的位置上变化很大吗?我知道卷积网络会更好,但我真的很想先用全连接网络试试。

1个回答

解决问题的另一种方法是单字符预测。如果您可以将图像拆分为单独的字符,请分别预测每个字符。

如果以这种方式构建问题,最合适的损失函数是 softmax。网络将学习预测每 36 个字符的相对可能性。