深度学习:摩尔纹识别(翻拍检测)

今年暑假开始在实习公司差不多从零基础学习深度学习,接到的第一个任务是CV的图像分类任务:翻拍检测。本文的目的是留档这次任务的一些思路以及tricks。

翻拍(recapture):用户拍摄其他用户上传的图片,进行二次上传

翻拍检测:检测某目标图片是否是翻拍图片。

切入点:摩尔纹

网上与摩尔纹相关的深度学习方面的工作主要在摩尔纹去除(去噪)方面,在摩尔纹检测这个领域,相关的工作都是17年左右的了,而且多数使用的是传统特征提取+机器学习去做的。

网络方面,我一开始的打算是,直接把图片扔到efficientnet或者resnet之类的网络里面,最后接一个二分类FC,通过softmax得到概率值。

数据集方面,我一开始是自己利用拍摄设备对着电脑录像,然后对原视频和翻拍视频采取抽帧的方法分别生成翻拍图片和真实图片,一共做了大约2k多张。后来在这个数据上跑过模型后,感觉这种自制的数据集质量不高(如果刚好在视频中物体移动的时候抽帧,画面会模糊),于是在网上找了一些摩尔纹去除相关的公开数据集。由于没有和摩尔纹相关的权威数据集,我使用的是AIM比赛和几篇paper作者自制的数据集。

目标:训练一个泛化能力尽可能强的神经网络,可以在不同数据集上都有不错的表现。

第一次尝试

我一开始以为这个任务就是一个简单的分类任务。直接把图片扔到resnet18里训练。事实证明resnet确实可以很快在某个数据集上将训练集、验证集、测试集都fit到接近100%。但是一换数据集,模型的表现就变得非常差,这与我一开始的目标相去甚远。

我认为网络并没有学到我想让它学到的东西。因为摩尔纹属于噪声数据,噪声数据的分布、位置都有极大的不确定性。resnet18虽然在现在看来不算是大模型,但是凭暴力fit一个不大的二分类训练集(一两万张)我认为不是难事。从最大似然MLE的角度来解释,我认为resnet18只是暴力靠上亿个参数fit了单个数据集的概率分布,没有”学习”到摩尔纹这一特征。

第二次尝试

在arxiv上找到一篇paper,使用了MCNN

IEEE SSCI-2018 publication https://ieeexplore.ieee.org/document/8628746

这里解释下作者的思路。首先要知道摩尔纹属于高维信息,所以Haar得到的三个高频信息特征图cH、cD、cV相当于做了一个高频信息的特征提取;然后摩尔纹强度和颜色有着很大关系,作者发现越亮的地方摩尔纹越明显,黑色的地方甚至看不到摩尔纹,于是作者希望cA的CNN可以从原图提取到颜色权重特征,与cH、cD、cV高频信息的CNN提取结果相乘。

最后MCNN能在训练集上fit到一个不错的结果,在其它几个数据集上表现也不错(自制数据集accuracy82+ 某论文数据集accuracy96+)本以为完事了,后来leader在coco2017上尝试了一下(即全都是真图),accuracy直接掉到30%……

这下我也懵逼了,不知道MCNN到底学到了个啥东西

PS: 该MCNN性能很不稳定,增加或删除BN层对性能的影响都特别大,所以我认为这版MCNN问题还是不小的。但是它在那两个测试集数据集上又拟合得不错……感叹一句,深度学习真的好炼丹啊

暑假只实习了两个月不到,MCNN的第二次尝试差不多是在实习最后几天卡着点弄完的。开学后偶尔还会考虑到这个问题(老牛角尖怪了),最近又有了新的思路。

其实很简单。传统对图像分类中噪声的解决方案一般是去噪,因为网络大部分情况需要提取的是图片的主体内容。摩尔纹属于噪声,除非有海量数据集,不然网络不容易学到我们想让它学到的东西。那既然如此,我们就学习原图和去噪后图片之间的差异不就好了吗?

解决方案:
先训练一个去噪网络,然后用(原图-去噪结果)作为输入,训练二分类网络。去噪网络希望减小信噪比,分类网络希望学习到去噪前后的差异,两者应该是可以互相促进的(GAN思想)。

为了节省时间(懒),我就使用中值滤波去噪代替去噪网络去噪了,把(原图-去噪结果)输入resnet18,得到二分类结果。最后测试,自制数据集accuracy65+ 某论文数据集accuracy95+ coco2017数据集accuracy90+。

在自制数据集上,非翻拍图片的精度低,召回高;翻拍图片的精度高,召回低。(换言之,模型更倾向于判断目标为正例)

该模型经过softmax后,输出被认为是有意义的(即概率),这点体现在后处理时通过调高模型结果softmax后的真图阈值,FN上升,FP下降,总体accuracy上升。在自制数据集上,真图阈值为0.9时,accuracy可达73+

之前的试验结果表明,如果某模型后处理调整阈值时FN FP没有一升一降,则可以认为这锅丹是炼得有问题的,即经过softmax后,输出的logits值被认为是没有意义的。

举个栗子,目前某模型容易判断目标为正例(负例召回太低)。TP为999,TN为1,FP为999,FN为1。

999个FP,结果都是输出假图概率为0.2真图概率为0.8;999个TP,输出假图概率为0.4真图为0.6。

可以看到FN太小,FP太大。我们调整真图阈值,从0.5到0.7,希望判断正确的负例(TN)多一些,判断正确的正例(TP)少一些。相对应的,FN多一些,FP少一些。且,TN增加的要比TP变少的多,这样总体f1、acc就能增加。

然后看上面的例子,FP没有变化,TP反倒从本来判别正确全部变成FP判别错误了,结果变成TP:0,TN:1, FP:999, FN:1000。

好嘛,现在就对一个了。

optimizer+scheduler:

Adam+CosineAnnWarm
看科大讯飞2021比赛,大伙都用的Adam和余弦退火组合。Adam,AdamW,cosineAnn,cosineAnnWarm自由组合,差别应该不大

Soft Label

为提高泛化能力(加之我对数据集的质量也不是很有信心),使用Soft Label交叉熵,soft值为0.02。(感觉大部分人取0.05左右,最终差别应该不大)
代码挺好写的,重写下Cross Entrophy就可以了。有时间我把代码模板贴上来。

Blur

img_mask = cv2.medianBlur(img, 5)
img = transforms.ToTensor()(img.astype(numpy.float32)/255-img_mask.astype(numpy.float32)/255)

这里使用大小为5*5的中值滤波,因为对比了高斯滤波和中值滤波结果的Haar高频特征图,从肉眼来看均值滤波对摩尔纹处理得比较干净。
有个细节,img默认是numpy.uint8,不能随意作减法(无符号0-255数),它的加法是对255取模,减法有一套奇怪的逻辑我还没摸清(计组那个符号数1、0什么的,懒得细究),作减法时要转为numpy.float32。

这里的优化空间较大,可以使用深度学习网络代替中值滤波。

Augmentation

RandomGridShuffle(grid=(4,4),p=p)
不写grid是默认不会GridShuffle哈。这个加强还蛮适合摩尔纹检测的,因为摩尔纹噪声的分布不是均匀的且可能出现在图片任意位置。

transforms

transform_train = transforms.Compose([
        transforms.ColorJitter(brightness=0.1),
        transforms.RandomHorizontalFlip(),
        transforms.RandomVerticalFlip(),
        transforms.RandomAffine(10),
    ])

没有用随机裁剪之类的,因为可能把摩尔纹部分给剪掉;椒盐噪声是个不错的选择,有时间可以尝试一下。

Test Time Augmentation
一般比赛里会对测试集做tta以提高结果的鲁棒性。但这里我对验证集做了一次tta,结果取验证集原图和数据增强后的加权和。这么做的原因依旧是因为我们想要网络可以分辨随机出现的摩尔纹特征,使网络在遇到最好accuracy时,可以保存一个鲁棒、准确的参数集合。

Post Processing
对新数据集,模型可能没有见过这种分布,后处理改变判P或者判N的阈值至FP与FN大致一样,能有效提高精度。

翻拍检测算是把我领进DL大门的新手任务吧,地位堪比网游里的送信任务。

整个流程走下来,搜查资料、处理数据、复现论文、模型原理……学到了很多的同时,这个过程本身也带给我了新的思考问题的方法与角度。

看似简单的二分类问题,如果执着于换各种fancy的网络用各种tricky数据处理,直接对原图提取特征,可能会卡得动弹不得;但如果换种思路,把鲜有前人踏足的原任务分解成比较成熟领域的子任务,去学习原图和去噪结果之间的差异,或许会柳暗花明又一村。

说到底,看待问题的角度以及数据本身才是深度学习里最重要的东西。

Original: https://blog.csdn.net/weixin_45590789/article/details/121888191
Author: Hikers、Wan
Title: 深度学习:摩尔纹识别(翻拍检测)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/532433/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球