Keras预训练cnn模型Xception迁移学习验证码识别(大小写字母+数字)

一.模型介绍

Keras官方中文文档
本文使用的是keras预训练的Xception模型
官方介绍如下:

Xception
在 ImageNet 上预训练的 Xception V1 模型。
在 ImageNet 上,该模型取得了验证集 top1 0.790 和 top5 0.945 的准确率。
注意该模型只支持 channels_last 的维度顺序(高度、宽度、通道)。
模型默认输入尺寸是 299x299。
参数
include_top: 是否包括顶层的全连接层。
weights: None 代表随机初始化, ‘imagenet’ 代表加载在 ImageNet 上预训练的权值。
input_tensor: 可选,Keras tensor 作为模型的输入(即 layers.Input() 输出的 tensor)。
input_shape: 可选,输入尺寸元组,仅当 include_top=False 时有效(否则输入形状必须是 (299, 299, 3),因为预训练模型是以这个大小训练的)。它必须拥有 3 个输入通道,且宽高必须不小于 71。例如 (150, 150, 3) 是一个合法的输入尺寸。
pooling: 可选,当 include_top 为 False 时,该参数指定了特征提取时的池化方式。
None 代表不池化,直接输出最后一层卷积层的输出,该输出是一个 4D 张量。
‘avg’ 代表全局平均池化(GlobalAveragePooling2D),相当于在最后一层卷积层后面再加一层全局平均池化层,输出是一个 2D 张量。
‘max’ 代表全局最大池化。
classes: 可选,图片分类的类别数,仅当 include_top 为 True 并且不加载预训练权值时可用。
返回值
一个 Keras Model 对象.

keras.applications.xception.Xception(include_top=True, weights='imagenet', input_tensor=None, input_shape=None, pooling=None, classes=1000)

二.数据集准备

回到验证码识别上,大小写字母+数字一共有62个类别


# 用于生成验证码的字符集
CHAR_SET = ['0', '1', '2', '3', '4', '5', '6', '7', '8', 
'9','A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z']
# 字符集的长度
CHAR_SET_LEN = 62
# 验证码的长度,每个验证码由4个数字组成
CAPTCHA_LEN = 4

captcha 是用 python 写的生成验证码的库,它支持图片验证码和语音验证码,我们使用的是它生成图片验证码的功能。

pip install captcha

验证码生成

import os
import shutil
import random
import time
from captcha.image import ImageCaptcha
# 用于生成验证码的字符集
CHAR_SET = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
# 字符集的长度
CHAR_SET_LEN = 62
# 验证码的长度,每个验证码由4个数字组成
CAPTCHA_LEN = 4
# 验证码图片的存放路径
CAPTCHA_IMAGE_PATH = 'train/'
# 用于模型测试的验证码图片的存放路径,它里面的验证码图片作为测试集
TEST_IMAGE_PATH = 'test/'
# 用于模型测试的验证码图片的个数,从生成的验证码图片中取出来放入测试集中
TEST_IMAGE_NUMBER = 2000
# 生成验证码图片,4位的十进制数字可以有10000种验证码
def generate_captcha_image(charSet=CHAR_SET, charSetLen=CHAR_SET_LEN, captchaImgPath=CAPTCHA_IMAGE_PATH):
    k = 0
    list=[]
    for i in range(20001):
        captcha_text=''

        for i in range(4):
            captcha_text += charSet[random.randint(0, 61)]
        temp_captcha=captcha_text.upper()
        #Windows文件名称不区分大小写,避免生成的验证码重复,用list存储
        if temp_captcha not in list:
            list.append(temp_captcha)
        #  fonts = ['./simsun.ttc'],可以加载字体文件生成不同字体的验证码
        #     image = ImageCaptcha(fonts = ['./simsun.ttc'],width=180,height=60)
            image = ImageCaptcha( width=120, height=40)
            image.write(captcha_text, captchaImgPath + captcha_text + '.jpg')
            k += 1
        else:
            continue

# 从验证码的图片集中取出一部分作为测试集,这些图片不参加训练,只用于模型的测试
def prepare_test_set():
    fileNameList = []
    for filePath in os.listdir(CAPTCHA_IMAGE_PATH):
        captcha_name = filePath.split('/')[-1]
        fileNameList.append(captcha_name)
    random.seed(time.time())
    random.shuffle(fileNameList)
    for i in range(TEST_IMAGE_NUMBER):
        name = fileNameList[i]
        shutil.move(CAPTCHA_IMAGE_PATH + name, TEST_IMAGE_PATH + name)
if __name__ == '__main__':
    generate_captcha_image(CHAR_SET, CHAR_SET_LEN, CAPTCHA_IMAGE_PATH)
    prepare_test_set()

Keras预训练cnn模型Xception迁移学习验证码识别(大小写字母+数字)_第1张图片

用于学校组织的人工智能挑战赛——验证码识别赛,因为数据集的数量有限,所以也用了imgaug库的数据增强,噪声+对比度变换

验证码数据增强

pip install imgaug
from imgaug import augmenters as iaa
seq = iaa.SomeOf((1, 3), [
    iaa.AdditiveGaussianNoise(loc=0, scale=(0.0, 0.1 * 255), per_channel=0.3),  
    iaa.AdditiveGaussianNoise(loc=1, scale=(0.01, 0.08*255)),
     iaa.ContrastNormalization((0.75, 1.5),per_channel=True),
     #0.75-1.5随机数值为alpha,对图像进行对比度增强,该alpha应用于每个通道
    iaa.AdditiveGaussianNoise(loc=0, scale=(0.0, 0.3*255), per_channel=0.5), 
    # loc 噪声均值,scale噪声方差,50%的概率,对图片进行添加白噪声并应用于每个通道
    iaa.Multiply((0.8, 1.2), per_channel=0.2), 
    #20%的图片像素值乘以0.8-1.2中间的数值           
 ],random_order=True)
imgs_aug = seq.augment_images(imgs)

数据集文件

链接:https://pan.baidu.com/s/1u4IP4cspT0_g7PnbEZw9mw
提取码:0qji
复制这段内容后打开百度网盘手机App,操作更方便哦(手动狗头doge.jpg)
另外我放的是我没有修改过的数据集,网盘里的图片不是按照xxxx.jpg这种格式的,
而是1.jpg这种按顺序的,不过有对应标签的csv文件,为了方便我就把图片用对应的label重命名了一下,数据集读取的时候也可以用csv文件来读取数据,id是图片名称,label是对应标签,文件路径+id的方式读取图片和对应图片的label

三.模型训练

import numpy as np
import glob
from keras.applications.xception import Xception, preprocess_input
from keras.engine.saving import load_model
from keras.layers import Input, Dense, Dropout
from keras.models import Model
from scipy import misc

#数据集文件夹里train是训练文件位置,验证码图片命名为 xxxx.jpg,图片名称就是验证码的label
samples = glob.glob('./train/*.jpg')  # 获取所有样本图片
np.random.shuffle(samples)  # 将图片打乱
nb_train = 18000  # 共有2万样本,1.8万用于训练,2k用于验证
train_samples = samples[:nb_train]
test_samples = samples[nb_train:]
img_size = (40, 120)
input_image = Input(shape=(img_size[0], img_size[1], 3))
# 直接将验证码输入,做几个卷积层提取特征,然后把这些提出来的特征连接62个分类器,
# 输入图片
# 用预训练的Xception提取特征,采用平均池化
base_model = Xception(input_tensor=input_image, weights='imagenet', include_top=False, pooling='avg')
# 用全连接层把图片特征接上softmax然后62分类,dropout为0.5
# Softmax - 用于多分类神经网络输出
predicts = [Dense(62, activation='softmax')(Dropout(0.5)(base_model.output)) for i in range(4)]

model = Model(inputs=input_image, outputs=predicts)
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

# model = load_model('./CaptchaXception.h5')#可以加载模型继续训练
def data_generator(data, batch_size):  # 样本生成器,节省内存
    while True:
        # 生成一个从x中抽取的随机数,维度为y的向量,y为抽取次数
        batch = np.random.choice(data, batch_size)
        x, y = [], []
        for img in batch:
            x.append(misc.imresize(misc.imread(img), img_size))  # 读取resize图片,再存进x列表
            imglabel=str(img).split('\\')[1].split('.')[0]
            label=str(imglabel)
            # print(label)
            y_list = []
            for i in label:
                # i = i.upper()
                if 48 <= ord(i) <= 57:
                    y_list.append(ord(i) - 48)
                if 65 <= ord(i) <= 90:
                    y_list.append(ord(i) - 55)
                if 97 <= ord(i) <= 122:
                    y_list.append(ord(i) - 61)
            y.append(y_list)
        # 把验证码标签添加到y列表,把对应字母转化为数字
        x = preprocess_input(np.array(x).astype(float))
        # 原先是dtype=uint8转成一个纯数字的array
        y = np.array(y)
        yield x, [y[:, i] for i in range(4)]
        # 输出:图片array和四个转化成数字的字母 例如:[array([6]), array([0]), array([3]), array([24])])
ep=10
#持续训练,epoch每10次保存一个模型,下方代码中data_generator(train_samples, 48)是
#每次读取48个数据,就是batchsize,steps_per_epoch是每轮训练的次数,#validation_data是验证集的设置
while True:
    model.fit_generator(data_generator(train_samples, 48), steps_per_epoch=375, epochs=10,
                    validation_data=data_generator(test_samples, 48), validation_steps=40)
    model.save('CaptchaXception'+str(ep)+'.h5')
    ep+=10
# 保存模型

四. 模型测试

生成验证的csv文件

import os

from keras.models import load_model
import numpy as np
from scipy import misc
from keras.applications.xception import preprocess_input
import matplotlib.pyplot as plt  # plt 用于显示图片
import matplotlib.image as mpimg  # mpimg 用于读取图片
import glob
import pandas as pd
img_size = (40, 120)
model = load_model('./CaptchaXception30.h5')
letter_list = [chr(i) for i in range(48, 58)] +[chr(i) for i in range(65, 91)]+[chr(i) for i in range(97, 123)]
def predict(img):
    x = []
    x.append(misc.imresize(misc.imread(img), img_size))
    x = preprocess_input(np.array(x).astype(float))
    z = model.predict(x)
    # print(z)
    z = np.array([i.argmax(axis=1) for i in z]).T
    # print(z)
    # print('----------------------')
    result = z.tolist()
    v = []
    for i in range(len(result)):
        for j in result[i]:
            v.append(letter_list[j])
    # image = mpimg.imread(test_samples1[n])
    # plt.axis('off')
    # plt.imshow(image)
    # plt.show()
    #输出测试结果
    str = ''
    for i in v:
        str += i
    return (str)
# print(predict1('./dataset/train/3.jpg'))
def pack(file_names, labels):
    frame = pd.DataFrame({'ID':file_names,'label':labels},columns=['ID','label'])
    return frame
imgpath='./test/'
imglist=os.listdir(imgpath)
imglist.sort(key=lambda x:int(x[:-4]))
predict_file_name=[]
labels=[]
for i in imglist:
    predict_file_name.append(str(i))
    # print(imgpath+str(i))
    label=predict(imgpath+str(i))
    # print(label)
    labels.append(label)
frame = pack(predict_file_name, labels)
frame.to_csv('./04.csv', index=False)

Keras预训练cnn模型Xception迁移学习验证码识别(大小写字母+数字)_第2张图片

五.测试结果及优化

模型提交后的准确率结果
kaggle平台提交结果
后续继续训练以及数据增强训练以后单个模型的准确率是86.733%,从比赛角度上可以生成预测的多个结果csv文件,通过集成学习(Voting投票)获得最佳的csv文件,或许可以达到90%以上的准确率。此外,可以读数据集做图像处理,例如高斯模糊去掉干扰线,灰度图二值化等去掉干扰背景。

你可能感兴趣的:(Keras预训练cnn模型Xception迁移学习验证码识别(大小写字母+数字))