Tagged: 惊悚内容识别

3,163  0

[鹅厂] 惊悚图像分类日志

警告:本文可能出现部分惊悚内容导致不适! 前言 有幸来到鹅厂学习,接手了惊悚图片分类的问题。这问题一听就很惊悚,事实上也很惊悚,每次打开数据集前我都要做一下心理建设。数据量很大,有标注的惊悚数据4w,正常数据6w;数据花样很多,囊括了形形色色的网图,从大字报到游戏场景,从屠宰场到显微镜下,就看我能不能玩出点花样了。 要求 目标:二分类,只需要标记出惊悚图片即可精度:准确率>80% 召回率>95% 难度 标注不正确,这是人工标注都存在的问题,理论上比较好的情况下能达到95%的准确率。 标注不全,惊悚图片可能同时具有多个惊悚属性,但仅有一个分类标注,例如手术场景,有器官、有血腥、甚至像虫子蠕动(此类图太扎眼,就不放了) 某些惊悚概念难以实际描述且不存在实体,如果说下图让人感到害怕是因为红色的眼睛和嘴,那为何红眼睛的兔子就可爱捏 某些令人毛骨悚然的东西藏在图片一角,占比很小 图片太丰富,若上线后每天有30T的图片,与训练数据必然有不同分布,那么该如何保证效果? 日志 第一阶段:初探标注情况 随意选择了Resnet50作为主体网络,看中的是强大的表达能力和较少的参数标注将惊悚图片分为20个子类,直接训练得到效果:验证集正确率Accuracy=0.53,各类正确率分布在0.15-0.56之间。观察到一个有意思的现象是A类较多(>0.2)识别为B类,B类较多识别为C类,但C较少(<0.05)识别为B,B也较少识别为A。根据此结果,粗暴的将子类合并为5个超类(血腥、怪兽、器官、密集、其它),又为了平衡类样本数量,拆分部分超类,最终得到10类,直接训练结果:验证集Accuracy=0.589,各类正确率分布在0.39-0.76之间。 第二阶段:初探分类情况-baseline 继续使用Resnet50作为主体网络,使用11类,新增的一类为正常图片。制作训练集,使得每个Batch内有一半为正常图片,另一半为均匀分布的10类惊悚图片,每个epoch中图片少的类会重复训练多次。制作验证集,从惊悚类别中按0.3的比例截取图片,从正常图片中取6000张,数量分布如下图。制作测试集,将后续新增的标注制作为测试集,因此与训练集和验证集的分布略有不同。使用softmax进行多分类,验证集p=0.61观察到在lr=0.001时网络前两个batch的loss数量级大于亿,很可能破坏了Resnet50预训练网络的参数,修改到lr=0.0003时,loss数量级为十,同时最终Accuracy=0.65,此时训练集p=1,loss已小于e-5。因此将此作为第二阶段的baseline,在测试集结果Accuracy=0.574。验证集混淆矩阵如下图,此矩阵按行表示识别为某类的比例: 支线1 考虑到每张图片可能同时属于多个惊悚类别,同时惊悚图片和正常图片是仅是二分类问题,所以这并不是一个多分类问题,修改 softmax 为 sigmod(lr=0.001),Accuracy=0.615,目前效果不明显。 支线2 为了实现每个Batch的类比例相同,采用了直接生成文件,指导每个batch应读取的图片,没有进行动态乱序,因此在第二个epoch后不同图片并没有重新组合,理论上会导致BN层失效。因此加入乱序,继续训练,由于train loss已趋近于0,乱序后并没有增加loss,因此无效果。 主线[task7] 样本增强 由于训练集已经学不到信息,对训练集进行样本增强,增加左右镜像和随机30度旋转,训练集loss<e-3,验证集Accuracy=0.695,混淆矩阵如下: 主线[task8] 聚类 从任务7中可以发现部分类别(含人血腥和非人血腥等)之间难以区分,因此将其聚类。去除样本数量少的分类(显微镜、排泄物),剩余分类聚为5类(惊悚造型、血腥、病态|组织器官、密集虫子|蛙|蛇、正常图片)。重新制作数据集如下图所示:训练集,共32396张图片,前16198张图片为按顺序放入的4类惊悚图片,后16198张图片为正常图片。训练时从前后各取batch_size/2张图片,进行一次乱序然后送入网络。每训练一个epoch后,将前后两部分图片分别乱序再组合。验证集,从惊悚类别中按0.3的比例截取图片。测试集,将后续新增的标注制作为测试集,因此与训练集和验证集的分布略有不同。 对训练集进行左右镜像和随机30度旋转的样本增强,验证集Accuracy=0.693,与11类并无明显变化。从混淆矩阵来看,惊悚类别之间的识别错误降低至0.1以下,大部分的错误来自于惊悚类别与正常图片之间的混乱,推测是因为类别数量变少,使得我们想要的惊悚类别与正常图片识别错误的损失减小了。 支线3 使用双GPU训练,第一块GPU负责Batch的前一半,即所有的惊悚图片,第二块GPU负责Batch的后一半,即所有的正常图片。因此对于第一块GPU使用sigmoid,第二块GPU使用softmax。因网络倾向于将所有图片归为正常图片类,失败。 主线 [task11] 修改损失函数 为了强化惊悚类图片和正常图片之间的区分度,重新定义损失函数令 loss = sigmoid(五类) + 2*softmax(惊悚类和正常类),即从 loss = tf.nn.softmax_cross_entropy_with_logits(labels = labels, logits = logits) 修改为 loss1 = tf.nn.sigmoid_cross_entropy_with_logits(labels = labels, logits = logits) label_ = tf.concat([tf.reshape(tf.reduce_sum(labels[:,0:-1], axis=1),(-1,1)),labels[:,-1:]],axis=1) logit_ = tf.concat([tf.reshape(tf.reduce_sum(logits[:,0:-1], axis=1),(-1,1)),logits[:,-1:]],axis=1) loss2 = 2 * tf.nn.softmax_cross_entropy_with_logits(labels = label_, logits = logit_) loss = tf.reduce_mean(loss1)+tf.reduce_sum(loss2) 训练100轮中在44轮达到最好效果,验证集Accuracy=0.772,测试集Accuracy=0.754,验证集混淆矩阵如下:从混淆矩阵可以看出惊悚图片和正常图片的区分度已经很高,剩下的应该是一些困难样本的问题了。将此作为第三阶段的baseline,计算二分类下的指标(惊悚图片为正,正常图片为负)验证集精确率 Precision=0.89,召回率 recall=0.974,测试集精确率 Precision=0.897,召回率 recall=0.946。附一张训练轮数与准确度的图片: 支线4 focal loss 为了使用到大量的正常照片,向训练集中加入4万张正常图片样本,修改每个batch中正常图片和惊悚图片比例为4:1,同时为了防止样本过于不均衡,使用focal loss进一步优化损失函数。验证集Accuracy<0.76,失败。 模型分析 浏览了一遍分类错误的图片,发现主要问题有以下几点: 忽略了小目标,例如图片小部分区域有惊悚内容 [改进网络结构] 需要先验知识,例如血迹正好被遮挡的车祸现场 [放弃] 抽象行为,例如动漫中杀了人的暗示(邪典动画) [放弃] 样本数量不足(雀斑与水泡、各种虫子特写)...