一、前述
VGG16是由16層神經網路構成的經典模型,包括多層卷積,多層全連線層,一般我們改寫的時候卷積層基本不動,全連線層從後面幾層依次向前改寫,因為先改引數較小的。
二、具體
1、因為本文中程式碼需要依賴OpenCV,所以第一步先安裝OpenCV
因為VGG要求輸入244*244,而資料集是28*28的,所以需要通過OpenCV在程式碼裡去改變。
2、把模型下載後離線放入使用者的管理目錄下面,這樣訓練的時候就不需要從網上再下載了
3、我們保留的是除了全連線的所有層。
4、選擇資料生成器,在真正使用的時候才會生成資料,載入到記憶體,前面yield只是做了一個標記
程式碼:
# 使用遷移學習的思想,以VGG16作為模板搭建模型,訓練識別手寫字型 # 引入VGG16模組 from keras.applications.vgg16 import VGG16 # 其次載入其他模組 from keras.layers import Input from keras.layers import Flatten from keras.layers import Dense from keras.layers import Dropout from keras.models import Model from keras.optimizers import SGD # 載入字型庫作為訓練樣本 from keras.datasets import mnist # 載入OpenCV(在命令列中視窗中輸入pip install opencv-python),這裡為了後期對影像的處理, # 大家使用pip install C:\Users\28542\Downloads\opencv_python-3.4.1+contrib-cp35-cp35m-win_amd64.whl # 比如尺寸變化和Channel變化。這些變化是為了使影像滿足VGG16所需要的輸入格式 import cv2 import h5py as h5py import numpy as np # 建立一個模型,其型別是Keras的Model類物件,我們構建的模型會將VGG16頂層(全連線層)去掉,只保留其餘的網路 # 結構。這裡用include_top = False表明我們遷移除頂層以外的其餘網路結構到自己的模型中 # VGG模型對於輸入影像資料要求高寬至少為48個畫素點,由於硬體配置限制,我們選用48個畫素點而不是原來 # VGG16所採用的224個畫素點。即使這樣仍然需要24GB以上的記憶體,或者使用資料生成器 model_vgg = VGG16(include_top=False, weights='imagenet', input_shape=(48, 48, 3))#輸入進來的資料是48*48 3通道 #選擇imagnet,會選擇當年大賽的初始引數 #include_top=False 去掉最後3層的全連線層看原始碼可知 for layer in model_vgg.layers: layer.trainable = False#別去調整之前的卷積層的引數 model = Flatten(name='flatten')(model_vgg.output)#去掉全連線層,前面都是卷積層 model = Dense(4096, activation='relu', name='fc1')(model) model = Dense(4096, activation='relu', name='fc2')(model) model = Dropout(0.5)(model) model = Dense(10, activation='softmax')(model)#model就是最後的y model_vgg_mnist = Model(inputs=model_vgg.input, outputs=model, name='vgg16') #把model_vgg.input X傳進來 #把model Y傳進來 就可以訓練模型了 # 列印模型結構,包括所需要的引數 model_vgg_mnist.summary() #以下是原版的模型結構 224*224 model_vgg = VGG16(include_top=False, weights='imagenet', input_shape=(224, 224, 3)) for layer in model_vgg.layers: layer.trainable = False#別去調整之前的卷積層的引數 model = Flatten()(model_vgg.output) model = Dense(4096, activation='relu', name='fc1')(model) model = Dense(4096, activation='relu', name='fc2')(model) model = Dropout(0.5)(model) model = Dense(10, activation='softmax', name='prediction')(model) model_vgg_mnist_pretrain = Model(model_vgg.input, model, name='vgg16_pretrain') model_vgg_mnist_pretrain.summary() # 新的模型不需要訓練原有卷積結構裡面的1471萬個引數,但是注意引數還是來自於最後輸出層前的兩個 # 全連線層,一共有1.2億個引數需要訓練 sgd = SGD(lr=0.05, decay=1e-5)#lr 學習率 decay 梯度的逐漸減小 每迭代一次梯度就下降 0.05*(1-(10的-5))這樣來變 #隨著越來越下降 學習率越來越小 步子越小 model_vgg_mnist.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy']) # 因為VGG16對網路輸入層需要接受3通道的資料的要求,我們用OpenCV把影像從32*32變成224*224,把黑白影像轉成RGB影像 # 並把訓練資料轉化成張量形式,供keras輸入 (X_train, y_train), (X_test, y_test) = mnist.load_data("../test_data_home") X_train, y_train = X_train[:1000], y_train[:1000]#訓練集1000條 X_test, y_test = X_test[:100], y_test[:100]#測試集100條 X_train = [cv2.cvtColor(cv2.resize(i, (48, 48)), cv2.COLOR_GRAY2RGB) for i in X_train]#變成彩色的 #np.concatenate拼接到一起把 X_train = np.concatenate([arr[np.newaxis] for arr in X_train]).astype('float32') X_test = [cv2.cvtColor(cv2.resize(i, (48, 48)), cv2.COLOR_GRAY2RGB) for i in X_test] X_test = np.concatenate([arr[np.newaxis] for arr in X_test]).astype('float32') print(X_train.shape) print(X_test.shape) X_train = X_train / 255 X_test = X_test / 255 def tran_y(y): y_ohe = np.zeros(10) y_ohe[y] = 1 return y_ohe y_train_ohe = np.array([tran_y(y_train[i]) for i in range(len(y_train))]) y_test_ohe = np.array([tran_y(y_test[i]) for i in range(len(y_test))]) model_vgg_mnist.fit(X_train, y_train_ohe, validation_data=(X_test, y_test_ohe), epochs=100, batch_size=50)
結果:
自定義的網路層: