lstm ctc 完成验证码 ocr
2017-10-11 本文已影响283人
bidai541
在【爬虫踩过的那些坑】中介绍了在数据抓取过程中遇到的一些问题,主要是验证码反爬带来的困扰,在这介绍下通过深度神经网络的一些算法来自己动手训练验证码ocr模型,实现自动打码,思路参考github。
验证码打码策略
- 通过字符切分,得到单个字符,然后用类似于LeNet这样的网络做单字符识别
-
不做字符切分,训练端到端字符识别网络
像车牌识别、身份证号识别这些应用场景,字符切割可能会更好一点,这样可以保证模型的鲁棒性(之所以说这种方法更加鲁邦是对比端到端字符ocr来讲),前期图像的预处理比如二值化、白化处理可以让单字符识别神经网络适应字体的轻微变化;但目前大多数的验证码生成器都会添加人为干扰,给字符切分造成了很大的困难。所以端到端对这一类特定的场景来讲还是非常有效的。
网络结构
#python
# 两层LSTM
rnn_cell_layer_1 = tf.contrib.rnn.LSTMCell(num_units=self.hidden_unions, state_is_tuple=True)
rnn_cell_layer_2 = tf.contrib.rnn.LSTMCell(num_units=self.hidden_unions, state_is_tuple=True)
rnn_block = tf.contrib.rnn.MultiRNNCell([rnn_cell_layer_1, rnn_cell_layer_2], state_is_tuple=True)
outputs, _ = tf.nn.dynamic_rnn(rnn_block, self.inputs, self.seq_len, dtype=tf.float32)
outputs_shape = tf.shape(outputs)
batch_size, max_steps = outputs_shape[0], outputs_shape[1]
outputs_reshape = tf.reshape(outputs, [-1, self.hidden_unions])
# 输出经过全连接层做映射
W = tf.Variable(tf.truncated_normal([self.hidden_unions, self.classes], stddev=0.1, dtype=tf.float32),
name="W")
b = tf.Variable(tf.constant(0.0, dtype=tf.float32, shape=[self.classes]), name="b")
output = tf.matmul(outputs_reshape, W) + b
output _reshape = tf.reshape(output, [batch_size, -1, self.classes])
output _transpose = tf.transpose(_reshape, perm=[1, 0, 2])
# 使用损失函数 ctc_loss,该函数内部做了soft_max操作,所以全连接输出直接输入,否则编码错误
loss = tf.nn.ctc_loss(labels=self.labels, inputs=output_transpose, sequence_length=self.seq_len)
# 解码过程
decoded, log_prob = tf.nn.ctc_beam_search_decoder(output_transpose, self.seq_len, merge_repeated=False)
该网络有一个非常明显的问题:收敛速度时快时慢,有时候5-6个epoch就可以收敛到理想状态,有时候需要100个epoch,不过总归都会收敛,一直没有搞明白这个问题。比如这次迭代40个epoch(2h左右),精度达到 accuracy = 98.2%,如果时间再长一些会更高。
learn_rate的设置至关重要,比如lr=0.001时收敛速度特别慢,设置为0.01时,快很多。接下来能不能对网络结构做一些改进使其有一个稳定的收敛过程呢?
未完待续......
欢迎一块交流讨论,文中有错误的地方,还请指正,谢谢~
email: bidai541@foxmail.com