本文讨论了基于卷积神经网络的验证码识别问题。提出了验证码训练数据获取新方法和基于卷积神经网络的无字符切割的识别算法。讨论了损失函数、Metrics函数的选择及网络参数选择的方向问题。
训练数据的生成
直觉上,我们应该从网站上抓取验证码后进行标注,然后用这些数据来进行训练。但这样做可能存在一些问题:
用于训练的图片往往需要达数万张甚至几十万张,要抓取这么多图片而不受网站惩罚可能并不容易。假设网站能容忍一个IP一秒中抓取一个验证码图片的话,一天也只能抓取8万张图片。如果这期间被网站惩罚,那么收集这些图片的时间就会更久了。
二是图片的标注问题。假设要收集50万张图片,对它们一一人工识别并标注。假设采用以验证码文字作为文件名的方式来完成标注,在windows上要完成这样一个操作可能需要5秒。这样全部标注完50万张图片就需要29天(按每天24小时,而不是8小是工作时间计算)。当然,我们可以使用一些脚本来加速这个操作。比如,首先将这50万张图片按数字从1到50万进行命名,分为若干个文件夹(减少出错,便于校对;另外出于性能考虑,也不适宜在一个文件夹中存放太多文件),然后再在资源管理器中以缩略图的方式顺序显示这些图片,人工识别后将验证码文件写入到文本文件中,一行一个,然后再使用脚本逐行读取这个存入大量验证码的文件,将本来以数字命名的验证码文件一一对应地改名。尽管如此,即使验证码仅由4位数字和英文字母组成,一次输入也要花大约2~3秒的时间。这样对50万张图片进行标注仍然需要近15天。
这还仅仅是完成一个网站验证码标注面临的时间和资源代价。
考虑到验证码识别并不是什么值得大投入的课题,很可能投入这么多资源来收集训练数据是不经济的,因此,我们必须思考更优的方法。
实际上,大多数网站使用开源的框架来生成验证码。这样的开源框架虽然很多,但其生成验证码的套路都差不多,仅有一些参数不同引起的视觉上的差异。如果我们的神经网络模型有足够的泛化能力,则应该可以容忍这些参数上的变化。这样,我们的思路变为,参考开源框架的实现,自己生成与网站相接近的验证码来进行训练,这样就较好地解决了训练数据问题。
Github上有很多开源的验证码生成框架,其中以PHP语言的最多:
如下是一款普通的验证码:
可以看到其生成有以下特点:字符颜色变化
背景颜色变化和底纹变化
插入了干扰线和干扰点
整张图片进行了变形
根据以上特点,我们用python来实现一个简单的验证码。主要由两个文件组成,一个是vocab.py,用来管理验证码的词汇;一个是captcha.py,用来实际生成验证码图片。
# vocab.py
import random
import numpy as np
'''A default vocab implementation and base class, to provide random letters and numbers.'''
class Vocab():
def __init__(