目录
基础理论
一、生成验证码数据集
1、生成验证码训练集
1-0、判断文件夹是否为空
1-1、创建字符集(数字、大小写英文字母)
1-2、随机生成验证码(1000个,长度为4)
2、生成验证码测试集
代码
二、获取数据(训练集、测试集)
1、获取数据和标签
1-1、获取训练集数据和标签(路径和标签)
1-2、获取测试集数据和标签(路径和标签)
1-3、数据组合(图像路径和标签)
2、打乱数据
3、处理每条数据
4、自定义重复周期和批次大小
5、处理每批数据
6、获取一批次数据和标签
三、创建神经网络
1、创建50层残差神经网络
2、设置输入层
3、平均池化(压缩数据)
4、配置多个输出层(多任务学习)
5、配置模型
6、编译(多任务学习)
7、回调函数配置
8、训练模型
总代码
基础理论
多任务学习(Multi-task Learning)是深度学习中很常用的一种模型训练策略,意思其实也很简单,就是同时训练多个任务,给大家举两个例子大家就明白了。比如目标检测项目中,我们既要知道1、目标所在的位置(也就是预测框坐标值),也要知道2、预测框内是什么物体。预测框的坐标值是连续型数据,所以是一个回归任务;预测框的物体是一个具体的类别,所以是一个分类任务。
不同的任务其实也可以共享卷积层。因为卷积层的作用主要是特征提取,先提取图像的特征,然后再使用这些特征来预测人的年龄,表情,性别。用于特征提取的卷积层可以共享,不过不同的任务还需要有自己的 task layer,专门用于训练特定任务。
我们要识别的验证码有 4 个字符,我们可以给模型定义 4 个任务,每个任务负责识别 1 个字符。第一个任务识别第一个字符,第二个任务识别第二个字符,第三个任务识别第三个字符,第四个任务识别第四个字符。
一、生成验证码数据集
1、生成验证码训练集
1-0、判断文件夹是否为空
if not os.listdir('D:\\Study\\AI\OpenCV\\draft.py\\captcha\\train'):Create_train_data()# 生成验证码训练集
1-1、创建字符集(数字、大小写英文字母)
# 1、创建字符集(字符包含所有数字和所有大小写英文字母,一共62(10+26+26)个)characters = string.digits + string.ascii_letters# 数字 英文字母(大小写)
得到如下数据:0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
1-2、随机生成验证码(1000个,长度为4)
# 2、随机产生验证码(共1000个,每个长度为4)for i in range(1000):verification_list = []
1、生成随机字符:
# 2-1、开始生产随机字符(4位)for j in range(4):c = random.choice(characters) # 随机选择(从characters里面随机抽取)verification_list.append(c)
2、实例化验证码生成器:
# 2-2、实例化验证码生成器image = ImageCaptcha(width=160, height=60) # 宽:160,高:60
3、连接列表字符(转字符串)
# 2-3、连接列表字符verification_list = ''.join(verification_list)
4、生成验证码
# 2-4、生成验证码image.write(verification_list, 'captcha/train/' + verification_list + '.jpg')
2、生成验证码测试集
过程同上,测试集数据不需要那么多,把1000张换成200张即可。
代码
# 创建训练集(验证码)def Create_train_data():# 1、创建字符集(字符包含所有数字和所有大小写英文字母,一共62(10+26+26)个)characters = string.digits + string.ascii_letters# 数字 英文字母(大小写)# 2、随机产生验证码(共1000个,每个长度为4)for i in range(1000):verification_list = []# 2-1、开始生产随机字符(4位)for j in range(4):c = random.choice(characters) # 随机选择(从characters里面随机抽取)verification_list.append(c)# 2-2、实例化验证码生成器image = ImageCaptcha(width=160, height=60) # 宽:160,高:60# 2-3、连接列表字符verification_list = ''.join(verification_list)# 2-4、生成验证码image.write(verification_list, 'captcha/train/' + verification_list + '.jpg')# 创建测试集(验证码)def Create_test_data():# 1、创建字符集(字符包含所有数字和所有大小写英文字母,一共62(10+26+26)个)characters = string.digits + string.ascii_letters# 数字 英文字母(大小写)# 2、随机产生验证码(共200个,每个长度为4)for i in range(200):verification_list = []# 2-1、开始生产随机字符(4位)for j in range(4):c = random.choice(characters) # 随机选择(从characters里面随机抽取)verification_list.append(c)# 2-2、实例化验证码生成器image = ImageCaptcha(width=160, height=60) # 宽:160,高:60# 2-3、连接列表字符verification_list = ''.join(verification_list)# 2-4、生成验证码image.write(verification_list, 'captcha/test/' + verification_list + '.jpg')
二、获取数据(训练集、测试集)
1、获取数据和标签
1-1、获取训练集数据和标签(路径和标签)
# 1-1、获取训练集数据和标签(路径和标签)train_data, train_target = get_filenames_and_classes("./captcha/train/")# 1000张图片,长度4
获取所有图片路径,标签转独热编码 :
# 获取所有验证码图片路径和标签def get_filenames_and_classes(dataset_dir):# 图片路径和标签paths ,targets = [], []# 获取每个图片的路径和标签for filename in os.listdir(dataset_dir):# 1、获取文件路径path = os.path.join(dataset_dir, filename)# 路径文件名# 完成1:保存图片路径paths.append(path)# 2、获取验证码标签(取文件名的前 4 位,也就是验证码的标签)target = filename[0:4]# 定义一个空label(获取4*62的数组,用0填充)label = np.zeros((4, classes_num), dtype=np.uint8)# 3、标签转独热编码for i, ch in enumerate(target):# i:索引 ch:字符# 标记(设置标签):独热编码 one-hot 格式label[i, characters.find(ch)] = 1# 数组索引 字符下标(字符ch在characters中的下标)# 完成2:保存独热编码的标签targets.append(label)# 返回图片路径和标签return np.array(paths), np.array(targets)
1-2、获取测试集数据和标签(路径和标签)
# 1-2、获取测试集数据和标签(路径和标签)test_data, test_target = get_filenames_and_classes("./captcha/test/") # 200张图片,长度4
获取数据函数同上。
1-3、数据组合(图像路径和标签)
# 1-3、数据组合(图像路径和标签)(创建 dataset 对象,传入图片路径和标签)dataset_train = tf.data.Dataset.from_tensor_slices((train_data, train_target))dataset_test = tf.data.Dataset.from_tensor_slices((test_data, test_target))
2、打乱数据
# 2、打乱数据dataset_train = dataset_train.shuffle(buffer_size=100, reshuffle_each_iteration=True) # map-可以自定义一个函数来处理每一条数据dataset_test = dataset_test.shuffle(buffer_size=20, reshuffle_each_iteration=True)# 数据缓冲器大小随机打乱(是/否)
3、处理每条数据
# 3、对每条数据进行处理(图像地址->3通道图像->归一化)dataset_train = dataset_train.map(image_function)dataset_test = dataset_test.map(image_function)# map函数:可以自定义一个函数来处理每一条数据
4、自定义重复周期和批次大小
# 4、自定义重复周期和批次大小dataset_train = dataset_train.repeat(1) # 数据重复生成 1 个周期dataset_test = dataset_test.repeat(1) # 数据重复生成 1 个周期dataset_train = dataset_train.batch(64) # 定义批次大小64dataset_test = dataset_test.batch(64) # 定义批次大小64
5、处理每批数据
# 5、处理每批数据# 注意这个 map 和前面的 map 有所不同,第一个 map 在 batch 之前,所以是处理每一条数据# 这个 map 在 batch 之后,所以是处理每一个 batch 的数据dataset_train = dataset_train.map(label_function)dataset_test = dataset_test.map(label_function)
6、获取一批次数据和标签
# 获取一批数据和标签trainx, trainy = next(iter(dataset_train))testx, testy = next(iter(dataset_test))
数据(归一化后的):
标签(独热编码):
三、创建神经网络
1、先配置好50层残差神经网络;
2、(用已配置好的残差神经网络)配置输入层;
3、把配置好的输入层池化;
4、(用池化后的结果)配置多个输出层(多任务学习);
5、(用输入层的shape和输出层)配置模型。
# 三、构造神经网络Create_Network()
1、创建50层残差神经网络
先配置好50层残差神经网络。
# 1、构造resnet50神经网络(50层残差网络)resnet50 = ResNet50(weights='imagenet', include_top=False, input_shape=(height, width, 3)) # 设置输入# weights:权重(imagenet:加载预训练权重)# include_top:是否保留顶层的全连接网络# input_shape:指明输入图片的shape,仅当include_top=False有效
2、设置输入层
用已配置好的残差神经网络配置输入层。
# 2、设置输入层inputs = Input((height, width, 3)) # 设置输入层大小x = resnet50(inputs) # 使用 resnet50 进行特征提取
3、平均池化(压缩数据)
平均池化,对输入层的进行压缩。
# 3、平均池化(压缩数据)x = GlobalAvgPool2D()(x)
4、配置多个输出层(多任务学习)
用池化后的结果配置多个输出层(多任务学习)。
多任务学习,把验证码识别的4个字符看成是4个不同的任务,每个任务负责识别1个字符。(4个任务,设置4个输出层)
# 4、配置输出层(多任务学习)# 把验证码识别的4个字符看成是4个不同的任务,每个任务负责识别1个字符x0 = Dense(classes_num, activation='softmax', name='out0')(x)x1 = Dense(classes_num, activation='softmax', name='out1')(x)x2 = Dense(classes_num, activation='softmax', name='out2')(x)x3 = Dense(classes_num, activation='softmax', name='out3')(x)
5、配置模型
用输入层的shape和输出层配置模型。
# 5、配置模型(输入层、输出层)model = Model(inputs, [x0, x1, x2, x3])
6、编译(多任务学习)
损失函数、权重、优化器、监视等等设置。
# 6、编译(多任务学习)(损失函数、权重、优化器、监视等等设置)# (4个任务我们可以定义4个loss)pile(loss={'out0': 'categorical_crossentropy','out1': 'categorical_crossentropy','out2': 'categorical_crossentropy','out3': 'categorical_crossentropy'},loss_weights={'out0': 1, 'out1': 1, 'out2': 1, 'out3': 1},optimizer=SGD(lr=0.01, momentum=0.9),metrics=['acc'])# loss:损失函数 loss_weights:权重 optimizer:优化器(lr:学习率;momentum:带动量的梯度下降)# metrics:监视(acc)
7、回调函数配置
# 7、回调函数(停止训练、保存数据、保存模型、调整学习率)callbacks = [EarlyStopping(monitor='val_loss', patience=6, verbose=1),CSVLogger('Captcha_tfdata.csv'),ModelCheckpoint('Best_Captcha_tfdata.h5', monitor='val_loss', save_best_only=True),ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, verbose=1)]# monitor='val_loss':监控指标'val_loss'# EarlyStopping:让模型停止(6个周期,val_loss没有下降则训练结束)# CSVLogger: 保存训练数据# ModelCheckpoint:保存模型(保存所有训练周期中val_loss最低的模型)# ReduceLROnPlateau 学习率调整,连续3个周期,val_loss没有下降,则当前学习率乘以0.1
8、训练模型
# 8、训练模型model.fit(x=dataset_train, epochs=epochs, validation_data=dataset_test, callbacks=callbacks)
训练效果:
第一次:
第12次:
虽说没有完全训练完,但是可以看到,第12次平均每个字符的正确率已经可以达到99%+了,效果挺好的。
总代码
# 验证码生成与识别import osos.environ['TF_CPP_MIN_LOG_LEVEL']='2'import tensorflow as tffrom tensorflow.keras.layers import Dense,GlobalAvgPool2D,Inputfrom tensorflow.keras.optimizers import SGDfrom tensorflow.keras.models import Modelfrom tensorflow.keras.applications.resnet50 import ResNet50from tensorflow.keras.callbacks import EarlyStopping,CSVLogger,ModelCheckpoint,ReduceLROnPlateauimport stringimport numpy as npimport osimport randomfrom captcha.image import ImageCaptchafrom plot_model import plot_model# 字符包含所有数字和所有小写英文字母,一共 62 个characters = string.digits + string.ascii_letters# 数字 字母# 类别数(62)classes_num = len(characters)# 周期数epochs = 100# 图片宽度width = 160# 图片高度height = 60# 创建训练集(验证码)def Create_train_data():# 1、创建字符集(字符包含所有数字和所有大小写英文字母,一共62(10+26+26)个)characters = string.digits + string.ascii_letters# 数字 英文字母(大小写)# 2、随机产生验证码(共1000个,每个长度为4)for i in range(1000):verification_list = []# 2-1、开始生产随机字符(4位)for j in range(4):c = random.choice(characters) # 随机选择(从characters里面随机抽取)verification_list.append(c)# 2-2、实例化验证码生成器image = ImageCaptcha(width=160, height=60) # 宽:160,高:60# 2-3、连接列表字符verification_list = ''.join(verification_list)# 2-4、生成验证码image.write(verification_list, 'captcha/train/' + verification_list + '.jpg')# 创建测试集(验证码)def Create_test_data():# 1、创建字符集(字符包含所有数字和所有大小写英文字母,一共62(10+26+26)个)characters = string.digits + string.ascii_letters# 数字 英文字母(大小写)# 2、随机产生验证码(共200个,每个长度为4)for i in range(200):verification_list = []# 2-1、开始生产随机字符(4位)for j in range(4):c = random.choice(characters) # 随机选择(从characters里面随机抽取)verification_list.append(c)# 2-2、实例化验证码生成器image = ImageCaptcha(width=160, height=60) # 宽:160,高:60# 2-3、连接列表字符verification_list = ''.join(verification_list)# 2-4、生成验证码image.write(verification_list, 'captcha/test/' + verification_list + '.jpg')# 获取所有验证码图片路径和标签def get_filenames_and_classes(dataset_dir):# 图片路径和标签paths ,targets = [], []# 获取每个图片的路径和标签for filename in os.listdir(dataset_dir):# 1、获取文件路径path = os.path.join(dataset_dir, filename)# 路径文件名# 完成1:保存图片路径paths.append(path)# 2、获取验证码标签(取文件名的前 4 位,也就是验证码的标签)target = filename[0:4]# 定义一个空label(获取4*62的数组,用0填充)label = np.zeros((4, classes_num), dtype=np.uint8)# 3、标签转独热编码for i, ch in enumerate(target):# i:索引 ch:字符# 标记(设置标签):独热编码 one-hot 格式label[i, characters.find(ch)] = 1# 数组索引 字符下标(字符ch在characters中的下标)# 完成2:保存独热编码的标签targets.append(label)# 返回图片路径和标签return np.array(paths), np.array(targets)# 图像处理函数# 输入:图像路径、标签# 输出:图像、标签def image_function(filenames, label):# 1、根据图片路径读取图片内容image = tf.io.read_file(filenames)# 2、解码为jpeg格式、3通道(正规图像)image = tf.image.decode_jpeg(image, channels=3)# 3、归一化image = tf.cast(image, tf.float32) / 255.0# 返回图片数据和标签return image, label# 标签处理函数# 获得每一个批次的图片数据和标签def label_function(image, label):# transpose 改变数据的维度,比如原来的数据 shape 是(64,4,62)# 这里的 64 是批次大小,验证码长度为 4 有 4 个标签,62 是 62 个不同的字符# tf.transpose(label,[1,0,2])计算后得到的 shape 为(4,64,62)# 原来的第 1 个维度变成了第 0 维度,原来的第 0 维度变成了 1 维度,第 2 维不变# (64,4,62)->(4,64,62)label = tf.transpose(label, [1, 0, 2])# 返回图片内容和标签,注意这里标签的返回,我们的模型会定义 4 个任务,所以这里返回 4 个标签# 每个标签的 shape 为(64,62),64 是批次大小,62 是独热编码格式的标签return image, (label[0], label[1], label[2], label[3])# 获取数据(训练集、测试集)def GetData():global dataset_train, dataset_test# 1、获取数据和标签# 1-1、获取训练集数据和标签(路径和标签)train_data, train_target = get_filenames_and_classes("./captcha/train/")# 1000张图片,长度4# 1-2、获取测试集数据和标签(路径和标签)test_data, test_target = get_filenames_and_classes("./captcha/test/") # 200张图片,长度4# 1-3、数据组合(图像路径和标签)(创建 dataset 对象,传入图片路径和标签)dataset_train = tf.data.Dataset.from_tensor_slices((train_data, train_target))dataset_test = tf.data.Dataset.from_tensor_slices((test_data, test_target))# 2、打乱数据dataset_train = dataset_train.shuffle(buffer_size=100, reshuffle_each_iteration=True) # map-可以自定义一个函数来处理每一条数据dataset_test = dataset_test.shuffle(buffer_size=20, reshuffle_each_iteration=True)# 数据缓冲器大小随机打乱(是/否)# 3、对每条数据进行处理(图像地址->3通道图像->归一化)dataset_train = dataset_train.map(image_function)dataset_test = dataset_test.map(image_function)# map函数:可以自定义一个函数来处理每一条数据# 4、自定义重复周期和批次大小dataset_train = dataset_train.repeat(1) # 数据重复生成 1 个周期dataset_test = dataset_test.repeat(1) # 数据重复生成 1 个周期dataset_train = dataset_train.batch(64) # 定义批次大小64dataset_test = dataset_test.batch(64) # 定义批次大小64# 5、处理每批数据# 注意这个 map 和前面的 map 有所不同,第一个 map 在 batch 之前,所以是处理每一条数据# 这个 map 在 batch 之后,所以是处理每一个 batch 的数据dataset_train = dataset_train.map(label_function)dataset_test = dataset_test.map(label_function)# 获取一批次数据和标签trainx, trainy = next(iter(dataset_train))testx, testy = next(iter(dataset_test))# print(trainx)# print(trainy)# print(testx)# print(testy)# 创建神经网络def Create_Network():# 1、构造resnet50神经网络(50层残差网络)resnet50 = ResNet50(weights='imagenet', include_top=False, input_shape=(height, width, 3)) # 设置输入# weights:权重(imagenet:加载预训练权重)# include_top:是否保留顶层的全连接网络# input_shape:指明输入图片的shape,仅当include_top=False有效# 2、设置输入层inputs = Input((height, width, 3)) # 设置输入层大小x = resnet50(inputs) # 使用 resnet50 进行特征提取# 3、平均池化(压缩数据)x = GlobalAvgPool2D()(x)# 4、配置输出层(多任务学习)# 把验证码识别的4个字符看成是4个不同的任务,每个任务负责识别1个字符x0 = Dense(classes_num, activation='softmax', name='out0')(x)x1 = Dense(classes_num, activation='softmax', name='out1')(x)x2 = Dense(classes_num, activation='softmax', name='out2')(x)x3 = Dense(classes_num, activation='softmax', name='out3')(x)# 5、配置模型(输入层、输出层)model = Model(inputs, [x0, x1, x2, x3])# 6、编译(多任务学习)(损失函数、权重、优化器、监视等等设置)# (4个任务我们可以定义4个loss)pile(loss={'out0': 'categorical_crossentropy','out1': 'categorical_crossentropy','out2': 'categorical_crossentropy','out3': 'categorical_crossentropy'},loss_weights={'out0': 1, 'out1': 1, 'out2': 1, 'out3': 1},optimizer=SGD(lr=0.01, momentum=0.9),metrics=['acc'])# loss:损失函数 loss_weights:权重 optimizer:优化器(lr:学习率;momentum:带动量的梯度下降)# metrics:监视(acc)# 7、回调函数(停止训练、保存数据、保存模型、调整学习率)callbacks = [EarlyStopping(monitor='val_loss', patience=6, verbose=1),CSVLogger('Captcha_tfdata.csv'),ModelCheckpoint('Best_Captcha_tfdata.h5', monitor='val_loss', save_best_only=True),ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, verbose=1)]# monitor='val_loss':监控指标'val_loss'# EarlyStopping:让模型停止(6个周期,val_loss没有下降则训练结束)# CSVLogger: 保存训练数据# ModelCheckpoint:保存模型(保存所有训练周期中val_loss最低的模型)# ReduceLROnPlateau 学习率调整,连续3个周期,val_loss没有下降,则当前学习率乘以0.1# 8、训练模型model.fit(x=dataset_train, epochs=epochs, validation_data=dataset_test, callbacks=callbacks)if __name__ == '__main__':# 一、创建验证码数据集# 判断训练集文件夹是否为空if not os.listdir('D:\\Study\\AI\OpenCV\\draft.py\\captcha\\train'):Create_train_data()# 生成验证码训练集# 判断测试集文件夹是否为空if not os.listdir('D:\\Study\\AI\OpenCV\\draft.py\\captcha\\test'):Create_test_data()# 生成验证码测试集# 二、获取数据GetData()# 三、构造神经网络Create_Network()
如果觉得《深度学习 -- TensorFlow(项目)验证码生成与识别(多任务学习)》对你有帮助,请点赞、收藏,并留下你的观点哦!