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