上一篇咱們對圖片作了預處理,構建了數據集,今天咱們就要用這個數據集來訓練神經網絡了。
咱們拿到任何一個數據集都要先進行觀察。一是咱們本身要學會分辨,這樣才能更有針對性的指導神經網絡來分類;二是要看咱們要處理的問題的複雜度,這樣也是便於瞭解咱們的神經網絡要有多複雜(或者多「深」)。html
上圖是咱們的數據集的截圖。觀察發現「0」、「1」、「9」,「I」,「O」這五個字符是沒有圖片的,那是咱們的數據集錯了嗎?檢查原始的驗證碼圖片發現,確實沒有這幾個字符。其實認真想一下就能知道,這幾個都是容易與別的字符產生混淆的字符,因此大機率是在生成驗證碼的時候就能夠把它們剔除了,在這裏也要爲這個程序員的細心點個贊~另外,觀察還發現每一個字符文件夾下面的圖片數量是差很少的,這樣也是爲了讓神經網絡能不偏不倚的爲每個字符尋找最優的參數。python
說了這麼多,終於要開始設計神經網絡了。用Python
編寫神經網絡的庫有不少,好比TensorFlow
、PyTorch
和Keras
等等,這裏咱們不討論各自的優劣勢,個人工做中用的是Keras
,因此這裏咱們採用Keras
。git
由於是圖像分類,因此咱們使用在圖像類任務中最經常使用到的神技——卷積神經網絡(CNN)。程序員
from keras.layers import Flatten, Input, Dropout, Conv2D, MaxPooling2D, Dense from keras.models import Model from keras.optimizers import Adam def model(input_size, class_num): input = Input(shape=input_size) x = Conv2D(16, (3,3), activation='relu', padding='same')(input) x = MaxPooling2D((2,2), strides=(2,2))(x) x = Conv2D(64, (3,3), activation='relu', padding='same')(input) x = MaxPooling2D((2,2), strides=(2,2))(x) x = Conv2D(256, (3,3), activation='relu', padding='same')(input) x = MaxPooling2D((2,2), strides=(2,2))(x) x = Flatten()(x) x = Dense(1024, activation='relu')(x) x = Dropout(0.5)(x) x = Dense(2048, activation='relu')(x) x = Dropout(0.5)(x) x = Dense(class_num, activation='softmax')(x) model = Model(input=input, output = x) model.compile(optimizer=Adam(lr=1e-4), loss='categorical_crossentropy', metrics=['accuracy']) return model
這基本上就是一個最簡單的CNN了,模型結構大體以下圖:github
就是簡單的卷積-池化-卷積-池化-卷積-池化-全鏈接-全鏈接-dropout結構,由於問題很簡單,因此模型結構不須要多複雜。網絡
網絡設計好了,就能夠準備開始訓練了,也就是想辦法把訓練圖片喂到模型裏面讓它自動更新各項參數。由於咱們前期其實已經作好了部分工做,因此只須要按照類別讀取圖片,而後輸入到模型中區便可,讀取圖片並生成標籤的代碼以下:app
image_path = './chars' data = [] labels = [] imagePaths = [] for label in os.listdir(image_path): for image in os.listdir(os.path.join(image_path, label)): imagePaths.append(os.path.join(image_path, label, image)) # 拿到圖像數據路徑,方便後續讀取 imagePaths = sorted(imagePaths) random.seed(42) random.shuffle(imagePaths) # 遍歷讀取數據 for imagePath in imagePaths: # 讀取圖像數據 image = cv2.imread(imagePath, 0) image = cv2.resize(image, (16, 16)) image = np.expand_dims(image, axis=-1) data.append(image) # 讀取標籤 label = imagePath.split(os.path.sep)[-2] labels.append(label) # 對圖像數據作scale操做 data = np.array(data, dtype="float") / 255.0 labels = np.array(labels) # 數據集切分 (trainX, testX, trainY, testY) = train_test_split(data, labels, test_size=0.25, random_state=42) # 轉換標籤爲one-hot encoding格式 lb = LabelBinarizer() trainY = lb.fit_transform(trainY) testY = lb.transform(testY)
訓練模型的代碼以下:dom
print("------準備訓練網絡------") # 設置初始化超參數 EPOCHS = 50 BS = 16 # 創建卷積神經網絡 model = model(input_size=(16,16,1), class_num=31) H = model.fit(trainX, trainY, validation_data=(testX, testY), epochs=EPOCHS, batch_size=BS)
訓練模型的代碼反而最少,是否是發現訓練一個神經網絡其實根本就不難。ide
來看一下訓練神經網絡時的輸出:性能
Train on 332 samples, validate on 111 samples Epoch 1/50 16/332 [>.............................] - ETA: 7s - loss: 3.4399 - accuracy: 0.0625 32/332 [=>............................] - ETA: 4s - loss: 3.4547 - accuracy: 0.0312 48/332 [===>..........................] - ETA: 3s - loss: 3.4442 - accuracy: 0.0208 64/332 [====>.........................] - ETA: 2s - loss: 3.4401 - accuracy: 0.0312 80/332 [======>.......................] - ETA: 2s - loss: 3.4368 - accuracy: 0.0250 96/332 [=======>......................] - ETA: 2s - loss: 3.4366 - accuracy: 0.0208 112/332 [=========>....................] - ETA: 1s - loss: 3.4371 - accuracy: 0.0179 128/332 [==========>...................] - ETA: 1s - loss: 3.4373 - accuracy: 0.0156 144/332 [============>.................] - ETA: 1s - loss: 3.4358 - accuracy: 0.0139 160/332 [=============>................] - ETA: 1s - loss: 3.4337 - accuracy: 0.0188 176/332 [==============>...............] - ETA: 1s - loss: 3.4330 - accuracy: 0.0170 192/332 [================>.............] - ETA: 1s - loss: 3.4310 - accuracy: 0.0156 208/332 [=================>............] - ETA: 0s - loss: 3.4313 - accuracy: 0.0192 224/332 [===================>..........] - ETA: 0s - loss: 3.4325 - accuracy: 0.0179 240/332 [====================>.........] - ETA: 0s - loss: 3.4300 - accuracy: 0.0208 256/332 [======================>.......] - ETA: 0s - loss: 3.4315 - accuracy: 0.0195 272/332 [=======================>......] - ETA: 0s - loss: 3.4334 - accuracy: 0.0184 288/332 [=========================>....] - ETA: 0s - loss: 3.4341 - accuracy: 0.0208 304/332 [==========================>...] - ETA: 0s - loss: 3.4349 - accuracy: 0.0197 320/332 [===========================>..] - ETA: 0s - loss: 3.4315 - accuracy: 0.0281 332/332 [==============================] - 2s 7ms/step - loss: 3.4340 - accuracy: 0.0271 - val_loss: 3.4193 - val_accuracy: 0.0270
神經網絡會在運行每個Epoch時更新參數,這樣不停更新,最後達到最優:
Epoch 50/50 16/332 [>.............................] - ETA: 1s - loss: 0.0155 - accuracy: 1.0000 32/332 [=>............................] - ETA: 1s - loss: 0.0132 - accuracy: 1.0000 48/332 [===>..........................] - ETA: 1s - loss: 0.0259 - accuracy: 1.0000 64/332 [====>.........................] - ETA: 1s - loss: 0.0289 - accuracy: 1.0000 80/332 [======>.......................] - ETA: 1s - loss: 0.0247 - accuracy: 1.0000 96/332 [=======>......................] - ETA: 1s - loss: 0.0271 - accuracy: 1.0000 112/332 [=========>....................] - ETA: 1s - loss: 0.0251 - accuracy: 1.0000 128/332 [==========>...................] - ETA: 1s - loss: 0.0243 - accuracy: 1.0000 144/332 [============>.................] - ETA: 1s - loss: 0.0230 - accuracy: 1.0000 160/332 [=============>................] - ETA: 1s - loss: 0.0234 - accuracy: 1.0000 176/332 [==============>...............] - ETA: 0s - loss: 0.0318 - accuracy: 0.9943 192/332 [================>.............] - ETA: 0s - loss: 0.0372 - accuracy: 0.9896 208/332 [=================>............] - ETA: 0s - loss: 0.0354 - accuracy: 0.9904 224/332 [===================>..........] - ETA: 0s - loss: 0.0395 - accuracy: 0.9866 240/332 [====================>.........] - ETA: 0s - loss: 0.0521 - accuracy: 0.9833 256/332 [======================>.......] - ETA: 0s - loss: 0.0491 - accuracy: 0.9844 272/332 [=======================>......] - ETA: 0s - loss: 0.0531 - accuracy: 0.9816 288/332 [=========================>....] - ETA: 0s - loss: 0.0510 - accuracy: 0.9826 304/332 [==========================>...] - ETA: 0s - loss: 0.0488 - accuracy: 0.9836 320/332 [===========================>..] - ETA: 0s - loss: 0.0488 - accuracy: 0.9844 332/332 [==============================] - 2s 6ms/step - loss: 0.0478 - accuracy: 0.9849 - val_loss: 0.0197 - val_accuracy: 0.9910
下面是整個訓練過程當中,各項參數值的曲線:
簡單的,就是在訓練過程當中,不管是訓練集仍是驗證集,它們的損失值不斷降低到無限接近於0,而模型的準確率則無限接近於1.
咱們隨便拿兩個字符來進行測試:
測試代碼以下:
# 加載測試數據並進行相同預處理操做 image = cv2.imread('./test_chars/3/1.jpg', 0) output = image.copy() image = cv2.resize(image, (16, 16)) # scale圖像數據 image = image.astype("float") / 255.0 image = np.expand_dims(image, axis=-1) # 對圖像進行拉平操做 image = image.reshape((1, image.shape[0], image.shape[1],image.shape[2])) # 讀取模型和標籤 print("------讀取模型和標籤------") model = load_model('./output/cnn.model') lb = pickle.loads(open('./output/cnn_lb.pickle', "rb").read()) # 預測 preds = model.predict(image) # 獲得預測結果以及其對應的標籤 i = preds.argmax(axis=1)[0] label = lb.classes_[i] # 在圖像中把結果畫出來 text = "{}: {:.2f}%".format(label, preds[0][i] * 100) print(text)
輸出結果爲:
再試一張:
輸出結果爲:
兩次實驗的結果都代表,咱們的神經網絡模型的性能是能夠的。
至此,驗證碼的識別就講完了。
本系列的全部源代碼都會放在下面的github倉庫裏面,有須要能夠參考,有問題歡迎指正,謝謝!
https://github.com/TitusWongCN/AutoTokenAppointment
獲得最新消息,最新的記念幣將於本月19號開始預定,因此本系列也立刻會在這個時間左右完結。敬請期待最後的自動預定部分~