深度学习 什么是微调(Fine Tune)?

微调,fine tune。英文也叫 fine tuning

在实践中,由于数据集不够大,很少有人从头开始训练网络。常见的做法是使用预训练的网络(例如在 ImageNet 上训练的分类 1000类的网络)来重新 fine-tuning(也叫微调),或者当做特征提取器。

什么是模型微调

假设有方程式:y = w * x

我们经过训练最终得出 w = 0.5

这个过程可能比较耗时,但是若是有人一开始就告诉你 w 在 0.47 附近

那么一开始,你与目标值的误差就只有 0.06 了!

总结来说,就是相当于给你一个预训练模型(Pre-trained model),然后我们基于这个模型微调(fine tune)。相比于从头开始训练(training a model from scatch),微调为你省去了大量计算资源和计算时间,提高了计算效率,甚至提高了准确率

什么是预训练模型

就是被人训练好的模型,比如 VGG16\19。

通常来说,VGG16\19 等网络已经是他人调试好的优秀网络,我们无需在修改其网络结构

当我们做深度学习任务时,比如说,一个涉及在图像数据集上训练卷积神经网络(Covnet)的任务,我们的第一个直觉就是从头开始训练网络。然而,实际上,从上图可以看到,卷积神经网络会有有大量的参数(Parameters),通常在几百万的范围内。在小数据集(小于参数数量)上训练CNN会极大地影响CNN泛化的能力,通常会导致过度拟合。

为什么要微调

卷积审计网络的核心是:

  • 浅层卷积层提取基础特征,比如边缘、轮廓等基础特征。
  • 深层卷积层提取抽象特征,比如整个脸型。
  • 全连接层根据特征组合进行评分分类。

用大型数据集做训练,已经具备了提取浅层基础特征和深层抽象特征的能力。但是:

  • 从头开始训练,需要大量的数据、计算时间、计算资源
  • 存在模型不收敛,参数不够优化,准确率低,模型泛化能力低,容易过拟合等风险

使用微调能有效避免以上问题。

什么情况下使用微调

1、数据集相似。如果不相似,比如用自然风景模型微调做人脸识别用途,效果可能就比较糟糕。因为特征提取不同,训练参数不同。

2、自己搭建的模型准确率太低。

3、计算资源太少

微调指导事项

1、通常的做法就是阶段预先训练好的网络的最后一层(softmax层)
2、冻结预训练网络的前几层的权重
3、使用较小的学习率

基于 keras 实现微调

微调网络的步骤如下:

  • 1、将自定义网络添加到已经训练好的基底网络之上
  • 2、冻结基底网络
  • 3、训练自定义网络
  • 4、加载上一步保存的训练模型,解冻基底网络中的一些神经层
  • 5、共同训练基底网络和自定义网络

深度学习 Keras 1.5 使用预先训练的卷积网络(convnets)模型 - 特征提取 - 方法2 中,我们已经完成了前三步,现在我们继续第四步吧

step4 解冻基底网络中的一些神经层

# 加载上面训练好的模型
from keras.models import load_model
conv_base = load_model("cats_and_dogs_small_3.h5")

conv_base.trainable = True # 解冻 "卷积基底"

# 所有层直到block4_pool都应该被冻结,而 block5_conv1,block5_conv2, block5_conv3 及 block5_pool则被解冻        
layers_frozen = ['block5_conv1','block5_conv2', 'block5_conv3', 'block5_pool']
for layer in conv_base.layers:
    if layer.name in layers_frozen:
        layer.trainable = True
    else:
        layer.trainable = False

# 把每一层是否可以被"trainable"的flat打印出来
for layer in conv_base.layers:
    print("{}: {}".format(layer.name, layer.trainable)) 

step5 共同训练基底网络和自定义网络

现在我们开始微调我们的网络。我们将使用非常低的学习率(learning rate)来使用 RMSprop 优化器。这里使用低学习率是因为希望对三个微调的卷积层表示(representations)所做的修改的幅度小一点。太大的更新可能会损害这些表示(representations)。

现在开始微调

model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-5), # 使用小的learn rate
              metrics=['acc'])

history = model.fit_generator(
      train_generator,
      steps_per_epoch=100,
      epochs=100,
      validation_data=validation_generator,
      validation_steps=50)

可视化展示

def smooth_curve(points, factor=0.8):
  smoothed_points = []
  for point in points:
    if smoothed_points:
      previous = smoothed_points[-1]
      smoothed_points.append(previous * factor + point * (1 - factor))
    else:
      smoothed_points.append(point)
  return smoothed_points

plt.plot(epochs,
         smooth_curve(acc), label='Smoothed training acc')
plt.plot(epochs,
         smooth_curve(val_acc), label='Smoothed validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs,
         smooth_curve(loss), label='Smoothed training loss')
plt.plot(epochs,
         smooth_curve(val_loss), label='Smoothed validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()

损失曲线没有显示任何实际的改善(实际上它正在变差)。你可以会想,若是损失不减少,准确性如何提高?答案很简单,我们显示的是一个平均值,但实际上对于精度来说重要的是损失值的分布,而不是它们的平均值。

现在用测试数据去做最终评估:

test_generator = test_datagen.flow_from_directory(
        test_dir,
        target_size=(150, 150),
        batch_size=20,
        class_mode='binary')

test_loss, test_acc = model.evaluate_generator(test_generator, steps=50)

print('test acc:', test_acc)

这里我们的测试精确度为 97%。在这个数据集的原始 Kaggle 比赛中,这将取得非常高的排名。

然而,使用现代深度学习技术,我们仅使用一部分的训练数据(约 10%)就可以达到此种结果。

总结

作为特征提取(feature extraction)的补充,可以使用微调(fine tune),它可以调整现有模型去学习新问题的一些表示特征。进一步推动了预测性能。

附完整代码

from keras.applications import VGG16

conv_base = VGG16(weights='imagenet',
                  include_top=False, # 在这里告诉 keras我们只需要卷积基底的权重模型资讯
                  input_shape=(150, 150, 3)) # 宣告我们要处理的图像大小与颜色通道数

##特征提取

import os
base_dir = os.path.join(os.getcwd(), "data")
base_dir = os.path.join(base_dir, "cats_and_dogs_small")
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')
test_dir = os.path.join(base_dir, 'test')

from keras import models
from keras import layers

model = models.Sequential() # 产生一个新的网络模型结构
model.add(conv_base)        # 把预训练的卷积基底叠上去
model.add(layers.Flatten()) # 打平
model.add(layers.Dense(256, activation='relu'))  # 叠上新的密集连接层来做为分类器
model.add(layers.Dense(1, activation='sigmoid')) # 因为我的资料集只有两类(cat & dog)

# “冻结”卷积基底
conv_base.trainable = False

from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers

train_datagen = ImageDataGenerator(
      rescale=1./255,
      rotation_range=40,
      width_shift_range=0.2,
      height_shift_range=0.2,
      shear_range=0.2,
      zoom_range=0.2,
      horizontal_flip=True,
      fill_mode='nearest')

# 请注意: 验证用的资料不要进行资料的增强
test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(
        # 图像资料的目录
        train_dir,
        # 设定图像的高(height)与宽(width)
        target_size=(150, 150),
        batch_size=20,
        # 因为我们的目标资料集只有两类(cat & dog)
        class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
        validation_dir,
        target_size=(150, 150),
        batch_size=20,
        class_mode='binary')

model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=2e-5),
              metrics=['acc'])

history = model.fit_generator(
      train_generator,
      steps_per_epoch=100,
      epochs=30,
      validation_data=validation_generator,
      validation_steps=50,
      verbose=2)

model.save('cats_and_dogs_small_3.h5') # 把模型储存到档案

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(acc))

import matplotlib.pyplot as plt

plt.plot(epochs, acc, label='Training acc')
plt.plot(epochs, val_acc, label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs, loss, label='Training loss')
plt.plot(epochs, val_loss, label='Validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()

# 加载上面训练好的模型
from keras.models import load_model
conv_base = load_model("cats_and_dogs_small_3.h5")

conv_base.trainable = True # 解冻 "卷积基底"

# 所有层直到block4_pool都应该被冻结,而 block5_conv1,block5_conv2, block5_conv3 及 block5_pool则被解冻
layers_frozen = ['block5_conv1','block5_conv2', 'block5_conv3', 'block5_pool']
for layer in conv_base.layers:
    if layer.name in layers_frozen:
        layer.trainable = True
    else:
        layer.trainable = False

# 把每一层是否可以被"trainable"的flat打印出来
for layer in conv_base.layers:
    print("{}: {}".format(layer.name, layer.trainable))

model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-5), # 使用小的learn rate
              metrics=['acc'])

history = model.fit_generator(
      train_generator,
      steps_per_epoch=100,
      epochs=100,
      validation_data=validation_generator,
      validation_steps=50)

def smooth_curve(points, factor=0.8):
  smoothed_points = []
  for point in points:
    if smoothed_points:
      previous = smoothed_points[-1]
      smoothed_points.append(previous * factor + point * (1 - factor))
    else:
      smoothed_points.append(point)
  return smoothed_points

plt.plot(epochs,
         smooth_curve(acc), label='Smoothed training acc')
plt.plot(epochs,
         smooth_curve(val_acc), label='Smoothed validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs,
         smooth_curve(loss), label='Smoothed training loss')
plt.plot(epochs,
         smooth_curve(val_loss), label='Smoothed validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()

test_generator = test_datagen.flow_from_directory(
        test_dir,
        target_size=(150, 150),
        batch_size=20,
        class_mode='binary')

test_loss, test_acc = model.evaluate_generator(test_generator, steps=50)

print('test acc:', test_acc)

转载请注明来源。 欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。 可以在下面评论区评论,也可以邮件至 sharlot2050@foxmail.com。

文章标题:深度学习 什么是微调(Fine Tune)?

字数:2.2k

本文作者:夏来风

发布时间:2021-02-02, 22:27:01

原始链接:http://www.demo1024.com/blog/ai-dl-fine-tune/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。