【Keras篇】---利用keras改寫VGG16經典模型在手寫數字識別體中的應用


一、前述

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)

 結果:

 自定義的網絡層:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM