原文:基于 Pytorch 的鞋子标签自动标注[译] - AIUAI
原文:Meta Tagging Shoes with Pytorch CNNs
Github - Generating-Tags
涉及的问题是对文本生成描述文本(generating text to describe images).
可行的解决方案有两种:
[1] - 采用 CNNs 进行特征提取,然后将提取的特征送入 LSTM,以生成最终的描述文本.
[2] - 构建 multi-label 分类模型,输出的每个节点(node) 分别对应特定的标签(tag).
第一种方案对于生成具有语法结构(grammatical structure) 的图像描述比较有优势.
第二种方案的多标签分类模型用于对于有限个标签(tags) 的生成与标注. 标签的数量可以足够大,只要有模型训练数据.
由于目的是,只采用图像作为输入,生成鞋子的标签标注,故这里采用 Multi-label 分类模型.
不采用 CNN+LSTM 的原因是,第一,这里不需要 English 等的语法结构(这是 LSTM 的作用);第二,需要更多的手工标注数据.
希望的是,采用预训练的网络模型,以快速构建多标签标注模型.
模型构建的第一个重要步骤是,收集一个小规模数据集,并进行标注,以用于 multi-label 分类.
为此,首先收集了 220 张图片(train-200 / validtation-20),然后在电子表格中进行标注.
标注的标签主要有 19 个,涉及了如颜色(color),风格(style)(如 flat, heel, loafer, sandal 等),及其它鞋子描述(如 tall, short, shiny, pattern).
注:这里给出的类别标注可能不够好,这里只是尝试下对与有降序但数量有限的标签的标注. 如,标签"在 ankle 上" 和 “在 ankle 下”. 这里尝试看网络是否能够只基于图像,而标注出鞋子的高度(how tall).
从技术角度来看,构建自定义的 pytorch dataset generator class 是很好的点.
只需基于 base pytorch dataset class,添加生成样本的函数即可.
这里,只添加了打开图像路径读取图片和对应的目标 labels 的函数. 此时,taget label shi 长度为 19 的向量.
相比于用于 multiclass 分类问题的 MultiLabelSoftMarginLoss(),BCEWithLogitsLoss() 可能更适用. 因为,该损失函数结合了 Sigmoid 层. Sigmoid 层输出概率值(类似于 Softmax),但每个节点(node) 是独立的(不同于 Softmax,各节点是相关的). 这可能有助于清理网络的输出.
在设置数据和损失函数后,准备开始测试网络和超参数. 最直接的是,采用开源的预训练网络模型. 测试的第一个网络是 ResNet50 模型. 在采用 200 张训练图片 fine-tune ResNet50 模型后,发现模型结果比较 terribly.
因为,模型对所有的测试图片都输出了一个 “boot” 标签,某些时候会输出 “black boot”.
基于当前的技术方案,首先想到的是,当前模型表现不佳;一种可能的方案是采用更多计算的模型. 假如 ResNet50 模型可能不能够提取用于该问题的足够有用的特征,故又采用了预训练的 ResNet152 模型.
虽然,ResNet152 比 ResNet50 有 3 倍的网络层,模型更强大,但得到的模型输出了更多的 “boots”. 此时,心情如 Hiro Hamada from Big Hero 6 中的一个截图:
在采用该技术方案失败多次之后,需要开始反思一下,往后退几步,重启思路.
在思考了问题以后,发现,不是模型不能提取有用特征,而是问题的目标空间很可能是对于数据集太稀疏了(too sparse for the size of the dataset).
对于任何给定图片,往往有 3-4 个 tags,target label 数组大部分都是 0. 在长度为 19 个类别中,模型只能够看到频繁出现的一些标签组合,但是对于大部分标签是很少出现的. 在标注的数据集中最普遍的组合是 “black boots”. 这也就解释了所尝试的模型返回 “boots” 和 “black boots” 结果的原因.
对此,换了一个新角度来处理目标问题. 可以将问题分为更小的段(pieces),并看作多个标签生成模型的 ensemble.
相比于直接采用一个大模型一次性预测所有的 19 个类别标签,这里发现,可以采用 3 个小的 ResNet18 模型.
第一个模型对 7 个颜色特征进行训练,black , white , red , blue, tan, grey, brown.
第二个模型对 7 个风格特征进行训练,boot, heel, sneaker, sandal, flat, studded, loafer.
第三个模型对 5 个混合特征进行训练,图案(patterns)(alligator texture, leopard print, weird characters etc), above the ankle, below the ankle, shiny, leather.
将原来长度为 19 的标签向量划分为 7, 7, 5 的三组后,训练了 3 个 ResNet18 模型. 每个 ResNet18 模型在 1080 Nvidia GPU 上训练大概 3 分钟,25 个 epochs.
为了生成以上图中的 Tags,需要对图片分别送入三个 ResNet18 模型,并评估模型的输出向量.
最后,将向量数组映射到对应的类别标签,并观察哪个类别标签的值是 positive,如果全部的值都是 negative 值,则保留最大值的类别标签.
对于三个模型,每张图片预测速度是 0.43s,因此在整个 220 张图片数据集上大概耗时 9.5s. 由于包含了两个 loops 循环,导致相对较慢. 对此,只在代码里都采用一个 loop 循环,每张图片能够提高 0.025s,总共耗时为 5.7s.
以这样的速度,对于大规模的数据集,如 10 million,大概耗时 69.4 h.
给定小规模的训练数据集,且有意的选择了大部分为白色背景的图片. 因此,对于非白色背景的图片,模型效果不好. 如图.
该例中,可以认为模型预测还算合适,但不应该预测出 Loafer,至少其被标注为类似的 boots 标签.
下面这个例子中,模型无法解释由于肤色区域所引起的额外变化. 可以认为模型预测的标签都不太正确. 图片中 ankle 以上的区域是非 black 的.
对于这种场景,语义分割方法可能会有用. 首先采用分割模型清理输入图片,然后在采用 ResNet18 模型生成标签,可能减少正确分类的麻烦.
虽然这里并未介绍如何生成大量的标签(HUGE Number of Tags),但基于这样少量数据的方案,可以扩展到相对多数量标签的场景.
当目标场景更复杂时,这里的网络模型可能不够使用,且更难构建. 但,如果是采用这里的技术方案,意味着必须调用大量的网络模型,来生成相对较少分组的类别标签,然后在将所有分段类别标签组合,以得到完整的鞋子 tags 标签列表. 如果输入图片总是发生变化,则训练多个模型可能是更麻烦的事.
在大规模数据的场景中,采用单个长的目标向量,训练更大的网络模型生成自动标注标签可能是可行的.
只要模型能够学习到足够多的样本,targets 的稀疏问题可能就不再是问题. 这还有待验证.
采用大模型的一个缺点在于,如果新增了类别标签,则必须要重新训练大模型,或者可以添加额外的小模型来辅助增强.