通过 resnet 实现对色情图片&性感图片的识别(代码/调优/数据)
Posted 我爱大猫咪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过 resnet 实现对色情图片&性感图片的识别(代码/调优/数据)相关的知识,希望对你有一定的参考价值。
零:代码
https://github.com/yangbisheng2009/nsfw-resnet (绝对良心代码,欢迎 star)
一、背景
线上海量图片,需要将其中性感图片、色情图片识别出来
比如:
二、调研
在经过一些列调研之后,确定了以下几种方案:
- 机器学习方法,利用p_hash或者图片hog特征或者傅里叶变化、小波变换抽取图片向量特征,采用传统机器学习的方法直接有监督分类
- 直接采用卷积神经网络方法,如 resnet、inception 等方法做有监督分类。或者对于我这种初学者来讲,不用深层卷积神经网络,直接采用 卷积层 + 池化 + 全连接 的基础神经网络结构。
列举了上述两种方法,经过调研大牛们的实现,决定不走弯路,直接上inception、resnet方法。并且最终确定了resnet101 + pytorch的组合(当然了,其它的实现,也有亲自试验,后面会讲到)
三、resnet原理
resnet就是一个做了一些小技巧的多层卷积神经网络,如果对基本的 卷积层-池化层-全连接层 结构不太了解,建议你可以先学习一下基础。我这里会对resnet原理一笔带过,因为网络上也有大批文章做介绍。
前提:深层网络对图片的分类效果好(实践证明,业界公认,尚无理论支撑)
问题:深层网络无法避免的梯度消失问题,导致深层神经网络模型可能效果还不如浅层效果
现在问题梳理清楚了,也就是只要我们能够解决梯度消失问题,那么就可以畅快的使用深层神经网络了。解决这个问题,就用到了残差。
假设现有一个比较浅的网络(Shallow Net)已达到了饱和的准确率,这时在它后面再加上几个恒等映射层(Identity mapping,也即y=x,输出等于输入),这样就增加了网络的深度,并且起码误差不会增加,也即更深的网络不应该带来训练集上误差的上升。通过“shortcut connections(捷径连接)”的方式,直接把输入x传到输出作为初始结果,输出结果为H(x)=F(x)+x,当F(x)=0时,那么H(x)=x,也就是上面所提到的恒等映射。于是,ResNet相当于将学习目标改变了,不再是学习一个完整的输出,而是目标值H(X)和x的差值,也就是所谓的残差F(x) = H(x)-x,因此,后面的训练目标就是要将残差结果逼近于0,使到随着网络加深,准确率不下降。
也就是说,即使我并不知道多少层是最佳,我通过残差模块,即使已经错过最佳深度我至少模型的精度不会有影响。起初看到这种网络模型很是奇怪,如果是一个浅层网络就能达到饱和,那么后面的残差结构目标是学习一个恒等映射,那么学习目标为F(x)接近为0。既然这样,为什么要去学习这个映射?直接写个恒等函数,或者直接设置F(x)=0 输出为x不就行了?残差网络的目的是学到y=x恒等映射函数,那么不就相当于加上的残差网络在最后没起到作用吗?那么为什么会有效呢?
首先这个饱和的浅层网络本身就不好寻找,有可能在达到饱和浅层网络深度之前,由于误差的原因模型精度已经下降。那么为什么持续增加层,让模型学习一个恒等映射就会使得模型表达变好呢?
假设:如果不使用残差网络结构,这一层的输出F'(5)=5.1 期望输出 H(5)=5 ,如果想要学习H函数,使得F'(5)=H(5)=5,这个变化率较低,学习起来是比较困难的。但是如果设计为H(5)=F(5)+5=5.1,进行一种拆分,使得F(5)=0.1,那么学习目标是不是变为F(5)=0,一个映射函数学习使得它输出由0.1变为0,这个是比较简单的。也就是说引入残差后的映射对输出变化更敏感了。
进一步理解:如果F'(5)=5.1 ,现在继续训练模型,使得映射函数F'(5)=5。(5.1-5)/5.1=2%,也许你脑中已经闪现把学习率从0.01设置为0.0000001。浅层还好用,深层的话可能就不太好使了。如果设计为残差结构呢?5.1变化为5,也就是F(5)=0.1变化为F(5)=0.这个变化率增加了100%。引入残差后映射对输出变化变的更加敏感了,这也就是为什么ResNet虽然层数很多但是收敛速度也不会低的原因。明显后者输出变化对权重的调整作用更大,所以效果更好。残差的思想都是去掉相同的主体部分,从而突出微小的变化,看到残差网络我第一反应就是差分放大器。这也就是当网络模型我们已经设计到一定的深度,出现了精准度下降,如果使用残差结构就会很容易的调节到一个更好的效果,即使你不知道此刻的深度是不是最佳,但是起码准确度不会下降。代码实现也比较简单,原本的输出结果由F(x)替换为输出F(x)+X,如果维度相同则直接相加,如果维度不同则利用1*1的卷积核变换。当然残差网络还有很多细节, 比如使用预batch normalize ,ResNet-v1 由relu非线性变换,替换为ResNet-v2恒等变换。
四、具体实现
这是我的代码库,里面有完整的代码实现:https://github.com/yangbisheng2009/nsfw-resnet
强烈建议大家使用pytorch来做图像相关的处理呦,性能高、灵活。
我采用加载预训练好的resnet101模型,通过样本数据,做全局finetune(后续你们也可以尝试局部finetune,只把微调深层网络参数)。
数据来源:
好心人提供的开源数据,给个赞:https://github.com/alexkimxyz/nsfw_data_scraper
数据标签:
porn
- 色情hentai
- 动漫色情、图画sexy
- 性感neutral
- 普通drawings
- 普通动漫、图画
一些能够提升准召的tips:
- 尽可能调大batch_size,我在我的P40机器上,设置了512
- 我最终选用了resnet101 pretrained model,它在诸多的方案中,表现最好
- 在整体finetune后,可以lock模型前面的N层,重新finetune一次。为什么这么做能带来更好的效果,我想你们都懂的
- 根据你的数据集、模型选择等因素,动态调整你的learning rate
- 我采用了很多数据增强的方法,如颜色变换、高斯噪声点、旋转、平移、剪切、色调对比度变换。但是结果发现这些方法,并没有太大的卵用(针对这个工程而言),最终只保留一小部分
效果:
五、和其它模型的对比
我尝试了resnet101、resnet50、inceptionv3、手写单层cnn 等三种方法。
resnet101效果最好,但是稍微比resnet50慢一点。但是可以接受
手写单层cnn稍后会把代码放出来,非常有助于大家对图片分类的理解
欢迎留言提问 或者 邮箱联系我: yangbisheng2009@gmail.com
以上是关于通过 resnet 实现对色情图片&性感图片的识别(代码/调优/数据)的主要内容,如果未能解决你的问题,请参考以下文章
浙大&川大提出脉冲版ResNet:继承ResNet优势,实现当前最佳