深度学习 -- TensorFlow(项目)验证码生成与识别(多任务学习)

目录

基础理论

一、生成验证码数据集

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、预测框内是什么物体预测框的坐标值是连续型数据,所以是一个回归任务预测框的物体是一个具体的类别,所以是一个分类任务

深度学习 -- TensorFlow(项目)验证码生成与识别(多任务学习)

 深度学习 -- TensorFlow(项目)验证码生成与识别(多任务学习)

        不同的任务其实也可以共享卷积层。因为卷积层的作用主要是特征提取,先提取图像的特征,然后再使用这些特征来预测人的年龄,表情,性别。 用于特征提取的卷积层可以共享 ,不过 不同的任务还需要有自己的 task layer,专门用于训练特定任务

 

一、生成验证码数据集

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')

深度学习 -- TensorFlow(项目)验证码生成与识别(多任务学习)

 

2、生成验证码测试集

过程同上,测试集数据不需要那么多,把1000张换成200张即可。

深度学习 -- TensorFlow(项目)验证码生成与识别(多任务学习)

 

代码

# 创建训练集(验证码)
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)

深度学习 -- TensorFlow(项目)验证码生成与识别(多任务学习)

 深度学习 -- TensorFlow(项目)验证码生成与识别(多任务学习)

 

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)         # 定义批次大小64
    dataset_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))

 数据(归一化后的):

深度学习 -- TensorFlow(项目)验证码生成与识别(多任务学习)

标签(独热编码):

深度学习 -- TensorFlow(项目)验证码生成与识别(多任务学习)

三、创建神经网络

# 三、构造神经网络
    Create_Network()

1、创建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个不同的任务,每个任务负责识别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、配置模型

# 5、配置模型(输入层、输出层)
    model = Model(inputs, [x0, x1, x2, x3])

 

6、编译(多任务学习)

损失函数、权重、优化器、监视等等设置。

# 6、编译(多任务学习)(损失函数、权重、优化器、监视等等设置)
    # (4个任务我们可以定义4个loss)
    model.compile(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)

训练效果:

暂时没有训练太多次,不过通过这几次的训练,已经可以看到准确率明显提高了许多。

深度学习 -- TensorFlow(项目)验证码生成与识别(多任务学习)

深度学习 -- TensorFlow(项目)验证码生成与识别(多任务学习)

 

 

总代码

# 验证码生成与识别
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'

import tensorflow as tf
from tensorflow.keras.layers import Dense,GlobalAvgPool2D,Input
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.models import Model
from tensorflow.keras.applications.resnet50 import ResNet50
from tensorflow.keras.callbacks import EarlyStopping,CSVLogger,ModelCheckpoint,ReduceLROnPlateau
import string
import numpy as np
import os
import random
from captcha.image import ImageCaptcha
from 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)         # 定义批次大小64
    dataset_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)
    model.compile(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()

上一篇:实验5:开源控制器实践——POX


下一篇:深度学习·猫狗识别实验 tensorflow 2.0