在上一章,我們得到了一個.npy檔,裡面裝著4500張男性影像和4500張女性影像。
在這一章,我們將建立訓練模型,並輸出成.h5的檔案
在開始之前,需要理解下列名詞:
- 卷積層
- 池化層
- Onehot encoding
- 平坦層
- 隱藏層
- 輸出層
- 活化函數
- 損失函數
CNN卷積神經網路可分為兩大部分:
- 影像的特徵提取:卷積層、池化層
- 完全連結神經網路:平坦層、隱藏層、輸出層
關於卷積運算:
卷積層的意義是將一個影像進行卷積運算,產生多個影像。 我們在進行影像操作時會使用到濾鏡,不同的濾鏡套用到影像中會產生不同的影像,可幫助程式提取不同的特徵。
關於縮減取樣:
池化層中的Max-Pool運算可將影像進行縮減取樣,例如一張14x14的影像,進行Max-Pool運算後,縮小為7x7的影像。
關於Onehot encoding: 經過Onehot encoding轉換,可幫助程式進行分類。
例如數字3,可轉換為[0,0,0,1,0,0,0,0,0,0]
例如數字8,可轉換為[0,0,0,0,0,0,0,0,1,0]
關於神經網路:
有個公式是:輸出=活化函數(輸入X權重X偏差)
例如現有250個輸入神經元,每個神經元乘上一個權重並加上偏差之後,可以傳遞到第二層(隱藏層)。
在隱藏層又乘上權重並加上偏差之後,可將結果傳達到第三層(輸出層或第二層隱藏層)。
當神經元接收刺激時(輸入X權重+輸出)經過活化函數的運算,大於臨界值會傳遞到下一個神經元。
關於損失函數:
損失函數用以計算誤差,從錯誤中學習。
建立一個train_4500x4500的python檔案,程式碼如下:
import array import sys
import numpy as np
import cv2
import glob
import random from keras.utils
import np_utils from keras.models
import Sequential from keras.layers
import Dense,Dropout,Activation,Flatten from keras.layers
import Conv2D,MaxPooling2D,ZeroPadding2D
#設定亂數種子,讓每次訓練產生的結果相同 np.random.seed(0)
#產生性別標籤清單
labellist=[]
#設定影像寬度、高度
imgwidth=128 imgheight=128
#將上次產生的.npy檔載入至名為x_img_train的Array中 x_img_train=np.load("size128_F4500_M4500.npy")
#設定前4500個影像標籤為女性(用數字1表示)
for i in range(0,4500):
(四個空格)labellist.append(1)
#設定後4500個影像標籤為男性(用數字0表示)
for i in range(4500,9000):
(四個空格)labellist.append(0)
#將性別標籤轉換成Array
y_label_train=np.array(labellist, dtype=np.int32)
#將x_img_train轉換成(9000x128x128x1)的四維陣列 x_img_train=np.reshape(x_img_train,9000,imgwidth,imgheight,1))
#將性別標籤進行Onehot encoding轉換 y_label_train_OneHot=np_utils.to_categorical(y_label_train)
#建立模型
model=Sequential()
#建立卷積層1
model.add(Conv2D(filters=32,kernel_size=(5,5),input_shape=(imgwidth,imgheight,1),activation='relu',padding='same'))
#隨機釋放神經元
model.add(Dropout(rate=0.3))
#建立池化層1
model.add(MaxPooling2D(pool_size=(2,2)))
#建立卷積層2
model.add(Conv2D(filters=64,kernel_size=(5,5),activation='relu',padding='same'))
#隨機釋放神經元
model.add(Dropout(0.3))
#建立池化層2
model.add(MaxPooling2D(pool_size=(2,2)))
#建立卷積層3
model.add(Conv2D(filters=128,kernel_size=(5,5),activation='relu',padding='same'))
#隨機釋放神經元
model.add(Dropout(0.5))
#建立池化層3
model.add(MaxPooling2D(pool_size=(2,2)))
#建立平坦層
model.add(Flatten())
#隨機釋放神經元
model.add(Dropout(rate=0.25))
#建立隱藏層
model.add(Dense(512,activation='relu'))
#隨機釋放神經元
model.add(Dropout(rate=0.4))
#建立輸出層
model.add(Dense(2,activation='softmax'))
#定義訓練方式 model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
#設定訓練用的函數
def training(times):
(四個空格)train_history=model.fit(x_img_train,y_label_train_OneHot,shuffle=True,epochs=times,batch_size=128,verbose=2)
#如未完成訓練,可載入上次產生的訓練檔接續訓練
from keras.models import load_model #model.load_weights("Fiborsis_sex.h5")
#訓練1回,每回訓練20次
for k in range(1):
(四個空格)print('訓練第:',k,'次')
training(20)
#輸出權重
model.save_weights("Fiborsis_sex.h5")
#輸出模型檔
model.save("Fiborsis_sex_result.h5")
程式碼解說: 我們一開始建立影像清單(labellist),並按照上次產生的size128_F4500_M4500.npy檔案中的性別順序填入標籤(女性為1男性為0)。
for i in range(0,4500):
labellist.append(1)
for i in range(4500,9000):
labellist.append(0)
接著對資料進行前置處理。
y_label_train=np.array(labellist, dtype=np.int32) x_img_train=np.reshape(x_img_train,9000,imgwidth,imgheight,1)) y_label_train_OneHot=np_utils.to_categorical(y_label_train)
建立卷積層,讓程式隨機產生32個濾鏡,每個濾鏡為5x5的大小,輸入的形狀為(寬度,長度,1),活化函數為relu 。
model.add(Conv2D(filters=32,kernel_size=(5,5),input_shape=(imgwidth,imgheight,1),activation='relu',padding='same'))
為了防止過度擬合的現象發生,隨機放棄30%的神經元。
model.add(Dropout(rate=0.3))
將圖片縮小,進行縮減取樣。
model.add(MaxPooling2D(pool_size=(2,2)))
再次建立卷積層,共產生64個濾鏡,每個濾鏡為5x5的大小,輸入的形狀為(寬度,長度,1),活化函數為relu 。
model.add(Conv2D(filters=64,kernel_size=(5,5),activation='relu',padding='same'))
隨機放棄30%的神經元。
model.add(Dropout(rate=0.3))
進行縮減取樣(然後依此類推)。
model.add(MaxPooling2D(pool_size=(2,2)))
輸出結果,共有兩種結果 。
model.add(Dense(2,activation='softmax'))
執行訓練,輸入x_img_train,引入y_label_train_OneHot做為參考解答。
啟動shuffle將資料順序打亂。 epochs代表進行幾次訓練周期,batch_size為每一批次共有幾筆資料,verbose=2代表顯示訓練過程。
train_history=model.fit(x_img_train,y_label_train_OneHot,shuffle=True,epochs=times,batch_size=128,verbose=2)
將訓練到一半的model儲存起來,下次可接續訓練(Fiborsis_sex.h5為檔名)
model.save_weights("Fiborsis_sex.h5")
載入上次儲存的模行檔(Fiborsis_sex.h5為檔名)
model.load_weights("Fiborsis_sex.h5")
輸出模型檔 (Fiborsis_sex_result.h5為檔名)
model.save("Fiborsis_sex_result.h5")
在下一個章節,我們將執行訓練檔,並驗證結果。