深度学习-迁移学习流程及代码解析

迁移学习

是机器学习方法之一,它可以把为一个任务开发的模型重新用在另一个不同的任务中,并作为另一个任务模型的起点。

这在深度学习中是一种常见的方法。由于在计算机视觉和自然语言处理上,开发神经网络模型需要大量的计算和时间资源,技术跨度也比较大。所以,预训练的模型通常会被重新用作计算机视觉和自然语言处理任务的起点。

迁移学习一般流程

  1. 训练好一个网络(base network)
  2. 把前n层复制到target network的前n层
  3. target network剩下的其他层随机初始化
  4. 开始训练target task。在做backpropogate(反向传播)的时候

有两种方法:

  • 把迁移过来的这前n层frozen(冻结)起来,即在训练target task的时候,不改变这n层的值;
  • 不冻结这前n层,而是会不断调整它们的值,称为fine-tune(微调)。

这个主要取决于target数据集的大小和前n层的参数个数,

如果target数据集很小,而参数个数很多,为了防止overfitting(过拟合),

通常采用frozen方法;反之,采用fine-tune。

Keras模型

Kera的应用模块Application提供了带有预训练权重的Keras模型,这些模型可以用来进行预测、特征提取和迁移学习/finetune。

比如常见模型:

  • Xception
  • VGG16
  • VGG19
  • ResNet50
  • InceptionV3

vgg16_weights_th_dim_ordering_th_kernels_notop.h5

vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5

vgg16_weights_tf_dim_ordering_tf_kernels.h5

对于tf和th说明

Keras提供了两套后端,Theano和Tensorflow,

th和tf的大部分功能都被backend统一包装起来了,但二者还是存在冲突,

比如:

dim_ordering,也就是维度顺序。比方说一张224*224的彩色图片,theano的维度顺序是(3,224,224),即通道维在前。而tf的维度顺序是(224,224,3),即通道维在后。

所以不同的后端,需要选用不同的权重文件。

notop说明:

是否包含最后的全连接层,notop表示没有包括最后的全连接层。

为何把全连接层和卷积层分开:

一般来说卷积层用于特征提取,全连接层用于分类。这也是为什么一般来说,在较多的情况下,卷积层的权重进行冻结或finetune,而全连接层用于重新设计和新的训练。当然,如果在包括全连接层的情况下,根据已有模型与自己分类任务的契合度,也是可以用新的数据进行finetune全连接层的。

流程分析:

1. 训练好一个网络(称它为base network)

2. 把它的前n层复制到target network的前n层

3. target network剩下的其他层随机初始化

注意看前面讲过的迁移学习的基本流程,是把已有模型的前n层的权重数据复制来,大家是否有思考过这个n怎么来合理的确定呢?

根据前面的讲述,一般这个n层就是前面的所有卷积层,但是在实际应用中,是可以根据实验来测试一个更加有效的n值,即:只是固定使用或finetune部分的卷积层,其他卷积层仍然是随机初始化后进行训练。

VGG16的一个例子分析


# coding: utf-8

# In[1]:

import numpy as np

from keras.datasets import mnist

import gc

from keras.models import Sequential, Model

from keras.layers import Input, Dense, Dropout, Flatten

from keras.layers.convolutional import Conv2D, MaxPooling2D

from keras.applications.vgg16 import VGG16

from keras.optimizers import SGD

import cv2

import h5py as h5py

import numpy as np

# In[2]:

def tran_y(y):

y_ohe = np.zeros(10)

y_ohe[y] = 1

return y_ohe

# In[4]:

# 直接使用下载的数据

data_dir = 'F:/2019-notebook/2017_2018_2/python_code/MTrain/MachineLearn/3_ML/20_TransferLearn/'

path=data_dir + 'mnist.npz'

f = np.load(path)

X_train, y_train = f['x_train'], f['y_train']

X_test, y_test = f['x_test'], f['y_test']

#(X_train, y_train), (X_test, y_test) = mnist.load_data()

# print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)

# VGG模型需要的图像的大小至少48,三个通道

ishape=48

X_train = [cv2.cvtColor(cv2.resize(i, (ishape, ishape)), cv2.COLOR_GRAY2BGR) for i in X_train]

#(48,48,3) -> (60000,48,48,3)

X_train = np.concatenate([arr[np.newaxis] for arr in X_train]).astype('float32')

X_train /= 255.0

X_test = [cv2.cvtColor(cv2.resize(i, (ishape, ishape)), cv2.COLOR_GRAY2BGR) for i in X_test]

X_test = np.concatenate([arr[np.newaxis] for arr in X_test]).astype('float32')

X_test /= 255.0

#0-9 转为one hot数据

# 0 -> 1 0 0 0 0 0 0 0 0 0

# 1 -> 0 1 0 0 0 0 0 0 0 0

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))])

y_train_ohe = y_train_ohe.astype('float32')

y_test_ohe = y_test_ohe.astype('float32')

# In[4]:

print(X_train.shape)

# VGG16 全参重训迁移学习,包括卷积层参数,在原来的基础上训练

# In[5]:

# 使用已经下载的权重

# 如果使用weights = 'imagenet'参数,系统会自动将model文件下载到 C:\\Users\\Think\\.keras\\models

# model_vgg = VGG16(include_top = False, weights = 'imagenet', input_shape = (ishape,ishape,3))

weights_path = data_dir + 'vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5'

model_vgg = VGG16(include_top = False, weights = weights_path, input_shape = (ishape,ishape,3))

# 卷积层的权重也参与训练

for layer in model_vgg.layers:

layer.trainable = True

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_vgg_mnist = Model(model_vgg.input, model, name = 'vgg16')

model_vgg_mnist.compile(loss = 'categorical_crossentropy', optimizer = 'adagrad', metrics = ['accuracy'])

model_vgg_mnist.summary()

# In[6]:

# fine tune

model_vgg_mnist.fit(X_train, y_train_ohe, validation_data = (X_test, y_test_ohe), epochs = 2, batch_size = 128)

# 直接使用VGG16如果发现拟合效果不好。一个解决办法是将卷积层的参数固化,不参与训练,只是训练全连接层权重。

深度学习-迁移学习流程及代码解析

样本迁移



分享到:


相關文章: