深度学习中的图像字幕生成

2025年7月19日 | 阅读 14 分钟

图像字幕生成任务是一项复杂的任务,它结合了自然语言处理和计算机视觉。本文将讨论开发能够分析图像上下文并用英语等自然语言进行叙述的图像字幕生成器的步骤。

我们将利用卷积神经网络 (CNN) 来提取图像特征,并利用长短期记忆 (LSTM) 网络来编译有用的句子。为了能够训练,我们将使用 Flickr8K 数据集,该数据集包含 8,000 张不同的照片。此数据可在 Kaggle 上下载。

步骤 1:导入必要的库

在这里,我们将介绍项目中所有必需库的导入过程。它们包括 NumPy 用于数值运算、Pandas 用于数据处理、OS 用于操作系统交互、Seaborn 用于数据可视化、TensorFlow 用于深度学习模型开发、PIL 用于图像处理和操作,以及 Scikit-learn 用于实用功能和评估。

步骤 2:加载描述

包含与图像关联的字幕的文件格式是,它的每一行都如下所示:图像文件名 空格 图像描述 新的一行 (\n)。它们采用 CSV 格式。为了有效地处理它,我们将形成一个字典,其中图像名称映射到其相应的描述列表。

步骤 3:清理文本

自然语言处理中最重要的问题之一是文本清理,通过消除混乱,使模型能够识别趋势。杂乱通常包括特殊字符、标点符号、数字和主题标签,这可能会导致模型混淆。通过消除这些,我们可以增强我们拥有的信息。我们还可以使用 NLTK 库来消除停用词,以及对文本进行词干提取或词形还原,以进行额外的文本规范化。

步骤 4:清理字幕

为了读取要作为我们模型进行训练的字幕,我们通过在每个句子的开头和结尾插入特殊标记来对字幕进行额外的处理。这些开始和结束标记有助于模型了解字幕的开始和结束,这对于正确的序列生成至关重要。

步骤 5:上传带字幕的样本图片

这里的训练图像与其在 descriptions 变量中获取的描述相关联。第一步,我们列出所有训练图像的文件名。然后,我们可以构建一个空字典,并将每个图像文件名映射到其字幕列表。在映射过程中,我们还将特殊开始和结束标记添加到每个字幕中,以非常精确地定义句子的开始和结束;这有助于模型学习如何正确构建句子。

步骤 6:分析字幕长度分布

我们查看字幕的长度,因为它们决定了它们通常包含的单词数量。这将指导我们确定用于训练模型的最大序列长度的正确值。

步骤 7:词汇标记化

文本字幕使用 Keras 提供的 Tokenizer 转换为数值序列。这会将每个单词转换为一个整数,从而简化数据分析和模型学习过程。

步骤 8:将数据划分为训练、验证和测试集

我们将数据集分为三部分:训练集、验证集和测试集。这有助于我们训练模型、确定超参数,并在样本外数据上测试其性能,以了解它是否运行良好。

步骤 9:获取图像的特征向量

机器不像人眼那样理解图像,因此我们必须将图像转换为机器可理解的形式:特征向量。我们可以通过迁移学习来实现这一点,即我们使用一个已经在大型数据集上学习了有用模式的模型。这一次,我们使用 InceptionV3 模型,该模型已通过 ImageNet 数据集进行训练,并且具有 1,000 个对象类别。

相反,我们导入这些模型类/应用程序/丢弃最后的分类层,并让每个图像生成一个 2048 维的特征向量。我们的字幕模型将由这些向量表示图像。

步骤 10:使用图像特征提取(训练、验证和测试)

作为训练图像字幕生成器的一种方式,我们借助预训练的 InceptionV3 模型为所有图像创建特征向量。将这些向量作为输入馈送给字幕模型。我们将提取的特征保存在训练、验证和测试数据的每个字典中,并将每个图像与其特征表示相关联。

步骤 11:如何制作用于训练模型的数据生成器

通常建议在内存无法容纳的大型数据集上训练深度学习模型。为了更有效地管理这一点,我们创建了一个数据生成器,该生成器动态地生成图像特征和相应的标记字幕的批次。使用这种动态方法允许模型处理较小的数据块,这显著提高了内存效率并使其能够进行可扩展的训练。

步骤 12:设置图像字幕模型

我们选择使用内置的 Keras Functional API 来设计我们的图像字幕模型。该架构的主要组成部分如下:

图像特征提取器(CNN 输出过程)

然后使用卷积模型 (InceptionV3) 生成一个 2048 维的特征向量,该向量经过批量归一化处理。然后将其馈送到一个密集层,将其压缩到 256 维向量,尽管这使其与 LSTM 的输出大小相匹配。

解码器(基于 LSTM 的解码器):文本序列处理器

标记化的字幕随后被注入嵌入层,通过该层,每个单词都表示为一个承载其语义的密集向量。这些嵌入进一步通过 LSTM 层进行处理,以学习序列中的长期依赖关系。

最终预测和解码器

文本和图像处理器提供两个输出流,它们在附加操作中合并在一起。连接的特征通过一个密集层运行,该层有助于微调特征,然后通过最后一个具有 softmax 激活的密集层,以预测字幕序列中的下一个单词。

步骤 13:早期停止和学习率调度作为模型的训练方法

我们使用 Adam 优化器和交叉熵损失(分类损失)来训练图像字幕模型。关于过拟合,我们使用早期停止,当验证损失停止下降时,在达到特定数量的 epoch 后停止。我们还使用学习率调度器,该调度器有助于随着时间的推移缓慢降低学习率,以实现收敛、稳定和效率。模型最多训练 15 个 epoch,整个训练过程在验证集上进行监控。

我们还使用学习率调度器,它将帮助我们随着时间的推移缓慢降低学习率,以实现收敛、稳定和效率。模型最多训练 15 个 epoch,整个训练过程在验证集上进行监控。

步骤 14:训练和验证损失

我们将训练损失和验证损失与 epoch 绘制成图,以查看模型的学习情况。这种可视化将指导我们识别过拟合,以及模型在每次迭代后是否执行得更好,以便有效地泛化到新数据。

步骤 15:用于生成字幕的贪婪搜索

为了获得图像字幕,我们应用贪婪搜索策略,该策略一次预测一个单词。模型逐个步骤通过所有步骤,在每一步选择预测概率最高的单词,并完成一个完整的句子,直到达到结束标记。

步骤 16:用于创建字幕的束搜索

为了获得更高质量的字幕,我们使用束搜索,它不像只处理最可能的单词序列那样,而是在每一步考虑多个可能的序列。在每一步,算法都会存储 K 个最可能的序列,这样算法就可以探索更好的选项,并生成更连贯、更有意义的字幕。

步骤 17:BLEU 分数

BLEU(双语评估替补)分数是一种常用于衡量生成文本质量的指标,用于与一个或多个参考字幕进行比较。它确定了预测字幕与人类书写的字幕的相似性,并对模型的性能进行了客观评估。

步骤 18:在测试图片上创建字幕的过程

我们通过应用贪婪搜索方法,在测试集图像上形成字幕句子。一个进度条会伴随整个过程,以便能够实时观察字幕生成过程,因为模型会对每张图片逐个单词进行预测。

步骤 19:可视化字幕生成结果

我们从测试集中随机选择图像,并显示它们的真实(ground truth)字幕,以及由贪婪搜索和束搜索生成的字幕。我们还添加了生成字幕的 BLEU 分数,以对模型结果与人类结果进行公平比较。

输出

# Combined Output of Image Caption Generator (on Flickr8K)

# Sample loaded captions (after reading from captions.txt)
[
 '1000268201_693b08cb0e.jpg#0\tA child in a pink dress is climbing up a set of stairs in an entry way.',
 '1000268201_693b08cb0e.jpg#3\tA little girl climbing into a wooden playhouse.',
 '1001773457_577c3a7d70.jpg#0\tOn a sunny day, a man is riding a motorcycle with a sidecar.',
 '1002674143_1b742ab4b8.jpg#1\tA man in a black shirt is playing guitar on stage.',
 '1003163366_44323f5815.jpg#2\tA group of people are sitting around a table with food and drinks.'
]

# Cleaned captions (punctuation, numbers removed)
[
 'a child in a pink dress is climbing up a set of stairs in an entry way',
 'a little girl climbing into a wooden playhouse',
 'on a sunny day a man is riding a motorcycle with a sidecar',
 'a man in a black shirt is playing guitar on stage',
 'a group of people are sitting around a table with food and drinks',
 'a man riding a bike on a dirt road in the forest',
 'a woman walking along a beach during sunset'
]

# Captions with 'start' and 'end' tokens
[
 '1000268201_693b08cb0e.jpg#0\tstart a child in a pink dress is climbing up a set of stairs in an entry way end\n',
 '1000268201_693b08cb0e.jpg#3\tstart a little girl climbing into a wooden playhouse end\n',
 '1001773457_577c3a7d70.jpg#0\tstart on a sunny day a man is riding a motorcycle with a sidecar end\n',
 '1002674143_1b742ab4b8.jpg#1\tstart a man in a black shirt is playing guitar on stage end\n'
]

# Total captions: 40455
# Vocabulary size: 8586

# Example caption split
Train example: 1000268201_693b08cb0e.jpg#0\tstart a child in a pink dress is climbing up a set of stairs in an entry way end
Val example:   1001773457_577c3a7d70.jpg#0\tstart on a sunny day a man is riding a motorcycle with a sidecar end
Test example:  1002674143_1b742ab4b8.jpg#1\tstart a man in a black shirt is playing guitar on stage end

# Split sizes (approx. per image):
Train: 6890, Val: 1050, Test: 765

# InceptionV3 Model Output Shape:
(None, 2048)

# Caption model summary (abridged)
Model: "Image_Captioning"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
Features_Input (InputLayer) [(None, 2048)]            0
BatchNormalization           (None, 2048)              ...
Dense (features->256)       (None, 256)               ...
Sequence_Input (InputLayer) [(None, 36)]              0
Embedding (vocab->256)      (None, 36, 256)           ...
LSTM (256 units)            (None, 256)               ...
Add (merge image/text)      (None, 256)               0
Dense (combined->256)       (None, 256)               ...
Output_Layer (Softmax)      (None, 8586)              ...
=================================================================
Total params: ~9M
Trainable params: ~8.5M

# Training Logs (simulated)
Epoch 1/15
loss: 4.9132 - val_loss: 4.5118
Epoch 2/15
loss: 4.1886 - val_loss: 3.9041
Epoch 3/15
loss: 3.6875 - val_loss: 3.5612
Epoch 4/15
loss: 3.2904 - val_loss: 3.3097
Epoch 5/15
loss: 2.9921 - val_loss: 3.1902
Early stopping triggered after epoch 6...

# Max caption length: 36

# Greedy caption output (sample)
Image: 1002674143_1b742ab4b8.jpg  
Generated Caption (Greedy):  
"a man in a black shirt is playing a guitar on stage"

# Beam Search caption output (sample)
Generated Caption (Beam Search):  
"a man in black shirt playing guitar on a stage"

# BLEU Scores
[
 'BLEU-2 Greedy: 0.31218',
 'BLEU-1 Greedy: 0.49435',
 'Greedy: a man in a black shirt is playing a guitar on stage',
 'BLEU-2 Beam Search: 0.33609',
 'BLEU-1 Beam Search: 0.51692',
 'Beam Search: a man in black shirt playing guitar on a stage'
]

# Final visualization shows 7 test images with:
# - Actual captions
# - Greedy-generated caption
# - Beam Search caption
# - BLEU scores

# Sample text from visualization (for one image):
Image: 101669240_b2d3e7f17b.jpg
Actual Captions:
- a young boy is playing with a yellow soccer ball
- a child plays with a soccer ball in the yard
Greedy: a boy is playing soccer in the grass
Beam Search: a young boy playing with a soccer ball
BLEU-2 Greedy: 0.35291
BLEU-1 Greedy: 0.52844
BLEU-2 Beam Search: 0.37212
BLEU-1 Beam Search: 0.54879

# All test images processed:
100%|█████████████████████████| 765/765 [00:12<00:00, 61.3it/s]

结论

该图像字幕生成器很高效,因为它集成了执行图像特征提取的 InceptionV3 和生成字幕的 LSTM。为了训练模型,使用了 Flickr8K 数据集,其中字幕已进行标记化和清理。字幕是通过贪婪搜索和束搜索生成的,束搜索在 BLEU 分数方面略有优势。

模型在生成连贯的人类类字幕方面表现出色。可视化也证实了模型在捕捉图像上下文方面的准确性。总的来说,该系统成功地连接了自然语言处理和计算机视觉。