Python 迁移学习实用指南:1~5(3)https://developer.aliyun.com/article/1426848
LeNet 架构
这是 LeCun 及其合作者于 1998 年设计的具有开创性的七级卷积网络,用于数字分类。 后来,它被几家银行用来识别支票上的手写数字。 网络的较低层由交替的卷积和最大池化层组成。
上层是完全连接的密集 MLP(由隐藏层和逻辑回归组成)。 第一个完全连接的层的输入是上一层的所有特征图的集合:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sOELaVTz-1681567233331)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/0cff1c62-e1c0-40ec-b7a8-cad1f3da34b0.png)]
在将 CNN 成功应用于数字分类之后,研究人员将重点放在构建可以对 ImageNet 图像进行分类的更复杂的架构上。 ImageNet 是根据 WordNet 层次结构(目前仅是名词的层次结构)组织的图像数据库,其中层次结构的每个节点都由数百或数千个图像表示。 ImageNet 项目每年举办一次软件竞赛 ImageNet 大规模视觉识别挑战赛(ILSVRC),该竞赛将大规模评估目标检测和图像分类的算法。 评估标准是前五名/最高分。 通过从最终的致密 softmax 层获取 CNN 的预测来计算这些值。 如果目标标签是前五个预测之一(概率最高的五个预测),则认为它是成功的。 前五名得分是通过将预测标签(位于前 5 名)与目标标签匹配的时间除以所评估图像的数量得出的。
最高得分的计算方法与此类似。
AlexNet
在 2012 年,AlexNet 的表现明显优于所有先前的竞争对手,并通过将前 5 名的错误率降低到 15.3% 赢得了 ILSVRC,而亚军则只有 26%。 这项工作推广了 CNN 在计算机视觉中的应用。 AlexNet 与 LeNet 的架构非常相似,但是每层具有更多的过滤器,并且更深入。 而且,AlexNet 引入了使用栈式卷积的方法,而不是始终使用替代性卷积池。 小卷积的栈优于大卷积层的接收场,因为这会引入更多的非线性和更少的参数。
假设我们彼此之间具有三个3 x 3
卷积层(在它们之间具有非线性或池化层)。 在此,第一卷积层上的每个神经元都具有输入体积的3 x 3
视图。 第二卷积层上的神经元具有第一卷积层的3 x 3
视图,因此具有输入体积的5 x 5
视图。 类似地,第三卷积层上的神经元具有第二卷积层的3 x 3
视图,因此具有输入体积的7 x 7
视图。 显然,与 3 个3 x 3
卷积的3 x (3 x 3) = 27
个参数相比,7 x 7
接收场的参数数量是 49 倍。
ZFNet
2013 年 ILSVRC 冠军是 Matthew Zeiler 和 Rob Fergus 的 CNN。 它被称为 ZFNet 。 通过调整架构的超参数,特别是通过扩展中间卷积层的大小并减小第一层的步幅和过滤器大小,它在 AlexNet 上得到了改进,从 AlexNet 的11 x 11
步幅 4 变为7 x 7
步幅。 ZFNet。 这背后的直觉是,在第一卷积层中使用较小的滤镜尺寸有助于保留大量原始像素信息。 此外,AlexNet 接受了 1500 万张图像的训练,而 ZFNet 接受了 130 万张图像的训练:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QqEpbOHO-1681567233331)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/4801ec05-89b1-43d2-ad9f-32b0d98b140e.png)]
GoogLeNet(Inception)
2014 年 ILSVRC 获奖者是来自 Google 的名为 GoogLeNet 的卷积网络。 它的前 5 个错误率达到 6.67%! 这非常接近人类水平的表现。 排在第二位的是来自 Karen Simonyan 和 Andrew Zisserman 的网络,称为 VGGNet 。 GoogLeNet 使用 CNN 引入了一个称为初始层的新架构组件。 初始层背后的直觉是使用较大的卷积,但对于图像上的较小信息也要保持较高的分辨率。
因此,我们可以并行处理不同大小的内核,从1 x 1
到更大的内核,例如5 x 5
,然后将输出级联以产生下一层:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-weKfuSRs-1681567233332)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/cf82886a-ab82-4903-a258-0b84f3f27b68.png)]
显然,增加更多的层会爆炸参数空间。 为了控制这一点,使用了降维技巧。 请注意,1 x 1
卷积基本上不会减小图像的空间尺寸。 但是,我们可以使用1 x 1
滤镜减少特征图的数量,并减少卷积层的深度,如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RSfshHwX-1681567233332)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/d71299bb-48ef-4a93-9098-e0aa50229f51.png)]
下图描述了完整的 GoogLeNet 架构:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zBncET8k-1681567233332)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/bc08ac4f-958f-4283-b679-35c221d7292a.png)]
VGG
牛津视觉几何学组或简称为 VGG 的研究人员开发了 VGG 网络,该网络的特点是简单,仅使用3 x 3
卷积层并排叠加,且深度不断增加。 减小卷大小由最大池化处理。 最后,两个完全连接的层(每个层有 4,096 个节点)之后是 softmax 层。 对输入进行的唯一预处理是从每个像素减去在训练集上计算出的 RGB 平均值。
通过最大池化层执行池化,最大池化层跟随一些卷积层。 并非所有卷积层都跟随最大池化。 最大合并在2 x 2
像素的窗口上执行,步幅为 2。每个隐藏层都使用 ReLU 激活。 在大多数 VGG 变体中,过滤器的数量随深度的增加而增加。 下图显示了 16 层架构 VGG-16。 下一节显示了具有均匀3 x 3
x卷积(VGG-19)的 19 层架构。 VGG 模型的成功证实了深度在图像表示中的重要性:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5cq8BaAb-1681567233332)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/4429ffc8-edae-4456-be09-62b672c01130.png)]
VGG-16:输入大小为224 x 224 x 3
的 RGB 图像,每层中的滤镜数量都被圈起来
残差神经网络
在 ILSVRC 2015 中,由 Kaiming He 及其来自 Microsoft Research Asia 的合著者介绍了一种具有跳跃连接和批量归一化的新颖 CNN 架构,称为残差神经网络(ResNet)。 这样,他们就可以训练一个具有 152 层(比 VGG 网络深八倍)的神经网络,同时仍比 VGG 网络具有更低的复杂度。 它的前 5 个错误率达到 3.57%,在此数据集上超过了人类水平的表现。
该架构的主要思想如下。 他们没有希望一组堆叠的层将直接适合所需的基础映射H(x)
,而是尝试适应残差映射。 更正式地讲,他们让堆叠的层集学习残差R(x) = H(x) - x
,随后通过跳过连接获得真实映射。 然后将输入添加到学习的残差R(x) + x
。
同样,在每次卷积之后和激活之前立即应用批量归一化:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JABagmPu-1681567233333)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/1682c55a-64fa-4819-8159-98e2f3f4887f.png)]
剩余网络的一个组成部分
与 VGG-19 相比,这是完整的 ResNet 架构。 点缀的跳过连接显示尺寸增加; 因此,为了使添加有效,不执行填充。 同样,尺寸的增加由颜色的变化表示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uS6T1lcj-1681567233333)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/e8526d3b-0776-40c7-8c03-aa7933a3889c.png)]
到目前为止,我们已经讨论过的 CNN 模型的所有变体都可以在 Keras 和 TensorFlow 中作为预训练模型使用。 我们将在我们的迁移学习应用中大量使用它们。 这是用于加载各种 VGG 模型的 Keras 代码段。 可以在这里中找到更多内容:
from keras.applications.vgg16 import VGG16 model = VGG16() print(model.summary())
胶囊网络
我们已经讨论了各种 CNN 架构是如何演变的,并且已经研究了它们的连续改进。 现在我们可以将 CNN 用于更高级的应用,例如高级驾驶员辅助系统(ADAS)和自动驾驶汽车吗? 我们能否在现实世界中实时地检测道路上的障碍物,行人和其他重叠物体? 也许不会! 我们还不在那里。 尽管 CNN 在 ImageNet 竞赛中取得了巨大成功,但 CNN 仍然存在一些严重的局限性,将它们的适用性限制在更高级的现实问题中。 CNN 的翻译不变性差,并且缺乏有关方向的信息(或姿势)。
姿势信息是指相对于观看者的三维方向,还指照明和颜色。 旋转物体或改变照明条件时,CNN 确实会带来麻烦。 根据 Hinton 的说法,CNN 根本无法进行顺手性检测; 例如,即使他们都接受过这两种训练,他们也无法从右鞋中分辨出左鞋。 CNN 受到这些限制的原因之一是使用最大池化,这是引入不变性的粗略方法。 通过粗略不变性,我们的意思是,如果图像稍有移位/旋转,则最大合并的输出不会发生太大变化。 实际上,我们不仅需要不变性,还需要等价性; 即,在图像的对称变换下的不变性。
边缘检测器是 CNN 中的第一层,其功能与人脑中的视觉皮层系统相同。 大脑和 CNN 之间的差异出现在较高水平。 有效地将低层视觉信息路由到高层信息,例如各种姿势和颜色或各种比例和速度的对象,这是由皮质微柱完成的,Hinton 将其命名为胶囊。 这种路由机制使人的视觉系统比 CNN 更强大。
胶囊网络(CapsNets)对 CNN 架构进行了两个基本更改:首先,它们用向量输出胶囊代替 CNN 的标量输出特征检测器; 其次,他们将最大池与按协议路由一起使用。 这是一个简单的 CapsNet 架构:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-InYDkezg-1681567233333)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/86ce06a7-a636-494c-b62f-1addb7e0d1a3.png)]
这是一种浅薄的架构,需要根据 MNIST 数据(28 x 28
个手写数字图像)进行训练。 这具有两个卷积层。 第一卷积层具有 256 个特征图,具有9 x 9
内核(步幅为 1)和 ReLu 激活。 因此,每个特征图是(28 - 9 + 1) x (28 - 9 + 1)
或20 x 20
。第二个卷积层又具有 256 个特征图,具有9 x 9
个内核(步幅为 2)和 ReLu 激活。 这里每个特征图是6 x 6
,6 = ((20 - 9) / 2 + 1)
。 对该层进行了重塑,或者将特征图重新分组为 32 组,每组具有 8 个特征图(256 = 8 x 32
)。 分组过程旨在创建每个大小为 8 的特征向量。为了表示姿势,向量表示是一种更自然的表示。 来自第二层的分组特征图称为主胶囊层。 我们有(32 x 6 x 6
)八维胶囊向量,其中每个胶囊包含 8 个卷积单元,内核为9 x 9
,步幅为 2。最后一个胶囊层(DigitCaps)对于每十个类别有一个十六维的胶囊,这些胶囊中的每一个都从主胶囊层中的所有胶囊接收输入。
胶囊的输出向量的长度表示由胶囊表示的实体存在于当前输入中的概率。 胶囊向量的长度被归一化,并保持在 0 到 1 之间。此外,在向量的范数上使用了压缩函数,以使短向量缩小到几乎零长度,而长向量缩小到略小于 1 的长度。
压缩函数为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-apeZSEYY-1681567233334)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/f9d8bcc5-8454-4231-a9eb-defa4e9761d3.png)]
其中x
是向量的范数,因此x > 0
(请参见下图):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RKfzHKWp-1681567233334)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/9b0a1cc5-3e19-4f90-9f9d-70dc2ecafe72.png)]
W[ij]
是每个初级胶囊中u[i]
,i ∈ (1, 32 x 6 x 6)
和v[j]
,在 DigitCaps 中j ∈ (1, 10)
。 在此,u_hat[j|i] = w[ij]u[i]
被称为预测向量,并且像一个已转换(旋转/翻译)的输入胶囊向量u[i]
。 胶囊的总输入s[j]
是来自下一层胶囊的所有预测向量的加权总和。 这些权重c[ij]
的总和为 1,在 Hinton 中称为耦合系数。 一开始,它假设胶囊i
应该与母体胶囊j
结合的对数先验概率对于所有i
和j
都是相同的,用b[ij]
表示。 因此,可以通过此众所周知的 softmax 转换来计算耦合系数:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OFpGZgsu-1681567233334)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/0890948e-245c-4806-90f2-b79e2218dbbe.png)]
通过称为协议路由的算法,这些耦合系数与网络的权重一起迭代更新。 简而言之,它执行以下操作:如果主胶囊i
的预测向量与可能的父级j
的输出具有大的标量积,则耦合系数b[ij]
对于该父对象增加而对于其他父对象减少。
完整的路由算法在这里给出:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OsIQDwcW-1681567233334)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/5dda55cb-a1a3-4ce4-a112-ec0d16c5466f.png)]
左侧显示了如何通过权重矩阵W[ij]
将所有主胶囊连接到数字胶囊。 此外,它还描述了如何通过非线性压缩函数计算耦合系数以及如何计算 DigitCaps 的十六维输出。 在右侧,假设主胶囊捕获了两个基本形状:输入图像中的三角形和矩形。 旋转后将它们对齐会根据旋转量给出房屋或帆船。 很明显,这两个物体在极少或几乎没有旋转的情况下结合在一起,形成了帆船。 即,两个主胶囊比房屋更对准以形成船。 因此,路由算法应更新b[i, 船]
的耦合系数:
procedure routing (, r, l): for all capsule i in layer l and capsule j in layer (l + 1): bij <- 0 for r iterations do: for all capsule i in layer l: ci <- softmax (bi) for all capsule j in layer (l + 1): for all capsule j in layer (l + 1): vj <- squash (sj) for all capsule i in layer l and capsule j in layer (l + 1): return vj
最后,我们需要适当的损失函数来训练该网络。 在此,将数字存在的余量损失用作损失函数。 它还考虑了数字重叠的情况。 对于每个胶囊k
,单独的裕量损失L[k]
用于允许检测多个重叠的数字。 L[k]
观察胶囊向量的长度,对于k
类的数字,第k
个胶囊向量的长度应最大:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FnuR2Gal-1681567233335)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/eca8cda7-e58c-4af2-ad66-5d3f9208be75.png)]
如果存在第k
位,则T[k] = 1
。 m+ = 0.9
,m- = 0.1
。 λ
用于降低缺少数字类别的损失的权重。 与L[k]
一起,图像重建误差损失被用作网络的正则化。 如 CapsNet 架构所示,数字胶囊的输出被馈送到由三个完全连接的层组成的解码器中。 逻辑单元的输出与原始图像像素强度之间的平方差之和最小。 重建损失缩小了 0.0005 倍,因此在训练过程中它不控制边际损失。
循环神经网络
循环神经网络(RNN)专用于处理一系列值,如x(1) ... x(t)
。 例如,如果要在给定序列的最新历史的情况下预测序列中的下一项,或者将一种语言的单词序列翻译为另一种语言,则需要进行序列建模。 RNN 与前馈网络的区别在于其架构中存在反馈环路。 人们常说 RNN 有记忆。 顺序信息保留在 RNN 的隐藏状态中。 因此,RNN 中的隐藏层是网络的内存。 从理论上讲,RNN 可以任意长的顺序使用信息,但实际上,它们仅限于回顾一些步骤。
我们将在后面解释:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5XM9pfZ6-1681567233335)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/3fe6be82-124d-4f5d-9594-db0a4b4c22af.png)]
通过展开网络中的反馈回路,我们可以获得前馈网络。 例如,如果我们的输入序列的长度为 4,则可以按以下方式展开网络。 展开相同的权重集后,在所有步骤中共享U
,V
和W
,与传统 DNN 不同。 因此,实际上我们在每个步骤都执行相同的任务,只是输入的内容不同。 这大大减少了我们需要学习的参数总数。 现在,要学习这些共享的权重,我们需要一个损失函数。 在每个时间步长处,我们都可以将网络输出y(t)
与目标序列s(t)
进行比较,并得出误差E(t)
。 因此,总误差为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3k9WKX1u-1681567233335)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/8d0d1fbc-ce0d-4beb-93f9-259f72be5b1f.png)]:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1AV87Tef-1681567233336)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/74d14517-90ed-4828-aad4-1cb89b7b96e1.png)]
让我们看一下使用基于梯度的优化算法学习权重所需的总误差导数。 我们有h[t] = Uφh[t-1] + Wx[t]
,Φ
是非线性激活,而y[t] = Vφh[t]
。
现在是:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AEzrlToq-1681567233336)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/c591f7f1-05aa-4bda-8f15-b98ea25a8336.png)]
根据链式规则,我们有:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r6KGvILC-1681567233336)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/1b5b0979-6df5-4b37-ba08-82f68f8c5558.png)]
在此,雅可比行列式∂h[t]/∂h[k]
,即层t
相对于前一层k
本身是雅可比行列式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qzNLwrcK-1681567233337)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/2abf6ed9-391a-4e77-a7d4-5b5757349a19.png)]
的乘积。
使用前面的h[t]
方程,我们有:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8cD8MJAn-1681567233337)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/eda57a9e-cf19-4646-bd30-9138f3371662.png)]
因此,雅可比式∂h[t]/∂h[k]
的范数由乘积
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WeBqnx7Z-1681567233337)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/044603aa-f36f-4c54-b019-71057b3fb0b1.png)]
给出。 如果数量||∂h[s]/∂h[s-1]||
小于 1,则在较长的序列(例如 100 步)中,这些规范的乘积将趋于零。 同样,如果范数大于 1,则长序列的乘积将成倍增长。 这些问题在 RNN 中称为消失梯度和梯度爆炸。 因此,在实践中,RNN 不能具有很长的记忆。
LSTM
随着时间的流逝,RNN 开始逐渐失去历史背景,因此很难进行实际训练。 这就是 LSTM 出现的地方! LSTM 由 Hochreiter 和 Schmidhuber 于 1997 年引入,可以记住来自非常长的基于序列的数据中的信息,并可以防止梯度消失等问题。 LSTM 通常由三个或四个门组成,包括输入,输出和忘记门。
下图显示了单个 LSTM 单元的高级表示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BMjJXBhE-1681567233338)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/28d6b1a5-598b-4a4b-8941-33a4ee4718dd.png)]
输入门通常可以允许或拒绝进入的信号或输入以更改存储单元状态。 输出门通常会根据需要将该值传播到其他神经元。 遗忘门控制存储单元的自循环连接以根据需要记住或忘记以前的状态。 通常,将多个 LSTM 单元堆叠在任何深度学习网络中,以解决现实世界中的问题,例如序列预测。 在下图中,我们比较了 RNN 和 LSTM 的基本结构:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y9R7yANf-1681567233338)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/c2f733e7-5563-4092-aeec-2e286cba3f6d.png)]
下图显示了 LSTM 单元和信息流的详细架构。 令t
表示一个时间步长; C
为单元状态;h
为隐藏状态。 通过称为门的结构,LSTM 单元具有删除信息或向单元状态添加信息的能力。 门i
,f
和o
分别代表输入门,忘记门和输出门,它们中的每一个都由 Sigmoid 层调制, 输出从零到一的数字,控制这些门的输出应通过多少。 因此,这有助于保护和控制单元状态:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oER1ilsH-1681567233338)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/572ea417-a601-4d49-b75c-24e4f2f6a6e0.png)]
通过 LSTM 的信息流包括四个步骤:
- 决定要从单元状态中丢弃哪些信息:该决定由称为遗忘门层的 Sigmoid 决定。 将仿射变换应用于
h[t]
,x[t-1]
,并将其输出通过 Sigmoid 挤压函数传递,以得到一个介于 0 和 1 之间的数字。 单元状态C[t-1]
。 1 表示应保留内存,零表示应完全擦除内存。 - 决定将哪些新信息写入内存:这是一个两步过程。 首先,使用一个称为输入门层的 Sigmoid 层,即
i[t]
来确定将信息写入哪个位置。接下来,tanh 层将创建新的候选信息。 书面。 - 更新内存状态:将旧的内存状态乘以
f[t]
,擦除确定为可忘记的内容。 然后,在通过i[t]
缩放它们之后,添加在步骤 2 中计算的新状态信息。 - 输出存储器状态:单元状态的最终输出取决于当前输入和更新的单元开始。 首先,使用 Sigmoid 层来确定我们要输出的单元状态的哪些部分。 然后,单元状态通过 tanh 并乘以 Sigmoid 门的输出。
我建议您在查看 Christophers 的博客,以获取有关 LSTM 步骤的更详细说明。 我们在这里查看的大多数图表均来自此。
LSTM 可以用于序列预测以及序列分类。 例如,我们可以预测未来的股价。 另外,我们可以使用 LSTM 构建分类器,以预测来自某些健康监控系统的输入信号是致命还是非致命信号(二分类器)。 我们甚至可以使用 LSTM 构建文本文档分类器。 单词序列将作为 LSTM 层的输入,LSTM 的隐藏状态将连接到密集的 softmax 层作为分类器。
栈式 LSTM
如果我们想了解顺序数据的分层表示,可以使用 LSTM 层的栈。 每个 LSTM 层输出一个向量序列,而不是序列中每个项的单个向量,这些向量将用作后续 LSTM 层的输入。 隐藏层的这种层次结构使我们的顺序数据可以更复杂地表示。 堆叠的 LSTM 模型可用于对复杂的多元时间序列数据进行建模。
编码器-解码器 – 神经机器翻译
机器翻译是计算语言学的一个子领域,涉及将文本或语音从一种语言翻译成另一种语言。 传统的机器翻译系统通常依赖于基于文本统计属性的复杂特征工程。 最近,深度学习已被用于解决此问题,其方法称为神经机器翻译(NMT)。 NMT 系统通常由两个模块组成:编码器和解码器。
它首先使用编码器读取源句子,以构建思想向量:代表该句子含义的数字序列。 解码器处理句子向量以发出对其他目标语言的翻译。 这称为编码器-解码器架构。 编码器和解码器通常是 RNN 的形式。 下图显示了使用堆叠 LSTM 的编码器-解码器架构。 在这里,第一层是一个嵌入层,用于通过密集的实向量来表示源语言中的单词。 为源语言和目标语言都预定义了词汇表。 不在词汇表中的单词由固定单词<未知>
表示,并由固定嵌入向量表示。 该网络的输入首先是源句子,然后是句子标记的结尾,指示从编码模式到解码模式的转换,然后馈入目标句子:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yUsN69DX-1681567233338)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/9c3d34f8-aa07-489d-b95e-1d215daf0dee.png)]
数据来源:https://www.tensorflow.org/tutorials/seq2seq
输入嵌入层后面是两个堆叠的 LSTM 层。 然后,投影层将最上面的隐藏状态转换为尺寸为V
(目标语言的词汇量)的对率向量。 这里,交叉熵损失用于通过反向传播训练网络。 我们看到在训练模式下,源句子和目标句子都被输入到网络中。 在推理模式下,我们只有源句。 在那种情况下,可以通过几种方法来完成解码,例如贪婪解码,与贪婪解码结合的注意力机制以及集束搜索解码。 我们将在这里介绍前两种方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bdRMwcYL-1681567233339)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/52fe1877-dded-4161-8520-ba0d425f2452.png)]
在贪婪的解码方案中(请参见前面两个图的左手图),我们选择最有可能的单词(以最大对率值描述为发射的单词),然后将其反馈给解码器作为输入。 继续该解码过程,直到产生句子结束标记作为输出符号。
由源句子的句子结尾标记生成的上下文向量必须对我们需要了解的有关源句子的所有内容进行编码。 它必须充分体现其含义。 对于长句子,这意味着我们需要存储非常长的记忆。 研究人员发现,反转源序列或两次馈入源序列有助于网络更好地记忆事物。 对于与英语非常相似的法语和德语这样的语言,反转输入是有意义的。 对于日语,句子的最后一个单词可能会高度预测英语翻译中的第一个单词。 因此,这里的反转会降低翻译质量。 因此,一种替代解决方案是使用注意机制(如前两个图的右图所示)。
现在,无需尝试将完整的源句子编码为固定长度的向量,而是允许解码器在输出生成的每个步骤中使参与到源句子的不同部分。 因此,我们将第t
个目标语言单词的基于注意力的上下文向量c[t]
表示为所有先前源隐藏状态的加权和:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DJg3FVX4-1681567233339)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/823d1b46-4dad-4194-b79e-9cef6d5164fa.png)]
注意权重为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dExSWr3j-1681567233339)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/d2be8a4c-1bd0-415e-ae4f-39d41a0985df.png)]
得分的计算如下:sc(h[t], h[s]) = h[t] W h[s]
。
W
是权重矩阵,将与 RNN 权重一起学习。 该得分函数称为 Luong 的乘法样式得分。 此分数还有其他一些变体。 最后,通过将上下文向量与当前目标隐藏状态组合如下来计算注意向量,a[t]
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xgQ8IWA8-1681567233340)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/4e505ad7-0de3-474e-b874-95c380aec9b5.png)]
注意机制就像只读存储器,其中存储了源的所有先前隐藏状态,然后在解码时读取它们。 TensorFlow 中 NMT 的源代码可在此处获得。
门控循环单元
门控循环单元(GRU)与 LSTM 相关,因为两者均利用不同的门控信息方式来防止梯度消失和存储长期记忆。 GRU 具有两个门:重置门r
和更新门z
,如下图所示。 复位门确定如何将新输入与先前的隐藏状态h[t-1]
组合在一起,而更新门则确定要保留多少先前状态信息。 如果我们将重置设置为全 1 并将更新门更新为全零,我们将得到一个简单的 RNN 模型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-doZGEGJU-1681567233340)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/35710e6e-1f70-4ab8-9727-9c318f0e0d4f.png)]
GRU 相对较新,其表现与 LSTM 相当,但由于结构更简单,参数更少,因此它们在计算上更加高效。 这是 LSTM 和 GRU 之间的一些结构差异:
- 一个 GRU 有两个门,而 LSTM 有三个门。 GRU 没有 LSTM 中存在的输出门。
- 除隐藏状态外,GRU 没有其他内部内存
C[t]
。 - 在 GRU 中,当计算输出时,是非线性(tanh)的。
如果有足够的数据,建议使用 LSTM,因为 LSTM 的更高表达能力可能会导致更好的结果。
记忆神经网络
大多数机器学习模型无法读取和写入长期内存组件,也无法将旧内存与推理无缝结合。 RNN 及其变体(例如 LSTM)确实具有存储组件。 但是,它们的内存(由隐藏状态和权重编码)通常太小,不像我们在现代计算机中发现的大块数组(以 RAM 的形式)。 他们试图将所有过去的知识压缩为一个密集的向量-记忆状态。 对于诸如虚拟协助或问题解答(QA)系统之类的复杂应用,该应用可能会受到很大限制,在这种系统中,长期记忆有效地充当了(动态)知识库, 输出是文本响应。 为了解决这个问题,Facebook AI 研究小组开发了记忆神经网络(MemNNs)。 MemNN 的中心思想是将深度学习文献中为推理而开发的成功学习策略与可以像 RAM 一样读写的内存组件相结合。 同样,模型被训练以学习如何与存储组件一起有效地操作。 存储网络由存储器m
,对象的索引数组(例如,向量或字符串数组)和要学习的四个组件I, G, O, R
组成:
I
:输入特征映射I
,它将输入输入转换为内部特征表示。G
:通用化组件,G
,在输入新输入的情况下更新旧内存。 这被称为泛化,因为网络有机会在此阶段压缩和泛化其内存,以备将来使用。O
:输出特征图O
,在给定新输入和当前存储状态的情况下,该特征图空间中将生成新输出。R
:响应组件R
,可将输出转换为所需的响应格式,例如文本响应或动作:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XkbxH0D9-1681567233340)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/18baa50d-ad2a-47cf-8b6f-59d223cc0ea7.png)]
当分量I
,G
,O
和R
是神经网络时,则所得系统称为 MemNN。 让我们尝试通过示例质量检查系统来理解这一点。 系统将获得一系列事实和问题。 它将输出该问题的答案。 我们有以下六个文本事实和一个问题,问:“牛奶现在在哪里?”:
- 乔去了厨房
- 弗雷德去了厨房
- 乔拿起牛奶
- 乔去了办公室
- 乔离开了牛奶
- 乔去洗手间
请注意,语句的某些子集包含答案所需的信息,而其他子集本质上是无关紧要的。 我们将用 MemNN 模块I
,G
,O
和R
来表示这一点。模块I
是一个简单的嵌入模块,它将文本转换为二元词袋向量。 文本以其原始形式存储在下一个可用的存储插槽中,因此G
模块非常简单。 一旦去除了停用词,给定事实中使用的单词词汇为V = {乔, 弗雷德, 旅行, 捡起, 离开, 离开, 去办公室, 洗手间, 厨房, 牛奶}
。 现在,这是所有文本存储后的内存状态:
内存位置序号 | 乔 | 弗雷德 | … | 办公室 | 浴室 | 厨房 | 牛奶 |
1 | 1 | 0 | 0 | 0 | 1 | 0 | |
2 | 0 | 1 | 0 | 0 | 1 | 0 | |
3 | 1 | 0 | 0 | 0 | 0 | 1 | |
4 | 1 | 0 | 1 | 0 | 0 | 0 | |
5 | 1 | 0 | 0 | 0 | 0 | 1 | |
6 | 1 | 0 | 0 | 1 | 0 | 0 | |
7 |
O
模块通过在给定问题q
的情况下找到k
个支持存储器来产生输出特征。 对于k = 2
,使用以下方法检索最高得分的支持内存:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dZZrZszn-1681567233341)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/113b62ab-656d-4d22-9e1c-26c2855cf9e5.png)]
其中s[0]
是输入q
和m[i]
之间的评分函数,o1
是具有最佳匹配的内存m
的索引。 现在,使用查询和第一个检索到的内存,我们可以检索下一个内存m[o2]
,这两个内存都很接近:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AfdmjCNe-1681567233341)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/2b447e60-be65-4f11-a9e0-0b28d3c0e730.png)]
合并的查询和内存结果为o = [q, m[o1], m[o2]] = [现在牛奶在哪里, 乔离开了牛奶, 乔去了办公室]
。 最后,模块R
需要产生文本响应r
。 R
模块可以输出一个单词的答案,或者可以输出一个完整句子的 RNN 模块。 对于单字响应,令r
是对[q, m[o1], m[o2]]
和单词w
的回应。 因此,最后的回应r
是办公室一词:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xwpXtJQD-1681567233341)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/7edbfaa7-ef11-4918-b0bf-23ecb6bb5098.png)]
这种模型很难使用反向传播来进行端到端训练,并且需要在网络的每个模块上进行监督。 对此有一点修改,实际上是称为端到端存储网络(MemN2N)的连续版本的存储网络。 该网络可以通过反向传播进行训练。
MemN2Ns
我们从一个查询开始:牛奶现在在哪里? 使用大小为V
的向量,用成袋的单词进行编码。 在最简单的情况下,我们使用嵌入B(d x V)
将向量转换为大小为d
的词嵌入。 我们有u = embeddingB(q)
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vUzQ5I0A-1681567233341)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/d6252a46-1170-4bd3-a61c-ec067acd5310.png)]
输入句子x1, x2, ..., xi
通过使用另一个嵌入矩阵A(d x V)
存储在内存中,其大小与B[mi] = embeddingA(x[i])
。 每个嵌入式查询u
与每个内存m[i]
之间的相似度是通过取内积和 softmax 来计算的:p[i] = softmax(u^T m[i])
。
输出存储器表示如下:每个x[i]
具有对应的输出向量c[i]
,可以用另一个嵌入矩阵C
表示。 然后,来自存储器的响应向量o
是c[i]
上的总和,并由来自以下输入的概率向量加权:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tZwQpZpF-1681567233342)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/f448c97e-6ab7-4718-90ff-cc360122bce3.png)]
最后,将o
和u
之和与权重矩阵W(V x d)
相乘。 结果传递到 softmax 函数以预测最终答案:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vu48ZcIm-1681567233342)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/00a99297-3d3b-4387-a888-ff58f137672d.png)]
神经图灵机
神经图灵机(NTM)受到图灵机(TM)的启发:定义了一个抽象机。 TM 可以根据规则表来操作一条胶带上的符号。 对于任何计算机算法,TM 都可以模拟该算法的逻辑。 机器将其头放在单元格上方并在其中读取或写入符号。 此后,根据定义的规则,它可以向左或向右移动甚至停止程序。
NTM 架构包含两个基本组件:神经网络控制器和内存。 下图显示了 NTM 架构的高层表示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yLuj2AC6-1681567233342)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/08a67c09-f33c-4ff9-aa7c-0d8d43e74d6d.png)]
控制器使用输入和输出向量与外部世界进行交互。 与标准神经网络不同,此处的控制器还使用选择性读取和写入操作与存储矩阵进行交互。 内存是一个实值矩阵。 内存交互是端到端可区分的,因此可以使用梯度下降对其进行优化。 NTM 可以从输入和输出示例中学习简单的算法,例如复制,排序和关联召回。 而且,与 TM 不同,NTM 是可通过梯度下降训练的可微分计算机,为学习程序提供了一种实用的机制。
控制器可以由 LSTM 建模,LSTM 具有自己的内部存储器,可以补充矩阵中更大的存储器。 可以将控制器与计算机中的 CPU 相比较,并且可以将存储矩阵与计算机的 RAM 相比较。
读写头选择要读取或写入的内存部分。 可以通过神经网络中的隐藏层(可能是 softmax 层)对它们进行建模,以便可以将它们视为外部存储单元上的权重之和,这些权重之和为 1。此外,请注意,模型参数的数量是受控的,不会随存储容量的增长而增加。
选择性注意力
控制器输出用于确定要读取或写入的存储器位置。 这由一组分布在所有内存位置上的权重定义,这些权重之和为 1。权重由以下两种机制定义。 想法是为控制器提供几种不同的读取或写入内存的模式,分别对应于不同的数据结构:
- 基于内容的:使用相似度度量(例如余弦相似度)将控制器的键
k
输出与所有存储位置进行比较,然后所有距离均由 softmax 归一化,得到和为一的权重:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QKRdGX9X-1681567233342)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/9c2898fa-79f4-4806-a527-d2a1fbf1f977.png)]
在这种情况下,β ≥ 1
称为清晰度参数,并控制对特定位置的聚焦。 它还为网络提供了一种方法来决定其希望内存位置访问的精确度。 就像模糊均值聚类中的模糊系数。
- 基于位置的:基于位置的寻址机制旨在跨存储器位置的简单迭代。 例如,如果当前权重完全集中在单个位置上,则旋转 1 会将焦点移到下一个位置。 负移将使权重朝相反方向移动。 控制器输出一个移位内核
s
(即[-n, n]
上的 softmax),将其与先前计算的存储器权重进行卷积以产生移位的存储器位置,如下图所示。 这种转变是循环的; 也就是说,它环绕边界。 下图是内存的热图表示—较深的阴影表示更多的权重:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UFIzIGIX-1681567233342)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/0952f060-fd33-4b79-a530-a3ef4c96a006.png)]
在应用旋转移位之前,将内容寻址所给定的权重向量与先前的权重向量w[t-1]
相结合,如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nvwmSVml-1681567233343)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/31390bf5-05d0-4451-926c-5146b31a240c.png)]
在此,g[t]
是由控制器头发出的标量内插门,范围为(0, 1)
。 如果g[t] = 1
,则忽略先前迭代的加权。
读操作
令M[t]
为时间t
的N x M
存储矩阵的内容,其中N
是存储位置的数量,M
是每个位置的向量大小。 时间t
的读取头由向量w[t]
给出。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4wOb7KNY-1681567233343)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/1e4d609a-d3bb-41ee-8b63-6e137fa2eb4a.png)]
M
读取向量r[t]
的长度定义为行向量M[t](i)
的凸组合,在内存中:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pFMXH1Gl-1681567233343)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/3e35f31d-36ad-4097-aa25-7dcd5b0fe6ad.png)]
写操作
每个写头接收一个擦除向量, e[t]
和一个加性向量,a[t]
,以像 LSTM 单元一样重置和写入存储器,如下所示:M[t](i) ← M[t](i) [1 - e[t](i) w[t](i)] + w[t](i) a[t](i)
。
这是上述操作的伪代码:
mem_size = 128 #The size of memory mem_dim = 16 #The dimensionality for memory shift_range = 1 # defining shift[-1, 0, 1] ## last output layer from LSTM controller: last_output ## Previous memory state: M_prev def Linear(input_, output_size, stddev=0.5): '''Applies a linear transformation to the input data: input_ implements dense layer with tf.random_normal_initializer(stddev=stddev) as weight initializer '''' def get_controller_head(M_prev, last_output, is_read=True): k = tf.tanh(Linear(last_output, mem_dim)) # Interpolation gate g = tf.sigmoid(Linear(last_output, 1) # shift weighting w = Linear(last_output, 2 * shift_range + 1) s_w = softmax(w) # Cosine similarity similarity = smooth_cosine_similarity(M_prev, k) # [mem_size x 1] # Focusing by content content_focused_w = softmax(scalar_mul(similarity, beta)) # Convolutional shifts conv_w = circular_convolution(gated_w, s_w) if is_read: read = matmul(tf.transpose(M_prev), w) return w, read else: erase = tf.sigmoid(Linear(last_output, mem_dim) add = tf.tanh(Linear(last_output, mem_dim)) return w, add, erase
NTM 的完整 TensorFlow 实现可在此处获得。 NTM 算法可以学习复制-他们可以学习复制随机数序列的算法。 下面显示了 NTM 如何使用内存读写头并将其移位以实现复制算法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n1yLQjrs-1681567233343)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/0284727e-ebf8-4bc9-8074-24022d4a2558.png)]
类似地,给定一组随机序列和相应的排序序列,NTM 可以从数据中高效地学习排序算法。
基于注意力的神经网络模型
我们已经讨论了基于注意力的机器翻译模型。 基于注意力的模型的优点在于,它们提供了一种解释模型并理解其工作方式的方式。 注意机制是记忆以前的内部状态的一种形式。 这就像内部存储器。 与典型的存储器不同,这里的存储器访问机制是软的,这意味着网络将检索所有存储器位置的加权组合,而不是单个离散位置的值。 软存储器访问使通过反向传播训练网络变得可行。 基于注意的架构不仅用于机器翻译,还可以用于自动生成图像标题。
这项工作于 2016 年发表在论文《Show,Attend and Tell:带有视觉注意的神经图像字幕生成》上,作者是 Kelvin Xu 及其合著者。 在这里,从注意力权重来看,我们看到随着模型生成每个单词,其注意力发生变化以反映图像的相关部分。 此关注模型的 TensorFlow 实现可在此处获得:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DAaL0ihy-1681567233343)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/9c470dba-210a-4bfd-8a95-1227d45362b9.png)]
总结
本章介绍了神经网络架构的各种进展及其在各种实际问题中的应用。 我们讨论了对这些架构的需求,以及为什么简单的深度多层神经网络不能充分解决各种问题,因为它具有强大的表达能力和丰富的假设空间。 讨论迁移学习用例时,将在后面的章节中使用其中讨论的许多架构。 提供了几乎所有架构的 Python 代码参考。 我们还试图清楚地解释一些最近的架构,例如 CapsNet,MemNN 和 NTM。 当您逐步学习迁移学习用例时,我们将经常参考本章。
下一章将介绍转学的概念。
四、迁移学习基础
我还在学习。
——米开朗基罗
人类具有在任务之间传递知识的固有能力。 我们在学习一项任务时获得的知识就是我们以相同的方式来解决相关任务。 任务越相关,我们就越容易迁移或交叉利用知识。 到目前为止,到目前为止,机器学习和深度学习算法都是设计为独立工作的。 这些算法经过训练可以解决特定任务。 一旦特征空间分布发生变化,就必须从头开始重建模型。 迁移学习是克服孤立的学习范式,并利用一项任务获得的知识来解决相关任务的想法。 在本章中,我们将介绍迁移学习的概念,并专注于深度学习上下文的各个方面。 本章将涵盖以下主题:
- 迁移学习导论
- 迁移学习策略
- 通过深度学习迁移知识
- 深度迁移学习的类型
- 迁移学习的挑战
迁移学习导论
传统上,学习算法设计为单独解决任务或问题。 根据用例和手头数据的要求,应用算法来训练给定特定任务的模型。 传统的机器学习(ML)根据特定的域,数据和任务单独地训练每个模型,如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mJJ17cMX-1681567233344)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/0c813b73-4ddd-42c6-a8c1-79fc1597e8f2.png)]
传统机器学习
迁移学习使学习的过程更进一步,并且更加符合人类如何跨任务利用知识。 因此,迁移学习是一种将模型或知识重用于另一个相关任务的方法。 迁移学习有时也被视为现有 ML 算法的扩展。 在迁移学习的背景下,以及在了解如何在任务之间迁移知识的过程中,正在进行大量的研究和工作。 但是,神经信息处理系统(NIPS)1995 研讨会《学习:归纳系统中的知识整合和迁移》被认为是这个领域的研究。
从那时起,诸如元学习,知识整合和归纳迁移等术语已与迁移学习互换使用。 总是有不同的研究人员和学术著作提供不同背景下的定义。 在他们的书深度学习中,Goodfellow 等人。 在泛化的背景下指迁移学习。 它们的定义如下:
利用一种情况下所学的知识来改善另一种情况下的泛化的情况。
让我们借助示例来了解前面的定义。 假设我们的任务是在餐厅的受限区域内识别图像中的对象。 让我们在定义的范围内将此任务标记为T[1]
。 给定该任务的数据集,我们训练模型并对其进行调整,以使它在来自同一域(餐厅)的看不见的数据点上表现良好(概括)。 当我们在给定领域中没有足够的训练示例来完成所需的任务时,传统的监督 ML 算法就会崩溃。 假设我们现在必须从公园或咖啡馆中的图像中检测物体(例如,任务T[2]
)。 理想情况下,我们应该能够应用针对T[1]
训练的模型,但实际上,我们面临着表现下降和模型不能很好推广的问题。 发生这种情况的原因多种多样,我们可以广泛地和集体地将其称为模型对训练数据和领域的偏见。 因此,迁移学习使我们能够利用先前学习的任务中的知识,并将其应用于更新的相关任务。 如果我们拥有任务T[1]
的大量数据,则可以利用其学习并将其概括用于任务T[2]
(其数据要少得多)。 在图像分类的情况下,某些低级特征(例如边缘,形状和照明)可以在任务之间共享,因此可以在任务之间传递知识。
下图显示了迁移学习如何使现有知识重用于新的相关任务:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bpyg3hNr-1681567233344)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/8a932ea8-9a32-4475-8017-88d5e3fb917b.png)]
如上图所示,在学习目标任务时,来自现有任务的知识将作为附加输入。
迁移学习优势
我们利用源模型中的知识来改进目标任务中的学习。 除了提供重用已经构建的模型的功能之外,迁移学习还可以通过以下方式帮助学习目标任务:
- 改进了基准表现:当我们使用源模型中的知识来增强孤立的学习器(也称为无知学习器)的知识时,由于这种知识迁移,基准表现可能会提高 。
- 模型开发时间:与从头开始学习的目标模型相比,利用源模型的知识也可能有助于充分学习目标任务。 反过来,这会导致开发/学习模型所需的总时间减少。
- 改进的最终表现:可以利用迁移学习获得更高的最终表现。
读者应注意,有可能获得这些收益中的一项或多项,我们将在接下来的章节中详细讨论。 如下图所示,它显示出更好的基线表现(更高的起始),效率增益(更高的斜率)和更好的最终表现(渐近线更高) :
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xt3ZxeNQ-1681567233344)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/8f69a68a-52a7-4ae5-a2b1-019f7a344fc4.png)]
使用迁移学习的可能好处(来源:迁移学习,Lisa Torrey 和 Jude Shavlik)
迁移学习已在归纳学习器(例如神经网络和贝叶斯网络)的上下文中得到应用和研究。 强化学习是另一个探索迁移学习可能性的领域。 因此,迁移学习的概念不限于深度学习。
在本章及后续章节中,我们将限制使用迁移学习的范围仅限于深度学习的上下文。
迁移学习策略
首先让我们看一下迁移学习的正式定义,然后利用它来理解不同的策略。 在他们的论文《迁移学习综述》中,潘和杨使用域,任务和边缘概率,以提供用于理解迁移学习的框架。 该框架定义如下:
域D
定义为由特征空间χ
和边缘概率P(X)
组成的二元元组,其中X
是样本数据点。
在此,x = {x[1], x[2], .... x[n]}
,其中x[i]
作为X
的特定向量ε χ
。 从而:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FsWRD6t3-1681567233344)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/bedd445a-346d-4dd4-97f8-bf38e2fe755c.png)]
另一方面,可以将任务T
定义为标签空间γ
和目标函数f
的二元组。 从概率的观点来看,目标函数也可以表示为P(γ|Χ)
。 从而:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MevKoEDc-1681567233345)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/d21e706b-b7fc-4321-8536-06c2f01ee8ce.png)]
使用此框架,我们可以将迁移学习定义为旨在改善目标目标函数f(T)
(或目标任务T(T)
)的过程。使用来自T(S)
源的知识,在目标域中将D[T] D[S]
域中的任务。 这导致以下四种情况:
- 特征空间:源域和目标域的特征空间互不相同,例如
χ[s] ≠ χ[t]
。 例如,如果我们的任务与文档分类有关,则此方案以不同的语言引用源任务和目标任务。 - 边缘概率:边缘概率或源域和目标域不同,例如
P(X[s]) ≠ P(X[t])
。 这种情况也称为域适配。 - 标签空间:在这种情况下,源域和目标域的标签空间不同,例如
γ[s] ≠ γ[t]
。 这通常也意味着方案 4 的存在-不同的条件概率。 - 条件概率:在这种情况下,
P(Υ[s] | Χ[s]) ≠ P(Υ[t] | Χ[t])
,因此源域和目标域中的条件概率不同。
到目前为止,我们已经看到迁移学习具有在目标任务中利用来自源学习器的现有知识的能力。 在迁移学习过程中,必须回答以下三个重要问题:
- 迁移什么:这是整个过程中的第一步,也是最重要的一步。 我们尝试寻求有关知识的哪一部分可以从源迁移到目标的答案,以提高目标任务的表现。 当试图回答这个问题时,我们试图确定知识的哪一部分是特定于来源的,以及哪些是来源与目标之间的共同点。
- 何时迁移:在某些情况下,为了知识而迁移知识可能比改善任何事情都变得更糟(也称为负向迁移)。 我们应该以利用迁移学习为目标,以提高目标任务的表现/结果,而不是使其退化。 我们需要注意何时迁移以及何时不迁移。
- 如何迁移:一旦回答了什么和什么时候,我们便可以着手确定跨领域/任务实际迁移知识的方式。 这涉及对现有算法和不同技术的更改,我们将在本章的后续部分中介绍。 此外,下一节将列出特定的用例,以更好地了解如何进行迁移。
Pan 和 Yang 撰写的论文《迁移学习综述》可以在此处找到。
分组技术可帮助我们了解整体特征并提供更好的框架来利用它们。 可以根据所涉及的传统 ML 算法的类型对迁移学习方法进行分类,例如:
- 归纳迁移:在这种情况下,源域和目标域相同,但是源任务和目标任务彼此不同。 该算法尝试利用源域的归纳偏置来帮助改进目标任务。 根据源域是否包含标记数据,可以将其进一步分为两个子类别,分别类似于多任务学习和自学学习。
- 无监督迁移:此设置类似于归纳迁移本身,重点是目标域中的无监督任务。 源域和目标域相似,但是任务不同。 在这种情况下,带标签的数据在两个域中都不可用。
- 传递式迁移:在这种情况下,源任务和目标任务之间存在相似之处,但相应的域不同。 在此设置中,源域具有很多标记数据,而目标域则没有。 可以参考特征空间不同或边缘概率不同的设置将其进一步细分为子类别。
上一节中讨论的三种迁移类别概述了可以应用和详细研究迁移学习的不同设置。 为了回答在这些类别中迁移什么的问题,可以采用以下一些方法:
- 实例迁移:从源域到目标任务的知识重用通常是理想的方案。 在大多数情况下,无法直接重用源域数据。 而是,源域中的某些实例可以与目标数据一起重用以改善结果。 在感应迁移的情况下,Dai 及其合作者的 AdaBoost 之类的修改有助于利用源域中的训练实例来改进目标任务。
- 特征表示迁移:此方法旨在通过识别可从源域到目标域使用的良好特征表示,以最小化域差异并降低错误率。 根据标记数据的可用性,可以将有监督或无监督的方法应用于基于特征表示的迁移。
- 参数迁移:此方法在以下假设下工作:相关任务的模型共享一些参数或超参数的先前分布。 与多任务学习不同,在多任务学习中同时学习源任务和目标任务,对于迁移学习,我们可以对目标域的损失施加额外的权重以提高整体表现。
- 关系知识迁移:与前面三种方法不同,关系知识迁移尝试处理非 IID 数据,例如非独立且分布相同的数据。 换句话说,每个数据点与其他数据点都有关系的数据; 例如,社交网络数据利用关系知识迁移技术。
在本节中,我们以非常通用的方式研究了在不同背景和环境下进行迁移学习的不同策略。 现在让我们利用这种理解,学习如何在深度学习的上下文中应用迁移学习。
迁移学习和深度学习
深度学习模型代表了归纳学习。 归纳学习算法的目的是从一组训练示例中得出映射。 例如,在分类的情况下,模型学习输入特征和类标签之间的映射。 为了使这样的学习器能够很好地对看不见的数据进行概括,其算法采用了与训练数据的分布有关的一组假设。 这些假设集合称为感应偏置。
归纳偏差或假设可以由多个因素来表征,例如它所限制的假设空间以及通过假设空间进行的搜索过程。 因此,这些偏差会影响模型在给定任务和领域上的学习方式和知识。
归纳迁移技术利用源任务的归纳偏差来辅助目标任务。 这可以通过不同的方式来完成,例如通过限制模型空间,缩小假设空间来调整目标任务的归纳偏差,或者借助源任务的知识来对搜索过程本身进行调整。 下图直观地描述了此过程:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H1IBLpdB-1681567233345)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/c65cedd9-a157-4389-8433-18945df2fc9d.png)]
归纳式传递(来源:传递学习,Lisa Torrey 和 Jude Shavlik)
除了归纳迁移,归纳学习算法还利用贝叶斯和层次迁移技术来帮助改进目标任务的学习和表现。
迁移学习方法
近年来,深度学习取得了长足的进步,其结果令人赞叹。 但是,这种深度学习系统所需的训练时间和数据量比传统的 ML 系统高出几个数量级。
跨计算机视觉和自然语言处理(NLP)。 在大多数情况下,团队/人员共享这些网络的详细信息以供其他人使用(第 3 章“了解深度学习架构”中共享了一些受欢迎的网络)。 这些预训练的网络/模型在深度学习的背景下构成了迁移学习的基础。
特征提取
如第 3 章“了解深度学习架构”中所述,深度学习系统是分层的架构,可在不同的层学习不同的特征。 然后将这些层最终连接到最后一层(在分类的情况下,通常是完全连接的层)以获得最终输出。 这种分层的架构使我们可以利用预先训练的网络(例如 Inception V3 或 VGG),而无需将其最终层用作其他任务的固定特征提取器。 下图表示基于特征提取的深度迁移:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PVRf5DsR-1681567233345)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/d120bc80-6174-4e45-91a0-7f900fb3142f.png)]
例如,如果我们使用没有最终分类层的 AlexNet,它将帮助我们将新领域任务的图像基于其隐藏状态转换为 4,096 维向量,从而使我们能够利用来自源域任务的知识,从新领域任务中提取特征。 这是使用深度神经网络执行迁移学习的最广泛使用的方法之一。
微调
这是一项涉及更多的技术,我们不仅要替换最后一层(用于分类/回归),而且还要选择性地重新训练一些先前的层。 深度神经网络是具有各种超参数的高度可配置的架构。 如前所述,最初的层已捕获通用特征,而后面的层则更多地关注手头的特定任务。 利用这种洞察力,我们可以在重新训练时冻结(固定权重)某些层,或者微调其余层以满足我们的需求。 在这种情况下,我们利用网络整体架构方面的知识,并将其状态用作我们再训练步骤的起点。 反过来,这有助于我们以更少的训练时间获得更好的表现。
预训练模型
迁移学习的基本要求之一是在源任务上表现良好的模型的存在。 幸运的是,深度学习世界相信共享。 他们各自的团队已经公开共享了许多最先进的深度学习架构。 这些跨不同领域,例如计算机视觉和 NLP。 我们在第 3 章“了解深度学习架构”中介绍了一些最著名和文档最丰富的架构。 这些网络背后的团队不仅分享了结果,而且分享了他们的预训练模型。 预训练模型通常以数百万个参数/权重的形式共享,该模型在被训练到稳定状态时所达到的模型。 预训练的模型可供每个人通过不同的方式使用。 著名的深度学习 Python 库keras
提供了下载各种可用的预训练网络的接口,例如 XCeption,VGG16 和 InceptionV3。 同样,也可以通过 TensorFlow 和其他深度学习库获得预训练的模型。 伯克利的模型动物园提供了多年来开发的更广泛的预训练模型集合。
应用领域
深度学习是一类算法,已被用来非常成功地获得迁移学习的好处。 以下是一些示例:
- 使用文本数据进行迁移学习:当涉及到机器学习和深度学习时,文本数据提出了各种挑战。 这些通常使用不同的技术进行转换或向量化。 嵌入(例如 Word2vec 和 fastText)已使用不同的训练数据集进行了准备。 通过从源任务中迁移知识,这些变量可用于不同任务中,例如情感分析和文档分类。
- 通过计算机视觉进行迁移学习:深度学习已成功使用各种 CNN 架构成功用于各种计算机视觉任务,例如对象识别。 在他们的论文《深层神经网络的特征如何可传递》中,Yosinski 及其合作者提出了他们的发现,关于较低的层如何作为常规的计算机视觉特征提取器,例如边缘检测器,而最后一层则用于特定任务的特征。 因此,这些发现有助于将现有的最新模型,例如 VGG,AlexNet 和 Inceptions 用于目标任务,例如作为样式转换和面部检测,与这些模型的训练方法不同。
- 语音/音频迁移学习:类似于文本和计算机视觉领域,深度学习已成功用于基于音频数据的任务。 例如,为英语开发的自动语音识别(ASR)模型已成功用于提高其他语言(例如德语)的语音识别表现。 同样,自动说话人识别是迁移学习大大帮助的另一个例子。
深度迁移学习类型
关于迁移学习的文献经历了许多迭代,并且如本章开头所提到的,与迁移学习相关的术语被松散使用并且经常可以互换使用。 因此,有时难以区分迁移学习,领域适应和多任务学习。 放心,这些都是相关的,并尝试解决类似的问题。 为了使本书保持一致,我们将采用迁移学习的概念作为一般概念,在此我们将尝试使用源任务域知识来解决目标任务。
领域适应
域适配通常是指源域和目标域之间的边缘概率不同的情况,例如P(X[s]) ≠ P(X[t])
。 源域和目标域的数据分布存在固有的偏移或漂移,需要进行调整才能迁移学习。 例如,标记为肯定或否定的电影评论语料库将不同于产品评论情感的语料库。 如果用于对产品评论进行分类,则经过电影评论情感训练的分类器将看到不同的分布。 因此,在这些情况下,领域自适应技术可用于迁移学习中。
域混乱
我们学习了不同的迁移学习策略,甚至讨论了如何将知识从源迁移到目标的三个问题。 特别是,我们讨论了特征表示传递如何有用。 值得重申的是,深度学习网络中的不同层捕获了不同的特征集。 我们可以利用这一事实来学习领域不变的特征,并提高其跨领域的可移植性。 代替让模型学习任何表示,我们将两个域的表示微调为尽可能相似。
这可以通过将某些预处理步骤直接应用于表示本身来实现。 孙宝琛,冯家石和 Kate Saenko 在他们的论文 《令人沮丧的轻松域自适应》中讨论了其中一些问题。 Ganin 等人也提出了对表示相似性的轻推,在他们的论文《神经网络领域专家训练》中。 该技术背后的基本思想是在源模型中添加另一个目标,以通过混淆域本身来鼓励相似性,从而使域混淆。
多任务学习
多任务学习与迁移学习世界略有不同。 在多任务学习的情况下,可以同时学习多个任务,而无需区分源和目标。 在这种情况下,与迁移学习相比,学习器一次就接收到有关多个任务的信息,在迁移学习中,学习器最初对目标任务一无所知。
如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-64cFqLWf-1681567233345)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/93186224-8b4d-4459-98e7-a21fd5aaf615.png)]
多任务学习:学习器同时从所有任务接收信息
单样本学习
深度学习系统天生就渴望数据,因此它们需要许多训练示例来学习权重。 这是深度神经网络的局限性之一,尽管人类学习并非如此。 例如,一旦向孩子展示了苹果的外观,他们就可以轻松识别出不同种类的苹果(带有一个或几个训练示例); 机器学习和深度学习算法并非如此。 单样本学习是迁移学习的一种变体,在这种学习中,我们尝试仅根据一个或几个训练示例来推断所需的输出。 这在无法为每个可能的类提供标签数据的现实世界场景中(如果是分类任务)和在经常可以添加新类的场景中非常有用。
据说 Fei-Fei 及其合作者具有里程碑意义的论文《对象类别的单发学习》。 在此子领域创造了“单样本学习和研究”一词。 本文提出了一种用于对象分类的表示学习的贝叶斯框架的变体。 此后,此方法已得到改进,并已使用深度学习系统进行了应用。
零样本学习
零镜头学习是迁移学习的另一个极端变体,它不依赖任何标记的示例来学习任务。 这听起来令人难以置信,尤其是当使用示例学习是大多数监督学习算法所要解决的问题时。 零数据学习或零短学习方法在训练阶段本身进行了巧妙的调整,以利用附加信息来理解看不见的数据。 在他们的《学会学习》一书中,Goodfellow 及其合作者提出了零样本学习作为学习三个变量的场景,例如传统输入变量x
,传统输出变量y
以及描述任务的其他随机变量T&
。 因此,训练模型以学习P(y | x, T)
的条件概率分布。 零镜头学习在机器翻译等场景中非常有用,在这种情况下,我们甚至可能没有目标语言的标签。
迁移学习的挑战
迁移学习具有巨大的潜力,并且是现有学习算法通常需要的增强。 但是,与迁移学习相关的某些相关问题需要更多的研究和探索。 除了难以回答关于什么,什么时候以及如何迁移的问题之外,负迁移和迁移界限也带来了重大挑战。
负迁移
到目前为止,我们讨论的案例都是基于源任务的知识迁移来实现目标任务的改进。 在某些情况下,迁移学习会导致表现下降。 负迁移是指从源到目标的知识迁移不会导致任何改善,而是导致目标任务的整体表现下降的情况。 负迁移的原因可能有多种,例如源任务与目标任务的关系不充分或迁移方法不能很好地利用源任务和目标任务之间的关系的情况。 避免负迁移非常重要,需要仔细调查。 在他们的工作中,Rosenstien 及其合作迁移经验上介绍了当源与目标过于不同时,暴力传递如何降低目标任务的表现。 正在研究 Bakker 及其合作者的贝叶斯方法,以及探索基于聚类的解决方案以识别相关性的其他技术,以避免产生负迁移。
迁移的界限
在迁移学习中量化迁移也非常重要,这对迁移的质量及其可行性具有影响。 为了衡量迁移的数量,哈桑·马哈茂德(Hassan Mahmud)及其合作者使用 Kolmogorov 复杂度证明了一定的理论界限,以分析迁移学习并衡量任务之间的相关性。 Eaton 及其合作者提出了一种新颖的基于图的方法来衡量知识迁移。 这些技术的详细讨论超出了本书的范围。 鼓励读者使用本节概述的出版物来探讨这些主题。
总结
在本书的第 1 章至第 3 章中设置了 ML 和深度学习的上下文和基础之后,本章开始了第二阶段的学习,即建立迁移学习的基础。 在深入研究实际用例之前,必须正式化对迁移学习的理解,并了解不同的技术和研究以及与之相关的挑战。 在本章中,我们介绍了迁移学习概念背后的基础知识,多年来的发展情况以及为什么首先需要迁移学习。
我们首先在学习算法及其相关优势的更广泛背景下理解迁移学习。 然后,我们讨论了用于理解,应用和分类迁移学习方法的各种策略。 在深度学习的背景下,迁移学习是下一个讨论的主题,为本章的其余部分定下了基调。 我们讨论了与深度迁移学习相关的不同迁移学习方法,例如特征提取和微调。 我们还介绍了著名的预训练模型和使用深度学习系统的迁移学习的流行应用。 近年来,深度学习已被证明是非常成功的,因此,在此领域中使用迁移学习已进行了大量研究。
我们简要讨论了深度迁移学习的不同变体,例如域自适应,域混淆,多任务学习,单样本学习, 和零样本学习。 我们通过介绍与迁移学习相关的挑战(例如负迁移和迁移边界)来结束本章。 在本章中,我们概述了与迁移学习相关的各种研究出版物和链接,并鼓励读者探索它们以获取更多信息。 本章将作为当前过渡学习领域的指导和概述。 敬请关注下一章的更多细节,我们将提供一些与转学相关的动手练习。
五、释放迁移学习的力量
在上一章中,我们介绍了围绕迁移学习的主要概念。 关键思想是,与从头开始构建自己的深度学习模型和架构相比,在各种任务中利用先进的,经过预训练的深度学习模型可产生更好的结果。 在本章中,我们将获得一个更动手的观点,即使用迁移学习实际构建深度学习模型并将其应用于实际问题。 有无迁移学习,我们将构建各种深度学习模型。 我们将分析它们的架构,并比较和对比它们的表现。 本章将涵盖以下主要方面:
- 迁移学习的必要性
- 从头开始构建卷积神经网络(CNN)模型:
- 建立基本的 CNN 模型
- 通过正则化改进我们的 CNN 模型
- 通过图像增强改善我们的 CNN 模型
- 在预训练的 CNN 模型中利用迁移学习:
- 使用预训练模型作为特征提取器
- 通过图像增强改进我们的预训练模型
- 通过微调改进我们的预训练模型
- 模型表现评估
我们要感谢 Francois Chollet 不仅创建了令人惊叹的深度学习框架 Keras,还感谢他在他的书《Python 深度学习》中谈到了有效学习迁移的现实世界问题。 在本章中,我们以此为灵感来刻画了迁移学习的真正力量。 本章的代码将在 GitHub 存储库中的文件夹中提供,根据需要遵循本章。
迁移学习的必要性
我们已经在第 4 章“迁移学习基础”中简要讨论了迁移学习的优势。 概括地说,与从头开始构建深度学习模型相比,我们获得了一些好处,例如,改善了基准表现,加快了整体模型的开发和训练时间,并且还获得了整体改进和优越的模型表现。 这里要记住的重要一点是,迁移学习作为一个领域早已在深度学习之前就存在了,并且还可以应用于不需要深度学习的领域或问题。
现在让我们考虑一个现实世界的问题,在本章中,我们还将继续使用它来说明我们不同的深度学习模型,并在同一模型上利用迁移学习。 您必须一次又一次听到深度学习的关键要求之一是,我们需要大量数据和样本来构建可靠的深度学习模型。 其背后的想法是模型可以从大量样本中自动学习特征。 但是,如果我们没有足够的训练样本并且要解决的问题仍然是一个相对复杂的问题,我们该怎么办? 例如,计算机视觉问题,例如图像分类,可能难以使用传统的统计技术或机器学习(ML)技术解决。 我们会放弃深度学习吗?
考虑到图像分类问题,由于我们要处理的图像本质上是高维张量,因此拥有更多数据可使深度学习模型学习更好的图像基本特征表示。 但是,即使我们每个类别的图像样本的范围从几百到数千,基本的 CNN 模型在正确的架构和规范化条件下仍能正常运行。 这里要记住的关键点是,CNN 会学习与缩放,平移和旋转不变的模式和特征,因此我们在这里不需要自定义特征工程技术。 但是,我们可能仍然会遇到模型过拟合之类的问题,我们将在本章稍后部分尝试解决这些问题。
关于迁移学习,已经在著名的 ImageNet 数据集上训练了一些出色的预训练深度学习模型。 我们已经在第 3 章“了解深度学习架构”中详细介绍了其中一些模型,本章将利用著名的VGG-16
模型。 想法是使用通常是图像分类专家的预训练模型来解决我们的问题,即数据样本较少。
制定我们的现实问题
正如我们前面提到的,我们将在图像分类问题上进行工作,每个类别的训练样本数量较少。 我们的问题的数据集可在 Kaggle 上获得,它是其中最受欢迎的基于计算机视觉的数据集之一。 我们将使用的数据集来自猫狗挑战,而我们的主要目标是建立一个可以成功识别图像并将其分类为猫或狗的模型。 就机器学习而言,这是一个基于图像的二分类问题。
首先,从数据集页面下载train.zip
文件并将其存储在本地系统中。 下载后,将其解压缩到文件夹中。 该文件夹将包含 25,000 张猫和狗的图像; 即每个类别 12500 张图像。
建立我们的数据集
虽然我们可以使用所有 25,000 张图像并在它们上建立一些不错的模型,但是,如果您还记得的话,我们的问题目标包括增加的约束,即每类图像的数量很少。 为此,我们构建自己的数据集。 如果您想自己运行示例,可以参考Datasets Builder.ipynb
Jupyter 笔记本。
首先,我们加载以下依赖项,包括一个名为utils
的工具模块,该模块在本章代码文件中的utils.py
文件中可用。 当我们将图像复制到新文件夹时,这主要用于获得视觉进度条:
import glob import numpy as np import os import shutil from utils import log_progress np.random.seed(42)
现在,如下所示将所有图像加载到原始训练数据文件夹中:
files = glob.glob('train/*') cat_files = [fn for fn in files if 'cat' in fn] dog_files = [fn for fn in files if 'dog' in fn] len(cat_files), len(dog_files) Out [3]: (12500, 12500)
我们可以使用前面的输出来验证每个类别有 12,500 张图像。 现在,我们构建较小的数据集,以使我们有 3,000 张图像用于训练,1,000 张图像用于验证和 1,000 张图像用于我们的测试数据集(两个动物类别的表示均相同):
cat_train = np.random.choice(cat_files, size=1500, replace=False) dog_train = np.random.choice(dog_files, size=1500, replace=False) cat_files = list(set(cat_files) - set(cat_train)) dog_files = list(set(dog_files) - set(dog_train)) cat_val = np.random.choice(cat_files, size=500, replace=False) dog_val = np.random.choice(dog_files, size=500, replace=False) cat_files = list(set(cat_files) - set(cat_val)) dog_files = list(set(dog_files) - set(dog_val)) cat_test = np.random.choice(cat_files, size=500, replace=False) dog_test = np.random.choice(dog_files, size=500, replace=False) print('Cat datasets:', cat_train.shape, cat_val.shape, cat_test.shape) print('Dog datasets:', dog_train.shape, dog_val.shape, dog_test.shape) Cat datasets: (1500,) (500,) (500,) Dog datasets: (1500,) (500,) (500,)
现在我们已经创建了数据集,让我们将它们写到单独文件夹中的磁盘中,以便我们将来可以在任何时候返回它们,而不必担心它们是否存在于主内存中:
train_dir = 'training_data' val_dir = 'validation_data' test_dir = 'test_data' train_files = np.concatenate([cat_train, dog_train]) validate_files = np.concatenate([cat_val, dog_val]) test_files = np.concatenate([cat_test, dog_test]) os.mkdir(train_dir) if not os.path.isdir(train_dir) else None os.mkdir(val_dir) if not os.path.isdir(val_dir) else None os.mkdir(test_dir) if not os.path.isdir(test_dir) else None for fn in log_progress(train_files, name='Training Images'): shutil.copy(fn, train_dir) for fn in log_progress(validate_files, name='Validation Images'): shutil.copy(fn, val_dir) for fn in log_progress(test_files, name='Test Images'): shutil.copy(fn, test_dir)
一旦所有图像都复制到各自的目录中,以下屏幕快照中描述的进度条将变为绿色:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k7fnSb6t-1681567233345)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/3a4d72af-af1e-4c54-810d-6190c28141c9.png)]
制定我们的方法
由于这是图像分类问题,因此我们将利用 CNN 模型或 convNets 尝试解决此问题。 在本章开始时,我们简要讨论了我们的方法。 我们将从头开始构建简单的 CNN 模型,然后尝试使用正则化和图像增强等技术进行改进。 然后,我们将尝试利用预训练的模型来释放转学的真正力量!
从头开始构建 CNN 模型
让我们开始构建图像分类分类器。 我们的方法是在训练数据集上建立模型,并在验证数据集上进行验证。 最后,我们将在测试数据集上测试所有模型的表现。 在进入建模之前,让我们加载并准备数据集。 首先,我们加载一些基本的依赖项:
import glob import numpy as np import matplotlib.pyplot as plt from keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array, array_to_img %matplotlib inline
现在,使用以下代码片段加载数据集:
IMG_DIM = (150, 150) train_files = glob.glob('training_data/*') train_imgs = [img_to_array(load_img(img, target_size=IMG_DIM)) for img in train_files] train_imgs = np.array(train_imgs) train_labels = [fn.split('/')[1].split('.')[0].strip() for fn in train_files] validation_files = glob.glob('validation_data/*') validation_imgs = [img_to_array(load_img(img, target_size=IMG_DIM)) for img in validation_files] validation_imgs = np.array(validation_imgs) validation_labels = [fn.split('/')[1].split('.')[0].strip() for fn in validation_files] print('Train dataset shape:', train_imgs.shape, 'tValidation dataset shape:', validation_imgs.shape) Train dataset shape: (3000, 150, 150, 3) Validation dataset shape: (1000, 150, 150, 3)
我们可以清楚地看到我们有3000
训练图像和1000
验证图像。 每个图像的尺寸为150 x 150
,并具有用于红色,绿色和蓝色(RGB)的三个通道,因此为每个图像提供(150
,150
,3
)尺寸。 现在,我们将像素值在(0, 255)
之间的每个图像缩放到(0, 1)
之间的值,因为深度学习模型在较小的输入值下确实可以很好地工作:
train_imgs_scaled = train_imgs.astype('float32') validation_imgs_scaled = validation_imgs.astype('float32') train_imgs_scaled /= 255 validation_imgs_scaled /= 255 # visualize a sample image print(train_imgs[0].shape) array_to_img(train_imgs[0]) (150, 150, 3)
前面的代码生成以下输出:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9yFjTnQx-1681567233346)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/cec84552-8b64-4c85-a3c1-41ebd47bfb10.png)]
前面的输出显示了我们训练数据集中的示例图像之一。 现在,让我们设置一些基本的配置参数,并将文本类标签编码为数值(否则,Keras 将抛出错误):
batch_size = 30 num_classes = 2 epochs = 30 input_shape = (150, 150, 3) # encode text category labels from sklearn.preprocessing import LabelEncoder le = LabelEncoder() le.fit(train_labels) train_labels_enc = le.transform(train_labels) validation_labels_enc = le.transform(validation_labels) print(train_labels[1495:1505], train_labels_enc[1495:1505]) ['cat', 'cat', 'cat', 'cat', 'cat', 'dog', 'dog', 'dog', 'dog', 'dog'] [0 0 0 0 0 1 1 1 1 1]
我们可以看到,我们的编码方案将0
分配给cat
标签,将1
分配给dog
标签。 现在,我们准备构建我们的第一个基于 CNN 的深度学习模型。
基本的 CNN 模型
我们将从建立具有三个卷积层的基本 CNN 模型开始,再加上用于从图像中自动提取特征的最大池化,以及对输出卷积特征图进行下采样。 要刷新有关卷积和池化层如何工作的记忆,请查看第 3 章“了解深度学习架构”中的 CNN 部分。
提取这些特征图后,我们将使用一个密集层以及一个具有 S 型函数的输出层进行分类。 由于我们正在执行二分类,因此binary_crossentropy
损失函数就足够了。 我们将使用流行的 RMSprop 优化器,该优化器可帮助我们使用反向传播来优化网络中单元的权重,从而使网络中的损失降到最低,从而得到一个不错的分类器。 请参阅第 2 章,“深度学习要点”中的“随机梯度下降”和“SGD 改进”部分,以获取有关优化器如何工作的深入见解。 简而言之,优化器(如 RMSprop)指定有关损耗梯度如何用于更新传递到我们网络的每批数据中的参数的规则。
让我们利用 Keras 并立即构建我们的 CNN 模型架构:
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout from keras.models import Sequential from keras import optimizers model = Sequential() # convolution and pooling layers model.add(Conv2D(16, kernel_size=(3, 3), activation='relu', input_shape=input_shape)) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(64, kernel_size=(3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(128, kernel_size=(3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Flatten()) model.add(Dense(512, activation='relu')) model.add(Dense(1, activation='sigmoid')) model.compile(loss='binary_crossentropy', optimizer=optimizers.RMSprop(), metrics=['accuracy']) model.summary() _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_1 (Conv2D) (None, 148, 148, 16) 448 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 74, 74, 16) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 72, 72, 64) 9280 _________________________________________________________________ max_pooling2d_2 (MaxPooling2 (None, 36, 36, 64) 0 _________________________________________________________________ conv2d_3 (Conv2D) (None, 34, 34, 128) 73856 _________________________________________________________________ max_pooling2d_3 (MaxPooling2 (None, 17, 17, 128) 0 _________________________________________________________________ flatten_1 (Flatten) (None, 36992) 0 _________________________________________________________________ dense_1 (Dense) (None, 512) 18940416 _________________________________________________________________ dense_2 (Dense) (None, 1) 513 ================================================================= Total params: 19,024,513 Trainable params: 19,024,513 Non-trainable params: 0
前面的输出向我们展示了我们的基本 CNN 模型摘要。 就像我们之前提到的,我们使用三个卷积层进行特征提取。 平整层用于平整我们从第三卷积层获得的17 x 17
特征图中的 128 个。 这被馈送到我们的密集层,以最终确定图像是狗(1)还是猫(0)。 所有这些都是模型训练过程的一部分,因此,让我们使用以下利用fit(...)
函数的代码片段训练模型。 以下几项对于训练我们的模型非常重要:
batch_size
表示每次迭代传递给模型的图像总数- 每次迭代后,将更新层中单元的权重
- 迭代总数始终等于训练样本总数除以
batch_size
- 一个周期是整个数据集一次通过网络,即所有迭代均基于数据批量而完成
我们使用30
的batch_size
,我们的训练数据总共有 3,000 个样本,这表示每个周期总共有 100 次迭代。 我们对模型进行了总共 30 个周期的训练,并因此在我们的 1,000 张图像的验证集上进行了验证:
history = model.fit(x=train_imgs_scaled, y=train_labels_enc, validation_data=(validation_imgs_scaled, validation_labels_enc), batch_size=batch_size, epochs=epochs, verbose=1) Train on 3000 samples, validate on 1000 samples Epoch 1/30 3000/3000 - 10s - loss: 0.7583 - acc: 0.5627 - val_loss: 0.7182 - val_acc: 0.5520 Epoch 2/30 3000/3000 - 8s - loss: 0.6343 - acc: 0.6533 - val_loss: 0.5891 - val_acc: 0.7190 ... ... Epoch 29/30 3000/3000 - 8s - loss: 0.0314 - acc: 0.9950 - val_loss: 2.7014 - val_acc: 0.7140 Epoch 30/30 3000/3000 - 8s - loss: 0.0147 - acc: 0.9967 - val_loss: 2.4963 - val_acc: 0.7220
根据训练和验证的准确率值,我们的模型似乎有点过拟合。 我们可以使用以下代码段绘制模型的准确率和误差,以获得更好的视角:
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4)) t = f.suptitle('Basic CNN Performance', fontsize=12) f.subplots_adjust(top=0.85, wspace=0.3) epoch_list = list(range(1,31)) ax1.plot(epoch_list, history.history['acc'], label='Train Accuracy') ax1.plot(epoch_list, history.history['val_acc'], label='Validation Accuracy') ax1.set_xticks(np.arange(0, 31, 5)) ax1.set_ylabel('Accuracy Value') ax1.set_xlabel('Epoch') ax1.set_title('Accuracy') l1 = ax1.legend(loc="best")
ax2.plot(epoch_list, history.history['loss'], label='Train Loss') ax2.plot(epoch_list, history.history['val_loss'], label='Validation Loss') ax2.set_xticks(np.arange(0, 31, 5)) ax2.set_ylabel('Loss Value') ax2.set_xlabel('Epoch') ax2.set_title('Loss') l2 = ax2.legend(loc="best")
以下图表利用了历史对象,其中包含每个周期的精度和损耗值:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sdudWwLP-1681567233346)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/d38f922d-b1ed-41c4-888c-146a5fa4c0a1.png)]
您可以清楚地看到,在 2-3 个周期之后,模型开始对训练数据进行过拟合。 我们在验证集中获得的平均准确率约为 72%,这不是一个不好的开始! 我们可以改进此模型吗?
Python 迁移学习实用指南:1~5(5)https://developer.aliyun.com/article/1426850