参考:A Comprehensive guide to Fine-tuning Deep Learning Models in Keras code: github
目录
6.6 自动:用keras.applicaitons.resnet50构建网络
1 为什么要调优:
一个深度神经网络模型,会包含成千上万的参数。参数越多,需要的样本数量也会随之增长。所以当我们在一个小的训练集上建立如此大的神经网络时,模型的泛化能力非常差,就会非常容易发生过拟合。所以实践中,为了在较小的训练集上建立深度神经网络模型并且避免发生过拟合,就会利用调优方法,即:将一个已经在较大的数据集上(例如ImageNet)训练好的网络模型,在自己的小数据集上继续训练。但是要保证,两个数据集不能毫不相关,这样才能保证预训练好的模型所学习到的特征是可以被利用的。
2 什么时候调优:
神经网络的底层学习到的特征,通常是基础特征。通常情况下,当我们的小数据集与预训练所用的大数据集相似时,就可以利用这些基础特征来继续训练网络,即调优。
当我们的数据集具有一些特殊性(医疗,中国书法),我们无法找到在相关领域预训练好的模型,此时就不得不从头开始训练网络了。
当我们的数据集非常小,并且找到的预训练模型的最后几层都是全连接层时,就会非常容易发生过拟合。经验来说,当数据有几千个,那么通过数据增益(翻转、裁剪等),调优后结果还是不错的。
3 调优技巧
- 将最后一层(softmax层)去掉,更换为符合当前任务的softmax层。如ImageNet上预训练的网络执行的是有1000个类别的分类任务,而当前数据集有num_classes个类别,那么就更改为Dense(num_classes,activation='softmax')
- 使用较小的学习率,一般为原lr的十分之一大小(将预训练网络的权重作为初始化权重,比随机效果好得多,所以尽量避免开始就大幅改变权重 )
- 冻结前几层网络的权重(底层学习到的特征都是基础的通用的特征,可以继续使用)
一般框架里面都会有一些预训练好的模型,方便直接调用——keras :application
4 调优方法(VGG16 )
Method 1:从头建立、修改、训练模型
from keras.layers import Input, Dense, Conv2D, MaxPooling2D,Flatten,Dropout,\
Activation,Reshape,merge,ZeroPadding2D,AveragePooling2D
from keras.models import Sequential
from keras.optimizers import SGD
from sklearn.metrics import log_loss
img_rows=224
img_cols=224
channel=3
num_classes=2
batchsize=10
epochs=5
#Method 1
def vgg16_model(img_rows,img_cols,channel=1,num_classes=None):
model=Sequential()
# No.1 two conv layers
model.add(ZeroPadding2D((1,1),input_shape=(img_rows,img_cols,channel)))
model.add(Conv2D(64,(3,3),activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Conv2D(64,(3,3),activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
#No.2 two conv layers
model.add(ZeroPadding2D((1,1)))
model.add(Conv2D(128,(3,3),activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Conv2D(128,(3,3),activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
#No.3 three conv layers
model.add(ZeroPadding2D((1,1)))
model.add(Conv2D(256,(3,3),activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Conv2D(256,(3,3),activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Conv2D(256,(3,3),activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
#No.4 three conv layers
model.add(ZeroPadding2D((1,1)))
model.add(Conv2D(512,(3,3),activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Conv2D(512,(3,3),activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Conv2D(512,(3,3),activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
#No.5 three conv layers
model.add(ZeroPadding2D((1,1)))
model.add(Conv2D(512,(3,3),activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Conv2D(512,(3,3),activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Conv2D(512,(3,3),activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
#No.6 Fully connected
model.add(Flatten())
model.add(Dense(4096,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(4096,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1000,activation='softmax'))
#加载权值(500M)https://drive.google.com/file/d/0Bz7KyqmuGsilT0J5dmRCM0ROVHc/view?usp=sharing
model.load_weights('vgg16_weights.hs')
#去掉最后一层全连接层softmax,替换成符合自己任务的softmax
model.pop()
model.outputs=[model.layers[-1].output]
model.layers[-1].outbound_nodes=[]
model.add(Dense(num_classes,activation='softmax'))
#冻结前10层的权重
for layer in model.layers[:10]:
layer.trainable=False
#调整学习率,缩小十倍
sgd=SGD(lr=0.001,decay=0.000006,momentum=0.9,nesterov=True)
model.compile(optimizer=sgd,loss='categorical_crossentropy',\
metrics=['accuracy'])
return model
vgg16=vgg16_model(img_rows,img_cols,channel,num_classes)
print(vgg16.summary())
history=vgg16.fit(X_train,Y_train,batch_size=batchsize,epochs=epochs,\
validation_data=(X_valid,Y_valid),verbose=1)
#预测
pred_test=vgg16.predict(X_test,batch_size=batchsize,verbose=1)
score=log_loss(Y_test,pred_test)
Method 2: 利用keras application 中现有的模型,读入、修改、训练
from keras.applications.vgg16 import VGG16
VGG16_model=VGG16()
print(type(VGG16_model))#默认Model 函数式类型
print(VGG16_model.summary())
#要改为Sequential序贯类型(线性结构,更为简单),逐层复制
model3=Sequential()
for layer in VGG16_model.layers:
model3.add(layer)
#将 Model类型的VGG16完全复制转化为 Sequential类型
print(model3.summary())
#删除最后一层
model3.layers.pop()
#替换最后一层为适合的softmax层
model3.add(Dense(num_classes,activation='softmax'))
5 调优VGG16 分类Cats. vs Dogs
5.1 准备数据
1 遍历读取目录中的文件方法:for file name in os.listdir(path)
2 openCV读取图片,类型是list,需要转换成array: np.array(data)
3 cv2.resize(image,size),方便转换图像尺寸
4 try ...except...结构,适合 error 处理
5 数据读取后要检查样本分布的均匀性:pd.Series(label).value_counts() #ndarray类型不能直接用value_counts()
#导入工具包
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from sklearn.model_selection import trai