验证码之旋转印刷文字识别实战
文本主要描述旋转印刷文字验证码的识别训练,适读人群为有识别验证码经验人群或当前寻找验证码项目试手人群。本文采用CRNN+CTC对文字进行识别,通过训练已对样例数据的识别率达到了97%。本文主要以实战代码展示的形式叙述整个项目的过程,方便大家理解和尝试。
CRNN模型简介
中文译文:CRNN论文翻译——中文版
CRNN基本网络结构
网络架构。架构包括三部分:
- 卷积层,从输入图像中提取特征序列,卷积层就是一个普通的CNN网络,用于提取输入图像的Convolutional feature maps;
- 循环层,预测每一帧的标签分布,循环网络层是一个深层双向LSTM网络,在卷积特征的基础上继续提取文字序列特征;
- 转录层,将每一帧的预测变为最终的标签序列,将RNN输出做softmax后,为字符输出。
在CRNN的底部,卷积层自动从每个输入图像中提取特征序列。在卷积网络之上,构建了一个循环网络,用于对卷积层输出的特征序列的每一帧进行预测。采用CRNN顶部的转录层将循环层的每帧预测转化为标签序列。虽然CRNN由不同类型的网络架构(如CNN和RNN)组成,但可以通过一个损失函数进行联合训练。
pytorch实现网络模型代码
class BidirectionalLSTM(nn.Module):
def __init__(self, nIn, nHidden, nOut):
super(BidirectionalLSTM, self).__init__()
self.rnn = nn.LSTM(nIn, nHidden, bidirectional=True)
self.embedding = nn.Linear(nHidden * 2, nOut)
def forward(self, input):
recurrent, _ = self.rnn(input)
T, b, h = recurrent.size()
t_rec = recurrent.view(T * b, h)
output = self.embedding(t_rec) # [T * b, nOut]
output = output.view(T, b, -1)
return output
class CRNN(nn.Module):
def __init__(self, imgH, nc, nclass, nh, n_rnn=2, leakyRelu=False):
super(CRNN, self).__init__()
assert imgH % 16 == 0, 'imgH has to be a multiple of 16'
ks = [3, 3, 3, 3, 3, 3, 2]
ps = [1, 1, 1, 1, 1, 1, 0]
ss = [1, 1, 1, 1, 1, 1, 1]
nm = [64, 128, 256, 256, 512, 512, 512]
cnn = nn.Sequential()
def convRelu(i, batchNormalization=False):
nIn = nc if i == 0 else nm[i - 1]
nOut = nm[i]
cnn.add_module('conv{0}'.format(i), nn.Conv2d(nIn, nOut, ks[i], ss[i], ps[i]))
if batchNormalization:
cnn.add_module('batchnorm{0}'.format(i), nn.BatchNorm2d(nOut))
if leakyRelu:
cnn.add_module('relu{0}'.format(i), nn.LeakyReLU(0.2, inplace=True))
else:
cnn.add_module('relu{0}'.format(i), nn.ReLU(True))
convRelu(0)
cnn.add_module('pooling{0}'.format(0), nn.MaxPool2d(2, 2)) # 64x16x64
convRelu(1)
cnn.add_module('pooling{0}'.format(1), nn.MaxPool2d(2, 2)) # 128x8x32
convRelu(2, True)
convRelu(3)
cnn.add_module('pooling{0}'.format(2), nn.MaxPool2d((2, 2), (2, 1), (0, 1))) # 256x4x16
convRelu(4, True)
convRelu(5)
cnn.add_module('pooling{0}'.format(3), nn.MaxPool2d((2, 2), (2, 1), (0, 1))) # 512x2x16
convRelu(6, True) # 512x1x16
self.cnn = cnn
self.rnn = nn.Sequential(BidirectionalLSTM(512, nh, nh), BidirectionalLSTM(nh, nh, nclass))
def forward(self, input):
conv = self.cnn(input)
b, c, h, w = conv.size()
assert h == 1, "the height of conv must be 1"
conv = conv.squeeze(2)
conv = conv.permute(2, 0, 1)
output = self.rnn(conv)
output = F.log_softmax(output, dim=2)
return output
def backward_hook(self, module, grad_input, grad_output):
for g in grad_input:
g[g != g] = 0
模型训练相关(代码提交至GitHub)
代码仓库
https://github.com/a2king/crnn_word_captcha
数据集
本项目训练集82W张,测试集1.9W张。数据集命名方式采用“文本内容_数据值.jpg”,其中覆盖文字2033个。
训练
# 生成用于训练的mdb文件--out文件输出路径, --folder数据集存放路径, 用此指令生成训练集文件和测试集文件
python tool/create_dataset.py --out data/train --folder path/to/folder
# 用于生成所有文字的映射文件,--trainfolder训练集路径,--testfolder测试集路径
python tool/select_words.py --trainfolder /path/train --testfolder path/test
# 训练模型--trainroot用于训练的mdb路径,--valroot用于测试的mdb训练路径
python train.py --trainroot data/train --valroot data/test
训练部分参数拆解描述
cuda = True # 是否使用GPU训练
multi_gpu = False # 是否使用多GPU进行训练
ngpu = 1 # 多GPU训练时的gpu数量
workers = 0 # 加载数据的worker,在机器允许的情况下设为8或16,降低CPU调度,提高训练效率
# training process
displayInterval = 100 # 每隔多少次训练展示损失率
valInterval = 1000 # 每隔多少次训练测试模型
saveInterval = 10 # 每隔多少次循环保存模型
nepoch = 1000 # 数据集最大循环训练次数
项目声明
本项目提供一种旋转文字验证码技术实战。项目仅供与个人研究,请勿进行商业操作或攻击网站。