Keras学习2:使用自己的数据实现迁移学习微调VGG-16

Why Keras?

由于TensorFlow更加注重底层设计,加载别人训练好的模型进行迁移学习非常麻烦,因此在这种场景下更多地使用Keras、TensorLayer等高层API

基于Keras和VGG-16的迁移学习

VGG-16是目前最常用的CNN之一,其网络结构不再赘述

大多数图像分类问题的数据规模通常较小(训练样本量基本上在10k以下),使用随机初始化的CNN进行训练,往往效果不好。此时最常用的解决方案就是加载在大数据集(如ImageNet)上训练好的模型,在其基础上根据实际问题调整分类层节点数,随后使用自己的数据进行微调训练。此时训练可以分两步:

第一步:锁定预训练模型,仅针对新添加层进行训练

from keras.applications.vgg16 import VGG16
from keras.models import Model, load_model
from keras.layers import Dense, Input, Dropout, Softmax, Flatten
from keras.optimizers import RMSprop, Adam
from keras.utils.np_utils import to_categorical

N_TRAIN = 5
N_CLASSES = 635
BATCH_SIZE = 32
MAX_EPOCH = 50

# load data
x_train, y_train, x_val, y_val = get_fv_data(N_TRAIN, N_CLASSES) # 该函数用于读取数据集,根据自己的实际情况调整
y_train = to_categorical(y_train, num_classes=N_CLASSES) # 使用keras.utils.np_utils.to_categorical将标签转化为one-hot形式
y_val = to_categorical(y_val, num_classes=N_CLASSES)

# bulid network
inputs = Input(shape=[224, 224, 3])
base_model = VGG16(include_top=False, weights='imagenet', input_tensor=inputs)
for l in base_model.layers:
    l.trainable = False # 第一步锁定前层,不进行训练
fla = Flatten()(base_model.output)
fc6 = Dense(4096, activation='relu')(fla) # 新增加的待训练全连接层fc6
drop6 = Dropout(rate=0.5)(fc6)
fc7 = Dense(4096, activation='relu')(drop6) # 新增加的待训练全连接层fc7
drop7 = Dropout(rate=0.5)(fc7)
fc8 = Dense(N_CLASSES, activation='softmax')(drop7) # 新增加的待训练全连接层fc8,节点数等于分类类别数
model = Model(inputs=inputs, outputs=fc8) # 完成Model构建

# compile model
optimizer = Adam(lr=0.00001)
model.summary() # 可打印模型概况
model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])
# train
model.fit(x_train, y_train, batch_size=BATCH_SIZE, epochs=MAX_EPOCH)
# save model to h5 file
model.save(filepath='./fv_vgg16.h5')
# evaluate
loss, accu = model.evaluate(x=x_val, y=y_val, batch_size=BATCH_SIZE)
print(loss)
print(accu)

第二步:对网络整体进行微调

inputs = Input(shape=[224, 224, 3])
base_model = VGG16(input_tensor=inputs, include_top=True, weights='./fv_vgg16.h5', classes=N_CLASSES) # 此时加载刚刚训练得到的模型
for l in base_model.layers:
    l.trainable = True # 所有层均为trainable
model = Model(inputs, base_model.output)
# compile model
optimizer = Adam(lr=0.00001)
model.summary()
model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])
# train
model.fit(x_train, y_train, batch_size=BATCH_SIZE, epochs=10)
# save model
model.save(filepath='./fv_vgg16_ft.h5')
# evaluate
loss, accu = model.evaluate(x=x_val, y=y_val, batch_size=BATCH_SIZE)
print(loss)
print(accu)

重点使用的函数:keras.applications.vgg16.VGG16

函数原型:

def VGG16(include_top=True,
          weights='imagenet',
          input_tensor=None,
          input_shape=None,
          pooling=None,
          classes=1000,
          **kwargs)

Instructions:

include_top:是否包含原始VGG-16的三个全连接层
weights:默认为'imagenet',即加载在ImageNet上训练的VGG-16,也可以设置为None,即随机初始化,或者给出你希望加载的权值文件路径
input_tensor:输入tensor,即网络输入
input_shape:include_top=False时该参数有效,即输入数据尺寸,以元组的形式给出,若不给出默认为(224, 224, 3)
pooling:include_top=False时该参数有效,默认为None即不对卷积层输出进行pooling,取值'ave'代表进行全局平均池化,取值'max'代表进行全局最大池化
classes:include_top=True时有效,用于调整最后一个全连接层(分类层)的节点数,默认为1000

你可能感兴趣的:(Keras学习)