关于SimGAN-Captcha的扩展实验(cnn验证码识别准确率99.5%)

在上一篇《关于验证码cnn识别的一些笔记》中提到,实验环境与真实环境准确率有7%的差距,文中最后希望尝试simgan来实现样本增强,看一下对准确率的提高是否会有帮助。经过这十几天的实验(训练一次太久了),对simgan原理有了更深的了解,SimGAN-Captcha的实验也完全复现,然后对其进行扩展,应用到自己的环境中进行样本增强,本文记录一些实验过程,并得出SimGAN-Captcha在验证码识别应用上的个人浅见,想看结论的可以跳过实验过程,直接看结果。

实验过程按着这样的思路来:

首先复现SimGAN-Captcha过程。然后改灰度图为RGB,通过无标识的真实数据和有标识的模拟数据,训练SimGAN-Captcha,通过训练好的模型,Refine上文提到的50万+1万模拟的训练数据,通过Refined的数据,重新训练验证码识别模型,统计准确率做对比。可是效果并不好,甚至肉眼放大也无法在像素层面上找到差异,可以说模拟的很逼真,也可以说Refine没效果。甚至让人怀疑,SimGAN-Captcha是否工作了。于是用另一套验证码生成器生成完全不相同的验证码,让SimGAN-Captcha在像素层面对新验证码进行强化,用以证明Refine确实是干活了。

经过一个周末的训练,SimGAN-Captcha有了明显的增强效果,举个例子:

为了方便表述,从左到右我们依次叫它们1号、2号、3号、4号。1号是用完全不同的算法X生成的验证码,灰头土脸的。3号、4号是上文提到的目标网站的真实的不同形式的验证码。以算法X生成的类1号验证码为Synthetic数据集,以类似3号、类似4号验证码为real数据集,refine出来的合成验证码为2号。仔细观察2号,已经有了很多3、4号的特征,比如:1、不再灰头土脸,变得鲜艳了,P,K,H色彩对比都比较明显;2、干扰线有了彩色断点,这个特征很好的模拟了类3号样本;3、字母P与E有了类4号的点阵效果,模拟点阵应该是SimGAN的拿手好戏,如果让它把干扰线变扭曲就难为它了。

看来SimGAN的确有效果,它能在像素层面上,把模拟样本尽量向着真实样本的方向改造,不过,即使改造的“像一些”了,好像对准确率的提高也没多大帮助。用谷歌的captcha生成的验证码做Synthetic数据集,目标网站验证码做real数据集,进行训练,然后用这样的模型生成cnn的训练集与测试集,再对目标网站的验证码进行测试,准确率提高不到0.5%。用上面提到的算法X生成的验证码做Synthetic数据集,目标网站验证码做real数据集进行训练,然后用这样的模型生成cnn的训练集与测试集训练cnn,与直接用X算法生成的训练集与测试训练出的cnn模型,在正确率的对比上,只提高0.1%。把上面的过程用语言描述出来,都已经很绕了,实际训练时,尽量安排在晚上或周末,累计在训练上花了4、5百小时,花了这么大的时间成本,取得这么小的进步,确有不值。而当我走了一大圈,回到起点,试着把cnn的训练加强,对它提高要求,不以准确率达到99%为中止条件,要准确率达到200%才停止训练(类似while 1 循环),只用了一顿午饭的时间,准确率就有了2.2%的提升。用同样的600份实验数据做对比,上篇文章中准确率是97.33%,这次提高到99.5%。对于验证码识别来说,在正确的道路上努力训练才是王道,SimGAN并没有那么好的效果。

SimGAN应该是有自己擅长的领域的,验证码增强不行,图像增强会不会效果不错?前文提到的苹果AI首秀的那篇论文,对眼球控制的图像进行样本增强,似乎效果显著啊,我准备来复现一下。

先准备两样东西:

1、https://www.cl.cam.ac.uk/research/rainbow/projects/unityeyes/ 这是一套模拟器,可以生成无数带标签的模拟眼图片。

2、http://datasets.d2.mpi-inf.mpg.de/MPIIGaze/MPIIGaze.tar.gz  这是真实环境下的人眼图片。

然后准备代码,对两份样本进行切割,只保留眼睛部分。上述两套样本都带有标签,里面应该有眼球位置信息,但我不知道怎么利用,也没找到现成的代码方便地根据标签来切图,于是自己写一段,如下:

import cv2
import os
def mkdir(path):
    # 去除首位空格
    path = path.strip ()
    # 去除尾部 \ 符号
    path = path.rstrip ("\\")
    # 判断路径是否存在
    # 存在     True
    # 不存在   False
    isExists = os.path.exists (path)
    # 判断结果
    if not isExists:
        # 如果不存在则创建目录
        # 创建目录操作函数
        os.makedirs (path)
        return True
    else:
        # 如果目录存在则不创建,并提示目录已存在
        return False
# 眼睛
eye_cascade = cv2.CascadeClassifier ('haarcascade_eye.xml')
eye_cascade.load ('D:\\build\\opencv\\opencv-4.0.1\\modules\\objdetect\\src\\haarcascade_eye.xml')

img_dir = 'D:/develop/simGan/synth_eye/'
save_dir= 'D:/develop/simGan/synth_eye_crop/'
# img_name = os.walk(img_dir)  # 列出文件夹下所有的目录与文件
# for i in range(len(img_name)):
i = 0
for root, dirs, files in os.walk(img_dir):
    for name in files:
        if name.endswith (".jpg"):
            i+=1
            img=cv2.imread (os.path.join (root, name))
            # print(os.path.join (root, name))
            gray = cv2.cvtColor (img, cv2.COLOR_BGR2GRAY)
            # 下面三行是真实图片
            # img = cv2.rectangle (img, (0, 0), (1280, 720), (255, 0, 0), 2)
            # roi_gray = gray[0:720, 0:1280]
            # roi_color = img[0:720, 0:1280]
            # 下面三行是模拟器生成
            img = cv2.rectangle (img, (0, 0), (1920, 1080), (255, 0, 0), 2)
            roi_gray = gray[0:1080, 0:1920]
            roi_color = img[0:1080, 0:1920]
            if not i % 10: print("Cut Num is : "+str(i))
            # 眼睛
            eyes = eye_cascade.detectMultiScale (roi_gray, 1.2, 3)
            for (ex, ey, ew, eh) in eyes:
                # cv2.rectangle (roi_color, (ex - int(ew/5) , ey), (ex + ew + int(ew/5), ey + eh), (0, 255, 0), 2)
                # 真实图片 截取位置h在60-80之间且w在70-90之间才截取
                # if eh>60 and eh<80 and  ew + int(ew/5)*2>70 and ew + int(ew/5)*2<90:
                #     cropImg = img[ey:ey + eh,ex - int(ew/5):ex + ew + int(ew/5) ]
                #     cropImg = cv2.resize (cropImg, (75, 60), interpolation=cv2.INTER_CUBIC)
                #     mkdir(save_dir+name.split('.')[0])
                #     cv2.imwrite (save_dir+name.split('.')[0]+'/crop_'+str(ex)+'_'+str(eh)+'_'+str(ew + int(ew/5)*2)+'_'+str(i)+'.jpg', cropImg)
                # 模拟图片 截取位置
                if eh > 400 and eh < 600 and ew + int (ew / 5) * 2 > 600 and ew + int (ew / 5) * 2 < 850:
                    cropImg = img[ey:ey + eh, ex - int (ew / 5):ex + ew + int (ew / 5)]
                    cropImg = cv2.resize (cropImg, (75, 60), interpolation=cv2.INTER_CUBIC)
                    mkdir (save_dir + str(eh))
                    cv2.imwrite (save_dir + str(eh) + '/crop_' + str (ex) + '_' + str (eh) + '_' + str (ew + int (ew / 5) * 2) + '_' + str (i) + '.jpg', cropImg)
                    # print(str(ex - int(ew/5))+'||'+str(ex + ew + int(ew/5))+'||'+str(ey)+'||'+str(ey + eh))
            cv2.destroyAllWindows ()

上面的代码运行完,目录下就都是切好的真眼和假眼了。

 

下面就是长达100多小时的训练,中间有反复有失败有调参有断点,最终取得的结果还可以,模拟器生成的眼睛确实太假了,合成的眼睛仿真度有了很大提高,有些凭人肉眼都不能分辨真伪,当然大部分还是看得出是模拟的,但用来训练模型足以乱真了。

图太小可能看不清,我截几个典型的,优化的惟妙惟肖。

左1,眼神方向未变的情况下,瞳孔右上角竟然给打上了高光,显得更有精神了,妙的是原图右上角和左下角截取了一部分灰色的模拟器背景,右上角给填上了肉色,象是眉骨的延展,左下角打上了黑边,模拟出带眼镜的效果。

左2,去掉了模拟器的高光,保留了眼白的血丝,并把左上,右上的灰色填上了色。

左3,模拟器生成的太高清了,皮肤细节都给描绘了出来,实际在眼球追踪时不会有那么多细节,真实图片都是偏模糊的,这张就模糊的恰到好处。

左4,同样的模糊+高光

结论:

1、训练SimGAN-Captcha时,尝试过几次,发现很快就不再收敛,也可能是运气,也可能是调参水平不够。用 SimGAN-Captcha 增强过的样本,重新训练识别模型,准确率的确有提升(甚至准确率的提升与SimGAN-Captcha是否有关都不是很确定,毕竟又多训练的几轮,即使不使用增强数据,多训几轮也可能提升准确率),但效果不明显,最终SimGAN-Captcha的模型经过24小时的对抗,仅提升了0.1%的准确率,投入产出不成比例。与其花费时间在训练SimGAN上,不如花时间认真分析目标验证码的细节,把模拟生成器做到更加逼真。

2、模拟生成器已经很逼真的情况下,SimGAN的R生成器优势太大,几乎都是把没有修正过的图像Refined出来,D判别器也无力对抗。而换一套生成器,生成完全不同的验证码后,SimGAN的D判别器优势巨大,R生成器无论怎么努力地修正,都会被D枪毙掉。上面两种情况,可能是在实验中导致模型无法收敛的根本原因。模拟生成器如果不那么逼真,又有7、8成相像的情况下,SimGAN有可能会对样本增强有不错的效果,但花费时间太多,不如人工优化模拟生成器来得效率高。无法人工优化的特殊情况下,SimGAN可能有一定的使用场景。

3、SimGAN在验证码增强上的效果,可能不会太好,对字符类的图片在像素级Refine,很难产生平等对抗。举个简单的例子,目标验证码的字符是扭曲的,如果模拟生成的是规矩的字符,R生成器在self-regularization loss损失函数的约束下,在像素级上如何努力也无法将字符扭曲。如果应用在Apple的眼球控制类数据增强上,效果应该不错。

4、引用《人工智能革命》作者王天一的说法推荐给大家:给定一只猫的图片,过往的神经网络算法只能区分出它到底是不是猫,还不一定分得准确。可生成式神经网络却能模仿现有的图片画出一只类似的猫。不管这是简单的数据拟合,还是更加高级的抽象特征重组,它都是由机器自己完成的再创作,这种行为方式无疑更加接近于真实的人类。关于生成器为什么能够从随机样本出发学习到真实的数据分布缺乏清晰的理论解释。凡此种种都让生成式对抗网络看起来更像是沙上之塔。没有坚实的理论基础,对算法的推广自然存在困难。除了在图像生成等少数领域表现突出,生成式对抗网络在大多数任务上还是乏善可陈。在算法的原理尚不清楚时,想要实现优化自然是空中楼阁。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Koa2 中使用 svg-captcha 生成验证码可以按照以下步骤进行: 1. 安装 svg-captcha 和 koa-svgrouter 模块 ```bash npm install svg-captcha koa-svgrouter --save ``` 2. 在 Koa2 应用中引入相关模块 ```javascript const Koa = require('koa'); const Router = require('koa-router'); const svgrouter = require('koa-svgrouter'); const svgCaptcha = require('svg-captcha'); const app = new Koa(); const router = new Router(); ``` 3. 设置路由,生成验证码 ```javascript router.get('/captcha', async (ctx, next) => { const captcha = svgCaptcha.create(); ctx.session.captcha = captcha.text; ctx.type = 'svg'; ctx.body = captcha.data; }); ``` 4. 添加 SVG 路由 ```javascript app.use(svgrouter('/captcha/:id', { useSession: true, sessionName: 'captcha' })); ``` 5. 在需要使用验证码的地方,可以通过如下代码获取验证码图片 ```html <img src="/captcha/1" /> ``` 注意,上述代码中的数字 1 是路由参数,可以自行设置。 6. 验证验证码 在需要验证验证码的地方,可以通过如下代码获取用户输入的验证码,并与之前生成的验证码进行比较。 ```javascript const userCaptcha = ctx.request.body.captcha; if (userCaptcha.toLowerCase() === ctx.session.captcha.toLowerCase()) { // 验证码输入正确 } else { // 验证码输入错误 } ``` 以上就是使用 svg-captcha 生成验证码的基本步骤。需要注意的是,在生成验证码和验证验证码时都需要使用到 Koa2 的 session 功能,因此需要在应用中添加相关中间件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值