当前位置:   article > 正文

视觉深度学习:迁移学习和微调_迁移学习 微调 csdn

迁移学习 微调 csdn

概述

训练深度学习模型需要大量的标记数据。在大多数情况下,这些数据需要可用或更易于清理。多年来,已经创建了许多处理有限数据集的方法,迁移学习是突破之一。迁移学习使我们能够在任务的大型数据集上微预先训练的模型。

介绍

迁移学习和微调是深度学习中的关键技术。它们允许将从解决一个问题中获得的知识转移到相关问题,从而减少训练所需的数据和计算量。迁移学习的过程涉及使用预训练模型作为起点,微调涉及通过更新其权重在新任务上进一步训练预训练模型。通过利用通过迁移学习和微调获得的知识,与从头开始相比,可以改进和加快训练过程。迁移学习和微调是许多深度学习应用中必不可少的组成部分,并且已被证明可以有效地实现最先进的结果。

本文通过创建一个网络来探索迁移学习和微调的概念,该网络可以通过微调在 ImageNet 数据集上预训练的模型(1000 个类)来识别猫和狗数据集中的两个不同类。

迁移学习

深度学习管道中,迁移学习通常是在可用数据太少而无法正确训练网络时完成的。迁移学习工作流的一般方法如下。

  • 根据与当前数据集类似的数据获取预训练模型。例如,在计算机视觉方法中,许多模型都是在 ImageNet 数据集上预先训练的。由于 ImageNet 数据集具有与现实生活中的物体和事物相关的类,因此在其上预先训练的模型已经对世界有了一定的了解。
  • 加载模型并了解其层结构。
  • 冻结模型的权重。冻结权重会使这些层无法训练,并防止它们被迁移学习过程破坏其现有知识。
  • 将新层追加到模型的冻结部分。这些新层可以进行训练,并使用预先训练的权重来更快地学习。
  • 在新数据集上训练新模型。

实施迁移学习

本文将探讨如何采用在 ImageNet 上训练的模型,并根据新数据对其进行微调。我们将在 Tensorflow 中创建此实现。

先决条件

在微调模型之前,我们必须确定我们需要什么基础模型。我们还需要加载和预处理数据集。由于迁移学习通常用于小型数据集,因此在此示例中,我们采用猫和狗数据集的子集。

进口

我们首先导入所需的库。我们将 Tensorflow 用于整个管道。

  1. import numpy as np
  2. import tensorflow as tf
  3. from tensorflow import keras
  4. from tensorflow.keras import layers
  5. import tensorflow_datasets as tfds
  6. import os
  7. import zipfile

加载数据

由于 Cats and Dogs 数据集不是 Tensorflow 的一部分,因此我们从 Kaggle 下载它,然后使用 tensorflow_datasets 库将其加载到内存中。

加载后,我们将数据拆分为训练和测试,同时对其进行子集。

  1. train_dataset, validation_dataset, test_dataset = tfds.load(
  2. "cats_vs_dogs",
  3. split=["train[:40%]", "train[40%:50%]", "train[50%:60%]"],
  4. as_supervised=True,
  5. )

数据的示例子集如下所示。

然后,我们可以将数据转换为批处理,将它们拆分为数据加载器,并使用缓存预取来优化数据加载。在此示例中,我们使用 32 的批处理大小。加载后,我们还可以应用一些简单的数据增强方法。例如,我们使用随机水平翻转随机旋转

  1. size = (150, 150)
  2. bs = 32
  3. aug_transforms = keras.Sequential(
  4. [layers.RandomFlip("horizontal"), layers.RandomRotation(0.1),]
  5. )
  6. train_dataset = train_dataset.map(lambda x, y: (tf.image.resize(x, size), y))
  7. validation_dataset = validation_dataset.map(lambda x, y: (tf.image.resize(x, size), y))
  8. test_dataset = test_dataset.map(lambda x, y: (tf.image.resize(x, size), y))
  9. train_dataset = train_dataset.cache().batch(bs).prefetch(buffer_size=10)
  10. validation_dataset = validation_dataset.cache().batch(bs).prefetch(buffer_size=10)
  11. test_dataset = test_dataset.cache().batch(bs).prefetch(buffer_size=10)

本文使用在 ImageNet 数据集上预训练并应用于图像的 Xception 模型150 x 150 x 3在大小上。重要的一点是排除预训练模型的最终分类层。最后一层仅用于分类;我们只关心它前面的层。

  1. model_pretrained = keras.applications.Xception(
  2. weights="imagenet",
  3. input_shape=(150, 150, 3),
  4. include_top=False,
  5. )

此处显示了 Xception 模型架构。

微调

微调是通过在小型数据集上训练预训练模型来使预训练模型适应新任务。当我们的任务可用的数据有限时,这种适应特别有用,因为它允许我们在更大的数据集上利用模型学到的知识。微调还可以使预训练模型适应新领域或提高其在特定任务上的性能。这种技术可以显著减少从头开始训练深度学习模型所需的时间和计算资源。以下部分演示了相同的代码。

实施微调

现在,我们通过将可训练参数设置为 False 来冻结刚刚加载的模型层。

之后,我们在冻结层之上创建一个模型,并应用我们定义的数据增强。

Xception 模型需要注意的是,它定义了从原始范围缩放的输入(0,255)( 0,2 5 5)到范围(−1.0,1.0)(−1.0, 1.0)。我们使用 Rescaling 图层执行此重新缩放,如下所示。

  1. model_pretrained.trainable = False
  2. inputs = keras.Input(shape=(150, 150, 3))
  3. rescale_layer = keras.layers.Rescaling(scale=1 / 127.5, offset=-1)
  4. x = aug_transforms(inputs)
  5. x = rescale_layer(x)

解冻模型的顶层

Xception 模型还包含批量归一化层,当模型解冻时,不应训练这些层。为了确保情况确实如此,我们禁用了训练模式。我们还应用了 GlobalAveragePooling,然后应用了 Dropout 层,以进一步提高性能。全局平均池化是全连接层 (FC) 的替代方法,可更好地保留空间信息。由于我们的预训练模型使用不同的数据,因此这些层在这里很有用。最后一层是用于二元分类任务的 FC 层。

  1. x = model_pretrained(x, training=False)
  2. x = keras.layers.GlobalAveragePooling2D()(x)
  3. x = keras.layers.Dropout(0.2)(x)
  4. outputs = keras.layers.Dense(1)(x)
  5. final_model = keras.Model(inputs, outputs)

现在,我们可以训练我们创建的新层。

  1. final_model.compile(
  2. optimizer=keras.optimizers.Adam(),
  3. loss=keras.losses.BinaryCrossentropy(from_logits=True),
  4. metrics=[keras.metrics.BinaryAccuracy()],
  5. )
  6. num_epochs = 5
  7. final_model.fit(train_dataset, epochs=num_epochs, validation_data=validation_dataset)

从训练进度可以看出,经过 5 个 epoch 后,我们的验证准确率为 0.97。在此之后,我们可以通过训练整个模型来提高性能。

  1. Epoch 1/5
  2. 291/291 [==============================] - 44s 105ms/step - loss: 0.1577 - binary_accuracy: 0.9338 - val_loss: 0.0790 - val_binary_accuracy: 0.9716
  3. Epoch 2/5
  4. 291/291 [==============================] - 25s 86ms/step - loss: 0.1130 - binary_accuracy: 0.9503 - val_loss: 0.0744 - val_binary_accuracy: 0.9729
  5. Epoch 3/5
  6. 291/291 [==============================] - 26s 90ms/step - loss: 0.1068 - binary_accuracy: 0.9553 - val_loss: 0.0713 - val_binary_accuracy: 0.9733
  7. Epoch 4/5
  8. 291/291 [==============================] - 26s 91ms/step - loss: 0.1072 - binary_accuracy: 0.9544 - val_loss: 0.0700 - val_binary_accuracy: 0.9733
  9. Epoch 5/5
  10. 291/291 [==============================] - 26s 91ms/step - loss: 0.1002 - binary_accuracy: 0.9584 - val_loss: 0.0725 - val_binary_accuracy: 0.9729
  11. <keras.callbacks.History at 0x7f225245fc10>

现在我们已经训练了新层,我们解冻了整个模型,然后以非常小的学习率训练它。这种循序渐进的训练会带来更好的表现。请注意,在此训练期间,批量规范化层不会更新,即使更新了,也会严重损害性能。

  1. model_pretrained.trainable = True
  2. final_model.summary()
  3. final_model.compile(
  4. optimizer=keras.optimizers.Adam(1e-5),
  5. loss=keras.losses.BinaryCrossentropy(from_logits=True),
  6. metrics=[keras.metrics.BinaryAccuracy()],
  7. )
  8. num_epochs = 5
  9. final_model.fit(train_dataset, epochs=num_epochs, validation_data=validation_dataset)
  1. Epoch 1/5
  2. 291/291 [==============================] - 101s 324ms/step - loss: 0.0853 - binary_accuracy: 0.9667 - val_loss: 0.0544 - val_binary_accuracy: 0.9755
  3. Epoch 2/5
  4. 291/291 [==============================] - 93s 318ms/step - loss: 0.0592 - binary_accuracy: 0.9765 - val_loss: 0.0461 - val_binary_accuracy: 0.9824
  5. Epoch 3/5
  6. 291/291 [==============================] - 94s 322ms/step - loss: 0.0463 - binary_accuracy: 0.9812 - val_loss: 0.0493 - val_binary_accuracy: 0.9794
  7. Epoch 4/5
  8. 291/291 [==============================] - 93s 320ms/step - loss: 0.0342 - binary_accuracy: 0.9870 - val_loss: 0.0575 - val_binary_accuracy: 0.9785
  9. Epoch 5/5
  10. 291/291 [==============================] - 93s 321ms/step - loss: 0.0301 - binary_accuracy: 0.9889 - val_loss: 0.0479 - val_binary_accuracy: 0.9811
  11. <keras.callbacks.History at 0x7f22c8fc5c10>

在对整个模型进行了五个周期的训练后,我们看到验证准确率增加到 0.98。这一进展表明,与仅训练某些层相比,重新训练整个模型确实提高了性能。

评估和预测

此示例显示了迁移学习对于快速训练小型数据集的有用性。训练模型后,我们评估测试数据集。尽管训练周期很少,数据也较少,但该模型仍然表现良好。

LayerOutput ShapeParam #
input_2[(None,150,150,3)]0
sequential(None,150,150,3)0
Rescaling(None,150,150,3)0
xception(None,5,5,2048)20861480
global_average_pooling2D(None,2048)0
dropout(None,2048)0
dense(None,1)2049

考虑一张模型从未见过的狗的图像,并且不是数据集的一部分。

数据集中的类列在此字典中。

  1. label_dict = {
  2. 0: "dog",
  3. 1 : "cat"
  4. }

从给定的字典中,我们可以看到网络正确地预测了图像。要自动获取生成的类,我们可以使用以下代码。

  1. Image.open('dog-583007.jpg').resize((150,150))
  2. label_dict[int(final_model.predict(image))]

结论

  • 当存在较少的数据时,迁移学习是一种强大的方法。
  • 只要预训练模型使用类似的数据,就可以使用它对利基模型进行微调。
  • 有选择地冻结预训练的层并训练其余层是实现微调效果的一种方式。
  • 在第一轮选择性训练之后,解冻模型并训练整个模型可以提高性能。
  • 因此,迁移学习和微调方法是深度学习的宝贵突破。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/649606
推荐阅读
相关标签
  

闽ICP备14008679号