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

驗證碼示例圖

用於學校組織的人工智能挑戰賽——驗證碼識別賽,因爲數據集的數量有限,所以也用了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)

在這裏插入圖片描述

五.測試結果及優化

模型提交後的準確率結果
kaggle平臺提交結果
後續繼續訓練以及數據增強訓練以後單個模型的準確率是86.733%,從比賽角度上可以生成預測的多個結果csv文件,通過集成學習(Voting投票)獲得最佳的csv文件,或許可以達到90%以上的準確率。此外,可以讀數據集做圖像處理,例如高斯模糊去掉干擾線,灰度圖二值化等去掉干擾背景。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章