# 七、迁移学习
迁移学习的作用恰如其名。 这个想法是将从一项任务中学到的东西迁移到另一项任务上。 为什么? 实际上,每次都从头开始训练整个模型的效率很低,其成功取决于许多因素。 另一个重要原因是,对于某些应用,公开可用的数据集不够大,无法训练出像 AlexNet 或 ResNet 这样的深层架构而又不会过拟合,这意味着无法推广。 示例应用可以从用户给出的一些示例中进行在线学习,也可以是细粒度的分类,其中类别之间的差异很小。
一个非常有趣的观察结果是,由于您冻结了所有其余部分(无论是检测还是分类),最终的层可以用于完成不同的任务,最终权重看起来非常相似。
这导致了迁移学习的想法。 这意味着在大量数据上训练的深度架构(例如 ImageNet)可以很好地概括化,以至于其卷积权重可以充当特征提取器,类似于常规的视觉表示,并且可以用于为各种任务训练线性分类器。
本章旨在教读者如何在 TensorFlow 中采用现成的训练有素的模型,更改其结构以及为特定任务重新训练某些层。 我们将看到迁移学习将如何帮助改善结果并加快训练时间。
本章涵盖的主要主题如下:
* 使用来自另一个训练过的模型的权重预先初始化一个模型
* 在需要时使用 TensorFlow 加载模型并冻结/解冻层
# 什么时候?
研究表明,在 ImageNet 上训练的卷积网络权重中的特征提取优于常规特征提取方法,例如 SURF,可变形部分描述符(**DPD**),**直方图定向梯度**(**HOG**)和**词袋**(**BoW**)。 这意味着无论常规视觉表示如何工作,卷积特征都可以同样好地使用,唯一的缺点是更深的架构可能需要更长的时间来提取特征。
当在 ImageNet 上训练深层卷积神经网络时,第一层中的卷积过滤器的可视化(请参见下图)显示,他们学习了*低层*特征,类似于边检测过滤器,而卷积过滤器在最后一层学习*高级*功能,这些功能捕获特定于类的信息。 因此,如果我们在第一个池化层之后提取 ImageNet 的特征并将其嵌入 2D 空间(例如,使用 t-SNE),则可视化将显示数据中存在一些无中心状态,而如果在全连接层上执行相同操作,我们将注意到具有相同语义信息的数据被组织成簇。 这意味着网络可以在更高层次上很好地概括,并且有可能将这种知识迁移到看不见的类别中。
![](https://img.kancloud.cn/a1/cc/a1cc8c6f8f4bb4a1e15b14a2b596ea1e_783x331.png)
根据对与 ImageNet 相似度较小的数据集进行的实验,在以下任务上,基于 ImageNet 训练的基于卷积神经网络权重的特征比常规特征提取方法的表现更好:
* **对象识别**:此 CNN 特征提取器可以成功地对其他类别不可见的数据集执行分类任务。
* **域适应**:这是当训练和测试数据来自不同的分布,而标签和类别数相同时。 不同的域可以考虑使用不同的设备或在不同的设置和环境条件下捕获的图像。 具有 CNN 功能的线性分类器可以在不同域中成功地将具有相同语义信息的图像聚类,而 SURF 功能则可以针对特定领域的特征进行过拟合。
* **精细分类**:这是我们要在同一高级类中的子类之间进行分类的时候。 例如,我们可以对鸟类进行分类。 尽管没有对细粒度数据进行训练,但 CNN 功能以及逻辑回归功能的表现优于基线方法。
* **场景识别**:在这里,我们需要对整个图像的场景进行分类。 在对象分类数据库上经过训练的 CNN 特征提取器,顶部带有一个简单的线性分类器,其表现优于应用于识别数据的传统特征提取器的复杂学习算法。
这里提到的某些任务与图像分类没有直接关系,图像分类是 ImageNet 训练的主要目标,因此有人希望 CNN 功能无法推广到看不见的场景。 但是,这些功能与简单的线性分类器相结合,表现优于手工制作的功能。 这意味着 CNN 的学习权重是可重用的。
那么什么时候应该使用迁移学习呢? 当我们有一个任务时,由于问题的性质,可用数据集很小(例如对蚂蚁/蜜蜂进行分类)。 在这种情况下,我们可以在包含相似语义信息的较大数据集上训练我们的模型,然后用较小的数据集仅训练最后一层(线性分类器)。 如果我们只有足够的可用数据,并且有一个更大的相似数据集,则对该相似数据集进行预训练可能会导致模型更健壮。 通常情况下,我们使用随机初始化的权重来训练模型,在这种情况下,将使用在其他数据集上训练过的权重来初始化模型。 这将有助于网络更快地融合并更好地推广。 在这种情况下,仅微调模型顶端的几层是有意义的。
经验法则是,从网络顶部开始,可用数据越多,可以训练的层就越多。 通过预训练(例如在 ImageNet 上)模型初始化模型权重。
# 怎么样? 概述
我们应该如何使用转学? 有两种典型的解决方法。 第一种不太及时的方法是使用所谓的预训练模型,即预先在大型数据集(例如 ImageNet 数据集)上训练过的模型。 这些经过预先训练的模型可以在不同的深度学习框架中轻松获得,并且通常被称为“模型动物园”。 预训练模型的选择在很大程度上取决于当前要解决的任务是什么,以及数据集的大小。 选择模型后,我们可以使用全部或部分模型作为要解决的实际任务的初始化模型。
深度学习的另一种不太常见的方式是自己预先训练模型。 当可用的预训练网络不适合解决特定问题时,通常会发生这种情况,我们必须自己设计网络架构。 显然,这需要更多的时间和精力来设计模型和准备数据集。 在某些情况下,用于进行网络预训练的数据集甚至可以是合成的,可以从计算机图形引擎(例如 3D Studio Max 或 Unity)或其他卷积神经网络(例如 GAN)生成。 可以对虚拟数据进行预训练的模型在真实数据上进行微调,并且可以与仅对真实数据进行训练的模型一起很好地工作。
例如,如果我们想区分猫和狗,而我们没有足够的数据,则可以从“模型动物园”下载在 ImageNet 上训练的网络,并使用除最后一层以外的所有层的权重。 最后一层必须调整为具有与类数量相同的大小,在本例中为两个,并且权重需要重新初始化和训练。 这样,通过将这些层的学习率设置为零或非常小的值(请参见下图),我们将冻结那些不需训练的层。 如果有更大的数据集,我们可以训练最后三个全连接层。 有时,预训练网络只能用于初始化权重,然后再进行正常训练。
迁移学习之所以有效,是因为在初始层计算出的特征更通用并且看起来很相似。 在顶层提取的特征对于我们要解决的问题变得更加具体。
为了进一步研究如何使用迁移学习,以及对该主题的更深刻理解,让我们看一下代码。
![](https://img.kancloud.cn/f6/6f/f66f0e29c073557f1863ef1b5e8bdc77_677x521.png)
# 怎么样? 代码示例
在本节中,我们将学习在 TensorFlow 中进行迁移学习所需的实用技能。 更具体地说,我们将学习如何从检查点选择要加载的层,以及如何指示我们的求解器仅优化特定的层而冻结其他层。
# TensorFlow 有用的元素
由于迁移学习是关于训练一个网络的权重,而该网络已从另一个训练后的模型中获取了权重,因此我们将需要找到一个。 在我们的示例中,我们将使用预训练卷积自编码器的编码部分,该部分在第 6 章中进行了说明。 使用自编码器的优点是我们不需要标记的数据,也就是说,可以完全不受监督地对其进行训练。
# 没有解码器的自编码器
包含两个卷积层和一个完全连接层的编码器(不带解码器部分的自编码器)如下所示。 父自编码器在 MNIST 数据集上进行了训练。 因此,网络将大小为`28x28x1`的图像作为输入,并在潜在空间将其编码为 10 维向量,每个类别一维:
```py
# Only half of the autoencoder changed for classification
class CAE_CNN_Encoder(object):
......
def build_graph(self, img_size=28):
self.__x = tf.placeholder(tf.float32, shape=[None, img_size * img_size], name='IMAGE_IN')
self.__x_image = tf.reshape(self.__x, [-1, img_size, img_size, 1])
self.__y_ = tf.placeholder("float", shape=[None, 10], name='Y')
with tf.name_scope('ENCODER'):
##### ENCODER
# CONV1: Input 28x28x1 after CONV 5x5 P:2 S:2 H_out: 1 + (28+4-5)/2 = 14,
# W_out= 1 + (28+4-5)/2 = 14
self.__conv1_act = tf.layers.conv2d(inputs=self.__x_image, strides=(2, 2), name='conv1',
filters=16, kernel_size=[5, 5], padding="same", activation=tf.nn.relu)
# CONV2: Input 14x14x16 after CONV 5x5 P:0 S:2 H_out: 1 + (14+4-5)/2 = 7,
# W_out= 1 + (14+4-5)/2 = 7
self.__conv2_act = tf.layers.conv2d(inputs=self.__conv1_act, strides=(2, 2),
name='conv2', filters=32, kernel_size=[5, 5], padding="same", activation=tf.nn.relu)
with tf.name_scope('LATENT'):
# Reshape: Input 7x7x32 after [7x7x32]
self.__enc_out = tf.layers.flatten(self.__conv2_act, name='flatten_conv2')
self.__dense = tf.layers.dense(inputs=self.__enc_out, units=200, activation=tf.nn.relu, name='fc1')
self.__logits = tf.layers.dense(inputs=self.__dense, units=10, name='logits')
def __init__(self, img_size=28):
if CAE_CNN_Encoder.__instance is None:
self.build_graph(img_size)
@property
def output(self):
return self.__logits
@property
def labels(self):
return self.__y_
@property
def input(self):
return self.__x
@property
def image_in(self):
return self.__x_image
```
# 选择层
一旦定义了模型`model = CAE_CNN_Encoder` `()`,选择将要使用预训练权重初始化的层就很重要。 请注意,两个网络的结构(要初始化的网络和提供训练后的权重的网络)必须相同。 因此,例如,以下代码片段将选择名称为`convs`为`fc`的所有层:
```py
from models import CAE_CNN_Encoder
model = CAE_CNN_Encoder()
list_convs = [v for v in tf.global_variables() if "conv" in v.name]
list_fc_linear = [v for v in tf.global_variables() if "fc" in v.name or "output" in v.name]
```
请注意,这些列表是从`tf.global_variables()`填充的; 如果选择打印其内容,则可能会发现它包含所有模型变量,如下所示:
```py
[<tf.Variable 'conv1/kernel:0' shape=(5, 5, 1, 16) dtype=float32_ref>,
<tf.Variable 'conv1/bias:0' shape=(16,) dtype=float32_ref>,
<tf.Variable 'conv2/kernel:0' shape=(5, 5, 16, 32) dtype=float32_ref>,
<tf.Variable 'conv2/bias:0' shape=(32,) dtype=float32_ref>,
<tf.Variable 'fc1/kernel:0' shape=(1568, 200) dtype=float32_ref>,
<tf.Variable 'fc1/bias:0' shape=(200,) dtype=float32_ref>,
<tf.Variable 'logits/kernel:0' shape=(200, 10) dtype=float32_ref>,
<tf.Variable 'logits/bias:0' shape=(10,) dtype=float32_ref>]
```
将定义图的层分为卷积和完全连接两个列表后,您将使用`tf.Train.Saver`加载所需的权重。 首先,我们需要创建一个保存器对象,将要从检查点加载的变量列表作为输入,如下所示:
```py
# Define the saver object to load only the conv variables
saver_load_autoencoder = tf.train.Saver(var_list=list_convs)
```
除了`saver_load_autoencoder`,我们还需要创建另一个`saver`对象,该对象将允许我们将要训练的网络的所有变量存储到检查点中。
```py
# Define saver object to save all the variables during training
saver = tf.train.Saver()
```
然后,在使用`init = tf.global_variables_initializer()`初始化图并创建会话之后,我们可以使用`saver_load_autoencoder`从检查点恢复卷积层,如下所示:
```py
# Restore only the weights (From AutoEncoder)
saver_load_autoencoder.restore(sess, "../tmp/cae_cnn/model.ckpt-34")
```
请注意,调用`restore`会覆盖`global_variables_initializer`,所有选定的权重都将替换为检查点的权重。
# 仅训练一些层
迁移学习的另一个重要部分是冻结不需要训练的层的权重,同时允许对某些层(通常是最后一层)进行训练。 在 TensorFlow 中,我们可以仅将要优化的层传递给求解器(在此示例中,仅将 FC 层传递给):
```py
train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss, var_list=list_fc_linear)
```
# 完整代码
在此示例中,我们将从 MNIST 卷积自编码器示例中加载权重。 我们将仅恢复编码器部分的权重,冻结卷积层,并训练 FC 层以执行数字分类:
```py
import tensorflow as tf
import numpy as np
import os
from models import CAE_CNN_Encoder
SAVE_FOLDER='/tmp/cae_cnn_transfer'
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
model = CAE_CNN_Encoder(latent_size = 20)
model_in = model.input
model_out = model.output
labels_in = model.labels
# Get all convs weights
list_convs = [v for v in tf.global_variables() if "conv" in v.name]
# Get fc1 and logits
list_fc_layers = [v for v in tf.global_variables() if "fc" in v.name or "logits" in v.name]
# Define the saver object to load only the conv variables
saver_load_autoencoder = tf.train.Saver(var_list=list_convs)
# Define saver object to save all the variables during training
saver = tf.train.Saver()
# Define loss for classification
with tf.name_scope("LOSS"):
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=model_out, labels=labels_in))
correct_prediction = tf.equal(tf.argmax(model_out,1), tf.argmax(labels_in,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# Solver configuration
with tf.name_scope("Solver"):
train_step = tf.train.AdamOptimizer(1e-4).minimize(loss, var_list=list_fc_layers)
# Initialize variables
init = tf.global_variables_initializer()
# Avoid allocating the whole memory
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.200)
sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options))
sess.run(init)
# Restore only the CONV weights (From AutoEncoder)
saver_load_autoencoder.restore(sess, "/tmp/cae_cnn/model.ckpt-34")
# Add some tensors to observe on tensorboad
tf.summary.image("input_image", model.image_in, 4)
tf.summary.scalar("loss", loss)
merged_summary = tf.summary.merge_all()
writer = tf.summary.FileWriter(SAVE_FOLDER)
writer.add_graph(sess.graph)
#####Train######
num_epoch = 200
batch_size = 10
for epoch in range(num_epoch):
for i in range(int(mnist.train.num_examples / batch_size)):
# Get batch of 50 images
batch = mnist.train.next_batch(batch_size)
# Dump summary
if i % 5000 == 0:
# Other summaries
s = sess.run(merged_summary, feed_dict={model_in:batch[0], labels_in:batch[1]})
writer.add_summary(s,i)
# Train actually here (Also get loss value)
_, val_loss, t_acc = sess.run((train_step, loss, accuracy), feed_dict={model_in:batch[0], labels_in:batch[1]})
print('Epoch: %d/%d loss:%d' % (epoch, num_epoch, val_loss))
print('Save model:', epoch)
saver.save(sess, os.path.join(SAVE_FOLDER, "model.ckpt"), epoch)
```
# 总结
在本章中,我们学习了如何,何时以及为什么使用迁移学习。 这被认为是一个非常强大的工具,因为它使我们能够使用从其他领域学到的功能来以较少的数据很好地概括。 我们看了一些示例,现在应该清楚如何在自己的任务中实现迁移学习。
在下一章中,我们将看到如何组织我们的数据以及如何扩展 CNN 架构,以构建准确而实用的机器学习系统。
- TensorFlow 1.x 深度学习秘籍
- 零、前言
- 一、TensorFlow 简介
- 二、回归
- 三、神经网络:感知器
- 四、卷积神经网络
- 五、高级卷积神经网络
- 六、循环神经网络
- 七、无监督学习
- 八、自编码器
- 九、强化学习
- 十、移动计算
- 十一、生成模型和 CapsNet
- 十二、分布式 TensorFlow 和云深度学习
- 十三、AutoML 和学习如何学习(元学习)
- 十四、TensorFlow 处理单元
- 使用 TensorFlow 构建机器学习项目中文版
- 一、探索和转换数据
- 二、聚类
- 三、线性回归
- 四、逻辑回归
- 五、简单的前馈神经网络
- 六、卷积神经网络
- 七、循环神经网络和 LSTM
- 八、深度神经网络
- 九、大规模运行模型 -- GPU 和服务
- 十、库安装和其他提示
- TensorFlow 深度学习中文第二版
- 一、人工神经网络
- 二、TensorFlow v1.6 的新功能是什么?
- 三、实现前馈神经网络
- 四、CNN 实战
- 五、使用 TensorFlow 实现自编码器
- 六、RNN 和梯度消失或爆炸问题
- 七、TensorFlow GPU 配置
- 八、TFLearn
- 九、使用协同过滤的电影推荐
- 十、OpenAI Gym
- TensorFlow 深度学习实战指南中文版
- 一、入门
- 二、深度神经网络
- 三、卷积神经网络
- 四、循环神经网络介绍
- 五、总结
- 精通 TensorFlow 1.x
- 一、TensorFlow 101
- 二、TensorFlow 的高级库
- 三、Keras 101
- 四、TensorFlow 中的经典机器学习
- 五、TensorFlow 和 Keras 中的神经网络和 MLP
- 六、TensorFlow 和 Keras 中的 RNN
- 七、TensorFlow 和 Keras 中的用于时间序列数据的 RNN
- 八、TensorFlow 和 Keras 中的用于文本数据的 RNN
- 九、TensorFlow 和 Keras 中的 CNN
- 十、TensorFlow 和 Keras 中的自编码器
- 十一、TF 服务:生产中的 TensorFlow 模型
- 十二、迁移学习和预训练模型
- 十三、深度强化学习
- 十四、生成对抗网络
- 十五、TensorFlow 集群的分布式模型
- 十六、移动和嵌入式平台上的 TensorFlow 模型
- 十七、R 中的 TensorFlow 和 Keras
- 十八、调试 TensorFlow 模型
- 十九、张量处理单元
- TensorFlow 机器学习秘籍中文第二版
- 一、TensorFlow 入门
- 二、TensorFlow 的方式
- 三、线性回归
- 四、支持向量机
- 五、最近邻方法
- 六、神经网络
- 七、自然语言处理
- 八、卷积神经网络
- 九、循环神经网络
- 十、将 TensorFlow 投入生产
- 十一、更多 TensorFlow
- 与 TensorFlow 的初次接触
- 前言
- 1. TensorFlow 基础知识
- 2. TensorFlow 中的线性回归
- 3. TensorFlow 中的聚类
- 4. TensorFlow 中的单层神经网络
- 5. TensorFlow 中的多层神经网络
- 6. 并行
- 后记
- TensorFlow 学习指南
- 一、基础
- 二、线性模型
- 三、学习
- 四、分布式
- TensorFlow Rager 教程
- 一、如何使用 TensorFlow Eager 构建简单的神经网络
- 二、在 Eager 模式中使用指标
- 三、如何保存和恢复训练模型
- 四、文本序列到 TFRecords
- 五、如何将原始图片数据转换为 TFRecords
- 六、如何使用 TensorFlow Eager 从 TFRecords 批量读取数据
- 七、使用 TensorFlow Eager 构建用于情感识别的卷积神经网络(CNN)
- 八、用于 TensorFlow Eager 序列分类的动态循坏神经网络
- 九、用于 TensorFlow Eager 时间序列回归的递归神经网络
- TensorFlow 高效编程
- 图嵌入综述:问题,技术与应用
- 一、引言
- 三、图嵌入的问题设定
- 四、图嵌入技术
- 基于边重构的优化问题
- 应用
- 基于深度学习的推荐系统:综述和新视角
- 引言
- 基于深度学习的推荐:最先进的技术
- 基于卷积神经网络的推荐
- 关于卷积神经网络我们理解了什么
- 第1章概论
- 第2章多层网络
- 2.1.4生成对抗网络
- 2.2.1最近ConvNets演变中的关键架构
- 2.2.2走向ConvNet不变性
- 2.3时空卷积网络
- 第3章了解ConvNets构建块
- 3.2整改
- 3.3规范化
- 3.4汇集
- 第四章现状
- 4.2打开问题
- 参考
- 机器学习超级复习笔记
- Python 迁移学习实用指南
- 零、前言
- 一、机器学习基础
- 二、深度学习基础
- 三、了解深度学习架构
- 四、迁移学习基础
- 五、释放迁移学习的力量
- 六、图像识别与分类
- 七、文本文件分类
- 八、音频事件识别与分类
- 九、DeepDream
- 十、自动图像字幕生成器
- 十一、图像着色
- 面向计算机视觉的深度学习
- 零、前言
- 一、入门
- 二、图像分类
- 三、图像检索
- 四、对象检测
- 五、语义分割
- 六、相似性学习
- 七、图像字幕
- 八、生成模型
- 九、视频分类
- 十、部署
- 深度学习快速参考
- 零、前言
- 一、深度学习的基础
- 二、使用深度学习解决回归问题
- 三、使用 TensorBoard 监控网络训练
- 四、使用深度学习解决二分类问题
- 五、使用 Keras 解决多分类问题
- 六、超参数优化
- 七、从头开始训练 CNN
- 八、将预训练的 CNN 用于迁移学习
- 九、从头开始训练 RNN
- 十、使用词嵌入从头开始训练 LSTM
- 十一、训练 Seq2Seq 模型
- 十二、深度强化学习
- 十三、生成对抗网络
- TensorFlow 2.0 快速入门指南
- 零、前言
- 第 1 部分:TensorFlow 2.00 Alpha 简介
- 一、TensorFlow 2 简介
- 二、Keras:TensorFlow 2 的高级 API
- 三、TensorFlow 2 和 ANN 技术
- 第 2 部分:TensorFlow 2.00 Alpha 中的监督和无监督学习
- 四、TensorFlow 2 和监督机器学习
- 五、TensorFlow 2 和无监督学习
- 第 3 部分:TensorFlow 2.00 Alpha 的神经网络应用
- 六、使用 TensorFlow 2 识别图像
- 七、TensorFlow 2 和神经风格迁移
- 八、TensorFlow 2 和循环神经网络
- 九、TensorFlow 估计器和 TensorFlow HUB
- 十、从 tf1.12 转换为 tf2
- TensorFlow 入门
- 零、前言
- 一、TensorFlow 基本概念
- 二、TensorFlow 数学运算
- 三、机器学习入门
- 四、神经网络简介
- 五、深度学习
- 六、TensorFlow GPU 编程和服务
- TensorFlow 卷积神经网络实用指南
- 零、前言
- 一、TensorFlow 的设置和介绍
- 二、深度学习和卷积神经网络
- 三、TensorFlow 中的图像分类
- 四、目标检测与分割
- 五、VGG,Inception,ResNet 和 MobileNets
- 六、自编码器,变分自编码器和生成对抗网络
- 七、迁移学习
- 八、机器学习最佳实践和故障排除
- 九、大规模训练
- 十、参考文献