学校网站建设的软件环境,学生网站设计,品牌网站建设 蝌蚪小7,上海手机网站制作哪家好原文#xff1a;Hands-On One-shot Learning with Python 协议#xff1a;CC BY-NC-SA 4.0 译者#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】#xff0c;采用译后编辑#xff08;MTPE#xff09;流程来尽可能提升效率。 不要担心自己的形象#xff0c;只关心如… 原文Hands-On One-shot Learning with Python 协议CC BY-NC-SA 4.0 译者飞龙 本文来自【ApacheCN 深度学习 译文集】采用译后编辑MTPE流程来尽可能提升效率。 不要担心自己的形象只关心如何实现目标。——《原则》生活原则 2.3.c 第一部分单样本学习简介
深度学习给制造业带来了重大变化无论是制造业医疗还是人力资源。 通过这一重大革命和概念验证几乎每个行业都在尝试调整其业务模型以适应深度学习但是它有一些主要要求可能并不适合每个业务或行业。 阅读本节后您将对深度学习的优缺点有适当的了解。
本节包括以下章节
第 1 章“单样本学习简介”
一、单样本学习简介
人们可以通过少量示例学习新事物。 当受到刺激时人类似乎能够快速理解新概念然后在将来认识到这些概念的变体。 孩子可以从一张图片中学会识别狗但是机器学习系统需要大量示例来学习狗的特征并在将来识别它们。 作为一个领域机器学习在各种任务例如分类和 Web 搜索以及图像和语音识别上都取得了巨大的成功。 但是这些模型通常在没有大量数据示例可供学习的情况下表现不佳。 本书的主要动机是使用很少的示例来训练模型而无需进行大量的重新训练就能够将其概括为不熟悉的类别。
深度学习在机器学习的发展中发挥了重要作用但它也需要大量的数据集。 不同的技术例如正则化可以减少在低数据环境中的过拟合但不能解决较少的训练示例所固有的问题。 此外大型数据集导致学习缓慢需要使用梯度下降法进行许多权重更新。 这主要是由于 ML 算法的参数方面在该方面需要慢慢学习训练示例。 相反许多已知的非参数模型例如最近邻居不需要任何训练但是表现取决于有时任意选择的距离度量例如 L2 距离。 单样本学习是计算机视觉中的对象分类问题。 尽管大多数基于 ML 的对象分类算法都需要数百或数千张图像和非常大的数据集进行训练但是单样本学习的目的是从一个或仅几个训练图像中学习有关对象类别的信息。 在本章中我们将学习单样本学习的基础知识并探索其实际应用。
本章将涵盖以下主题
人脑概述机器学习-历史概述单样本学习-概述设置环境编码练习
技术要求
需要使用以下库来学习和执行本章中的项目
PythonAnacondaJupyter 笔记本PyTorchMatplotlibScikit-Learn
您可以在本书的 GitHub 存储库中找到本章的代码文件。
人脑概述
自文明开始以来人脑一直是研究的主题。 如果我们研究孩子的成长我们会发现随着他们的成长他们的学习能力也会提高。 首先他们了解食物然后学习识别面孔。 每当孩子学到东西时信息就会被编码到大脑的某个部分。 尽管如此真正的问题仍然存在信息如何存储在我们的大脑中 为什么有些信息被硬编码而其他信息却容易被忘记
人脑如何学习
关于大脑如何训练自己以处理数据的大多数信息是未知的但是有各种理论可以对其进行探索。 如下图所示如果我们查看大脑神经元的结构则神经元的工作方式类似于收集器其中它通过树突从其他神经元收集信号。 一旦信号变强神经元就会通过称为轴突的细链向附近的神经元发出电信号。 在该网络的末端突触将信号活动转换为激发活动并激活连接的神经元。 大脑神经元通过改变突触的有效性来学习将信号发送到大脑的不同部分类似于人工神经网络中某些神经元的权重变为接近零的方式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a4p8Nc9s-1681785569470)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/30194677-af4a-47bf-9e51-058911b43b19.png)]
有许多理论表明神经元之间的紧密连接会增加人类的学习能力。 反过来许多神经科学家认为随着通过学习和刺激来更多地利用大脑就会形成密集的树突状连接。 因此随着学习的越来越多我们变得越来越聪明。
比较人类神经元和人工神经元
尽管人类神经元一直是创建人工神经网络的灵感但它们在多种方式上却有所不同。 研究人员正在尝试通过尝试不同的激活激励函数和非线性系统来弥合这些差距。 与我们的大脑具有收集和传输从我们的感官接收到的信息的神经元的方式类似神经网络也由多层一组神经元组成这些层通过跨层传输信息来学习任务。 在某些情况下我们可以说人造神经元的工作方式类似于大脑中存在的神经元。 让我们看下图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TVQiEmkX-1681785569473)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/571d3436-3f5f-46aa-9057-efe3e52dd3c8.png)]
如上图所示信息流经每个连接每个连接都有特定的权重该权重控制数据流。 如果将人脑神经元的活动与人工神经网络进行比较我们将看到只要为任务创建神经网络就如同创建新的脑神经元。 如果环顾四周我们已经开始依靠计算机做出决策例如在信用卡欺诈垃圾邮件/非垃圾邮件和推荐系统方面。 就像我们为周围的小任务创造了新的大脑。 仍然存在问题人与人工神经网络之间有什么区别 让我们找出
主要区别之一是所需的学习数据量。 要学习神经网络我们需要大量数据而人脑可以学习的数据更少。 如果我们希望拥有与人脑相似的神经网络则需要改进现有的优化算法。另一个关键区别是速度。 通常神经网络比人类更快地处理数据和信息。
机器学习–历史概述
机器学习是一个程序在给定任务损失函数的情况下可以通过经验训练数据进行学习。 凭着经验该程序将学会按照给定的标准执行给定的任务。 在 1960 年代机器学习主要集中于创建不同形式的数据预处理过滤器。 随着图像过滤器的引入重点逐渐转向计算机视觉并在 1990 年代和 2000 年代在这一领域进行了重大研究。 在开发了传统机器学习算法方面的一些稳定性之后研究人员转向了概率领域因为随着高维数据的引入它变得更有希望。 深度学习在 2012 年赢得 ImageNet 挑战赛时便开始蓬勃发展并且自此在数据科学领域中发挥了重要作用。
机器学习可以分为两类
参数使用给定训练数据例如逻辑回归支持向量机和神经网络的算法调整数学或统计模型中的参数即可完成学习。非参数通过存储训练数据记忆并执行一些降维映射来完成学习例如 k 最近邻kNN和决策树。
由于学习参数的要求参数方法通常需要大量数据。 顺便说一句如果我们有大量的数据集则最好使用参数方法因为非参数方法通常需要存储数据并针对每个查询对其进行处理。
机器学习和深度学习中的挑战
机器学习和深度学习已经彻底改变了计算机科学行业但它们各有利弊。 我们当前方法面临的一些常见挑战如下
数据收集为每个类别收集足够的相关数据以供机器学习非常费力。数据标记通常标记数据需要专家或由于隐私安全或道德问题而无法进行。硬件限制由于数据量大而且参数模型大因此训练它们需要昂贵的硬件GPU 和 TPU。结果分析尽管有某些提供分析参数的开源库但了解结果也是一项重大挑战。
除了这些挑战之外机器学习在处理特征选择和高维数据方面也面临挑战。
在下一节中我们将介绍单样本学习并学习如何尝试解决机器学习和深度学习所面临的挑战。
单样本学习概述
单样本学习可以看作是一种类似于人类学习方式的机器训练方法。 单样本学习是一种在有限的监督数据的帮助下借助强大的先验知识来学习新任务的方法。 李菲菲博士最早发表的导致图像分类问题精度高的著作可以追溯到 2000 年代-尽管近年来研究人员在通过不同的深度学习架构和优化算法例如 匹配网络不可知论元学习模型和记忆增强神经网络。 单样本学习在多个行业中都有很多应用尤其是在医疗和制造业中。 在医学上当可用数据有限时例如在治疗罕见疾病时我们可以使用单样本学习。 而在制造中我们可以减少人为误差例如表壳制造中的缺陷。
单样本学习的先决条件
如果我们进一步讨论如何从有限的数据中学习必要的信息我们将意识到人脑已经受过训练以提取重要信息的神经元。 例如如果教导孩子球形物体是球那么他们的大脑也会处理有关球的大小和纹理的信息也称为物体的过滤器。 因此对于任何形式的单样本学习我们都可以说我们至少需要满足以下条件之一
先前训练过的过滤器和预定架构正确的数据分布假设一种确定形式的分类法用于存储或收集的信息
在某些情况下我们观察到只能具有非常低的特征提取水平。 在这些情况下我们只能依靠非参数或概率方法因为要学习参数我们需要足够数量的数据。 即使我们以某种方式强迫神经网络几乎不学习任何数据也将导致过拟合。
在下一部分中我们将进行简短的编码练习以了解当我们拥有小的数据集时简单的非参数 kNN 的表现要优于神经网络。 不幸的是它在现实世界中可能无法很好地工作因为我们仍然存在学习良好的特征表示并选择合适的距离函数的问题。
单样本学习的类型
解决单样本学习的方法多种多样。 粗略地说它们可以分为五个主要类别
数据扩充方法基于模型的方法基于指标的方法基于优化的方法基于生成建模的方法
下图显示了单样本学习的类别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BvRcaoUT-1681785569473)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/7da6c666-88ab-45dc-ada6-3081219fd02c.png)]
数据扩充是深度学习社区中最常用的方法可以为数据增加变化增加数据大小并平衡数据。 这是通过在数据中添加某种形式的噪声来实现的。 例如图像可能会被缩放平移和旋转。 而在自然语言处理任务中可能会有同义词替换随机插入和随机交换。
尽管数据扩充方法在预处理中起着至关重要的作用但本书不会涉及到该主题。 在本书中我们将着重于单样本学习的算法方法以及如何实现它们。 我们还将在常用的单样本学习数据集上进行实验例如 Omniglot 数据集和 Mini ImageNet。
设置环境
在本节中我们将使用以下步骤为我们的编码练习和问题设置虚拟环境
通过进入您选择的目录并在 Git Bash 命令行中运行以下命令来克隆存储库
git clone https://github.com/Packt-Publishing/Hands-on-One-Shot-Learning.git转到克隆的存储库的Chapter01目录
cd Hands-on-One-Shot-Learning/Chapter01然后打开一个终端并使用以下命令安装 Python 版本 3.6 的 Anaconda并创建一个虚拟环境
conda create --name environment_name python3.6在“步骤 3”和4中可以将environment_name替换为易于记忆的名称例如one_shot或您选择的名称。
使用以下命令激活环境
source activate environment_name使用以下命令安装requirements.txt
pip install -r requirements.txt运行以下命令以打开 Jupyter 笔记本
jupyter notebook现在我们已经建立了环境让我们继续进行编码练习。
编码练习
在本节中我们将探索一种基本的单样本学习方法。 作为人类我们有一种分层的思维方式。 例如如果我们看到一些未知的东西我们会寻找它与我们已经知道的对象的相似性。 同样在本练习中我们将使用非参数 kNN 方法查找类。 我们还将其表现与基本神经网络架构进行比较。
kNN – 基本的单样本学习
在本练习中我们将把 kNN 与拥有少量数据集的神经网络进行比较。 我们将使用从scikit-learn库导入的iris数据集。
首先我们将首先讨论 kNN 的基础知识。 kNN 分类器是一个非参数分类器它简单地存储训练数据D并使用对它的k个最近邻居的多数投票对每个新实例进行分类并使用任何距离函数来计算 。 对于 kNN我们需要选择距离函数d和邻居数k
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BnjsJ0Ix-1681785569473)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/16ca7a17-01fc-4139-a2af-1e12225d1e1b.png)]
您还可以在以下 GitHub 链接上引用代码文件。
请按照以下步骤将 kNN 与神经网络进行比较
使用以下代码导入此练习所需的所有库
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, accuracy_score
from sklearn.model_selection import cross_val_score
from sklearn.neural_network import MLPClassifier导入iris数据集
# import small dataset
iris datasets.load_iris()
X iris.data
y iris.target为了确保我们使用的数据集非常小我们将随机选择 30 个点并使用以下代码进行打印
indicesnp.random.choice(len(X), 30)
XX[indices]
yy[indices]
print (y)这将是结果输出
[2 1 2 1 2 0 1 0 0 0 2 1 1 0 0 0 2 2 1 2 1 0 0 1 2 0 0 2 0 0]为了理解我们的特征我们将尝试以散点图的形式将它们绘制在 3D 中
from mpl_toolkits.mplot3d import Axes3D
fig plt.figure(1, figsize(20, 15))
ax Axes3D(fig, elev48, azim134)
ax.scatter(X[:, 0], X[:, 1], X[:, 2], cy,cmapplt.cm.Set1, edgecolork, s X[:, 3]*50)for name, label in [(Virginica, 0), (Setosa, 1), (Versicolour, 2)]:ax.text3D(X[y label, 0].mean(),X[y label, 1].mean(),X[y label, 2].mean(), name,horizontalalignmentcenter,bboxdict(alpha.5, edgecolorw, facecolorw),size25)ax.set_title(3D visualization, fontsize40)
ax.set_xlabel(Sepal Length [cm], fontsize25)
ax.w_xaxis.set_ticklabels([])
ax.set_ylabel(Sepal Width [cm], fontsize25)
ax.w_yaxis.set_ticklabels([])
ax.set_zlabel(Petal Length [cm], fontsize25)
ax.w_zaxis.set_ticklabels([])plt.show()下图是输出。 正如我们在 3D 可视化中所看到的数据点通常在组中找到
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uO9QaLd6-1681785569473)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/ea368c60-84e7-477f-87c8-f3f5081638a5.png)]
首先我们将首先使用 80:20 拆分将数据集拆分为训练集和测试集。 我们将使用k3作为最近的邻居
X_train, X_test, y_train, y_test train_test_split(X, y, test_size 0.2, random_state 0)
# Instantiate learning model (k 3)
classifier KNeighborsClassifier(n_neighbors3)# Fitting the model
classifier.fit(X_train, y_train)# Predicting the Test set results
y_pred classifier.predict(X_test)cm confusion_matrix(y_test, y_pred)accuracy accuracy_score(y_test, y_pred)*100
print(Accuracy of our model is equal str(round(accuracy, 2)) %.)这将导致以下输出
Accuracy of our model is equal 83.33 %.初始化隐藏层的大小和迭代次数
mlp MLPClassifier(hidden_layer_sizes(13,13,13),max_iter10)
mlp.fit(X_train,y_train)您可能会收到一些警告具体取决于 scikit-learn 的版本例如/sklearn/neural_network/multilayer_perceptron.py:562:ConvergenceWarning: Stochastic Optimizer: Maximum iterations (10) reached and the optimization hasnt converged yet. % self.max_iter, ConvergenceWarning)。 这只是表明您的模型尚未收敛。
我们将预测 kNN 和神经网络的测试数据集然后将两者进行比较
predictions mlp.predict(X_test)accuracy accuracy_score(y_test, predictions)*100
print(Accuracy of our model is equal str(round(accuracy, 2)) %.)以下是结果输出
Accuracy of our model is equal 50.0 %.对于我们当前的情况我们可以看到神经网络的准确率不如 kNN。 这可能是由于许多原因造成的包括数据集的随机性邻居的选择以及层数。 但是如果我们运行足够的时间我们会发现 kNN 总是会存储更好的数据因为它总是存储数据点而不是像神经网络那样学习参数。 因此kNN 可以称为单样本学习方法。
总结
深度学习已经彻底变革了数据科学领域并且仍在不断进步但是仍然有一些主要行业尚未体验到深度学习的所有优势例如医疗和制造业。 人类成就的顶峰将是创造一种可以像人类一样学习并且可以像人类一样成为专家的机器。 但是成功的深度学习通常需要拥有非常庞大的数据集才能进行工作。 幸运的是本书重点介绍了可以消除此先决条件的架构。
在本章中我们了解了人类的大脑以及人工神经网络的结构如何接近我们的大脑结构。 我们介绍了机器学习和深度学习的基本概念及其挑战。 我们还讨论了单样本学习及其各种类型然后在iris数据集上进行了实验以比较在数据稀缺情况下的参数方法和非参数方法。 总的来说我们得出结论正确的特征表示在确定机器学习模型的效率方面起着重要作用。
在下一章中我们将学习基于度量的单样本学习方法并探索单样本学习算法的特征提取领域。
问题
为什么对于单样本学习任务kNN 比新近训练的人工神经网络更好地工作什么是非参数机器学习算法决策树是参数算法还是非参数算法将其他分类算法作为编码练习进行实验并比较结果。
第二部分深度学习架构
单样本学习一直是许多科学家的活跃研究领域他们试图找到一种在学习方面与人类尽可能接近的认知机器。 由于存在关于人类如何进行单样本学习的各种理论因此我们可以使用许多不同的深度学习方法来解决这一问题。 本书的这一部分将重点介绍基于度量基于模型和基于优化的深度学习架构以解决单样本学习问题及其实现。
本节包括以下章节
第 2 章“基于度量的方法”第 3 章“基于模型的方法”第 4 章“基于优化的方法”
二、基于指标的方法
深度学习已在各种应用中成功实现了最先进的表现例如图像分类对象检测语音识别等。 但是深度学习架构在被迫对几乎没有监督信息的数据进行预测时常常会失败。 众所周知数学是所有机器学习和深度学习模型的基础。 我们使用数据的数学表示将数据和目标传达给机器。 这些表示形式可以有多种形式特别是如果我们想学习复杂的任务例如疾病检测或者如果我们希望我们的架构根据不同的目标学习表示形式例如计算两个图像之间的相似度我们可以计算欧几里得距离和余弦相似度。
在本章中我们将学习可以从较小的数据集中学习正确的数学表示形式的深度学习架构。 总体而言我们的目标是创建一种无需大量数据收集或训练过程即可概括不熟悉类别的架构。
本章将涵盖以下主题
参数方法–概述连体网络匹配网络编码练习
技术要求
需要使用以下库来学习和执行本章中的项目
PythonAnacondaJupyter 笔记本PyTorchMatplotlibscikit 学习
您可以在该书的 GitHub 存储库中找到该章的代码文件。
参数方法概述
在上一章中我们简要讨论了非参数机器学习方法。 本节将主要关注机器学习的参数方法是什么以及它们实际学习了什么。
简而言之参数化机器学习算法试图学习数据及其标签的联合概率分布。 我们学习的参数是联合概率分布给出的方程 例如众所周知逻辑回归可以看作是一层神经网络。 因此考虑到一个单层神经网络它实际学习的是方程的权重和偏差以便使P(Y | X)适应Y标签。
逻辑回归是判别式分类器的一种形式在判别式分类器中我们仅关注P(Y | X)即我们尝试对Y标签的概率分布做出假设并尝试以某种方式将我们的X输入映射到它。 因此本质上我们尝试在逻辑回归中进行以下操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mPs0fwQp-1681785569474)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/010cceaa-cf25-4883-a25d-5800e070dc87.png)]
在这里P(Y | X)是分类分布这意味着我们正在尝试学习可能类别上的分布。 简单来说给定X我们将学习Y可以具有的所有可能类别。 由于数据的缘故这都是可能的-随着数据量的增加我们对Y的近似值也随之增加。 在下一节中我们将学习神经网络的学习过程并了解哪些属性在逼近Y标签中起着重要的作用。
神经网络学习器
众所周知神经网络通过使用随机梯度下降优化方法使损失函数或目标函数最小化来学习。 因此损失函数是决定神经网络架构目标的主要因素之一。 例如如果要分类数据点我们将选择损失函数例如类别交叉熵0-1 损失和铰链损失 相反如果我们的目标是回归我们将选择损失函数例如均方误差均方根误差和 Huber 损失。 一些常见的方程式如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pxX1cslS-1681785569474)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/47a48789-8ff8-42cf-a648-96d68b1df236.png)]
在知道损失函数对神经网络有重大影响之后每个人首先想到的是我们需要提出更好的损失函数。 如果您研究最新的研究您会发现主要的发展是基于更改损失函数的对象检测图像分割机器翻译等。 找出新的损失函数可能很棘手原因有两个
目标函数本质上必须是凸形的才能满足随机梯度下降优化的要求。通常通过不同函数获得的最小值在数值上相同。
在下一节中我们将了解这些损失函数如何帮助架构学习不同的图像特征以及如何结合这些特征来为其他各种目标训练模型。
可视化参数
神经网络通过梯度下降学习但是它们学到什么呢 答案是参数但我们希望了解这些参数的含义。 在下图中如果我们看一下前几层将看到简单易懂的提取特征例如边缘和兴趣点而更深层的特征则更复杂。 例如如果我们查看下图中的最后一层将观察到与初始层特征相比特征是不可识别的。 这是因为随着我们进入更深的层次越来越多的信息丰富的特征正在通过各种矩阵运算来提取。 这使得高维信息可以压缩到低维损失函数空间中并得到训练后的模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KrhCklNm-1681785569474)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/2ea3be34-ced7-4c60-a302-98d1f0c35e3e.jpeg)]
因此例如如果我们查看花朵与汽车等类别则初始层的特征就足够了。 但是如果我们有诸如汽车类型之类的类别则需要更深层次的模型因为我们需要提取更复杂的特征这需要更大的数据集。 问题是什么决定了模型学习的特征或参数的类型是否有可能在初始层学习这些重要参数 在下一部分中我们将探索连体网络它是一种神经网络架构可以通过更改损失函数及其架构设计来学习前几层的复杂特征。
了解连体网络
顾名思义连体网络是一种具有两个并行层的架构。 在此架构中模型学会了在两个给定的输入之间进行区分而不是学习使用分类损失函数对其输入进行分类的模型。 它根据相似性度量比较两个输入并检查它们是否相同。 与任何深度学习架构相似连体网络也有两个阶段-训练和测试阶段。 但是对于单样本学习方法因为我们没有很多数据点我们将在一个数据集上训练模型架构并在另一个数据集上对其进行测试。 为了简单起见我们使用带监督的基于度量的方法使用连体神经网络来学习图像嵌入然后将该网络的特征重新用于单样本学习而无需进行微调或重新训练。
机器学习算法的良好特征的提取在确定模型效率方面起着至关重要的作用。 在各种情况下当可用数据有限时事实证明它要么计算量大要么困难。
如下图所示我们的目标是训练网络以了解两个图像或声音是否相同。 假设第一个图像中有两个足球 即使背景不同两者都是足球所以被认为是相同的。 单词cow的声音也是如此。 在图像和声音不同的地方例如鳄鱼和足球它们被标记为不同的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eAUUkAwK-1681785569474)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/0d94a582-9d00-4f5b-a28f-7e4df967ea31.png)]
关键思想听起来可能类似于转学但有所不同。 连体网络使用对比损失函数来学习这些特征。 其次连体网络方法仅适用于相似的域因为它还需要注意域的适应性也就是说它需要尝试确保我们的训练和测试数据集在域方面是紧密的。 例如如果您要创建一个系统来测试两个手写示例是否属于同一个人则可以在 MNIST 数据集上训练一个连体网络架构通过该架构可以学习特定于手写体的特征例如曲线 和给定字符的笔划。 在下一节中我们将研究连体网络的架构并了解其优化。
构建
连体网络由两个相同的神经网络组成它们共享相似的参数每个头部获取一个输入数据点。 在中间层由于权重和偏差相同因此我们提取了相似的特征。 这些网络的最后一层被馈送到对比损失函数层该层计算两个输入之间的相似度。
您可能会遇到的一个问题是为什么连体网络的层共享参数 如果我们已经在努力改变损失函数这是否有助于我们分别训练各层
我们不单独训练层的主要原因有两个
对于每一层我们都添加了数千个参数。 因此类似于我们在共享参数的卷积神经网络方法中所做的工作我们可以更快地优化网络。权重共享确保两个相似的图像不会映射到特征嵌入空间中的不同位置。
特征嵌入是将特征投影到某个更高维度的空间也称为特征嵌入空间具体取决于我们要实现的任务。
下图说明了一个示例连体网络架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OAN6kOQv-1681785569475)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/be19cfde-bc78-4b64-92a9-85e89e1df3ce.png)]
如我们所见前面的图是简单明了的。 现在我们将讨论训练连体网络所需的预处理步骤。
预处理
为了训练连体网络我们需要对数据集进行特殊的预处理。 在预处理数据集时我们必须仔细创建数据点对如下所示
相似的图像对不同的图像对
下图说明了 Omniglot 的连体网络目标的示例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1fVbmz6d-1681785569475)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/67555406-abd0-4471-b5e1-deb9c87c2813.jpg)]
我们还需要为相似的数据点y 1和不相似的数据点y 0相应地创建标签 然后将每一对馈入连体体系。 在层的最后连体网络使用损失函数的微分形式来学习各层之间的微分特征。 通常对于连体网络我们仅使用两种类型的函数-对比损失函数和三重损失函数。 我们将在下一节中详细了解这些内容。
对比损失函数
使用连体架构的整体思想不是在类别之间进行分类而是学习区分输入。 因此它需要损失函数的微分形式称为对比损失函数。 给出如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eVWw6PXJ-1681785569475)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/aaedf542-dd84-4589-8774-94190df0b2f6.png)]
在该等式中 D[w] √((f(X1) - f(X2))²)f(X)代表连体神经网络m代表裕度。
让我们进一步求解损失方程。 以Y 1表示相似的货币对
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8aGqVHNf-1681785569475)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/029593cf-8b9d-4162-8c8f-4b58a97c679d.png)]
如果两个输入X1和X2相同则意味着连体网络应该能够学习制作D²[w] 0。 我们在方程式中增加余量m以使连体网络不使W 0从而使D²[w] 0。 通过强制执行边距我们确保连体网络学习到良好的决策边界。
类似地对于不相似对的Y 0这将产生以下结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MvFva8yr-1681785569476)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/50d96d9a-18f2-41b9-a4af-0df76984984e.png)]
从数字上讲对于相同的对情况仅当D[w] 0时损失函数才为零否则它将表现为回归损失并尝试学习特征以确保D[w]接近 0。
尽管对比损失函数是学习判别特征的一种好方法但是在连体网络架构的其他修改版本中对比损失函数不能非常清楚地学习决策边界。 在这种情况下我们可以使用称为三重损失的新损失函数该函数可帮助架构获得更好的结果。
三重损失函数
三重态损失函数是对比损失函数的替代方法。 与对比损失函数相比它具有收敛优势。
要了解三重态损失函数首先我们需要成对定义数据点如下所示
锚点A主数据点正例P类似于锚点的数据点负例N与锚点不同的数据点
考虑到f(X)是连体网络的输出理想情况下我们可以假设以下内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LAmdKh7G-1681785569476)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/73760b22-b575-40f1-85be-396c6822a5d5.png)]
用距离函数项我们可以说以下几点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-saWm77m0-1681785569476)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/e89f8c0f-2387-40bf-9cd0-b346ff3fdc52.png)]
由于我们不希望连体网络学习f(X) 0, X ∈ R因此我们将添加余量类似于对比损失函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iH5PvTjk-1681785569476)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/aa0e72e6-1a0c-4888-a75d-1e4276061bb4.png)]
使用以下等式我们将定义三重态损失如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PpnHF8kX-1681785569476)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/5c387438-e9c3-499e-b6ed-5c92097ee9a0.png)]
下图表示三元组损失函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AMdW5ClQ-1681785569477)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/8d24886d-e1ca-4322-848e-32251f118edd.png)]
三重损失函数的收敛性优于对比损失函数因为它一次考虑了三个示例并保持了正和负点之间的距离如上图所示从而可以更准确地学习决策边界而对比损失函数一次只考虑成对示例因此从某种意义上讲它更贪婪这会影响决策边界。
应用领域
通常可以使用各种方法解决问题。 例如我们手机上的人脸检测。 图像分类是一种需要大量数据点的方法而如果使用单样本学习的连体网络架构则仅需几个数据点就可以实现更高的准确率。 连体网络架构已成为软件行业采用的最流行的单样本学习架构之一。 它可用于各种其他应用例如面部检测手写检测和垃圾邮件检测。 但是仍然有很多改进的余地并且各种各样的研究者正在为此努力。 在下一节中以相似的主题进行工作我们将学习匹配的网络架构该架构使用注意力机制和不同的训练过程来学习训练集标签上的概率分布。
了解匹配网络
匹配网络通常会提出一个框架该框架学习一个网络该网络映射一个小的训练数据集并在相同的嵌入空间中测试未标记的示例。 匹配网络旨在学习小型训练数据集的正确嵌入表示并使用具有余弦相似性度量的可微 kNN 来检查是否已经看到测试数据点。
匹配网络的设计有两个方面
建模级别在建模级别他们提出了匹配网络该网络利用注意力和记忆力方面的进步实现快速有效的学习。训练过程在训练级别上他们有一个条件-训练和测试集的分布必须相同。 例如这可能意味着每个类显示一些示例并将任务从小批量切换到小批量类似于在展示新任务的一些示例时如何对其进行测试。
匹配网络结合了参数模型和非参数模型的最佳特性也被称为差分最近邻居。
在下一节中我们将研究在建模级别由匹配网络做出的贡献随后我们将经历训练过程的贡献。
模型架构
匹配的网络架构主要受关注模型和基于内存的网络的启发。 在所有这些模型中都定义了神经注意力机制来访问存储矩阵该矩阵存储有用的信息来解决手头的任务。 首先我们需要了解匹配网络中使用的某些术语
标签集这是所有可能类别的样本集。 例如如果我们使用 ImageNet 数据集它包含数千个类别例如猫狗和鸟但是作为标签集的一部分我们将仅使用其中的五个类别。支持集这是我们标签集类别的采样输入数据点例如图像。批量类似于支持集批量也是由标签集类别的输入数据点组成的采样集。N路k次方法此处N是支撑集的大小或更简单地说是训练集中可能类别的数量。 例如在下图中我们有四种不同类型的狗品种并且我们计划使用 5 样本学习方法即每种类别至少有五个示例。 这将使我们的匹配网络架构使用 4 路 5 样本学习如下图所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uwBi4jQk-1681785569477)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/3118bc82-3dc7-473f-8e77-f57c6f17b84e.png)]
匹配网络的关键思想是将图像映射到嵌入空间该空间也封装了标签分布然后使用不同的架构在相同的嵌入空间中投影测试图像。 然后我们以后用余弦相似度来衡量相似度。 让我们看一下匹配网络如何创建其嵌入空间。
训练器
在训练架构方面匹配网络遵循某种技术它们尝试在训练阶段复制测试条件。 简而言之正如我们在上一节中所了解的那样匹配网络从训练数据中采样标签集然后它们从同一标签集生成支持集和批量集。 数据预处理之后匹配网络通过训练模型以将支持集作为训练集并将批量集作为测试集来最小化误差从而学习其参数。 通过将支持集作为训练集将批量集作为测试集的训练过程可使匹配的网络复制测试条件。
在下一部分中我们将介绍匹配网络的架构和算法并学习如何在模型的训练阶段使用批量集即测试集。
建模级别–匹配的网络架构
匹配网络将支持集k示例映射到分类器C[s](·)的支持集k示例S (x[i], x[i]), i 1, ..., k。 基本上匹配网络将映射S - C[s](·)定义为参数化神经网络P(y_hat | x_hat, S)。 如果我们谈论P(y_hat | x_hat, S)的最简单形式它将是支持集标签的线性组合形式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G3YQOhWG-1681785569477)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/94576b62-c681-443b-ba09-e6e280e2407f.png)]
在此a(x_hat, x[i])是 softmax 函数。 从逻辑上看我们可以看到y_hat正在非参数意义上正确计算。
例如如果我们有 2 个类分别为 0 和 1则 2 个示例k 2如下y (0, 1)。
通过将y变成单热编码向量我们将获得以下信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KqQQntfm-1681785569477)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/725b5feb-44c8-43ed-8a13-b4c530b590e8.png)]
它们各自的核值如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ugcAoyIF-1681785569477)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/8c500245-cdfc-485c-8f8b-16692f891db5.png)]
通过引入a和y的值我们将获得以下方程式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kbFiT3mm-1681785569478)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/0b1398a4-325e-475e-84e6-a59cdc029dfd.png)]
解决此问题后我们将获得以下方程式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6o3GIOvP-1681785569478)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/d3c88db6-018b-4740-a01d-e40f57052f55.png)]
总体而言我们可以看到y_hat如何成为确定测试输入x_hat属于哪个类别的概率的线性组合。 要将任何形式的函数转换为概率空间深度学习社区使用的最佳选择是 softmax 函数使得a(x_hat, x[i])如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fGJD1eHt-1681785569478)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/6d449b9b-9813-4ed7-9f19-37f2889465e4.png)]
在此c是训练集和测试数据点的嵌入之间的余弦相似度函数。
现在出现了关于如何从测试集和训练集中提取嵌入的问题。 任何形式的神经网络都可以工作。 对于图像著名的 VGG16 或 Inception Net 将通过使用迁移学习为测试图像和训练图像提供适当的嵌入 本质上这是过去大多数基于度量的方法所做的但是无法获得人类水平的认知结果。
VGG16 和 Inception Net 是深度学习架构它们在 ImageNet 数据集上提供了最新的结果。 它们通常用于任何图像的初始特征提取因为这将为我们的架构适当地初始化训练过程。
匹配网络指出了上述简单化非参数方法的两个问题
问题 1即使分类策略P(y_hat | x_hat, S)已设定条件训练集图像的嵌入也彼此独立而不认为它们是支持集的一部分。
解决方案匹配网络使用双向长短期记忆LSTM在整个支持集范围内启用每个数据点的编码。 通常LSTM 用于理解数据序列因为它们能够使用其单元内部的门保持整个数据的上下文。 同样使用双向 LSTM 可以更好地理解数据序列。 匹配网络使用双向 LSTM 来确保支持集中一幅图像的嵌入将具有所有其他图像嵌入的上下文。
问题 2如果要计算两个数据点之间的相似度首先需要将它们放入相同的嵌入空间。 因此支持集S必须能够有助于提取测试图像嵌入。
解决方案匹配网络使用 LSTM并且具有对支持集S的注意。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bymx6VrL-1681785569478)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/d8c095d5-729c-49ac-8834-ef3b2c1f861e.png)]
这里K是展开步骤的数量embeddings(x_hat)是通过 VGG16/Inception 网络获得的测试图像嵌入 g(S)是将测试图像嵌入带到同一空间的样本集。
下图说明了匹配的网络架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XYbuWrUG-1681785569478)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/5840cf24-bfa3-424f-a151-23cf76511e2c.png)]
匹配的网络架构解决了通过设置框架在训练模型时复制测试条件的单样本学习问题如训练过程部分中所述。 匹配网络的架构包含许多子部分。 为了简化和更清楚地了解它我们将从左到右进行每个过程 作为预处理数据的一部分将创建k示例的支持集S作为(x[i], y[i]), i 1 ... k。 获取支持集后它会通过标准特征提取层g例如 VGG 或 Inception。 在提取支持集S的嵌入g层的输出之后将它们放入双向 LSTM 架构中。 这有助于模型学习支持集中存在的标签的概率分布。 与训练集类似查询图像即测试图像的全上下文嵌入提取也经历了组合的双向 LSTM 架构同时从g(x[i)获得了贡献从而映射到相同的嵌入空间。 从这两种架构获得输出后这些输出将通过 softmax 层也称为注意核步骤a(h[k-1], g(x[i]))传递。 然后从g(x[i])和f(x)获得的输出用于检查查询图像属于哪个类别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aOgkXl52-1681785569479)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/61fbf48b-9b8f-4de8-96b1-487001701281.png)]
在此等式中y_hat是支持集中标签的加权和。
在此注意核是 softmax 函数其余弦距离的值介于g(x[i])和f(x)之间。 为了训练模型我们可以使用任何基于分类的损失函数例如交叉熵损失函数。
匹配网络的关键思想是创建一个即使在训练数据即支持集中不存在的类也可以表现良好的架构。
匹配网络因其创新的训练过程和完全上下文嵌入而成为一站式学习的著名方法之一。 如果我们尝试从人类学习的角度理解匹配网络的方法则它与儿童的教学过程非常相似。 要学习新任务将为他们提供一系列小型示例然后是小型测试集然后重复进行。 使用此程序并借助人脑的上下文记忆保持功能孩子们可以学习一项新的任务。
在下一部分中我们将使用著名的 MNIST 和 Omniglot 数据集探索连体网络的实现和匹配网络架构。
编码练习
在本节中我们将学习连体网络和匹配网络的实现。
让我们从连体网络开始。
连体网络-MNIST 数据集
在本教程中我们将按照此处列出的顺序执行以下操作
数据预处理创建偶对创建连体网络架构使用小型 MNIST 数据集对其进行训练可视化嵌入
执行以下步骤进行练习
首先使用以下代码导入所需的所有库
# -*- encoding: utf-8 -*-
import argparse
import torch
import torchvision.datasets as dsets
import random
import numpy as np
import time
import matplotlib.pyplot as plt
from torch.autograd import Variable
from torchvision import transforms
import pickle
import torch
import torch.nn as nn正如我们在理论“了解连体网络”部分中学到的作为数据预处理的一部分我们需要创建对
相似对y 1不同对y 0
我们正在使用对比损失函数–这就是为什么我们只有两对的原因。 对于三重损失函数我们需要其他形式的预处理。
要预处理数据并为模型创建迭代器请首先创建Dataset类
class Dataset(object):Class Dataset:Input: numpy valuesOutput: torch variables.def __init__(self, x0, x1, label):self.size label.shape[0] self.x0 torch.from_numpy(x0)self.x1 torch.from_numpy(x1)self.label torch.from_numpy(label)def __getitem__(self, index):return (self.x0[index],self.x1[index],self.label[index])def __len__(self):return self.size在创建迭代器之前让我们创建pairs函数并对其进行预处理
def create_pairs(data, digit_indices):x0_data []x1_data []label []n min([len(digit_indices[d]) for d in range(10)]) - 1for d in range(10): # for MNIST dataset: as we have 10 digitsfor i in range(n):z1, z2 digit_indices[d][i], digit_indices[d][i 1]x0_data.append(data[z1] / 255.) # Image Preprocessing Stepx1_data.append(data[z2] / 255.) # Image Preprocessing Steplabel.append(1)inc random.randrange(1, 10)dn (d inc) % 10z1, z2 digit_indices[d][i], digit_indices[dn][i]x0_data.append(data[z1] / 255.) # Image Preprocessing Stepx1_data.append(data[z2] / 255.) # Image Preprocessing Steplabel.append(0)x0_data np.array(x0_data, dtypenp.float32)x0_data x0_data.reshape([-1, 1, 28, 28])x1_data np.array(x1_data, dtypenp.float32)x1_data x1_data.reshape([-1, 1, 28, 28])label np.array(label, dtypenp.int32)return x0_data, x1_data, label然后创建iterator函数。 为了我们的训练目的这将返回给定的batchsize参数集
def create_iterator(data, label, batchsize, shuffleFalse):digit_indices [np.where(label i)[0] for i in range(10)]x0, x1, label create_pairs(data, digit_indices)ret Dataset(x0, x1, label)return ret然后创建loss函数。 众所周知contrastive_loss_function包含两个部分
对于类似的点(1-y)*(distance_function)^2对于不同的点 y*{max(0,(m-distance_function^2)}
在这里distance_function被视为欧几里得距离也称为均方根
def contrastive_loss_function(x0, x1, y, margin1.0):# euclidean distancediff x0 - x1dist_sq torch.sum(torch.pow(diff, 2), 1)dist torch.sqrt(dist_sq)mdist margin - distdist torch.clamp(mdist, min0.0)loss y * dist_sq (1 - y) * torch.pow(dist, 2)loss torch.sum(loss) / 2.0 / x0.size()[0]return loss接下来创建连体网络架构。 为此我们首先创建一个带有两个函数的名为SiameseNetwork的类
forward_once在forward_once中训练数据将穿过所有层并返回输出的嵌入。forward在forward中对于给定的输入对将两次调用forward_once这将返回获得的嵌入的 NumPy 数组。
正如在连体网络的理论部分所讨论的那样我们与两个并行层共享参数因此我们不需要显式创建两个分支我们只需创建一个分支即可
class SiameseNetwork(nn.Module):def __init__(self,flag_kafFalse):super(SiameseNetwork, self).__init__()self.cnn1 nn.Sequential(nn.Conv2d(1, 20, kernel_size5),nn.MaxPool2d(2, stride2),nn.Conv2d(20, 50, kernel_size5),nn.MaxPool2d(2, stride2))self.fc1 nn.Sequential(nn.Linear(50 * 4 * 4, 500),nn.ReLU(inplaceTrue),nn.Linear(500,10),nn.Linear(10, 2))def forward_once(self, x):output self.cnn1(x)output output.view(output.size()[0], -1)output self.fc1(output)return outputdef forward(self, input1, input2):output1 self.forward_once(input1)output2 self.forward_once(input2)return output1, output2减少MNIST数据集并选择2000随机点将batchsize设置为 2 的任意幂例如128然后导入MNIST数据集
batchsize128
train dsets.MNIST(root../data/,trainTrue,downloadTrue)
test dsets.MNIST(root../data/,trainFalse,transformtransforms.Compose([transforms.ToTensor(),]))
indices np.random.choice(len(train.train_labels.numpy()), 2000, replaceFalse)
indices_test np.random.choice(len(test.test_labels.numpy()), 100, replaceFalse)我们在“步骤 4”中创建了一个迭代器我们将使用它来创建训练和测试集迭代器
train_iter create_iterator(train.train_data.numpy()[indices],train.train_labels.numpy()[indices],batchsize)
test_iter create_iterator(test.test_data.numpy()[indices_test],test.test_labels.numpy()[indices_test],batchsize)# call model
model SiameseNetwork()
learning_rate 0.01 # learning rate for optimization
momentum 0.9 # momentum
# Loss and Optimizer
criterion contrastive_loss_function # we will use contrastive loss function as defined above
optimizer torch.optim.SGD(model.parameters(), lrlearning_rate,momentummomentum)# creating a train loader, and a test loader.
train_loader torch.utils.data.DataLoader(train_iter,batch_sizebatchsize, shuffleTrue)
test_loader torch.utils.data.DataLoader(test,batch_sizebatchsize, shuffleTrue)然后我们训练模型一定数量的时间并打印结果
train_loss []
epochs 100
for epoch in range(epochs):print(Train Epoch:str(epoch)------------------)for batch_idx, (x0, x1, labels) in enumerate(train_loader):labels labels.float()x0, x1, labels Variable(x0), Variable(x1), Variable(labels)output1, output2 model(x0, x1)loss criterion(output1, output2, labels)optimizer.zero_grad()loss.backward()optimizer.step()train_loss.append(loss.item())if batch_idx % batchsize 0:print(Epoch: {} \tLoss: {:.6f}.format(epoch, loss.item()))这将给出以下输出
Epoch: 0 Loss: 0.269623
Epoch: 1 Loss: 0.164050
Epoch: 2 Loss: 0.109350
Epoch: 3 Loss: 0.118925
Epoch: 4 Loss: 0.108258
...
...
Epoch: 97 Loss: 0.003922
Epoch: 98 Loss: 0.003155
Epoch: 99 Loss: 0.003937现在让我们创建所有用于绘制嵌入的函数和一个损失函数
def plot_loss(train_loss,nametrain_loss.png):plt.plot(train_loss, labeltrain loss)plt.legend()plt.show()def plot_mnist(numpy_all, numpy_labels,name./embeddings_plot.png):c [#ff0000, #ffff00, #00ff00, #00ffff, #0000ff,#ff00ff, #990000, #999900, #009900, #009999]for i in range(10):f numpy_all[np.where(numpy_labels i)]plt.plot(f[:, 0], f[:, 1], ., cc[i])plt.legend([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])plt.savefig(name)使用以下代码绘制loss函数
plot_loss(train_loss)这将给出以下图作为结果输出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rVUxiGwN-1681785569479)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/aba64cc3-f3b4-4d14-a3bf-8d0ae4a62c36.png)]
然后我们将定义test_model和testing_plots来绘制MNIST数据集的测试集嵌入
def test_model(model):model.eval()all_ []all_labels []with torch.no_grad():for batch_idx, (x, labels) in enumerate(test_loader):x, labels Variable(x), Variable(labels)output model.forward_once(x)all_.extend(output.data.cpu().numpy().tolist())all_labels.extend(labels.data.cpu().numpy().tolist())numpy_all np.array(all_)numpy_labels np.array(all_labels)return numpy_all, numpy_labelsdef testing_plots(model):dict_pickle{}numpy_all, numpy_labels test_model(model)dict_pickle[numpy_all]numpy_alldict_pickle[numpy_labels]numpy_labelsplot_mnist(numpy_all, numpy_labels)然后绘制testing_plots
testing_plots(model)这将给出以下图作为结果输出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5p1fQlYw-1681785569479)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/9b174385-0416-496d-b96a-6eee5e7b5f61.png)]
在上图中我们可以观察到大多数点都在一个群集中而其他一些点则不在群集中可以看作是离群值。
匹配网络– Omniglot 数据集
在本教程中我们将学习如何创建匹配的网络架构并将其训练在 Omniglot 数据集上。 首先让我们首先了解什么是 Omniglot 数据集。
Omniglot 数据集旨在开发更多类似于人类的学习算法。 它包含来自 50 个不同字母的 1,623 个不同的手写字符。 1,623 个字符中的每个字符都是由 20 个不同的人通过亚马逊的 Mechanical Turk 在线绘制的。 每个图像都与笔划数据配对序列[x, y, t]与时间的坐标t以毫秒为单位。 有关更多详细信息请参考这里。
您可以从这里下载 Omniglot 数据集。
我们的匹配网络架构实现包括以下五个重要部分有关更多详细信息您可以参考“建模级别-匹配网络架构”部分中的匹配网络架构图
嵌入提取器g完全上下文嵌入和双向 LSTM f余弦相似距离函数c注意模型softmax(c)损失函数交叉熵损失
现在我们将遍历匹配网络的每个部分并实现它
导入所有库
import numpy as np
import torch
import torch.nn as nn
import math
import numpy as np
import torch.nn.functional as F
from torch.autograd import Variable
import tqdm
import torch.backends.cudnn as cudnn
from torch.optim.lr_scheduler import ReduceLROnPlateau
import matplotlib.pyplot as plt
%matplotlib inline我们将加载omniglot数据集该数据集将使用帮助程序脚本转换为.npy格式。 在帮助程序脚本中我们仅以以下大小格式加载数据[total_number, character, 28,28]有关更多详细信息请通过本书的 GitHub 存储库中的helper.py脚本进行操作
x np.load(data/data.npy) # Load Data
x np.reshape(x, newshape(x.shape[0], x.shape[1], 28, 28, 1)) # expand dimension from (x.shape[0],x.shape[1],28,28)
np.random.shuffle(x) # shuffle dataset
x_train, x_val, x_test x[:1200], x[1200:1411], x[1411:] # divide dataset in to train, val,ctest
batch_size 16 # setting batch_size
n_classes x.shape[0] # total number of classes
classes_per_set 20 # Number of classes per set
samples_per_class 1 # as we are choosing it to be one shot learning, so we have 1 sample如果您想了解有关数据加载方法的更多信息可以参考 GitHub 上的helper.py文件。
使用规范化方法预处理图像
def processes_batch(data, mu, sigma):return (data - mu) / sigma# Normalize Dataset
x_train processes_batch(x_train, np.mean(x_train), np.std(x_train))
x_val processes_batch(x_val, np.mean(x_val), np.std(x_val))
x_test processes_batch(x_test, np.mean(x_test), np.std(x_test))# Defining dictionary of dataset
datatset {train: x_train, val: x_val, test: x_test}现在运行以下代码以可视化由 20 个人编写的一个字符的第0个示例
temp x_train[0,:,:,:,:]
for i in range(0,20):plt.figure()plt.imshow(temp[i,:,:,0])通过运行前面的代码您将获得以下 20 个
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v6rPY2JW-1681785569479)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/fd4f59b6-874c-4f35-b486-0072c2a2426a.png)]
接下来我们将对训练数据进行一些处理。
要加载 Omniglot 数据集并准备将其用于匹配的网络架构我们需要创建以下内容
标签集choose_label支持集support_set_xsupport_set_y支持集示例中的一批
我们将执行以下步骤
首先创建一个可以提供支持集和目标集的批量
def sample_batch(data):Generates sample batch :param : data - one of(train,test,val) our current dataset shape [total_classes,20,28,28,1]:return: [support_set_x,support_set_y,target_x,target_y] for Matching Networkssupport_set_x np.zeros((batch_size, classes_per_set, samples_per_class, data.shape[2], data.shape[3], data.shape[4]), np.float32)support_set_y np.zeros((batch_size, classes_per_set, samples_per_class), np.int32)target_x np.zeros((batch_size, data.shape[2], data.shape[3], data.shape[4]), np.float32)target_y np.zeros((batch_size, 1), np.int32)for i in range(batch_size):choose_classes np.random.choice(data.shape[0], sizeclasses_per_set, replaceFalse) # choosing random classeschoose_label np.random.choice(classes_per_set, size1) # label setchoose_samples np.random.choice(data.shape[1], sizesamples_per_class 1, replaceFalse)x_temp data[choose_classes] # choosing classesx_temp x_temp[:, choose_samples] # choosing sample batch from classes chosen outputs 20X2X28X28X1y_temp np.arange(classes_per_set) # will return [0,1,2,3,...,19]support_set_x[i] x_temp[:, :-1]support_set_y[i] np.expand_dims(y_temp[:], axis1) # expand dimensiontarget_x[i] x_temp[choose_label, -1]target_y[i] y_temp[choose_label]return support_set_x, support_set_y, target_x, target_y # returns support of [batch_size, 20 classes per set, 1 sample, 28, 28,1]def get_batch(dataset_name):gen batch while training:param dataset_name: The name of dataset(one of train,val,test):return: a batch imagessupport_set_x, support_set_y, target_x, target_y sample_batch(datatset[dataset_name])support_set_x support_set_x.reshape((support_set_x.shape[0], support_set_x.shape[1] * support_set_x.shape[2],support_set_x.shape[3], support_set_x.shape[4], support_set_x.shape[5]))support_set_y support_set_y.reshape(support_set_y.shape[0], support_set_y.shape[1] * support_set_y.shape[2])return support_set_x, support_set_y, target_x, target_y如果您还记得在匹配的网络架构中网络有四个主要部分
嵌入提取器g全文上下文嵌入f注意模型a距离函数c
创建一个分类器
def convLayer(in_channels, out_channels, dropout_prob0.0)::param dataset_name: The name of dataset(one of train,val,test):return: a batch imagescnn_seq nn.Sequential(nn.Conv2d(in_channels, out_channels, 3, 1, 1),nn.ReLU(True),nn.BatchNorm2d(out_channels),nn.MaxPool2d(kernel_size2, stride2),nn.Dropout(dropout_prob))return cnn_seqclass Embeddings_extractor(nn.Module):def __init__(self, layer_size64, num_channels1, dropout_prob0.5, image_size28):super(Embeddings_extractor, self).__init__()Build a CNN to produce embeddings:param layer_size:64(default):param num_channels::param keep_prob::param image_size:self.layer1 convLayer(num_channels, layer_size, dropout_prob)self.layer2 convLayer(layer_size, layer_size, dropout_prob)self.layer3 convLayer(layer_size, layer_size, dropout_prob)self.layer4 convLayer(layer_size, layer_size, dropout_prob)finalSize int(math.floor(image_size / (2 * 2 * 2 * 2)))self.outSize finalSize * finalSize * layer_sizedef forward(self, image_input)::param: Image:return: embeddingsx self.layer1(image_input)x self.layer2(x)x self.layer3(x)x self.layer4(x)x x.view(x.size()[0], -1)return x在分类器之后创建注意力模型。a(x, x_hat)为余弦相似度的 softmax
class AttentionalClassify(nn.Module):def __init__(self):super(AttentionalClassify, self).__init__()def forward(self, similarities, support_set_y):Products pdfs over the support set classes for the target set image.:param similarities: A tensor with cosine similarites of size[batch_size,sequence_length]:param support_set_y:[batch_size,sequence_length,classes_num]:return: Softmax pdf shape[batch_size,classes_num]softmax nn.Softmax(dim1)softmax_similarities softmax(similarities)preds softmax_similarities.unsqueeze(1).bmm(support_set_y).squeeze()return preds创建一个距离网络该距离网络将从测试图像和训练嵌入中获取输出以计算距离。 找到支持集和input_test_image之间的余弦相似度
class DistanceNetwork(nn.Module):def __init__(self):super(DistanceNetwork, self).__init__()def forward(self, support_set, input_image):eps 1e-10similarities []for support_image in support_set:sum_support torch.sum(torch.pow(support_image, 2), 1)support_manitude sum_support.clamp(eps, float(inf)).rsqrt()dot_product input_image.unsqueeze(1).bmm(support_image.unsqueeze(2)).squeeze()cosine_similarity dot_product * support_manitudesimilarities.append(cosine_similarity)similarities torch.stack(similarities)return similarities.t()创建BidirectionalLSTM它将从测试图像获取输入和输出并将它们放在相同的嵌入空间中。 如果我们希望使用全上下文嵌入则匹配网络为此引入了双向 LSTM
class BidirectionalLSTM(nn.Module):def __init__(self, layer_size, batch_size, vector_dim):super(BidirectionalLSTM, self).__init__()self.batch_size batch_sizeself.hidden_size layer_size[0]self.vector_dim vector_dimself.num_layer len(layer_size)self.lstm nn.LSTM(input_sizeself.vector_dim, num_layersself.num_layer, hidden_sizeself.hidden_size, bidirectionalTrue)self.hidden (Variable(torch.zeros(self.lstm.num_layers * 2, self.batch_size, self.lstm.hidden_size),requires_gradFalse),Variable(torch.zeros(self.lstm.num_layers * 2, self.batch_size, self.lstm.hidden_size),requires_gradFalse))def repackage_hidden(self,h):Wraps hidden states in new Variables, to detach them from their history.if type(h) torch.Tensor:return Variable(h.data)else:return tuple(self.repackage_hidden(v) for v in h)def forward(self, inputs):self.hidden self.repackage_hidden(self.hidden)output, self.hidden self.lstm(inputs, self.hidden)return output
现在让我们结合所有已制成的小模块并创建一个匹配的网络
class MatchingNetwork(nn.Module):def __init__(self, keep_prob, batch_size32, num_channels1, learning_rate1e-3, fceFalse, num_classes_per_set20, num_samples_per_class1, image_size28):super(MatchingNetwork, self).__init__()self.batch_size batch_sizeself.keep_prob keep_probself.num_channels num_channelsself.learning_rate learning_rateself.num_classes_per_set num_classes_per_setself.num_samples_per_class num_samples_per_classself.image_size image_size# Lets set all peices of Matching Networks Architectureself.g Embeddings_extractor(layer_size64, num_channelsnum_channels, dropout_probkeep_prob, image_sizeimage_size)self.f fce # if we are considering full-context embeddingsself.c DistanceNetwork() # cosine distance among embeddingsself.a AttentionalClassify() # softmax of cosine distance of embeddingsif self.f: self.lstm BidirectionalLSTM(layer_size[32], batch_sizeself.batch_size, vector_dimself.g.outSize)def forward(self, support_set_images, support_set_y_one_hot, target_image, target_y):# produce embeddings for support set imagesencoded_images []for i in np.arange(support_set_images.size(1)):gen_encode self.g(support_set_images[:, i, :, :])encoded_images.append(gen_encode)# produce embeddings for target imagesgen_encode self.g(target_image)encoded_images.append(gen_encode)output torch.stack(encoded_images,dim0)# if we are considering full-context embeddingsif self.f:output self.lstm(output)# get similarities between support set embeddings and targetsimilarites self.c(support_setoutput[:-1], input_imageoutput[-1])# produce predictions for target probabilitiespreds self.a(similarites, support_set_ysupport_set_y_one_hot)# calculate the accuracyvalues, indices preds.max(1)accuracy torch.mean((indices.squeeze() target_y).float())crossentropy_loss F.cross_entropy(preds, target_y.long())return accuracy, crossentropy_loss创建一个数据集加载器。 对于我们的案例当我们使用 Omniglot 数据集时它将创建一个 Omniglot 构建器该构建器将调用匹配的网络并运行其周期以进行训练测试和验证
def run_epoch(total_train_batches, nametrain):Run the training epoch:param total_train_batches: Number of batches to train on:return:total_c_loss 0.0total_accuracy 0.0for i in range(int(total_train_batches)):x_support_set, y_support_set, x_target, y_target get_batch(name)x_support_set Variable(torch.from_numpy(x_support_set)).float()y_support_set Variable(torch.from_numpy(y_support_set), requires_gradFalse).long()x_target Variable(torch.from_numpy(x_target)).float()y_target Variable(torch.from_numpy(y_target), requires_gradFalse).squeeze().long()# convert to one hot encodingy_support_set y_support_set.unsqueeze(2)sequence_length y_support_set.size()[1]batch_size y_support_set.size()[0]y_support_set_one_hot Variable(torch.zeros(batch_size, sequence_length,classes_per_set).scatter_(2,y_support_set.data,1), requires_gradFalse)# reshape channels and change ordersize x_support_set.size()x_support_set x_support_set.permute(0, 1, 4, 2, 3)x_target x_target.permute(0, 3, 1, 2)acc, c_loss matchNet(x_support_set, y_support_set_one_hot, x_target, y_target)# optimize processoptimizer.zero_grad()c_loss.backward()optimizer.step()iter_out tr_loss: {}, tr_accuracy: {}.format(c_loss, acc)total_c_loss c_losstotal_accuracy acctotal_c_loss total_c_loss / total_train_batchestotal_accuracy total_accuracy / total_train_batchesreturn total_c_loss, total_accuracy设置实验变量
batch_size20
num_channels1
lr1e-3
image_size28
classes_per_set20
samples_per_class1
keep_prob0.0
fceTrue
optimadam
wd0
matchNet MatchingNetwork(keep_prob, batch_size, num_channels, lr, fce, classes_per_set, samples_per_class, image_size)
total_iter 0
total_train_iter 0
optimizer torch.optim.Adam(matchNet.parameters(), lrlr, weight_decaywd)
scheduler ReduceLROnPlateau(optimizer, min,verboseTrue)# Training setup
total_epochs 100
total_train_batches 10
total_val_batches 5
total_test_batches 5现在运行实验
train_loss,train_accuracy[],[]
val_loss,val_accuracy[],[]
test_loss,test_accuracy[],[]for e in range(total_epochs):############################### Training Step ##########################################total_c_loss, total_accuracy run_epoch(total_train_batches,train)train_loss.append(total_c_loss)train_accuracy.append(total_accuracy)################################# Validation Step #######################################total_val_c_loss, total_val_accuracy run_epoch(total_val_batches, val)val_loss.append(total_val_c_loss)val_accuracy.append(total_val_accuracy)print(Epoch {}: train_loss:{:.2f} train_accuracy:{:.2f} valid_loss:{:.2f} valid_accuracy:{:.2f}.format(e, total_c_loss, total_accuracy, total_val_c_loss, total_val_accuracy))运行此代码块后您将看到模型开始训练并打印以下输出
Epoch 0: train_loss:2.99 train_accuracy:0.11 valid_loss:2.98 valid_accuracy:0.22
Epoch 1: train_loss:2.97 train_accuracy:0.20 valid_loss:2.97 valid_accuracy:0.28
Epoch 2: train_loss:2.95 train_accuracy:0.31 valid_loss:2.94 valid_accuracy:0.37现在通过运行以下代码块来获得测试的准确率
total_test_c_loss, total_test_accuracy run_epoch(total_test_batches,test)
print(test_accuracy:{}%.format(total_test_accuracy*100))运行此代码块后您将看到以下输出
test_accuracy:86.0%让我们可视化我们的结果
def plot_loss(train,val,name1train_loss,name2val_loss):plt.plot(train, labelname1)plt.plot(val, labelname2)plt.legend()plot_loss(train_loss,val_loss)运行这些单元格后您将看到如下图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8zFmgUaC-1681785569480)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/97d99dae-968d-45c3-9d2f-13cf0b663c2b.png)]
在本节中我们探索了使用 MNIST 数据集的连体网络的实现以及使用 Omniglot 数据集的匹配网络架构。 在连体网络编码练习中我们创建了一个小的卷积层并由一个全连接层姐妹架构进行了扩展。 训练模型后我们还绘制了模型获得的二维嵌入图并观察了某些数字如何聚类在一起。 同样在匹配网络编码练习中我们为匹配网络的每个模块实现了小型架构例如嵌入提取器注意力模型和完全上下文嵌入。 我们还观察到仅用 100 个周期我们就可以达到约 86% 的精度并绘制了匹配网络架构的精度和损失图。
您可能还观察到某些模型是从头开始训练的-我们可能已经使用了迁移学习架构或者增加了 LSTM 架构的隐藏大小或者也许被认为是加权的交叉熵损失函数。 总是有实验和改进的空间。 如果您想进一步尝试使用该模型建议您访问本书的 GitHub 页面。
总结
在本章中我们学习了基于指标的单样本学习方法。 我们探索了两种神经网络架构它们已在研究界和软件行业中用于单样本学习。 我们还学习了如何评估经过训练的模型。 然后我们使用 MNIST 数据集在连体网络中执行了一个练习。 总之可以说匹配网络和连体网络架构都已经成功证明通过更改损失函数或特征表示我们可以用有限的数据量实现目标。
在下一章中我们将探索不同的基于优化的方法并了解它们与基于度量的方法之间的区别。
问题
什么是相似度指标 为什么余弦相似度最有效为什么匹配网络使用 LSTM 架构来获取嵌入对比损失函数有哪些缺点三重损失函数如何帮助解决它维度的诅咒是什么 我们该如何处理
进一步阅读
要更深入地了解本章介绍的架构并探讨它们的工作方式和原因请阅读以下文章
《用于一次图像识别的连体神经网络》《单样本学习的匹配网络》
三、基于模型的方法
在上一章中我们讨论了两种基于优化的方法。 我们试图用元学习机制来训练模型这与人类所见相似。 当然除了学习新事物的能力外人类在执行任何任务时还可以访问大量内存。 通过回忆过去的经历和经验这使我们能够更轻松地学习新任务。 遵循相同的思想过程设计了基于模型的架构并添加了外部存储器以快速概括单样本学习任务。 在这些方法中使用存储在外部存储器中的信息模型仅需几个训练步骤即可收敛。
本章将涵盖以下主题
了解神经图灵机记忆增强神经网络元网络编码练习
技术要求
您将需要 PythonAnacondaJupyter 笔记本PyTorch 和 Matplotlib 库在本章中学习和执行项目。
您可以在本书的 GitHub 存储库中找到本章的代码文件。
了解神经图灵机
在 AI 的早期该领域主要由一种象征性的处理方法主导。 换句话说它依靠使用符号和结构以及操纵它们的规则来处理信息。 直到 1980 年代人工智能领域才采用了另一种方法-连接主义。 连接主义最有前景的建模技术是神经网络。 但是他们经常遭到两个严厉的批评
神经网络仅接受固定大小的输入这在输入长度可变的现实生活中不会有太大帮助。神经网络无法将值绑定到我们已知的两个信息系统人脑和计算机大量使用的数据结构中的特定位置。 简单来说在神经网络中我们无法将特定的权重设置到特定的位置。
第一个问题可以通过在各种任务上实现最先进表现的 RNN 来解决。 通过查看神经图灵机NTM可以解决第二个问题。 在本节中我们将讨论 NTM 的总体架构这是理解记忆增强神经网络MANN的基础这些神经网络修改了 NMT 的架构并使之适用于单样本学习任务。
NTM 的架构
在过去的 50 年中现代计算机发生了很大的变化。 但是它们仍然由三个系统组成-内存控制流和算术/逻辑运算。 来自生物学和计算神经科学领域的研究提供了广泛的证据表明记忆对于快速有效地存储和检索信息至关重要。 从中汲取灵感NTM 基本上由神经网络组成该神经网络由控制器和称为存储库或存储矩阵的二维矩阵组成。 在每个时间步长神经网络都会接收一些输入并生成与该输入相对应的输出。 在这样做的过程中它还访问内部存储库并对其执行读取和/或写入操作。 从传统的图灵机中汲取灵感NMT 使用术语头部来指定内存位置。 下图显示了总体架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-trrJCU4K-1681785569480)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/29d7adbd-0103-4c43-b5b0-c2a65a121d48.png)]
整体架构看起来不错 但是这有一个问题。 如果通过在内存矩阵中指定行索引和列索引来访问内存位置则无法获取该索引的梯度。 此操作不可反向传播并且会使用标准的反向传播和基于梯度下降的优化技术来限制 NMT 的训练。 为了解决此问题NTM 的控制器使用模糊读写操作与内存进行交互这些操作与内存的所有元素进行不同程度的交互。 更准确地说控制器以差分方式在所有存储位置上生成权重这有助于使用基于标准梯度的优化方法从头到尾训练网络。
在下一节中我们将讨论如何产生这些权重以及如何执行读写操作。
建模
在时间步tM[t]的存储矩阵具有R行和C列。 有一种注意力机制用于指定注意头应该读取/写入的内存位置。 控制器生成的注意力向量是长度R的向量称为权重向量w[t]其中向量w[t](i)的条目是存储库第i行的权重。 权重向量已标准化这意味着它满足以下条件*
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7A2AFjWA-1681785569480)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/eed93f02-4abc-465e-b009-2912f63ccb39.png)]
读取
读取头将返回长度为C的向量 r[t]它是存储器行M[t](i)由权重向量缩放
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-83DMFHmv-1681785569480)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/7b4dda93-17d9-4c36-ab06-7af57479b100.png)]
写入
写入是两个步骤的结合擦除和添加。 为了擦除旧数据写头使用附加长度C擦除向量e[t]以及权重向量。 以下方程式定义了擦除行的中间步骤
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kistk1um-1681785569480)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/cb6720e7-9a40-4e30-b015-966dd1074fb0.png)]
最后写入头使用长度C的向量 a[t]以及M_erased[t]根据前面的方程式和权重向量更新存储矩阵的行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-agR1IydJ-1681785569480)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/6d9c4431-8618-4953-a442-b2320bd662fb.png)]
寻址
读取和写入操作的关键是权重向量该权重向量指示要从中读取/写入的行。 控制器分四个阶段生成此权重向量。 每个阶段都会产生一个中间向量该向量将传递到下一个阶段
第一步是基于内容的寻址其目的是基于每一行与给定的长度为C的给定关键字向量k[t]的相似度来生成权重向量。 更精确地说控制器发出向量k[t]并使用余弦相似性度量将其与M[t]的每一行进行比较。 如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XmBkp4HH-1681785569481)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/d338c2ca-2226-4543-abc4-5ab988fc0a28.png)]
内容权重向量尚未规范化因此可以通过以下操作进行规范化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rVPXuOk8-1681785569481)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/e9fa7fd5-b836-4dc6-a320-74200df1183a.png)]
第二阶段是基于位置的寻址其重点是从特定存储位置读取/写入数据而不是在阶段 1 中完成的位置值。其后标量参数g[t] ∈ (0, 1)称为插值门将内容权重向量w[t]^c与前一个时间步的权重向量w[t-1]混合以产生门控权重w[t]^g。 这使系统能够学习何时使用或忽略基于内容的寻址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jzhRclXJ-1681785569481)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/906b96f2-1a9f-4b09-ad23-f551d40f82d5.png)]
在第三阶段插值后头部发出归一化的移位加权s[t]以执行R模的移位运算即向上或向下移动行。 这由以下操作定义
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wmwCGGqe-1681785569481)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/8ad09342-cba4-4cfe-8b3e-3536756a491d.png)]
第四个也是最后一个阶段锐化用于防止偏移的权重w_tilde[t]模糊。 这是使用标量γ 1并应用以下操作完成的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RZscwMJJ-1681785569481)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/f6a0bbfd-bfe5-4d2d-8d0e-015fc55c1642.png)]
所有操作包括读取写入和寻址的四个阶段都是差分的因此可以使用反向传播和任何基于梯度下降的优化器从头到尾训练整个 NMT 模型。 控制器是一个神经网络可以是前馈网络也可以是循环神经网络例如长短期记忆LSTM。 它已显示在各种算法任务例如复制任务上均具有良好的表现这些任务将在本章的稍后部分实现。
既然我们了解了 NTM 的架构和工作原理我们就可以开始研究 MANN这是对 NMT 的修改并且经过修改可以在单样本学习中表现出色。
记忆增强神经网络
MANN 的目标是在单样本学习任务中表现出色。 正如我们之前阅读的NMT 控制器同时使用基于内容的寻址和基于位置的寻址。 另一方面MANN 控制器仅使用基于内容的寻址。 有两个原因。 原因之一是单样本学习任务不需要基于位置的寻址。 在此任务中对于给定的输入控制器可能只需要执行两个操作并且这两个操作都与内容有关而与位置无关。 当输入与先前看到的输入非常相似时将采取一种措施在这种情况下我们可以更新内存的当前内容。 当当前输入与以前看到的输入不相似时将采取另一种操作在这种情况下我们不想覆盖最近的信息。 相反我们写到使用最少的内存位置。 在这种情况下该存储模块称为最久未使用的访问LRUA模块。
读取
MANN 的读取操作与 NTM 的读取操作非常相似唯一的区别是此处的权重向量仅使用基于内容的寻址NMT 寻址的阶段 -1。 更准确地说控制器使用标准化的读取权重向量w[t]^r将其与M[t]的行一起使用以生成读取向量r[t]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ZQhEgEW-1681785569482)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/dc63f6b2-8a4b-4774-8ed6-0d720f31bb7b.png)]
读取权重向量w[t]^r由控制器产生该控制器由以下操作定义
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6LHaCXoZ-1681785569482)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/b947ff46-f23a-45ed-a252-2ceaa0ca82b6.png)]
在此运算K()是余弦相似度类似于为 NMT 定义的余弦相似度。
写入
为了写入存储器控制器在写入最近读取的存储器行和写入最近读取的存储器行之间进行插值。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1DYAg09m-1681785569482)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/940cbf9a-4794-43e5-917a-171886d6871a.png)]
通过对 Omniglot 数据集进行一次一次性分类任务MANN 已显示出令人鼓舞的结果。 由于其基本的模型 NTM它们表现良好。 NTM 能够快速编码存储和检索数据。 它们还能够存储长期和短期权重。 可以使用 MANN 的方法添加 NTM以跟踪最久未使用的存储位置以执行基于内容的寻址以读取和写入最久未使用的位置。 它使 MANN 成为少量学习的理想人选。
在下一部分中我们将学习另一种基于模型的架构该架构由四个架构的网络组成并为单样本学习领域做出了重大贡献。
了解元网络
顾名思义元网络是基于模型的元学习方法的一种形式。 在通常的深度学习方法中神经网络的权重是通过随机梯度下降来更新的这需要大量的时间来训练。 众所周知随机梯度下降法意味着我们将考虑每个训练数据点进行权重更新因此如果我们的批量大小为 1这将导致模型优化非常缓慢-换句话说较慢的权重更新。
元网络建议通过训练与原始神经网络并行的神经网络来预测目标任务的参数从而解决权重缓慢的问题。 生成的权重称为快速权重。 如果您还记得的话LSTM 元学习器请参阅第 4 章“基于优化的方法”也是基于类似的基础来预测使用 LSTM 单元的任务的参数更新 。
与其他元学习方法类似元网络包含两个级别
元学习器元学习器获得有关不同任务的一般知识。 在元网络的情况下这是一个嵌入函数用于比较两个不同数据点的特征。基础学习器基础学习器尝试学习目标任务任务目标网络可以是简单的分类器。
元级学习器的目标是获得有关不同任务的一般知识。 然后可以将知识迁移到基础级学习器以在单个任务的上下文中提供概括。
如所讨论的元网络学习权重的两种形式慢权重和快权重。 要为元学习器嵌入函数和基础学习器分类模型两者学习这些权重我们需要两个不同的网络。 这使得元网络成为迄今为止我们在本书中讨论过的最复杂的网络之一。 简而言之元网络由四种类型的神经网络组成它们各自的参数要训练。 在下一节中我们将遍历元网络中存在的每个网络并了解其架构。
元网络算法
要开始学习元网络我们首先需要定义以下项
支持集训练集中的采样输入数据点xy。测试集来自训练集的采样数据点x和。嵌入函数f[θ]作为元学习器的一部分嵌入函数与连体网络非常相似。 经过训练可以预测两个输入是否属于同一类。基本学习器模型g[φ]基本学习器模型尝试完成实际的学习任务例如分类模型。θ⁺嵌入函数的快速权重f[θ]。φ⁺基本学习器模型的快速权重g[φ]。F[w]一种 LSTM 架构用于学习嵌入函数的快速权重θf[θ]的慢速网络。G[v]通过v学习快速权重φ参数化的神经网络用于基础学习器g[φ]来自其损失梯度。
下图说明了元网络架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HG064yIu-1681785569482)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/7ee8a46f-a88d-4310-a261-da0df68aa4f7.png)]
如图所示元学习器基础学习器由较慢的权重θ, φ组成。 为了学习快速权重θ⁺, φ⁺元网络使用两个不同的网络
LSTM 网络F[w]学习嵌入函数的元学习器快速权重-即θ⁺。神经网络G[v]以学习基本学习器的快速权重即φ⁺。
现在我们已经了解了快速权重和慢速权重的概念和架构让我们尝试观察整个元网络架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k0J7P1e0-1681785569482)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/d98e350d-6d91-4bff-b79d-6f33824b0e59.png)]
如上图所示元网络由基本学习器和配备外部存储器的元学习器嵌入函数组成。 我们还可以看到快速参数化箭头同时进入元学习器和基础学习器。 这些是元权重的输出其中包括用于学习快速权重的模型。
现在让我们简单介绍一下训练。 随着训练输入数据的到来它会同时通过元学习器和基础学习器。 在元学习器中它用于连续学习更新参数而在基础学习器中对输入进行预处理之后它将元信息梯度传递给元 -学习器。 之后元学习器使用元信息梯度将参数化更新快速返回给基础学习器以通过使用慢速权重和快速权重的集成来进行优化如图所示 在下图中。 元网络的基本关键思想是通过处理元信息以快速的方式学习权重以进行快速概括。
在 MetaNet 中学习器的损失梯度是任务的元信息。 MetaNet 还有一个重要的问题它如何使用快速权重和慢速权重进行预测
在 MetaNet 中将慢速权重和快速权重组合在一起以在神经网络中进行预测如下图所示。 在这里⊕表示元素方式的和
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ewDk3StF-1681785569483)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/e3036523-f829-413a-85ad-fe9838ae6684.png)]
在下一节中我们将逐步介绍算法提取元信息以及最终模型预测。
算法
元网络也遵循与匹配网络相似的训练过程。 在此训练数据分为两种类型支持集S (x[i], y[i])和测试集U (x[i], y[i])。
请记住目前我们有四个网络f[θ], g[φ], F[w], G[v])和四组要学习的模型参数(θ, ϕ, w, v)。 让我们看一下算法的所有步骤
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nq94NlUA-1681785569483)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/6a8a41af-c6a4-471a-8998-920cf7d1d0c7.png)]
以下是算法的步骤
支持集S的样本的K个随机对。
对于t 1, ..., K
通过嵌入函数f[θ]正向传播数据点。计算交叉熵损失L_emb。
通过 LSTM 网络向前传递数据以计算θ⁺θ⁺ F[w](▽L_emb)。接下来遍历支持集S中的示例并为每个示例计算快速权重。 同时使用获得的嵌入内容更新外部存储器。
对于i 1, ..., K
将基本学习器g[φ](x[i])例如分类模型向前传递并计算损失函数L_task[i]例如交叉熵。计算基本学习器梯度▽L_task[i]并使用它们来计算示例级快速权重φ⁺[i] G[v](▽L_task[i])。将基础学习器φ⁺[i]的计算得出的快速权重存储在存储器的M部分的i位置处。在嵌入网络中使用⊕合并快速权重和缓慢权重。将支持样本转发通过嵌入网络并获得嵌入r[i] f[θ,θ⁺](x[i])。将r[i]存储在内存R的k部分的i位置。
最后是时候使用测试集U (x[i], y[i])构建训练损失了。 从L_train 0开始。
对于j 1, ..., L 将测试样本转发通过嵌入网络并获得测试嵌入r[i] f[θ,θ⁺](x[j])。 计算支持集的存储嵌入R和获得的嵌入r[j]之间的相似度。 您可以使用a[j] cos(R, r[j])来执行此操作。 在此R是指存储在外部存储器中的数据。 现在通过使用支持集样本M的快速权重来计算基础学习器的快速权重φ⁺。 您可以使用φ⁺[j] softmax(a[j])^T M来执行此操作。 在此M是指存储在外部存储器中的数据。 使用最新的φ⁺将测试样本向前传递通过基本学习器并计算损失函数L_task[i]。 使用公式更新训练损失 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-melCfz13-1681785569483)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/14423e78-c644-4cec-b7dc-f5879e000a7a.png)]
使用L_train更新所有参数(θ, ϕ, w, v)。
在选择嵌入网络时元网络使用 LSTM 架构。 如我们所见匹配网络和 LSTM 元学习器也遵循相同的策略分别用于提取数据和元信息的上下文嵌入。 这是因为 LSTM 架构倾向于记住历史这使得元学习器的目标能够跨任务提取重要信息。
例如假设我们正在训练我们的网络以完成多种任务例如猫的品种分类和狗的品种分类。 当我们使用 LSTM 元学习器进行训练时它会学习例如狗品种分类中权重更新的策略并使用这些学习到的信息以较少的步骤和较少的数据来优化其用于猫品种分类的操作。 使用元网络在 Omniglot 数据集上达到了 95.92% 的准确率而人类的准确率仅为 95.5%因此元网络被认为是最新模型之一。
编码练习
在本节中我们将首先介绍 NTM 的实现然后再使用 Omniglot 数据集介绍 MAAN。 所以让我们开始吧
本练习不包括代码的某些部分。 如果希望获得可运行的代码请在这个页面中查看本书的 GitHub 存储库。
NTM 的实现
如上所述NTM 由两个重要组成部分组成
神经网络也称为控制器称为记忆的二维矩阵
在本教程中我们将实现两者的简化版本并尝试展示复制任务。
任务目标如下
NTM 模型显示为T时间步长的随机k维向量。网络的工作是在每个时间步从零向量输出这些T[k]维随机向量。
执行以下步骤来实现 NTM
首先导入所有必需的库
import torch
from torch import nn
import torch.nn.functional as F
import numpy as np
from time import time
import torchvision.utils as vutils
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
%matplotlib inline然后实现Controller。 作为控制器的一部分我们将实现以下三个组件 两层前馈网络使用 Xavier 方法进行权重初始化Sigmoid 非线性
class Controller(nn.Module):def __init__(self, input_size, output_size, hidden_size):super(Controller, self).__init__()self.layer1 nn.Linear(input_size, hidden_size)self.layer2 nn.Linear(hidden_size, output_size)self.intialize_parameters()def intialize_parameters(self):# Initialize the weights of linear layersnn.init.xavier_uniform_(self.layer1.weight, gain1.4) nn.init.normal_(self.layer1.bias, std0.01)nn.init.xavier_uniform_(self.layer2.weight, gain1.4)nn.init.normal_(self.layer2.bias, std0.01)def forward(self, x, last_read):# Forward pass operation, depending on last_read operationx torch.cat((x, last_read), dim1)x torch.sigmoid(self.layer1(x))x torch.sigmoid(self.layer2(x))return x我们也可以有一个 LSTM 控制器但是由于简单起见我们构建了一个两层的全连接控制器。
接下来实现Memory模块。 Memory是一个二维矩阵具有M行和N列
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hsrIEyx3-1681785569483)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/3a4d2e1c-a7df-4316-b1cd-5a67640f0bdf.png)]
address()函数执行存储器寻址它由四个函数组成
similarityinterpolateshiftsharpen
class Memory(nn.Module):def __init__(self, M, N, controller_out):super(Memory, self).__init__()self.N Nself.M Mself.read_lengths self.N 1 1 3 1self.write_lengths self.N 1 1 3 1 self.N self.Nself.w_last [] # define to keep track of weight_vector at each time step.self.reset_memory()def address(self, k, beta, g, s, gamma, memory, w_last):# Content focuswc self._similarity(k, beta, memory) # CB1 to CB3 equations# Location focuswg self._interpolate(wc, g, w_last) # CS1 equationw_hat self._shift(wg, s) # CS2 and CS3 equationw self._sharpen(w_hat, gamma) # S1 equationreturn w# Implementing Similarity on basis of CB1 followed by CB2 and CB3 Equationdef _similarity(self, k, beta, memory):w F.cosine_similarity(memory, k, -1, 1e-16) # CB1 Equationw F.softmax(beta * w, dim-1) # CB2 and CB3 Equationreturn w # return CB3 equation obtained weights# Implementing CS1 Equation. It decides whether to use the weights we obtained# at the previous time step w_last or use the weight obtained through similarity(content focus)def _interpolate(self, wc, g, w_last):return g * wc (1 - g) * w_last
# .... Rest Code is available at Github......接下来执行read操作。 在这里我们将定义ReadHead它可以根据read操作访问和更新内存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xRLV2MNX-1681785569483)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/006a56d0-58c8-429e-a160-c9f33966e585.png)]
class ReadHead(Memory):# Reading based on R2 equationdef read(self, memory, w):return torch.matmul(w, memory)# Use Memory class we formed above to create a ReadHead operationdef forward(self, x, memory):param self.fc_read(x) # gather parameters# initialize necessary parameters k, beta, g, shift, and gammak, beta, g, s, gamma torch.split(param, [self.N, 1, 1, 3, 1], dim1)k torch.tanh(k)beta F.softplus(beta)g torch.sigmoid(g)s F.softmax(s, dim1)gamma 1 F.softplus(gamma) # obtain current weight address vectors from Memoryw self.address(k, beta, g, s, gamma, memory, self.w_last[-1])# append in w_last functionself.w_last.append(w)mem self.read(memory, w) return mem, w与read操作类似在这里我们将执行write操作
class WriteHead(Memory):def write(self, memory, w, e, a):# Implement write function based on E1 and A1 Equationw, e, a torch.squeeze(w), torch.squeeze(e), torch.squeeze(a)erase torch.ger(w, e)m_tilde memory * (1 - erase) # E1 equationadd torch.ger(w, a)memory_update m_tilde add # A1 equationreturn memory_updatedef forward(self, x, memory):param self.fc_write(x) # gather parameters# initialize necessary parameters k, beta, g, shift, and gammak, beta, g, s, gamma, a, e torch.split(param, [self.N, 1, 1, 3, 1, self.N, self.N], dim1)k torch.tanh(k)beta F.softplus(beta)g torch.sigmoid(g)s F.softmax(s, dim-1)gamma 1 F.softplus(gamma)a torch.tanh(a)e torch.sigmoid(e)# obtain current weight address vectors from Memoryw self.address(k, beta, g, s, gamma, memory, self.w_last[-1])# append in w_last functionself.w_last.append(w)# obtain current mem location based on R2 equationmem self.write(memory, w, e, a)return mem, wReadHead和WriteHead都使用全连接层来生成用于内容编址的参数kbetagsgamma。
实现神经图灵机结构其中包括
全连接控制器读写头部记忆体参数在无法训练的记忆上运行的工具函数
class NTM(nn.Module):def forward(self, XNone):if X is None:X torch.zeros(1, self.num_inputs)controller_out self.controller(X, self.last_read) self._read_write(controller_out)# use updated last_read to get sequenceout torch.cat((X, self.last_read), -1)out torch.sigmoid(self.fc_out(out))return outdef _read_write(self, controller_out):# Read Operationread, w self.read_head(controller_out, self.memory)self.last_read read# Write Operationmem, w self.write_head(controller_out, self.memory)self.memory mem在forward函数中X可以是None。 这是因为在复制任务中针对一个特定序列训练分两步进行 在第一步中网络显示为t时间步长的k维输入。 在第二步预测步骤中网络采用k维零向量来产生预测该预测对每个时间步执行输入的复制。 在这里我们正在为复制任务生成向量的随机序列。 它由 NTM 模型复制
class BinaySeqDataset(Dataset):def __init__(self, sequence_length, token_size, training_samples):self.seq_len sequence_lengthself.seq_width token_sizeself.dataset_dim training_samplesdef _generate_seq(self):# A special token is appened at beginning and end of each# sequence which marks sequence boundaries.seq np.random.binomial(1, 0.5, (self.seq_len, self.seq_width))seq torch.from_numpy(seq)# Add start and end tokeninp torch.zeros(self.seq_len 2, self.seq_width)inp[1:self.seq_len 1, :self.seq_width] seq.clone()inp[0, 0] 1.0inp[self.seq_len 1, self.seq_width - 1] 1.0outp seq.data.clone()return inp.float(), outp.float()def __len__(self):return self.dataset_dimdef __getitem__(self, idx):inp, out self._generate_seq()return inp, out我们还将实现梯度剪切因为剪切梯度通常是一个好主意以使网络在数值上稳定
def clip_grads(net, min_grad-10,max_grad10):parameters list(filter(lambda p: p.grad is not None, net.parameters()))for p in parameters:p.grad.data.clamp_(min_grad,max_grad)初始化训练参数
memory_capacity64
memory_vector_size128
controller_output_dim256
controller_hidden_dim512
learning_rate1e-2sequence_length, token_size, training_samples 2, 10, 99
min_grad, max_grad -10, 10然后初始化训练模型
# Initialize the dataset
dataset BinaySeqDataset(sequence_length, token_size, training_samples)
dataloader DataLoader(dataset, batch_size1,shuffleTrue, num_workers4)
model NTM() # Initialize NTM
criterion torch.nn.BCELoss()
optimizer torch.optim.RMSprop(model.parameters(), lrlearning_rate)
losses []
# Train the Model
for e, (X, Y) in enumerate(dataloader):tmp time()model.initalize_state()optimizer.zero_grad()inp_seq_len sequence_length 2out_seq_len sequence_lengthX.requires_grad True# Forward Pass: Feed the Sequencefor t in range(0, inp_seq_len):model(X[:, t])# Predictions: Obtain the already feeded sequencey_pred torch.zeros(Y.size())for i in range(0, out_seq_len):y_pred[:, i] model() # Here, X is passed as Noneloss criterion(y_pred, Y)loss.backward()clip_grads(model)optimizer.step()losses [loss.item()]if (e%100):print(iteration: {}, Loss:{} .format(e, loss.item()))if e 5000:break运行此单元格后您将看到以下输出
iteration: 0, Loss:0.7466866970062256
iteration: 10, Loss:0.7099956274032593
iteration: 20, Loss:0.6183871626853943
iteration: 30, Loss:0.6750341653823853
iteration: 40, Loss:0.7050653696060181
iteration: 50, Loss:0.7188648581504822定义一个plot_signal函数并绘制训练损失losses
def plot_signal(grid_image, fig_size(500,100)):plt.figure(figsizefig_size)plt.imshow(grid_image.data.permute(2, 1, 0))plt.plot(losses)
plt.show()测试 NTM 模型的复制任务
X, Y dataset._generate_seq()
X, Y X.unsqueeze(0), Y.unsqueeze(0)# Add the batch dimensionmodel.initalize_state()for t in range(0, inp_seq_len):model(X[:, t])y_pred torch.zeros(Y.size())
for i in range(0, out_seq_len):y_pred[:, i] model()grid_img_truth vutils.make_grid(Y, normalizeTrue, scale_eachTrue)
grid_img_pred vutils.make_grid(y_pred, normalizeTrue, scale_eachTrue)plt.figure(figsize(200,200))
plt.imshow(grid_img_truth.data.permute(2, 1, 0))plt.figure(figsize(200,200))
plt.imshow(grid_img_pred.data.permute(2, 1, 0))运行前面的代码将给出以下输出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GEebHoA4-1681785569484)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/0dc925d0-48d7-4b5c-958f-fe2f911fdb8d.png)]
在这里我们创建了一个 300 个时间步长的随机信号并观察了模型复制该信号的程度。 在此步骤中您观察了复制任务输出。 这两个信号应该非常接近。 如果不是我们建议您更多地训练模型。
MAAN 的实现
正如我们在上一节中展示的那样NTM 的控制器能够使用基于内容的寻址基于位置的寻址或同时使用这两种而 MANN 则使用纯基于内容的内存写入器来工作。
MANN 还使用一种称为最久未访问的新寻址方案。 该模式背后的思想是最久未使用的内存位置由读取操作确定而读取操作由基于内容的寻址执行。 因此我们基本上执行基于内容的寻址以读取和写入最久未使用的位置。
在本教程中我们将实现read和write操作。
首先导入所需的所有库
import torch
from torch import nn
import torch.nn.functional as F
import numpy as np
import copy实现类似于 NTM 的Memory模块并对 MANN 进行一些更改
class Memory(nn.Module):def __init__(self, M, N, controller_out):super(Memory, self).__init__()self.N Nself.M Mself.read_lengths self.N 1 1 3 1self.write_lengths self.N 1 1 3 1 self.N self.Nself.w_last [] # define to keep track of weight_vector at each time stepself.reset_memory()def address(self, k, beta, g, s, gamma, memory, w_last):# Content focusw_r self._similarity(k, beta, memory)return w_r# Implementing Similaritydef _similarity(self, k, beta, memory):w F.cosine_similarity(memory, k, -1, 1e-16) w F.softmax(w, dim-1)return w # return w_r^t for reading purpose定义ReadHead使其可以根据read操作访问和更新内存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LaxQm6Z8-1681785569484)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/295304f9-1168-4b66-8274-4550618d7e6e.png)]
ReadHead函数定义如下
class ReadHead(Memory):def read(self, memory, w):# Calculate Memory Updatereturn torch.matmul(w, memory)def forward(self, x, memory):param self.fc_read(x) # gather parameters# initialize necessary parameters k, beta, g, shift, and gammak, g, s, gamma torch.split(param, [self.N, 1, 1, 3, 1], dim1)k torch.tanh(k)g F.sigmoid(g)s F.softmax(s, dim1)gamma 1 F.softplus(gamma)# obtain current weight address vectors from Memoryw_r self.address(k, g, s, gamma, memory, self.w_last[-1])# append in w_last function to keep track content based locationsself.w_last.append(w_r)# obtain current mem location based on above equationsmem self.read(memory, w_r)w_read copy.deepcopy(w_r)return mem, w_r与read操作类似在这里我们将执行write操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6eoF5Q1I-1681785569484)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/1560e10f-2d4c-4532-a273-9d87c961a89e.png)]
write操作的实现如下
class WriteHead(Memory):def usage_weight_vector(self, prev_w_u, w_read, w_write, gamma):w_u gamma * prev_w_u torch.sum(w_read, dim1) torch.sum(w_write, dim1)return w_u # Equation F2def least_used(self, w_u, memory_size3, n_reads4):_, indices torch.topk(-1*w_u,kn_reads)wlu_t torch.sum(F.one_hot(indices, memory_size).type(torch.FloatTensor),dim1,keepdimTrue)return indices, wlu_tdef mann_write(self, memory, w_write, a, gamma, prev_w_u, w_read, k):w_u self.usage_weight_vector(prev_w_u, w_read, w_write, gamma)w_least_used_weight_t self.least_used(w_u)# Implement write step as per (F3) Equationw_write torch.sigmoid(a)*w_read (1-torch.sigmoid(a))*w_least_used_weight_tmemory_update memory w_write*k # Memory Update as per Equation (F4)def forward(self, x, memory):param self.fc_write(x) # gather parametersk, beta, g, s, gamma, a, e torch.split(param, [self.N, 1, 1, 3, 1, self.N, self.N], dim1)k F.tanh(k)beta F.softplus(beta)g F.sigmoid(g)s F.softmax(s, dim-1)gamma 1 F.softplus(gamma)a F.tanh(a)# obtain current weight address vectors from Memoryw_write self.address(k, beta, g, s, gamma, memory, self.w_last[-1])# append in w_last function to keep track content based locationsself.w_last.append(w_write)# obtain current mem location based on F2-F4 equationsmem self.write(memory, w_write, a, gamma, prev_w_u, w_read, k)w_write copy.deepcopy(w)return mem, wReadHead和WriteHead都使用全连接层来生成用于内容编址的参数kbetags和gamma。
请注意此练习只是为了展示 MANN 如何受到 NTM 的启发。 如果您想在真实的数据集上探索前面的练习请参考GitHub 存储库。
总结
在本章中我们探索了用于单样本学习的不同形式的基于模型的架构。 我们观察到的最常见的事情是使用外部存储器这对学习神经网络不同阶段的表示形式有什么帮助。 NMT 方法在单样本学习任务中表现良好但是由于手工设计的内存寻址函数它们的能力仍然有限因为它们必须具有差异性。 探索更复杂的函数来处理内存可能很有趣。 在元网络中我们看到了如何定义一个新网络以实现对原始网络的快速学习以及如何在元学习器级别上存储有关表示的信息如何在基础级别上微调参数。 尽管基于模型的架构是实现单样本学习的好方法但它们具有外部存储器的先决条件因此与其他方法相比实现基于模型的架构的成本昂贵。
在下一章中我们将介绍基于优化的方法例如与模型无关的元学习和 LSTM 元学习。 内存为我们提供了一种方式来存储我们所学到的信息因此优化策略使我们能够更快地学习事物。 在后面的章节中我们将探索一些不同形式的优化策略这些策略可以用来学习目标。
问题
什么是神经图灵机它们如何帮助学习记忆矩阵如何帮助模型更快地学习元学习器和基础学习器之间的分裂如何帮助架构学习单样本学习
进一步阅读
基于模型的方法是您需要学习的更复杂的主题之一因此如果您想更深入地研究所涉及的概念则可以阅读以下论文
《神经图灵机》《记忆增强神经网络》《元网络》
四、基于优化的方法
大多数深度学习模型都是使用梯度下降法来学习目标的。 但是梯度下降优化需要大量训练样本才能使模型收敛这使其不适合进行少量学习。 在通用深度学习模型中我们训练模型以学习实现确定的目标而人类则训练为学习任何目标。 遵循此观察结果各种研究人员创建了针对元学习机制的不同优化方法。
换句话说系统着重于如何收敛任何损失函数目标而不是最小化单个损失函数目标这使该算法方法任务和域不变。 例如您不需要训练模型就可以使用交叉熵损失函数来识别花朵的类型。 相反您可以训练模型以了解任何两个图像之间的差异从而使模型任务不可知例如花识别花检测和领域不可知例如猫识别。
在本章中我们将介绍以下主题
梯度下降概述了解模型不可知的元学习了解 LSTM 元学习器编码练习
技术要求
在本章中将需要 PythonAnacondaJupyter 笔记本Matplotlib 和 Scikit-learn 库来学习和执行该项目。
您可以从本书的 GitHub 存储库中找到本章的代码文件。
梯度下降概述
如果我们研究神经网络架构的学习方法它通常由很多参数组成并使用梯度下降算法进行了优化该算法需要对许多示例进行许多迭代以使其表现良好。 但是梯度下降算法在其模型中提供了不错的表现但是在某些情况下梯度下降优化算法会失败。 让我们在接下来的部分中介绍这种情况。
当给出有限数量的数据时梯度下降算法无法优化神经网络的主要原因有两个
对于每个新任务神经网络必须从其参数的随机初始化开始这会导致后期收敛。 迁移学习已通过使用预训练的网络来缓解此问题但由于数据应具有相似的域而受到限制。即使是梯度下降的权重更新步骤方法例如 AdaGradAdamRMS 等的变体也无法在较少的周期内表现良好。 这些算法不能保证收敛特别是在用于非凸优化时。
真正有用的是学习一些可以在所有域中使用的通用初始化这是初始化的一个好地方。 梯度下降算法的关键思想是基于下一步的方向该方向是根据概率分布假设选择的。 因此如果我们能够以某种方式完全近似概率分布则仅需几个步骤就可以优化网络。 这是一次/小样本学习基于优化的算法的基本思想。
了解模型不可知的元学习
与模型无关的元学习MAML尝试通过为每个新任务提供更好的权重初始化来解决梯度下降方法的缺点。 这种方法的关键思想是使用不同的数据集训练模型的参数。 当将其用于新任务时该模型通过使用已初始化的参数通过一个或多个梯度步骤来微调架构从而提供更好的表现。 从特征学习的角度来看这种训练模型参数以使一些梯度步骤可以优化损失函数的方法也可以从构建内部表示的角度来看。 在这种方法中我们选择通用模型的架构以便可以将其用于各种任务。 MAML 的主要贡献是一种与模型和任务无关的简单快速学习算法。
了解 MAML 背后的逻辑
MAML 的目的是为模型的参数提供良好的初始化从而以较少的梯度步骤实现对新任务的最佳快速学习。 它还尝试避免过拟合的情况这种情况在训练具有较少数据架构的神经网络时会发生。 下图是 MAML 的表示形式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u1nzw41d-1681785569484)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/b3cabe38-594a-4604-a177-7da4089882bb.png)]
如上图所示θ是模型的参数粗黑线是元学习阶段。 假设我们有三个不同的新任务并且为每个任务带有箭头的灰色线执行了一个梯度步骤。 我们可以看到参数θ接近三个任务的所有三个最佳参数这使θ成为可以快速适应不同新任务的最佳参数初始化。 结果参数θ的很小变化将导致任何任务的损失函数的最佳最小化。 根据这一观察结果MML 建议我们首先应通过主要数据集学习θ 在对实际数据集进行微调的同时我们仅需移动一小步。
顾名思义与模型无关的元学习可以用于任何形式的模型无论是分类回归还是强化学习。 但是对于这本书我们将只关注 MAML 算法的单样本学习分类方面。 所以让我们开始吧
算法
要了解 MAML 的单样本学习/小样本学习首先我们需要学习某些项。 这些类似于我们在匹配网络时学到的知识
T这表示各种任务-例如我们希望我们的模型学习识别猫狗马等以及T[i]代表一种识别猫的训练模型。 在此T[i] ∈ T。P(T)这表示所有任务之间的概率分布。 我们的目标是通过 MAML 学习P(T)。L(T)这表示任务生成的损失函数T数据点。 对于分类我们可以使用交叉熵损失
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fXeIwkVF-1681785569484)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/db9617c8-2ef5-4a11-8dec-bf17f01a1a38.png)]
假设我们希望训练一个分类模型f[θ]该模型可以学习识别图像中的猫狗和马。 让我们逐步介绍如何设置 MAML 随机初始化模型参数θ ~ N(0, 1)。 重复直到完成。 从P(T)中提取T[i]-例如我们从所有可能的任务中随机抽取识别猫的任务。 对于从P(T)采样的所有T[i]执行以下操作
T[i]的样本 K 训练数据点D[i] (x[i], y[i])对于单样本学习K 1。前向穿过层f[θ]以计算L[T[i]]和▽[θ] L[T[i]] f[θ]。使用梯度下降法更新参数。 由于我们正在针对特定任务训练模型因此我们将学习θ[i]特定于任务的参数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vAhxmL2D-1681785569485)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/4848ff3d-a327-43fe-8c92-7d6f69977ac1.png)]
来自T[i]的样本测试数据点D[i] (x[i], y[i])用于元更新。
结束for循环。
通过使用模型f[θ[i]]上的采样测试数据点D[i]计算损失及其梯度来更新θ
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-srwnunb7-1681785569485)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/00a98b32-110e-44d8-9a49-e36078be0d57.png)]
结束repeat循环。
对于 Omniglot 和 mini-ImageNet 数据集MAML 能够实现比连体网络匹配网络和内存增强神经网络更好的表现。 由于事实证明 MAML 的表现更好因此还有许多其他任务可以使用 MAML。 让我们来看一个这样的变体-域自适应元学习DAML。
MAML 应用–域自适应元学习
当涉及到模仿学习时机器人需要接收适当的数据这些数据包括有关动觉变化有关其身体部位运动的意识遥距操作控制和其他类型输入的信息。 另一方面人脑只需观看一些视频即可学习。 DAML 尝试通过使用元学习MAML解决模仿学习的问题。 它提出了一种仅通过利用从不同任务的数据中提取的强大先验知识例如关于动觉学习的信息就可以从人类的单个视频中学习机器人操纵技能的系统如下图所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NAXlPsfQ-1681785569485)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/7f72e13d-4f5d-4cb6-99c3-fd2394d5cc99.png)]
由于无法使用模仿学习损失函数来训练机器人因此 DAML 提出了行为克隆目标的暂时损失该目标也充当日志空间中的正则化项。 众所周知在任何情况下都要进行强正则化对于避免过拟合非常重要尤其是在单样本学习的情况下。
了解 LSTM 元学习器
LSTM 元学习器是一种元学习。 LSTM 元学习器分为两个阶段
元学习器在此阶段模型着重于学习跨各种任务的常识。基础学习器在基础学习器中模型尝试优化以学习任务特定目标的参数。
LSTM 元学习器的关键思想是训练 LSTM 单元以学习我们原始任务的更新规则。 用元学习框架的术语来说 LSTM 单元将用作元学习器而特定于任务的目标例如狗的品种分类将被用作基础学习器。
现在问题来了为什么我们要使用 LSTM 单元 LSTM 元学习器的作者做出了一个关键的观察即 LSTM 中的单元状态更新与反向传播中的基于梯度的更新相似可用于学习基本学习器目标的更新规则
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5yVKzA4u-1681785569485)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/7f93507c-8eba-4a42-a6f5-8eb229b65be1.png)]
LSTM 在各种门的帮助下存储信息历史记录如上图所示。 我们还知道随机梯度下降SGD有多种变化形式例如动量RMSpropAdam 等它们实质上存储了有关过去学习的信息以梯度形式以实现更好的优化。 因此从逻辑上讲可以将 LSTM 单元视为一种更好的优化策略该策略使模型能够捕获特定任务的短期知识和公共长期知识。
在下一部分中我们将了解架构LSTM 单元背后的逻辑以及权重更新算法。
LSTM 元学习器的架构
如果我们研究梯度下降的更新方法我们将看到一个这样的方程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zwY4kVJH-1681785569485)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/5a9a4fca-cdb7-4c9d-9aba-27c879fc4481.png)]
此处 θ[t]是时间步长t的参数▽L[t]是t时的损失梯度并且α[t]是时间t时的学习率。
另一方面LSTM 单元的单元更新方程看起来像这样
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HrpVbwvY-1681785569486)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/1994255e-a722-4cfe-bfac-9a66d91048e2.png)]
此更新看起来与 LSTM 中单元的更新方式非常相似。 LSTM 元学习器的作者提出如果将以下值放在单元更新方程中那么我们将获得梯度下降更新规则
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CeHbwDMy-1681785569486)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/b38cc62b-318b-4b9e-ba28-0e5eb9a1106d.png)]
从逻辑上考虑这一点我们只想学习i[t]因为这与估计梯度下降的学习率基本相似。 因此LSTM 元学习器将i[t]定义如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q2pu9vkP-1681785569486)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/da2cd6b1-bca0-456b-8064-23bdb90ef26c.png)]
本质上i[t]被定义为具有当前梯度当前损失和先前学习率i[t-1]的组合的 Sigmoid 函数。
对于f[t]应为 1但为避免梯度缩小的问题其定义如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SnZS3OZD-1681785569486)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/1d551c2d-de09-4a7b-8657-0c310ee85bbb.png)]
本质上f[t]被定义为具有当前梯度当前损失和遗忘门的 Sigmoid 函数。
您可能想知道为什么他们使用 LSTM 单元的这种特定选择 如果仔细观察会根据当前梯度和当前损失选择i[t]和f[t]。 故意这样做是为了使元学习器能够控制学习率以便在更少的时间内训练基础学习器。
数据预处理
在一般的深度学习设置中要在给定数据集D上训练模型我们将数据集分为三个部分训练验证和测试集。 但是在元学习设置中我们首先将数据集划分为特定于任务的集例如猫品种分类和狗品种分类称为元集例如D[n]。 对于每个D ∈ D[n]由D_n_train和D_n_test组成因此对于K样本学习每个D_n_train由K * N个示例组成其中N是类数。
此后D_n_train进一步分为三个部分D_meta_trainD_meta_valD_meta_test。 在这里目标是使用D_meta_train训练学习算法该算法可以将任何特定于任务的集合作为训练集D_train并产生更好的分类器学习器。
算法–伪代码实现
要训练一个单样本学习模型您需要匹配训练条件以测试时间条件例如像在匹配网络中一样在较少的数据上进行训练但要进行多个批量。 LSTM 元学习器也遵循与匹配网络相同的概念并已被证明在特定任务目标上确实表现出色。
要开始理解 LSTM 元学习器首先我们需要了解某些项
基础学习器M具有特定任务的主要目标带有参数θ-例如用于识别猫的分类器元学习器RLSTM 单元带有参数θ数据点X, Y从D_meta_train采样的数据点损失L用于调整主要任务特定目标的损失函数例如二进制交叉熵损失
让我们开始逐步学习 LSTM 元学习器算法
首先随机初始化 LSTM 单元的初始参数θ[0]。对于D 1至n步骤请执行以下操作
从D_meta_train中随机抽取D_train, D_test。随机初始化基础学习器分类模型的初始参数θ[0]。对于t 1至T步骤重复以下步骤从D_train中随机采样输入输出对(X[t], Y[t])。使用L[t] L(M(X[t], θ[t-1]), Y[t])计算基础学习器分类模型的损失。使用单元格的基本学习器的损失L[t]及其梯度▽[θ[t-1]] L[t]更新单元格状态c[t] 状态方程。将基本学习器分类模型参数更新为θ[t] c[t]请参阅 LSTM 元学习器的“架构”部分。
结束T步骤循环。
现在从D_test中随机采样输入输出对(X_test, Y_test)。使用L_test L(M(X_test, θ[T]), Y_test)计算基础学习器分类模型的损失。使用▽[θ[d-1]] Y_test请参阅 LSTM 元学习器“架构”部分更新元学习器LSTM 单元参数θ[t]。
结束n步骤循环。
简而言之在迭代T步骤的同时基本学习器参数也会更新。 在T步骤之后最终的基本学习器参数将用于评估测试集并更新元学习器参数。 有关该算法的图形表示请参考以下架构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p9DlaC1x-1681785569486)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/968555da-ab84-4ab1-9e2a-cd4ba196a50d.png)]
LSTM 元学习器的总体思路非常引人注目。 您可能想知道为什么我们只使用一个 LSTM 单元为什么 LSTM 元学习器的作者没有像在匹配网络中看到的那样使用整个 LSTM 网络。 您确实可以在元学习器中添加一些复杂的架构但这要付出大量训练参数的代价。 LSTM 单元的使用使这种元学习架构对于单样本学习变得可行。
在下一部分中我们将进行 MAML 和 LSTM 元学习器的编码练习这将有助于我们更全面地了解架构。
练习题
在本节中我们将首先使用 MAML 进行正弦数据回归的简单练习。
模型无关元学习的简单实现
在本教程中我们将展示如何应用 MAML 来学习正弦数据的简单曲线。 本教程的第二部分在 GitHub 上可用我们可以在其中学习如何使用 torch-meta 库在 mini-ImageNet 上训练 MAML。
让我们通过以下步骤开始本教程
导入所有库
import math
import random
import torch
from torch import nn
from torch.nn import functional as F
import matplotlib as mpl
mpl.use(Agg)
import matplotlib.pyplot as plt
%matplotlib inline创建一个简单的神经网络架构。 我们将获得随机生成的正弦曲线数据。 我们将使用这个非常小的网络因为我们不需要大的网络来学习曲线
def net(x, params):x F.linear(x, params[0], params[1])x F.relu(x)x F.linear(x, params[2], params[3])x F.relu(x)x F.linear(x, params[4], params[5])return xparams [torch.Tensor(32, 1).uniform_(-1., 1.).requires_grad_(),torch.Tensor(32).zero_().requires_grad_(),torch.Tensor(32, 32).uniform_(-1./math.sqrt(32), 1./math.sqrt(32)).requires_grad_(),torch.Tensor(32).zero_().requires_grad_(),torch.Tensor(1, 32).uniform_(-1./math.sqrt(32), 1./math.sqrt(32)).requires_grad_(),torch.Tensor(1).zero_().requires_grad_(),
]设置训练参数。 初始化alphabeta学习率优化器和循环数的参数
opt torch.optim.SGD(params, lr1e-2)
n_inner_loop 5
alpha 3e-2实现优化算法
for it in range(100000): # training for large number of iterationsb 0 if random.choice([True, False]) else math.pi # setting up beta variable randomly#### Randomly obtain task 1 sinusoidal data ####x torch.rand(4, 1)4math.pi - 2*math.piy torch.sin(x b)#### Randomly obtain the task 2 sinusoidal data ####v_x torch.rand(4, 1)4math.pi - 2*math.piv_y torch.sin(v_x b)opt.zero_grad() # setup optimizernew_params params # initialize weights for inner loopfor k in range(n_inner_loop):f net(x, new_params) # re-initialize task 2 neural network with new parametersloss F.l1_loss(f, y) # set loss as L1 Lossgrads torch.autograd.grad(loss, new_params, create_graphTrue)new_params [(new_params[i] - alpha*grads[i]) for i inrange(len(params))] # update weights of inner loopv_f net(v_x, new_params) # re-initialize task 1 neural network with new parametersloss2 F.l1_loss(v_f, v_y) # calculate Lossloss2.backward() # Backward Passopt.step()运行此命令后您将以以下形式查看优化输出
Iteration 0 -- Inner loop 0 -- Loss: 0.3558
Iteration 0 -- Inner loop 1 -- Loss: 0.3815
Iteration 0 -- Inner loop 2 -- Loss: 0.3788
Iteration 0 -- Inner loop 3 -- Loss: 0.3265
Iteration 0 -- Inner loop 4 -- Loss: 0.4066
Iteration 0 -- Outer Loss: 0.7631
Iteration 100 -- Inner loop 0 -- Loss: 0.9611
Iteration 100 -- Inner loop 1 -- Loss: 0.9364
Iteration 100 -- Inner loop 2 -- Loss: 0.9122
Iteration 100 -- Inner loop 3 -- Loss: 0.8883
Iteration 100 -- Inner loop 4 -- Loss: 0.8641
Iteration 100 -- Outer Loss: 1.0115绘制获得的结果。 一旦获得正确的参数我们将首先生成一些随机数据点以对五个数据点进行子采样。 如果将结果绘制成图我们将看到神经网络能够在正弦数据点上获得正确的曲线
# Randomly generate 5 data points.
t_b math.pi
t_x torch.rand(4, 1)4math.pi - 2*math.pi
t_y torch.sin(t_x t_b)opt.zero_grad()t_params params
for k in range(n_inner_loop):t_f net(t_x, t_params)t_loss F.l1_loss(t_f, t_y)grads torch.autograd.grad(t_loss, t_params, create_graphTrue)t_params [(t_params[i] - alpha*grads[i]) for i in range(len(params))]test_x torch.arange(-2*math.pi, 2*math.pi, step0.01).unsqueeze(1)
test_y torch.sin(test_x t_b)test_f net(test_x, t_params)plt.plot(test_x.data.numpy(), test_y.data.numpy(), labelsin(x))
plt.plot(test_x.data.numpy(), test_f.data.numpy(), labelnet(x))
plt.plot(t_x.data.numpy(), t_y.data.numpy(), o, labelExamples)
plt.legend()
plt.savefig(maml_output.png)运行此命令后您应该能够获得如下图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qfIrxeMf-1681785569487)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/1255afd0-ad98-404e-8676-0adad4b09236.png)]
如果查看该图您将看到网络能够大致学习sin(x)曲线。
域自适应元学习的简单实现
在本教程中我们将使用域自适应元学习来学习正弦数据的简单曲线。 它是模型不可知的元学习的一种变体但是增加了先验信息也就是说已经添加了有关该域的其他相关信息。
让我们开始
元学习算法优化了模型快速学习新任务的能力。 为此他们使用跨各种任务收集的数据并根据其学习新的元测试任务的能力进行评估。 此过程可以形式化为学习数据一系列任务的先验知识即提取重要信息并且微调过程成为在学习到的先验知识下的推断
导入所有库
import math
import random
import sys
import torch # v0.4.1
from torch import nn
from torch.nn import functional as F
from tqdm import tqdm
from time import sleep
import matplotlib as mpl
mpl.use(Agg)
import matplotlib.pyplot as plt
%matplotlib inline
import warnings
warnings.filterwarnings(ignore)创建一个简单的神经网络架构将学习正弦曲线。 我们将从正弦曲线中获取随机生成的数据因此我们将使用这个非常小的网络因为我们不需要大的网络来学习曲线
def meta_net(x, params): # main network which is suppose to learn our main objective i.e; learn sinusoidal curve family here.x F.linear(x, params[0], params[1])x1 F.relu(x)x F.linear(x1, params[2], params[3])x2 F.relu(x)y F.linear(x2, params[4], params[5])return y, x2, x1params [torch.Tensor(32, 1).uniform_(-1., 1.).requires_grad_(),torch.Tensor(32).zero_().requires_grad_(),torch.Tensor(32, 32).uniform_(-1./math.sqrt(32), 1./math.sqrt(32)).requires_grad_(),torch.Tensor(32).zero_().requires_grad_(),torch.Tensor(1, 32).uniform_(-1./math.sqrt(32), 1./math.sqrt(32)).requires_grad_(),torch.Tensor(1).zero_().requires_grad_(),
]创建另一个简单的神经网络架构以添加有关该域的先验信息。 我们将在我们的主要网络中增加一些先验知识 因此我们需要创建一个简单的adap_net
def adap_net(y, x2, x1, params): # the net takes forward pass from meta_net and provides efficient parameter initializations.# It works adapts the meta_net easily to any form of changex torch.cat([y, x2, x1], dim1)x F.linear(x, params[0], params[1])x F.relu(x)x F.linear(x, params[2], params[3])x F.relu(x)x F.linear(x, params[4], params[5])return xadap_params [torch.Tensor(32, 13232).uniform_(-1./math.sqrt(65), 1./math.sqrt(65)).requires_grad_(),torch.Tensor(32).zero_().requires_grad_(),torch.Tensor(32, 32).uniform_(-1./math.sqrt(32), 1./math.sqrt(32)).requires_grad_(),torch.Tensor(32).zero_().requires_grad_(),torch.Tensor(1, 32).uniform_(-1./math.sqrt(32), 1./math.sqrt(32)).requires_grad_(),torch.Tensor(1).zero_().requires_grad_(),
]设置训练参数。 我们将使用内循环而不是外循环训练因此我们需要设置某些参数例如alphabeta学习率优化器和循环数
opt torch.optim.SGD(params adap_params, lr1e-2)
n_inner_loop 5
alpha 3e-2实现优化算法。 如“域自适应元学习”部分所述这种方法只能从一个人的视频中学习新技能。 为此它首先使用人类演示和远程演示来训练元网络以在元训练阶段建立强大而丰富的先于任务
inner_loop_loss[]
outer_lopp_loss[]
# Here, T ∼ p(T ) {or minibatch of tasks} is to learn sinusoidal family curves
with tqdm(total100000, filesys.stdout) as pbar:for it in range(100000):b 0 if random.choice([True, False]) else math.pi#### Randomly obtain the task 2 sinusoidal data ####v_x torch.rand(4, 1)4math.pi - 2*math.pi v_y torch.sin(v_x b)opt.zero_grad()new_params paramsfor k in range(n_inner_loop):sampled_data torch.FloatTensor([[random.uniform(math.pi/4, math.pi/2) if b 0 else random.uniform(-math.pi/2, -math.pi/4)]]# Here, si is adap_net parameters: adap_params and theta is meta_net parametersf, f2, f1 meta_net(sampled_data, new_params) h adap_net(f, f2, f1, adap_params) adap_loss F.l1_loss(h, torch.zeros(1, 1)) # Calculate Lossgrads torch.autograd.grad(adap_loss, new_params, create_graphTrue)# Compute policy parameters phi_t(new_params)new_params [(new_params[i] - alpha*grads[i]) for iin range(len(params))]if it % 100 0: inner_loop_loss.append(adap_loss)v_f, _, _ meta_net(v_x, new_params) # forward pass using learned policy parameters loss F.l1_loss(v_f, v_y) # calculate the loss of meta_netloss.backward() opt.step() # optimize the policy parameters(theta and si)pbar.update(1)if it % 100 0: outer_lopp_loss.append(loss)在此阶段机器人meta_net学习如何使用数据向人类学习。 在元训练阶段之后机器人可以通过将其学习到的先验知识与执行新技能的人员的一个视频相结合来获得新技能。 此方法包括两个阶段
在元训练阶段目标是使用人类和机器人的演示数据获取先验策略φ使用学到的知识然后快速学习如何仅用几个数据点来模仿新任务
一旦运行了上面的代码您将获得以下输出
Iteration 0 -- Inner loop 0 -- Loss: 0.0211
Iteration 0 -- Inner loop 1 -- Loss: 0.0183
Iteration 0 -- Inner loop 2 -- Loss: 0.0225
Iteration 0 -- Inner loop 3 -- Loss: 0.0180
Iteration 0 -- Inner loop 4 -- Loss: 0.0156
Iteration 0 -- Outer Loss: 0.5667
Iteration 100 -- Inner loop 0 -- Loss: 0.0009
Iteration 100 -- Inner loop 1 -- Loss: 0.0007
Iteration 100 -- Inner loop 2 -- Loss: 0.0003
Iteration 100 -- Inner loop 3 -- Loss: 0.0003
Iteration 100 -- Inner loop 4 -- Loss: 0.0000
Iteration 100 -- Outer Loss: 0.8096 ...微调主网。 一旦获得正确的参数我们将首先生成一些随机数据点以对五个数据点进行子采样并使用adap_net的损失微调主要的meta_net
t_b math.pi
opt.zero_grad()
t_params paramsfor k in range(n_inner_loop):# sample the new task datanew_task_data torch.FloatTensor([[random.uniform(math.pi/4, math.pi/2) if t_b 0 else random.uniform(-math.pi/2, -math.pi/4)]])# forward pass through meta_net to extract the input for adap_nett_f, t_f2, t_f1 meta_net(new_task_data, t_params)# extract the information from adap_nett_h adap_net(t_f, t_f2, t_f1, adap_params)# calculate the loss, here we used true label as torch.zeros(1, 1), because t_b pit_adap_loss F.l1_loss(t_h, torch.zeros(1, 1))grads torch.autograd.grad(t_adap_loss, t_params, create_graphTrue)# learn the policy using the loss of adap_nett_params [(t_params[i] - alpha*grads[i]) for i in range(len(params))]部署后机器人可以仅使用人类与这些对象一起执行任务的单个视频即可适应具有新颖对象的特定任务。
使用以下代码可视化输出
test_x torch.arange(-2*math.pi, 2*math.pi, step0.01).unsqueeze(1)
test_y torch.sin(test_x t_b)test_f, _, _ meta_net(test_x, t_params) # use the learned parametersplt.plot(test_x.data.numpy(), test_y.data.numpy(), labelsin(x))
plt.plot(test_x.data.numpy(), test_f.data.numpy(), labelmeta_net(x))
plt.legend()
plt.savefig(daml-sine.png)运行代码后您将看到类似于以下内容的图形
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zoMfmvr2-1681785569487)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/e8692140-1570-4eda-add5-c8331e6abf96.png)]
如果您无法获得理想的正弦曲线形状则将迭代次数加倍。
在这里您可以看到我们的净模型橙色线非常接近真实数据集蓝色线。 如果您希望使用真实的数据集探索这些模型请参考上的 GitHub 存储库 https://github.com/PacktPublishing/Hands-On-One-shot-Learning-with-Python/tree/ master / Chapter04 。 在这里您会发现使用 Omniglot 和 mini-ImageNet 数据集的其他优化算法。
总结
要求解任何方程通常我们可以使用很多方法。 同样为了进行优化学习神经网络的参数许多研究人员也公开了许多方法但是事实证明梯度下降是一种适用于每种情况的通用方法。 如果我们希望处理特定类型的神经网络问题那么最好探索可能适合我们任务的不同优化技术。
在这一章中我们研究了两种最著名的单样本学习优化方法MAML 和 LSTM 元学习器。 我们了解了 MAML 如何通过优化我们的初始参数设置来解决单样本学习问题从而在几个数据点上进行一个或几个梯度下降步骤可以导致更好的概括。 我们还探讨了 LSTM 元学习器对如何训练 LSTM 单元作为元学习器以预测基础学习器权重更新的见解。
在下一章中我们将探讨一种著名的 ML 方法贝叶斯学习。 我们将通过用概率模型表示对象类别来观察几个贝叶斯学习框架的发展。 我们将对判别式K样本学习和贝叶斯程序学习及其在现实世界中的应用进行恰当的解释。
问题
梯度下降优化算法的优缺点是什么梯度下降优化算法有其他选择吗为什么训练神经网络需要那么多的周期
进一步阅读
有关本章中介绍的一些架构的更多详细信息建议阅读以下论文
《与模型无关的元学习》《作为小样本学习模型的优化》
第三部分其他方法和结论
深度学习架构已被证明是非常有效的但是它们仍然不是单样本学习的最佳方法。 贝叶斯编程语言之类的不同贝叶斯方法仍然可以一口气击败人类。 在本节中我们将学习贝叶斯方法并讨论该领域的最新进展。 此外我们将贝叶斯方法与深度学习圈中解决任何问题的众所周知的技术迁移学习进行比较。 我们还将学习何时在迁移学习中使用单发方法。
本节包括以下章节
第 5 章“基于生成建模的方法”第 6 章“结论和其他方法”
五、基于生成建模的方法
当人们对看不见的数据进行推断时他们会利用有关他们已经看到听到触摸或经历过的相关事件的强大先验知识或归纳偏见。 例如与狗一起长大的婴儿可能第一次见到猫并立即推断出它与家犬的宠物般的性情相似。 当然猫和狗作为物种和个体是千差万别的。 但是公平地说猫比狗更像狗而不是孩子经历的其他随机事物例如食物。 与机器学习模型相反人类不需要成千上万的猫实例就可以从头开始学习只要他们已经学会了识别狗就可以识别猫。 人脑具有元学习的固有能力这与机器学习语言中的迁移学习和多任务学习有关。 此能力通过利用从相关任务中学到的知识来加速新概念的学习。
生成模型是概率模型旨在弥合人类学习与机器学习之间的鸿沟。 这些模型旨在从对象的各个部分学习高级抽象特征并将这些学习的特征应用于新的但相似的对象类别。 在本章中我们将研究如何生成这些生成模型拥有先验知识意味着什么如何用数学术语构筑先验知识如何从一些对象中学习高级概念模型的参数学习 以及如何将这些新学到的知识与先验知识相结合以对新对象做出有意义的决策推断。
本章将涵盖以下主题
贝叶斯学习概述了解有向图模型概率方法概述贝叶斯程序学习判别式 K 样本学习
技术要求
本章将基于理论因此没有正式的技术要求但是需要对贝叶斯建模有基本的了解。
贝叶斯学习概述
在本节中我们将从数学的角度简要讨论贝叶斯学习背后的思想这是单样本学习概率模型的核心。 贝叶斯学习的总体目标是在给定训练数据的情况下对参数θ的分布进行建模即学习分布p(θ | Data)。
在机器学习的概率视图中我们尝试求解以下方程式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IZeO3ujs-1681785569487)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/461dfab6-3cd8-4782-a6de-e092332fa3b6.png)]
在此设置中我们尝试找到可以解释数据的最佳参数集θ。 因此我们在θ上最大化给定方程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G2SNvKhF-1681785569487)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/59ce0f8b-fa97-4605-98f6-78bf3737c14f.png)]
我们可以对两边取对数这不会影响优化问题但会使数学容易且易于处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RaobFfry-1681785569487)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/f1da3c33-07dc-4b1d-8a75-aa4162729d8c.png)]
我们可以从数据的右侧删除P(data)因为它不依赖于θ来进行优化因此优化问题如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wDd9RnXm-1681785569488)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/d5a1d317-b037-40b4-b612-10d2e168e328.png)]
在非概率视图也称为期望最大化框架中右侧等式中的项p(Data | θ)和P(θ)分别成为损失函数和正则化。 在给定的概率设置中相同的项称为给定θ的数据的似然和先验在参数空间中的先验信念。 这种概率优化称为最大后验MAP估计因为我们正在从数据中最大化模型参数的后验分布。 但是贝叶斯统计不相信 MAP 估计因为它可能给我们有关最终学习参数的错误结果。 一个不同的数据集很有可能会给我们完全不同的学习参数这些参数在参数空间中与从原始数据集中学习的参数相距甚远。 这就是贝叶斯学习试图解决的问题。 它显式地模拟参数空间中的不确定性。
考虑给定左撇子和右撇子人数据集的参数分布示例。 下图显示了分布
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MuZD2wuB-1681785569488)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/ad909edc-738b-40ed-a6fb-4d3893f9efc9.png)]
最大化来自数据的参数θ概率的 MAP 估计将收敛至点A。但是大多数概率量都更偏向于惯用右手的人这与世界上惯用右手的人多于惯用左手的人这一事实相吻合。
因此在贝叶斯学习中重点是解决后验参数P(Data | θ)以明确地对参数中的不确定性建模。
了解有向图模型
现在在深入研究用于单样本学习的概率模型之前我们将简要研究有向图模型。 有向图模型也称为贝叶斯网络由与有向边相连的随机变量定义如在父子关系中。 下图显示了一个这样的贝叶斯网络
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RjRvCVMY-1681785569488)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/169cea75-5669-4783-a7c4-a4b77f185c91.png)]
此图中SRLW和T的随机变量的联合分布通过一个简单的链式规则可分为多个分布
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ns0qgE1-1681785569488)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/9511985a-1153-4134-8e00-3c8126a5dc83.png)]
前面方程右侧的条件分布具有大量参数。 这是因为每个分布都以许多变量为条件并且每个条件变量都有其自己的结果空间。 如果我们在有大量条件变量的情况下在图中走得更远则这种影响会更加突出。 因此要学习每种条件分布的庞大参数集我们需要大量的标记数据这在现代机器学习任务中通常是不可用的。
这是有向图模型进入图片的地方。 它断言了概率的一些条件独立性从而简化了前面描述的方程式。 有向图模型中的每个变量在条件上独立于给定其父对象的非后代。 有向图模型不过是条件独立性的表示。 更正式地讲如果X[i]是有向图中的顶点则V是顶点数X[pa(t)]都是顶点X[t]的父级则所有顶点上的联合概率分布可写为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F7mRkCFD-1681785569488)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/4bb469f5-c12f-455b-9a29-06e6eff50baa.png)]
鉴于此前面公式中定义的联合分布可简化为以下形式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6101q0mF-1681785569489)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/8f18500d-a05b-498d-949b-2d311af7bcbd.png)]
这减少了模型中参数的数量并易于使用相对较少的数据来学习模型。
概率方法概述
人类的概念学习趋向于在两个主要方面不同于机器学习。 在下图中考虑来自大量词汇的手写数字示例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SGuay8K2-1681785569489)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/06cbc1c2-9840-44aa-b8f3-a41e2abac4c4.png)]
首先人们倾向于仅从一个或几个示例中学习关于对象的有意义的信息例如对象边界并对其进行高精度分类请参见上图中的i)部分。 另一方面深度学习模型需要大量带标签的数据才能在诸如对象识别之类的任务上达到人类水平的表现。
其次人类从一个示例中学习了绝大多数能力例如创建新字符参见上图中的ii)部分将对象/字符分解为各个部分和关系请参见iii)部分并根据有关现有概念的现有知识开发新的有意义的概念/字符请参见上图中的iv)部分。 相反深度学习模型针对每个任务都需要特殊的损失函数和架构由于该任务可用的标记数据非常有限因此通常不切实际。
人们如何仅从一个示例中学习对对象和概念的如此丰富强大的表示
学习理论指出需要更多的数据而不是更少的数据来学习更复杂的可以很好地概括的模型。 但是人类往往会从非常稀疏的数据中学习到更丰富的表述这些表述可以很好地概括。
概率模型旨在弥合数据饥渴的机器模型与人类采用的高度健壮的元学习方法之间的鸿沟。 在本章中我们将讨论两行概率方法这些方法在从很少的数据中学习各种任务方面已经获得了广泛的成功
第一种方法是对对象零件子零件及其之间的关系进行显式建模以学习概念对象。 这可用于从一个或几个示例中对新对象进行分类并从预定义的零件和子零件列表中绘制新类型的对象。第二种方法基于深度学习方法通过从初始的大量训练数据中学习新类别其中只有一个类别的图像以及来自其他类别的大量图像来完成一次分类任务。 这种方法将潜在变量定义为概念类的先验。 最初的大量训练数据集有助于学习有关概念的强大先验知识这些概念随后可用于从一次镜头分类中对新对象进行分类。
贝叶斯程序学习
贝叶斯程序学习BPL进行三个步骤
第一步是生成模型BPL 通过从“模型”部分的图的 A 侧部分组成请参考iii)来学习新概念以学习新概念 下图 A 侧的子部分请参见ii)和它们在下图 A 侧的空间关系请参见iv)。 例如它可以从零件和子零件中采样新类型的概念在这种情况下为手写字符并以新的方式将它们组合在一起。在第二步中第一步中抽取的概念形成另一个较低层的生成模型以产生新示例如 A 侧的v)部分所示。最后一步将渲染原始字符级图像。 因此BPL 是生成模型的生成模型。 下图的 B 侧显示了该生成模型的伪代码。
模型
给定如图 A 所示的有向图模型类型ψ的联合分布 一组M个标记 θ[1], ..., θ[M] 及其相应的原始图像I[1], ..., I[M]分解如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mfziZhnd-1681785569489)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/a87b8aac-2728-4f0f-bfb7-9e588762ceca.png)]
这三个生成过程分别是类型生成P(ψ)标记生成P(θ[m] | ψ[m])和图像生成P(I[m] | θ[m])分别在下图中用其伪代码进行了讨论
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1qWjoBOP-1681785569489)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/16ff2f50-55be-44fd-8da5-661c7c7ea3a6.png)]
类型生成
手写字符类型ψ是字符的各个部分和子部分之间以及它们之间的关系的抽象架构。 反映现实生活中的字符书写过程字符部分S[i]形成了笔向下移动到笔抬起操作的一个笔触。 这些字符笔划由S[i1], ..., S[in[i]]子部分组成表示笔的短暂停顿。 生成新字符类型的伪代码显示在上图的 B 侧其执行过程如下 为了生成新的字符类型模型首先为每个部分采样零件数k和子零件数n[i]。 采样参数来自它们在训练数据集中的经验分布。 训练数据还提供了子部分的预定义原语集。 每个字符部分都是通过对预定义集合中的子部分进行采样而产生的因此对下一个子部分进行采样的概率取决于前一个子部分。 为零件S[i]采样了关系R[i]该关系定义了该零件与先前零件的连接方式。
标记生成
字符标记θ[m]是通过对墨水从笔到纸的流动方式进行建模而由零件和关系生成的。 用于标记生成的伪代码在上图的 B 侧进行了描述。 首先将噪声此处称为运动方差添加到子零件的比例尺和控制点以定义冲程或零件轨迹s[m]。 轨迹的精确开始位置L[m]由关系R[i]决定。 最后将变换A[m]用于减轻概率推断。
图像生成
使用随机渲染函数生成原始二进制字符图像I[m]该函数将笔划轨迹与灰度墨水映射。 这是通过为每个像素分配独立的伯努利概率来实现的。
BPL 是一种高度直观的模型可以在贝叶斯框架下使用简单的程序为概念建模。 从训练数据中学习概率分布的参数。 在分类和生成的单次计算机视觉任务上该模型的表现与人类水平的表现相当其数据需求远低于某些最新的深度学习模型。 这里研究的概率程序非常基础适合于相当容易的字符识别任务。 BPL 框架支持设计更复杂的程序这些程序可以对各种对象的复杂表示进行建模。 例如可以使用此框架对在零件和关系方面具有清晰直观描述的对象例如车辆食品动物甚至人脸进行建模。 为此BPL 框架甚至支持建模抽象知识例如自然语言语义和物理理论。 然而这些概率程序需要对数据及其部分子部分和关系进行手动标记这是一个耗时的过程而深度学习方法则是自己学习这些人类直观特征和深层抽象特征。
判别式 K 样本学习
K 样本学习的一种非常常见的方法是训练具有相关任务的大型模型而我们为此拥有大型数据集。 然后通过 K 次特定任务对该模型进行微调。 因此来自大型数据集的知识被提炼为到模型中这仅从几个示例中增加了对新相关任务的学习。 2003 年Bakker 和 Heskes 提出了一种用于 K 样本学习的概率模型其中所有任务共享一个公共特征提取器但具有各自的线性分类器其中仅包含几个特定于任务的参数。
这里讨论的 K 样本学习的概率方法与 Bakker 和 Heskes 引入的方法非常相似。 该方法通过从很少的数据中学习概率模型来解决分类任务针对图像。 这个想法是使用一个强大的神经网络该网络从大量监督数据中学习可靠的特征并将其与概率模型结合起来。 神经网络最后一层的权重充当以贝叶斯方式规范化 K 次子模型权重的数据。
学习框架包括四个阶段
表示学习概念学习K 样本学习K 次测试
下图显示了具有四个阶段的框架。 以下各节将对它们进行更正式的讨论
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UA29kkWo-1681785569489)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/5f07d8c6-f555-4b6f-89a9-72d141ed72f9.png)]
表示学习
在第一阶段表示学习使用大型数据集D_tilde训练 CNNΦ[φ]该数据集训练参数φ的网络W_tilde。 此后这些参数φ是固定的并在以后的阶段中共享。 来自 CNN 最后一层的激活被映射到两组 softmax 层由W_tilde和W参数化。 参数W_tilde对应于大型数据集D_tilde中的C_tilde类参数W对应于 K 次任务的数据集D中的C类。 如下图所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qoIZuYhe-1681785569490)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/f23a6f16-745c-44e0-bc32-0ca3befa7b6a.png)]
权重的概率模型
假设由于最大数据集D_tilde而在第一阶段获知的 softmax 权重W_tilde的不确定性很小。 将此近似值与上图中的图模型结构结合起来我们可以摆脱原始数据集D_tilde并使用W_tilde的 MAP 估计值W_MAP处于概念学习和 K 样本学习阶段。 完整的概率模型遵循以下步骤
K 样本学习过程将信息合并到两个数据集D_tilde和D中以在W上生成后验分布
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pH7WtcsP-1681785569490)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/3f0ac346-6f71-413c-9364-4da122454208.png)]
从图模型在上图中我们知道给定父级W的情况D有条件地独立于D_tilde我们有以下内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IucwwUOw-1681785569490)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/93b309a8-288c-4cd2-883f-f166d5f51c7d.png)]
因此等式 1 变为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dx9JUQPf-1681785569490)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/be56381d-889a-404b-95e6-1ebe2a7002bc.png)]
我们可以将项P(D_tilde)吸收到比例常数中从而使前面的方程式变为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H5BUaiKt-1681785569490)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/a32d4c87-1014-4d11-b7c1-563e0c5bfd97.png)]
主要挑战是在给定初始数据集D_tilde的情况下计算超参数θ的后验这会使该模型的推理变得难以处理。 由于使用了较大的初始数据集来学习权重W_tilde后分布P(W_tilde | D_tilde)可以通过其 MAP 估计值安全地近似即P(W_tilde | D_tilde) ≈ δ(W - W_MAP)。 因此我们可以摆脱等式 2 中的D_tilde并用W_tilde代替。
选择权重模型
给定图模型我们可以写出概念超参数θ和模型权重WW_tilde的联合分布如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T7qqu61c-1681785569490)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/cd64030c-1e6b-4a97-bc41-e5043bf94a5e.png)]
做出两个简单但合理的假设以使机器在计算上易于处理
首先对于每个类别从最后一个隐藏层到 softmax 的隐藏权重W和W_tilde被视为独立的。第二给定θP(w_tilde[c] | θ)和P(w[c] | θ)的权重分布W和W_tilde是相同的。
然后等式 3 中的联合分布简化为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O147xEil-1681785569491)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/0c67309f-24e7-462a-abaa-039674855756.png)]
一个简单的高斯模型用于权重P(w | θ) N(w | μ, Σ)及其共轭正反 Wishart 先验P(θ) P(μ, Σ) NIW(μ[0], κ[0], Λ[0], v[0])并估计 MAP 解的参数θ_MAP {μ_MAP, Σ_MAP}。
这导致分发简化为以下内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vASiwi5T-1681785569491)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/4a4c76f8-4524-4ba0-bda8-afec7fa80efe.png)]
K 样本学习等式 2期间新权重W的后验分布简化为以下表达式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-drwATmue-1681785569491)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/bd2213cb-753d-470a-994d-2b8cc7b6a7c4.png)]
每个阶段的计算和近似
在讨论了先前模型的机制之后以下小节总结了判别式 K 次模型的四个阶段中的所有计算和近似。
第一阶段–表示学习
最初深度学习训练特征提取器Φ[φ]。 在以下阶段中使用输入图像u的最后一层的激活x Φ[φ](u)。 原始数据集中类别的 softmax 权重为 MAP 估计值W_tilde_MAP。
第二阶段–概念学习
概率模型直接适合于 MAP 权重P(θ | W_tilde) ∝ P(θ)P(W_tilde | θ)。 对于共轭模型后验分布是通过解析获得的。 否则将使用P(θ | W_tilde)的 MAP 估计值。
第三阶段– K 样本学习
在 softmax 权重WP(W | D, W_tilde_MAP) ∝ P(W | W_tilde_MAP) Π[n 1, ..., N] p(y[n] | x[n], w)上的后缀是难以处理的。 通过使用 MAP 估计W_MAP或通过采样W[m] P(W | D, W_tilde_MAP)可以近似得出。 必须注意P(W | W_tilde_MAP) ∫P(W | θ)P(θ | W_tilde_MAP)dθ是针对共轭模型的分析。 但是如果在阶段 2 中根据 MAP 估计来估计θ则如等式 4 中所述使用P(W | W_tilde_MAP) ≈ P(W | θ_MAP)。
第四阶段 – K 次测试
K 次测试时间P(y*, x*, D, W_tilde_MAP) ∫p(y* | x*, W)P(W | D, W_tilde_MAP)dW的推断是难以理解的因此此处使用近似值。 如果从阶段 3 开始使用W的 MAP 估计值W_MAP则P(y*, x*, D, W_tilde_MAP) P(y* | x*, W_MAP)。 如果在阶段 3 中重新采样则使用P(y*, x*, D, W_tilde_MAP) 1/m Σ[m 1, ..., M] p(y* | x*, W[m])。
在 miniImageNet 数据集由 100 个类组成每个类中包含 600 个图像上此方法可以单样本学习一次和五样本学习获得最先进的结果。 离统一概率模型和深度学习的领域又迈进了一步将两者结合起来可以开发出真正强大的模型从而利用概率领域的强大数学保证和深度学习模型的强大健壮功能。 判别式 K 样本学习方法仍然需要大量带标签的训练数据来训练基于深度学习的特征提取器。 另一方面贝叶斯程序学习方法利用模型中的归纳偏差和手工设计的特征因此需要较少的标注训练数据。
总结
在本章中我们学习了在贝叶斯框架内开发概率模型的方法该模型可以极大地减少数据需求并达到人类水平的表现。 从前面讨论的手写字符的示例中我们还观察到概率模型不仅可以学习如何对字符进行分类还可以学习基本概念即以新的方式应用获得的知识例如从集合中仅有的几个字符生成全新的字符以及将字符解析为部分和关系。
但是人类学习器需要从具有丰富重叠结构的许多经验中获得的广泛的先前经验来完成新的学习任务。 为了模仿人类学习图结构需要具有更多的依赖性并且需要在模型中内置丰富的归纳偏差。 还应注意人类在很小的时候就对物体的物理特性形状运动和其他力学有很好的认识。 学习模型不会隐式地捕获对象的直观物理特性也不会显式地将其嵌入对象中。 直观物理类似于游戏引擎中嵌入的物理与概率模型和深度学习的集成是朝着更健壮的单发学习迈出的重要一步。 最后由于先验知识以强先验和图结构的形式嵌入到概率模型中因此与必须从头学习任务的深度学习模型相比它们的数据消耗更少。 但这是以在概率模型中进行有效推理的计算挑战为代价的。 在推断时这些模型必须搜索巨大的概率空间这对于现代计算机而言是不实际的。 相反深度学习模型具有精确且计算上便宜的推断。 最近的工作通过使用前馈映射对摊销概率推理计算来解决图模型中的这一推理挑战可以使用成对的生成/识别网络来学习。 这提供了另一条有希望的研究领域使深度学习和概率模型更加接近。
进一步阅读
要了解有关本章涵盖的主题的更多信息请阅读以下文章
《通过概率性规划归纳的人类级别概念学习》《可以无监督单样本学习对象类别的一种贝叶斯方法》《使用概率模型的判别性 K 样本学习》《构建像人一样学习和思考的机器》《简单视觉概念的单样本学习》《使用分层非参数贝叶斯模型的单样本学习》
六、总结和其他方法
在这本书中我们了解了用于深度学习的各种形式的架构以及从手动特征提取到变型贝叶斯框架的各种技术和方法。 单样本学习是一个特别活跃的研究领域因为它专注于根据人类的神经能力更紧密地建立一种机器意识。 过去 5 年中随着深度学习社区的进步我们至少可以说我们正在开发一种可以像人类一样同时学习多个任务的机器。 在这一章中我们将看到单样本学习还有哪些其他选择并讨论本书中未深入探讨的其他方法。
将涵盖以下主题
最新进展相关领域应用领域
最新进展
在深度学习社区中已经提出了用于单样本学习的各种其他方法例如使用 GAN 的生成建模图像变形元网络基于代表的度量学习等。 到目前为止我们已经看到了使用单样本学习进行分类的模型但是在对象检测和语义分割方面也取得了一些进步。 在本节中我们将介绍一些主要的基于机器学习的会议的最新论文例如 CVPRNeurIPSICLR 等。
基于度量的学习是进行单样本学习的较旧方法之一。 尽管该区域较旧但仍在探索许多方面。 一个很好的例子是关于《为短时学习重新研究基于局部描述符的图像到类度量》主题的研究工作。 在本文中作者提出了一种卷积神经网络架构称为 D4N深度最近邻神经网络该架构可提取图像级特征。 它与其他神经网络架构的主要区别是用基于局部描述符的图像到类度量替代了最后一层。
《通过类别遍历查找与几次任务学习相关的任务相关特征》也为改进度量学习方法做出了贡献方法是引入一个插件框架。 在本文中作者讨论了众所周知的度量学习方法例如连体网络和匹配网络如何一次只关注一个任务而不是整个学习所有任务。 类别遍历模块CTM插件组件通过完成所有支持任务来学习重要的尺寸特征。 CTM 在集中器和投影仪单元的帮助下为相似类别提取通用特征嵌入并在不同类别中提取唯一特征。 使用 CTM 的输出我们可以在元学习器之前添加一个强大的先验这可以使我们更快更好地进行优化。 通过使用此框架他们显示了基于度量的学习方法的显着改进。
在对象检测和语义分割领域也有一些显着贡献。 让我们讨论其中的两种方法。
小样本领域中的对象检测
《RepMet用于分类和几次对象检测的基于代表的度量学习》是一种小样本学习对象检测方法。 在本文中作者提出了一种用于对象区域提议的特征金字塔网络的变体并且在其顶部他们添加了基于度量的分类器该分类器根据与学习的类代表的距离对建议的区域进行分类。 他们还通过在 ImageNet 数据集上建立了用于少发物体检测任务的基准为研究界做出了贡献。
同样《具有共同注意和共同激励的一次目标检测》也可以使用传统的视觉方法在建议的区域基础上进行过滤。 在这项工作中作者假设将提供目标图像和查询图像。 例如如果我们要检测笔架则目标图像将是笔架而查询图像将是桌子上的笔架。 在这种方法中我们首先从目标图像中提取有关对象的空间信息然后从查询图像中提取上下文对象。 上下文和空间信息在确定对象方面起着重要作用。 例如如果有一张桌子出现笔架的可能性就会增加。 这类似于人类使用上下文学习的方式。 该模型还通过将输入传递给注意力模型来利用上下文的帮助。
小样本领域中的图像分割
研究工作《CANet具有迭代细化和专注的小样本学习的类不可知分割网络》证明了医学影像行业的潜在增长。 在本文中作者提出了一个用于语义分割的两级框架密集比较模块DCM和迭代优化模块IOM。 DCM 通过使用通用的 ResNet 架构提取特征在训练集示例和测试集示例之间进行了密集的特征比较而 IOM 通过残差块加 CNN 和粗糙的空间金字塔池ASPP模块。
同样 《PANet具有原型对齐的几次语义分割》通过以下方式解决了少数镜头分割问题 度量学习方法。 本文还提出了一种对齐网络以更好地利用从支持集中提取的信息。 在 PANet 中最初网络从特定嵌入空间内的一些支持图像中学习特定于类别的表示然后通过将每个像素与学习到的特定于类别的表示进行匹配对查询/目标图像执行分割。 通过使用这种方法PANet 可以利用支持集中的重要见解并在几次分割的情况下提供更可靠的概括。
如我们所见这些解决方案适用于数据有限的情况。 我们如何量化有限的和足够的 我们需要查看我们希望训练的模型架构的能力以及希望解决的问题的复杂性。 类似于单样本学习多年来研究人员提出了其他一些方法也旨在解决数据有限的问题。 在下一节中我们将学习机器学习的这些领域以及它们与单样本学习相比的效率。
相关领域
众所周知单样本学习是机器学习的一个子领域。 有多种不同的相关解决方案与单样本学习方法非常相似但其解决方案方法略有不同。 这些问题也可以通过使用单样本学习算法来解决。 让我们遍历 ML 的每个相关领域观察它们与单样本学习问题的相似之处
半监督学习学习不平衡元学习迁移学习
半监督学习
假设我们有 10,000 个数据点其中只有 20,000 个被标记而 80,000 个未被标记。 在这种情况下我们将采用半监督学习。 在半监督学习中我们使用未标记的数据来总体上进一步了解人口结构。 半监督学习通过伪标签技术来增加训练集。 也就是说我们使用 20,000 个带标签的数据集训练模型并在大小相等的测试数据点上使用该模型为它们创建伪标签。 下图说明了半监督学习架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8F3ksliq-1681785569491)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/59858a66-819e-4871-955e-a0c5ffb64345.png)]
获得伪标签后我们将实标签与伪标签连接起来将实特征与伪特征连接在一起。 连接后我们训练了一个新模型事实证明该模型比初始模型更准确。 我们一直这样做直到获得最佳精度。
学习不平衡
在学习不平衡的情况下我们有一个不平衡的数据集。 也就是说我们从一个类别中获得的样本要多于从其他类别中获得的样本。 这也被普遍称为偏态分布数据集。让我们看一下处理偏斜数据集的一些流行方法
度量标准的选择度量标准的多种形式可以帮助评估模型的准确率例如混淆矩阵精度召回率和 F1 得分。算法的选择参数算法通过数据集学习其参数因此如果数据集存在偏差则参数模型最有可能也会受到偏差。 对于有偏数据集非参数方法例如 k 最近邻和集合例如 AdaBoostXGBoost 等被证明是最佳方法。数据采样方法的选择也可以考虑进行数据采样以确保数据集不会保持偏斜。
这种方法接近单样本学习因为我们期望创建的机器学习模型应该能够从一些示例中学习分布。
要了解有关度量形式的更多信息请参阅第 2 章“基于度量的方法”。
元学习
元学习最近在研究界引起了很多关注。 本书中讨论的大多数方法都是元学习型方法例如与模型无关的元学习和元网络。 元学习是一种在不同任务上训练模型然后针对特定任务使用通常学到的特征的方法。 它帮助模型在许多任务上学习先验从而帮助模型在有限的数据下达到优化。 用简单的话来说元学习是一种训练模型以元学习任何目标的方法。
迁移学习
迁移学习是指使用从解决一个问题中获得的知识并将其用于解决另一个问题的技术。 以下是迁移学习方法的简化视图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gRLMQhm6-1681785569492)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-1shot-learn-py/img/d2619e72-ed14-4933-9ca1-7d658c79f2f2.png)]
换句话说在一个数据集上训练的神经网络模型可以通过对前一个网络进行微调而用于其他数据集就像我们如何使用在不同域数据集例如 MNIST 数据集上训练的连体网络来提取更好的特征用于签名匹配手写匹配等。 迁移学习在深度学习领域引起了很多关注并已被证明对于许多应用非常有用。 但是由于数据限制我们无法在制造医药化学等非常见领域中使用它。
应用领域
从理论上讲单样本学习有多种应用但直到最近才开始在实际场景中使用。 使用单样本学习已取得了最新进展例如编写 SQL 代码改进变形的医学图像以及运行签名验证。 还有其他几个领域仍在研究中。 OpenAIGoogleMicrosoft 和 Amazon 等公司正在 AI 研究方面投入巨资。 解决单样本学习将意味着创建具有人类能力的机械大脑。 这种进步可以通过多种方式挽救生命可以为罕见病的发现铺平道路解决全球粮食危机或优化供应链模型。
在本书中我们探讨了一些单样本学习的可能方法。 如果您想探索更多内容请参阅“进一步阅读”部分。
进一步阅读
要进一步了解本章请参考以下作品
《元学习实践》《为小样本学习重新研究基于局部描述符的图像到类度量》《通过类别遍历查找与几项学习相关的任务相关特征》《RepMet基于代表的度量学习用于分类和几次检测》《具有共同注意和共同激励的一次对象检测》《CANet具有迭代细化和专心的少样本学习的类不可知分割网络》《PANet具有原型对齐的几次图像语义分割》