最新结果请参考:http://kexue.fm/archives/4503/

前段时间有幸得到了一个网友提供的一批带标签的腾讯验证码样本(验证码样板:http://captcha.qq.com/getimage),于是抽了点时间,测试了一下验证码识别的模型。

腾讯验证码

腾讯验证码

样本 #

这批验证码比较简单,4位的英文字母,有大小写,但输入的时候不区分大小写,图案有一定的混淆,传统的基于分割的方案估计比较难办。端到端的方案是,直接将验证码输入,做几个卷积层,然后连接几个分类器(26分类),然后就直接输出四个字母标签了。其实还真没有什么好说的,有样本就能做了,而且这个框架是通用的,可以用到区分大小写的情形(52分类),也可以用到英文数字混合的情形(再加10个类别而已)。

不过,有一个我认为是比较难搞的地方,就是标签不区分大小写。这批样本中,标签全部是小写的,但是图片上的验证码有大写有小写。这样,如果只是26分类的话,那么强行要将A、a归为同一类,而A、a从外形上来看区别还是有点大的,强行归类,似乎有点“强模型所难”...我估计这也是我模型准确率上不去的原因之一。但我也没什么好思路。

代码 #

也不多说了,直接上代码
https://github.com/bojone/n2n-ocr-for-qqcaptcha

模型非常简洁,也很常规(只是单文件,能有多复杂?)

就是用4个卷积层提取了图片特征,然后将这个图片特征分别接4个softmax,每个都分为26类,注意这里不能图方便用TimeDistributed,TimeDistributed是权值共享的,而我们这里要对同一个特征分别输出不同的标签,权值相同结果不就也相同了么?另外要注意,我的Keras是用theano做后端,不是tensorflow,两者对图像的处理有所不同,因此用tensorlfow的朋友要自己调整过来。

_____________________________________________________________
Layer (type) Output Shape Param # Connected to
=============================================================
input_15 (InputLayer) (None, 3, 129, 53) 0
_____________________________________________________________
convolution2d_40 (Convolution2D) (None, 32, 127, 51) 896 input_15[0][0]
_____________________________________________________________
maxpooling2d_48 (MaxPooling2D) (None, 32, 63, 25) 0 convolution2d_40[0][0]
_____________________________________________________________
convolution2d_41 (Convolution2D) (None, 32, 61, 23) 9248 maxpooling2d_48[0][0]
_____________________________________________________________
maxpooling2d_49 (MaxPooling2D) (None, 32, 30, 11) 0 convolution2d_41[0][0]
_____________________________________________________________
activation_37 (Activation) (None, 32, 30, 11) 0 maxpooling2d_49[0][0]
_____________________________________________________________
convolution2d_42 (Convolution2D) (None, 32, 28, 9) 9248 activation_37[0][0]
_____________________________________________________________
maxpooling2d_50 (MaxPooling2D) (None, 32, 14, 4) 0 convolution2d_42[0][0]
_____________________________________________________________
activation_38 (Activation) (None, 32, 14, 4) 0 maxpooling2d_50[0][0]
_____________________________________________________________
convolution2d_43 (Convolution2D) (None, 32, 12, 2) 9248 activation_38[0][0]
_____________________________________________________________
maxpooling2d_51 (MaxPooling2D) (None, 32, 6, 1) 0 convolution2d_43[0][0]
_____________________________________________________________
flatten_15 (Flatten) (None, 192) 0 maxpooling2d_51[0][0]
_____________________________________________________________
activation_39 (Activation) (None, 192) 0 flatten_15[0][0]
_____________________________________________________________
dense_63 (Dense) (None, 26) 5018 activation_39[0][0]
_____________________________________________________________
dense_64 (Dense) (None, 26) 5018 activation_39[0][0]
_____________________________________________________________
dense_65 (Dense) (None, 26) 5018 activation_39[0][0]
_____________________________________________________________
dense_66 (Dense) (None, 26) 5018 activation_39[0][0]
=============================================================
Total params: 48712
_____________________________________________________________

经过几十轮训练后,得到模型,第1、2、3、4字识别的准确率分别是0.89、0.72、0.73、0.87,这样,四个全对的准确率应该是
$$0.89\times0.72\times0.73\times0.87\approx 0.41$$
即应该会有41%的全对率,经过实际测试,效果还更好一些,全对率为46%,这样差不多两张就有一张识别正确,应该在不少情形都很实用了。当然,这个准确率只针对这批样本的,实际准确率可能还要更低一些,但是估计10%应该有吧?^_^

训练样本就不方便公开了,模型权重也不好直接公开,有需要的,请私下联系我。

后话 #

按送我样本的朋友的说法,他现在接入了一个别人提供的接口,全对率有95%以上,我瞬间肃然起敬啊,真想好好向那个人学习,不过那个程序已经商业化了,估计也不可能给我观摩了,估计别人就是长期盯着腾讯验证码识别这个需求做的,不像我,泛而不精。

欢迎读者提供更好的建模思路哈,请大家多多指教。目前的模型才5万个参数不到,可能欠拟合了,有空在好好调整一下。

转载到请包括本文地址:https://spaces.ac.cn/archives/4138

更详细的转载事宜请参考:《科学空间FAQ》

如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。

如果您觉得本文还不错,欢迎分享/打赏本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!

如果您需要引用本文,请参考:

苏剑林. (Dec. 14, 2016). 《端到端的腾讯验证码识别(46%正确率) 》[Blog post]. Retrieved from https://spaces.ac.cn/archives/4138

@online{kexuefm-4138,
        title={端到端的腾讯验证码识别(46%正确率)},
        author={苏剑林},
        year={2016},
        month={Dec},
        url={\url{https://spaces.ac.cn/archives/4138}},
}