0%

电影海报标签生成

基于电影海报图像的影片标签生成任务

付碧波 王仲煜

源代码:https://paste.ubuntu.com/p/RPdTG3yZJk/

任务分析

zidan

电影类型可分为动作、喜剧、恐怖、冒险、爱情、警匪、科幻、战争、灾难、悬疑、西部等等

所以,根据电影海报生成标签,是一个多标签图像分类问题

环境配置

2021 06 20 16 54 51

tensorflow_gpu 2.0

Keras 2.3.1

tensorflow-hub 0.6.0

加载和处理数据集

读取csv文件(MovieGenre.csv)

2021 06 19 18 39 30

2021 06 19 18 38 09

下载图片(数据集)

2021 06 19 18 42 46

download_parallel函数定义在utils.py中

持久化

2021 06 19 18 43 03

标签频率可视化

2021 06 19 18 49 41

222

清除低频标签

并非所有电影流派都以相同数量表示。其中一些可能很少出现。忽略少于1000个观察值的所有标签(简短,西方,音乐,体育)。这意味着由于缺少对这些标签的观察,因此不会训练该模型预测这些标签。

2021 06 19 18 52 58

搭建模型

2021 06 19 20 14 06

划分数据集

将建模数据拆分为训练和验证在机器学习实践中很常见。 将分配 80% 的图像用于训练,20% 用于验证。

2021 06 19 20 27 35

y二值化

我们需要目标是一个字符串列表,以适合二值化器(多热编码)。

2021 06 19 20 30 49

一些案例

2

label encoding

最初的目标是人类可以轻松理解的字符串列表。但是,如果我们要构建和训练神经网络,我们需要创建二进制标签(多热编码)。
这对于多标签分类至关重要。为了二值化我们的标签,我们将使用 scikit-learn 的 MultiLabelBinarizer。

2021 06 19 20 38 58

2021 06 19 20 40 35

建立快速输入管道

首先需要编写一些函数来解析图像文件并生成一个表示特征的张量和一个表示标签的张量。在这个函数中,可以调整图像的大小以适应模型期望的输入。还可以对像素值进行归一化 介于 0 和 1 之间。这是有助于加速训练收敛的常见做法。如果我们将每个像素视为一个特征,我们希望这些特征具有相似的范围,以便梯度不会超出 并且我们只需要一个全局学习率乘数。

2021 06 20 11 56 36

要在数据集上训练模型,希望数据为:

  • Well shuffled,使数据满足独立同分布
  • Batched 分批
  • Batches to be available as soon as possible.,批量尽快供货。

2021 06 20 12 05 02

AUTOTUNE 动态适配预处理和预取

创建一个为 TensorFlow 生成训练和验证数据集的函数。

2021 06 20 14 34 38

每个批次将是一对数组(一个保存特征,另一个保存标签)。
特征数组的形状为 (BATCH_SIZE, IMG_SIZE, IMG_SIZE, CHANNELS)。
标签数组的形状为 (BATCH_SIZE, N_LABELS),其中 N_LABELS 是标签的最大数量。
让我们通过分析第一批来验证这些数组的形状:

2021 06 20 14 38 07

Model Building

TF.hub

一个模型仓库,在这里你可以获取到任何你想要的模型,并且用它来做transfer learning;准确来说,tensorflow hub是一个包,包含了一些下载的操作,直接帮你把模型搞下来。

使用TF.Hub迁移学习

我们将在称为迁移学习的过程中使用预训练模型,而不是从头开始构建和训练新模型。大多数用于视觉应用的预训练模型都是在ImageNet 上训练的,ImageNet 是一个拥有超过 1400 万个图像的大型图像数据库 图像分为 2 万多个类别。 迁移学习背后的想法是,由于这些模型是在大型和一般分类任务的背景下训练的,因此可以通过提取和迁移先前学习的有意义的特征来处理更具体的任务。 我们需要做的就是获取一个预先训练好的模型,并在其上简单地添加一个新的分类器。 新的分类头将从头开始训练,以便我们将目标重新用于我们的多标签分类任务。

来自tfhub.dev的任何与Tensorflow 2兼容的图像特征矢量URL都可能对数据集很有趣。唯一的条件是确保准备的数据集中图像特征的形状与要重用的模型的预期输入形状相匹配。

首先,准备特征提取器。将使用MobileNet V2的预训练实例,其深度乘数为1.0,输入大小为224x224。实际上,MobileNet V2是一大类神经网络体系结构,其主要目的是加快设备上的推理速度。它们的大小不同,具体取决于深度乘数(隐藏的卷积层中的要素数量)和输入图像的大小。

2021 06 20 14 45 34

特征提取器接受形状为 (224, 224, 3) 的图像并为每个图像返回一个 1280 长度的向量。

我们应该冻结特征提取层中的变量,以便训练只修改新的分类层。
通常,在处理与特征提取器训练的原始数据集相比非常小的数据集时,这是一个很好的做法。

2021 06 20 14 48 00

Sequential

现在,可以将特征提取器层包装在tf.keras.Sequential模型中,并在顶部添加新层。

2021 06 20 14 52 00

需要在最终的神经元中应用S型激活函数,以计算出每种流派的概率得分。这样就可以依靠多个逻辑回归在同一模型中同时进行训练。每个最终神经元将充当一个单一类别的单独的二进制分类器,即使提取的特征对于所有最终神经元而言都是相同的。

使用此模型生成预测时,应该期望每个流派都有一个独立的概率得分,并且所有概率得分不一定总和为1。这与在多类分类中使用softmax层(其中概率得分的总和)不同。输出等于1。

2021 06 20 14 58 31

训练模型

损失函数

在前面的步骤中,我们准备了数据集并通过在预训练网络(无输出)之上附加多标签神经网络分类器来构建模型。我们现在可以继续训练我们的模型,但我们需要定义两个主要功能:

损失函数:我们需要它来测量训练批次的模型误差(成本)。它必须是可微的,以便反向传播神经网络中的误差并更新权重。

评估函数:它应该代表我们真正关心的最终评估指标。与损失函数不同,它必须更直观地了解模型在现实世界中的表现。
这个笔记本的目的不仅是分享多标签分类的一般设计,而且是研究定制损失函数的选择以直接优化我们关心的评估指标的优势。

F1-score

https://blog.csdn.net/qq_14997473/article/details/82684300

https://zhuanlan.zhihu.com/p/64315175

假设我们需要 F1-score来评估模型在每个标签上的性能。 F1-score是 Precision 和 Recall 的调和平均值。并且,在考虑任何特定标签时,Precision 和 Recall 的计算会考虑TP的数量、FP的数量和 FN 的数量。

confusion matrix

我们计算与标签总数一样多的F1-score ,然后将它们平均以获得我们所说的宏观 F1-score 。如果它们在多标签分类任务中具有相同的重要性,则取所有标签的平均值是合理的。

F1-score 的问题在于它不可微,因此我们不能将其用作损失函数来计算梯度并在训练模型时更新权重。这是因为F1-score 需要测量二元预测 (0/1)。这些二元预测是通过对模型生成的概率分数应用决策阈值来获得的。例如,如果动作的概率高于阈值 0.5,我们可以预测 1(一部电影是关于动作的),否则我们预测 0(没有动作)。

通常我们使用二元交叉熵损失表示特定类别的观测值的负对数似然 -log(p),模型预测该类别的概率 p。一般来说,这种损失效果很好,并被广泛用于训练分类器,但它并不直接与我们想要最大化的 F1-score 相关联和对齐。

我们可以做的是修改 F1-score 以使其可微。我们可以通过使用概率而不应用任何阈值,将真阳性、假阳性、假阴性的数量计算为离散整数值,而不是将它们计算为似然值的连续总和。

我们将这个版本的 F1-score 称为 soft-F1-score。 下面,您可以看到在 TensorFlow 中的一批预测中实现它的代码。

这里有一些事情需要考虑:

每个标签的成本实际上是 1 - 该标签的 soft-F1。 如果我们想最大化 soft-F1,我们应该最小化 1 - soft-F1。
可以替换soft-F1定义中的Precision和Recall,得到更直接的基于TP、FP和FN的公式。 您要这样做的原因是因为当 TP = 0 时 F1 的调和平均表达式未定义,但已定义翻译表达式。 F1 = 2.TP / (2.TP + FN + FP)
一批观察的总成本将是所有标签的平均成本。 我们将其称为macro soft-F1 loss。
我们必须确保批量大小足够大,以便在训练时看到具有代表性的macro soft-F1 loss。

2021 06 20 15 22 17

接下来,我们将训练两个具有相同架构但有两个不同损失函数的模型:

第一个将使用macro soft-F1 loss进行训练。
第二个将使用二元交叉熵损失进行训练。
另一方面,我们可能会默认为两个模型考虑一个单一的评估指标:macro F1-score @ threshold 0.5。

2021 06 20 15 24 56

Train with macro soft-F1 loss

2021 06 20 16 10 15

2021 06 20 16 11 16

2021 06 20 16 12 20

2021 06 20 16 12 45

2021 06 20 16 18 10

2021 06 20 16 05 54

下载

Train with binary cross-entropy loss

2021 06 20 16 21 13

2021 06 20 16 21 35

2021 06 20 16 21 53

2021 06 20 16 06 27

3

到目前为止,我们已经训练了两个具有相同架构的神经网络模型。
第一个是直接针对macro F1 分数进行优化,而第二个则更经典,针对二元交叉熵进行了优化。
在这两种情况下,训练的模型在预测电影海报的类型时都会为每个标签生成一个独立的概率分数。
要创建最终决策系统,我们需要为每个标签选择一个介于 0 和 1 之间的决策阈值,以便将每个概率转换为二元信息。 通常系统的性能取决于这些决策阈值的选择。
因此,让我们根据我们为每个标签设置阈值的级别来检查系统在验证集上的行为。

utils 模块中有一个名为 perf_grid 的函数,可以帮助创建性能网格。
在性能网格中,每个标签的阈值以 0.01 的步长从 0 增加到 1。
对于每个阈值和每个标签,我们计算不同的度量(tp、fn、fp、精度、召回率、f1-score)。

2021 06 20 16 27 56

对于每个标签,都有一个阈值可以最大化使用二元交叉熵损失训练的第二个模型的性能。
使用具有 bce 损失的第二个模型时,哪些标签具有最高的最大性能?

2021 06 20 16 29 39

数据集中标签的频率与其实现的性能之间是否存在相关性?

相关性0.99

现在,比较两个不同模型的性能曲线。

10

2021 06 20 16 39 52

使用每个模型可视化标签概率值的直方图。

30

40

当使用二元交叉熵损失训练时,输出的概率分布具有一些高斯特性(注意蓝色直方图的钟形)。实际上,这种优化是从数据的原始分布中学习的。我们可以看到,对于覆盖数据集 50% 的标签“Drama”,概率分布以 0.5 为中心。顺便说一句,为“戏剧”构建的分类器似乎非常弱,因为这两个类似乎没有在概率值上分开。我们还可以注意到,标签越不频繁,分布就越向左移动。例如,“犯罪”的概率分数似乎非常低,而该标签仅覆盖了数据集的 14%。该模型从这种稀有性中学习以预测较低的概率值。另一方面,当使用Macro soft-F1 损失时,我们正在创建一个系统,它不会反映条件概率值的相同幅度。相反,它学会了减少犹豫并生成非常接近 1 或非常接近 0 的预测。我们在中间范围内的概率值较少。因此,在该范围内改变阈值时,性能不会发生太大变化。
使用Macro soft-F1 损失进行优化可以取代一些详尽的技术,例如:

搜索使验证集性能最大化的最佳决策阈值
通过在训练前对少数类进行过采样或对多数类进行欠采样来校准概率值(在多标签分类的情况下非常复杂)

测试

2021 06 20 16 48 10

55

72

74

导出模型

2021 06 20 16 51 37

2021 06 20 16 53 09

2021 06 20 16 53 26

-------------本文结束感谢您的阅读-------------
Your support will be the driving force of my creation