(第三章)TF框架之实现验证码识别
这里实现一个用神经网络(卷积神经网络也可以)实现验证码识别的小案例,主要记录本人做这个案例的流程,不会像之前那么详细,主要用作个人记录用。。。
-
-
字母验证码识别设计:
-
这两个(真实值和预测值)104的一阶张量进行交叉熵损失计算,得出损失大小。会提高四个位置的概率,使得4组中每组26个目标值中为1的位置对应的预测概率值越来越大,在预测的四组当中概率值最大。这样得出预测中每组的字母位置。所有104个概率相加为1
-
-
流程设计
-
1、把图片的特征值和目标值,-----> 转换成tfrecords格式,方便数据特征值、目标值统一读取
-
[b'NZPP' b'WKHK' b'WPSJ' ..., b'FVQJ' b'BQYA' b'BCHR'] -----> [[13, 25, 15, 15], [22, 10, 7, 10], [22, 15, 18, 9], [16, 6, 13, 10]]
-
"ABCD……Z" —>"0, 1, …, 25"
-
-
2、训练验证码、准确率的计算
-
将原来的图片数据(特征)和csv数据(标签)------> 转变为tfrecords格式的数据,注意example协议(序列化后)
代码如下:
import tensorflow as tf import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' FLAGS = tf.app.flags.FLAGS tf.app.flags.DEFINE_string("tfrecords_dir", "./tfrecords/captcha.tfrecords", "验证码tfrecords文件") tf.app.flags.DEFINE_string("captcha_dir", "../data/Genpics/", "验证码图片路径") tf.app.flags.DEFINE_string("letter", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "验证码字符的种类") def dealwithlabel(label_str): # 构建字符索引 {0:'A', 1:'B'......} num_letter = dict(enumerate(list(FLAGS.letter))) # 键值对反转 {'A':0, 'B':1......} letter_num = dict(zip(num_letter.values(), num_letter.keys())) print(letter_num) # 构建标签的列表 array = [] # 给标签数据进行处理[[b"NZPP"], ......] for string in label_str: letter_list = []# [1,2,3,4] # 修改编码,b'FVQJ'到字符串,并且循环找到每张验证码的字符对应的数字标记 for letter in string.decode('utf-8'): letter_list.append(letter_num[letter]) array.append(letter_list) # [[13, 25, 15, 15], [22, 10, 7, 10], [22, 15, 18, 9], [16, 6, 13, 10], [1, 0, 8, 17], [0, 9, 24, 14].....] print(array) # 将array转换成tensor类型 label = tf.constant(array) return label def get_captcha_image(): """ 获取验证码图片数据 :param file_list: 路径+文件名列表 :return: image """ # 构造文件名 filename = [] for i in range(6000): string = str(i) + ".jpg" filename.append(string) # 构造路径+文件 file_list = [os.path.join(FLAGS.captcha_dir, file) for file in filename] # 构造文件队列 file_queue = tf.train.string_input_producer(file_list, shuffle=False) # 构造阅读器 reader = tf.WholeFileReader() # 读取图片数据内容 key, value = reader.read(file_queue) # 解码图片数据 image = tf.image.decode_jpeg(value) image.set_shape([20, 80, 3]) # 批处理数据 [6000, 20, 80, 3] image_batch = tf.train.batch([image], batch_size=6000, num_threads=1, capacity=6000) return image_batch def get_captcha_label(): """ 读取验证码图片标签数据 :return: label """ file_queue = tf.train.string_input_producer(["../data/Genpics/labels.csv"], shuffle=False) reader = tf.TextLineReader() key, value = reader.read(file_queue) records = [[1], ["None"]] number, label = tf.decode_csv(value, record_defaults=records) # [["NZPP"], ["WKHK"], ["ASDY"]] label_batch = tf.train.batch([label], batch_size=6000, num_threads=1, capacity=6000) return label_batch def write_to_tfrecords(image_batch, label_batch): """ 将图片内容和标签写入到tfrecords文件当中 :param image_batch: 特征值 :param label_batch: 标签值 :return: None """ # 转换类型 label_batch = tf.cast(label_batch, tf.uint8) print(label_batch) # 建立TFRecords 存储器 writer = tf.python_io.TFRecordWriter(FLAGS.tfrecords_dir) # 循环将每一个图片上的数据构造example协议块,序列化后写入 for i in range(6000): # 取出第i个图片数据,转换相应类型,图片的特征值要转换成字符串形式 image_string = image_batch[i].eval().tostring() # 标签值,转换成整型 label_string = label_batch[i].eval().tostring() # 构造协议块 example = tf.train.Example(features=tf.train.Features(feature={ "image": tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_string])), "label": tf.train.Feature(bytes_list=tf.train.BytesList(value=[label_string])) })) writer.write(example.SerializeToString()) # 关闭文件 writer.close() return None if __name__ == "__main__": # 获取验证码文件当中的图片 image_batch = get_captcha_image() # 获取验证码文件当中的标签数据 label = get_captcha_label() print(image_batch, label) with tf.Session() as sess: coord = tf.train.Coordinator() threads = tf.train.start_queue_runners(sess=sess, coord=coord) # [b'NZPP' b'WKHK' b'WPSJ' ..., b'FVQJ' b'BQYA' b'BCHR'] label_str = sess.run(label) print(label_str) # 处理字符串标签到数字张量 label_batch = dealwithlabel(label_str) print(label_batch) # 将图片数据和内容写入到tfrecords文件当中 write_to_tfrecords(image_batch, label_batch) coord.request_stop() coord.join(threads)
- 训练验证码,得到准确率的代码
import tensorflow as tf class CaptchaIdentification(object): """ 验证码的读取数据、网络训练 """ def __init__(self): # 验证码图片的属性 self.height = 20 self.width = 80 self.channel = 3 # 每个验证码的目标值个数(4个字符) self.label_num = 4 self.feature_num = 26 # 每批次训练样本个数 self.train_batch = 100 @staticmethod def weight_variables(shape): w = tf.Variable(tf.random_normal(shape=shape, mean=0.0, stddev=0.1)) return w @staticmethod def bias_variables(shape): b = tf.Variable(tf.random_normal(shape=shape, mean=0.0, stddev=0.1)) return b def read_captcha_tfrecords(self): """ 读取验证码特征值和目标值数据 :return: """ # 1、构造文件的队列 file_queue = tf.train.string_input_producer(["./tfrecords/captcha.tfrecords"]) # 2、tf.TFRecordReader 读取TFRecords数据 reader = tf.TFRecordReader() # 单个样本数据 key, value = reader.read(file_queue) # 3、解析example协议 feature = tf.parse_single_example(value, features={ "image": tf.FixedLenFeature([], tf.string), "label": tf.FixedLenFeature([], tf.string) }) # 4、解码操作、数据类型、形状 image = tf.decode_raw(feature["image"], tf.uint8) label = tf.decode_raw(feature["label"], tf.uint8) # 确定类型和形状 # 图片形状 [20, 80, 3] # 目标值 [4] image_reshape = tf.reshape(image, [self.height, self.width, self.channel]) label_reshape = tf.reshape(label, [self.label_num]) # 类型 image_type = tf.cast(image_reshape, tf.float32) label_type = tf.cast(label_reshape, tf.int32) # 5、 批处理 # print(image_type, label_type) # 提供每批次多少样本去进行训练 image_batch, label_batch = tf.train.batch([image_type, label_type], batch_size=self.train_batch, num_threads=1, capacity=self.train_batch) print(image_batch, label_batch) return image_batch, label_batch def captcha_model(self, image_batch): """ 建立全连接层网络 :param image_batch: 验证码图片特征值 :return: 预测结果 """ # 全连接层 # [100, 20, 80, 3] --->[100, 20 * 80 * 3] # [100, 20 * 80 * 3] * [20 * 80 * 3, 104] + [104] = [None, 104] 104 = 4*26 with tf.variable_scope("captcha_fc_model"): # 初始化权重和偏置参数 self.weight = self.weight_variables([20 * 80 * 3, 104]) self.bias = self.bias_variables([104]) # 4维---->2维做矩阵运算 x_reshape = tf.reshape(image_batch, [self.train_batch, 20 * 80 * 3]) # [self.train_batch, 104] y_predict = tf.matmul(x_reshape, self.weight) + self.bias return y_predict def loss(self, y_true, y_predict): """ 建立验证码4个目标值的损失 :param y_true: 真实值 :param y_predict: 预测值 :return: loss """ with tf.variable_scope("loss"): # 先进行网络输出的值的概率计算softmax,在进行交叉熵损失计算 # y_true:[100, 4, 26]------>[None, 104] # y_predict:[100, 104] y_reshape = tf.reshape(y_true, [self.train_batch, self.label_num * self.feature_num]) all_loss = tf.nn.softmax_cross_entropy_with_logits(labels=y_reshape, logits=y_predict, name="compute_loss") # 求出平均损失 loss = tf.reduce_mean(all_loss) return loss def turn_to_onehot(self, label_batch): """ 目标值转换成one_hot编码 :param label_batch: 目标值 [None, 4] :return: """ with tf.variable_scope("one_hot"): # [None, 4]--->[None, 4, 26] y_true = tf.one_hot(label_batch, depth=self.feature_num, on_value=1.0) return y_true def sgd(self, loss): """ 梯度下降优化损失 :param loss: :return: train_op """ with tf.variable_scope("sgd"): train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss) return train_op def acc(self, y_true, y_predict): """ 计算准确率 :param y_true: 真实值 :param y_predict: 预测值 :return: accuracy """ with tf.variable_scope("acc"): # y_true:[None, 4, 26] # y_predict:[None, 104] y_predict_reshape = tf.reshape(y_predict, [self.train_batch, self.label_num, self.feature_num]) # 先对最大值的位置去求解 这里的2指的是维度 euqal_list = tf.equal(tf.argmax(y_true, 2), tf.argmax(y_predict_reshape, 2)) # 需要对每个样本进行判断 这里的1指的是维度 # x = tf.constant([[True, True], [False, False]]) # tf.reduce_all(x, 1) # [True, False] accuracy = tf.reduce_mean(tf.cast(tf.reduce_all(euqal_list, 1), tf.float32)) return accuracy def train(self): """ 模型训练逻辑 :return: """ # 1、通过接口获取特征值和目标值 # image_batch:[100, 20, 80, 3] # label_batch: [100, 4] # [[13, 25, 15, 15], [22, 10, 7, 10]] image_batch, label_batch = self.read_captcha_tfrecords() # 2、建立验证码识别的模型 # 全连接层神经网络 # y_predict [100, 104] y_predict = self.captcha_model(image_batch) # 转换label_batch 到one_hot编码 # y_true:[None, 4, 26] y_true = self.turn_to_onehot(label_batch) # 3、利用真实值和目标值建立损失 loss = self.loss(y_true, y_predict) # 4、对损失进行梯度下降优化 train_op = self.sgd(loss) # 5、计算准确率 accuracy = self.acc(y_true, y_predict) # 会话训练 with tf.Session() as sess: sess.run(tf.global_variables_initializer()) # 生成线程的管理 coord = tf.train.Coordinator() # 指定开启子线程去读取数据 threads = tf.train.start_queue_runners(sess=sess, coord=coord) # 循环训练打印结果 for i in range(1000): _, acc_run = sess.run([train_op, accuracy]) print("第 %d 次训练的准确率为:%f " % (i, acc_run)) # 回收线程 coord.request_stop() coord.join(threads) return None if __name__ == '__main__': ci = CaptchaIdentification() ci.train()