【Fine Tune】神经网络调优总结

参考:A Comprehensive guide to Fine-tuning Deep Learning Models in Keras  code: github

目录

1 为什么要调优:

2 什么时候调优:

3 调优技巧

4 调优方法(VGG16 )

 5 调优VGG16 分类Cats. vs Dogs

5.1 准备数据

5.2 网络结构

5.3 构建网络 

5.3 测试评估

5.4 Explore冻结层数 

6 调优 ResNet50 

6.1 ResNet50 结构特点

6.2 调优问题 

6.3 手动:建立/修改/训练 模型

6.5 预测评估

6.6 自动:用keras.applicaitons.resnet50构建网络

总结


1 为什么要调优:

一个深度神经网络模型,会包含成千上万的参数。参数越多,需要的样本数量也会随之增长。所以当我们在一个小的训练集上建立如此大的神经网络时,模型的泛化能力非常差,就会非常容易发生过拟合。所以实践中,为了在较小的训练集上建立深度神经网络模型并且避免发生过拟合,就会利用调优方法,即:将一个已经在较大的数据集上(例如ImageNet)训练好的网络模型,在自己的小数据集上继续训练。但是要保证,两个数据集不能毫不相关,这样才能保证预训练好的模型所学习到的特征是可以被利用的。

2 什么时候调优:

神经网络的底层学习到的特征,通常是基础特征。通常情况下,当我们的小数据集与预训练所用的大数据集相似时,就可以利用这些基础特征来继续训练网络,即调优。

当我们的数据集具有一些特殊性(医疗,中国书法),我们无法找到在相关领域预训练好的模型,此时就不得不从头开始训练网络了。

当我们的数据集非常小,并且找到的预训练模型的最后几层都是全连接层时,就会非常容易发生过拟合。经验来说,当数据有几千个,那么通过数据增益(翻转、裁剪等),调优后结果还是不错的。

3 调优技巧

  1. 将最后一层(softmax层)去掉,更换为符合当前任务的softmax层。如ImageNet上预训练的网络执行的是有1000个类别的分类任务,而当前数据集有num_classes个类别,那么就更改为Dense(num_classes,activation='softmax')
  2. 使用较小的学习率,一般为原lr的十分之一大小(将预训练网络的权重作为初始化权重,比随机效果好得多,所以尽量避免开始就大幅改变权重 )
  3. 冻结前几层网络的权重(底层学习到的特征都是基础的通用的特征,可以继续使用)                                                                

一般框架里面都会有一些预训练好的模型,方便直接调用——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 train_test_split
from keras.callbacks import EarlyStopping, ReduceLROnPlateau

#准备数据

path="./kaggle/train"  #./是当前目录 ../是父级目录
img_rows=224
img_cols=224
channel=3
IMAGE_SIZE
  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值