李宏毅机器学习深度学习笔记-2021-二-

李宏毅机器学习深度学习笔记 2021(二)

深度学习基础教程 P2:L1.2 - 深度学习基本概念简介 🧠

在本节课中,我们将要学习深度学习的基本概念。我们将从一个简单的线性模型开始,探讨其局限性,并逐步引入更复杂的模型结构,最终理解神经网络(Neural Network)和深度学习(Deep Learning)的核心思想。我们将使用简单的语言和直观的例子,确保初学者能够跟上。


线性模型的局限性

上一节我们介绍了使用线性模型进行预测的基本思路。本节中我们来看看线性模型存在哪些问题。

线性模型的形式是 Y = B + W * X。对于这个模型来说,X 和 Y 的关系被限制为一条直线。无论我们如何调整参数 W(斜率)和 B(截距),它始终是一条直线。这意味着 Y 永远随着 X 的增加而单调增加。

但现实世界的关系往往更复杂。例如,前一天观看人数(X)和隔天观看人数(Y)的关系可能并非简单的正比。可能存在一个“峰值”,当 X 小于某个值时,Y 随 X 增加而增加;但当 X 超过这个峰值后,Y 反而可能减少。这种关系更像一条曲线,而非直线。

线性模型无法表示这种复杂的、非单调的关系。这种由于模型本身形式简单而带来的限制,称为 模型的偏差(Model Bias)。注意,这里的“偏差”与参数 B(Bias)含义不同,它指的是模型拟合真实世界复杂模式的能力不足。

从分段线性曲线到复杂函数

既然线性模型不够用,我们需要一个更复杂、更有弹性的函数。我们可以观察一条复杂的红色曲线。

这条红色曲线可以看作是由一个常数项,加上许多个蓝色的“基础函数”组合而成。每个蓝色函数具有这样的特性:当输入 X 小于某个阈值时,输出是一个定值;大于另一个阈值时,输出是另一个定值;中间是一个斜坡。这种函数称为 Hard Sigmoid 函数。

通过调整这些蓝色函数的起始点、转折点和斜率,并将它们与一个常数项相加,我们就可以组合出这条红色的分段线性曲线。实际上,任何分段线性曲线(Piecewise Linear Curve)都可以用常数项加上一系列 Hard Sigmoid 函数来表示

如果分段线性曲线的转折点越多,需要的蓝色函数就越多。更进一步,任何连续的曲线都可以用足够多的点来近似,然后用一条转折点足够多的分段线性曲线去逼近它。因此,只要有足够多的 Hard Sigmoid 函数,我们就可以逼近任何连续曲线

这意味着,无论 X 和 Y 的真实关系多么复杂,我们都可以尝试用一组带有未知参数的函数来表示它,这组函数就是一系列 Hard Sigmoid 函数的和。

Sigmoid 函数

然而,直接写出 Hard Sigmoid 函数的表达式可能不太方便。我们可以用另一个更平滑、易于计算的函数来近似它,这就是 Sigmoid 函数

Sigmoid 函数的公式如下:

y = c * sigmoid(b + w * x)

其中,sigmoid(z) = 1 / (1 + exp(-z))。因此,完整的表达式是:

y = c / (1 + exp(-(b + w * x)))

这个函数的形状是 S 型。通过调整参数:

  • w:改变斜坡的陡峭程度(斜率)。
  • b:将函数图像左右移动。
  • c:改变函数的最大高度。

使用不同的 w、b、c 参数,我们可以制造出不同形状的 Sigmoid 函数。用这些不同的 Sigmoid 函数代替之前的 Hard Sigmoid 函数,叠加起来,同样可以逼近各种分段线性曲线,进而逼近各种连续函数。

构建新模型

现在,我们可以构建一个新的、更有弹性的模型。假设我们用三个 Sigmoid 函数来组合,模型公式如下:

y = b + c1 * sigmoid(b1 + w1 * x) + c2 * sigmoid(b2 + w2 * x) + c3 * sigmoid(b3 + w3 * x)

这里,b, c1, c2, c3, b1, b2, b3, w1, w2, w3 都是未知参数。通过为这些参数设定不同的值,我们就可以组合出不同的曲线,从而拥有模拟复杂关系的能力。

这个模型克服了线性模型的“模型偏差”,因为它能表示的非线性关系要丰富得多。

引入多个特征

之前我们只使用了一个特征(如前一天的观看人数)。在实际问题中,我们通常会使用多个特征(如前1天、前2天……前N天的数据)。将模型扩展到多个特征也很简单。

假设我们有 j = 1 到 N 个特征。对于第 i 个 Sigmoid 函数,其输入不再是单一的 w * x,而是所有特征与其对应权重的加权和。模型公式扩展为:

y = b + Σ_i [ ci * sigmoid(bi + Σ_j [ wij * xj ]) ]

其中:

  • i 代表第 i 个 Sigmoid 函数。
  • j 代表第 j 个输入特征。
  • wij 是第 i 个 Sigmoid 函数中,第 j 个特征对应的权重。
  • bi 是第 i 个 Sigmoid 函数的偏置项。
  • ci 是第 i 个 Sigmoid 函数输出后的缩放系数。
  • b 是整个模型的偏置项。

模型的神经网络表示

上面的数学公式可能有些抽象。我们可以用更直观的图(神经网络结构图)来表示这个计算过程。

  1. 输入层:输入特征 x1, x2, ..., xj
  2. 隐藏层:每个 Sigmoid 函数对应一个“神经元”。每个神经元做的事情是:
    • 接收所有输入特征。
    • 计算加权和 ri = bi + Σ_j (wij * xj)
    • ri 通过 Sigmoid 函数,得到输出 ai = sigmoid(ri)
  3. 输出层:将所有神经元的输出 ai 乘以权重 ci 后求和,再加上偏置 b,得到最终预测值 y

这个过程可以简洁地用线性代数表示:

  • r = W * x + b_vec
  • a = sigmoid(r)
  • y = c^T * a + b

其中,W 是权重矩阵,b_vec 是偏置向量,c 是输出权重向量。

重新定义损失函数与优化

我们将所有未知参数(所有权重 W、偏置 b_vec、输出权重 c、最终偏置 b)拼接成一个很长的向量,记作 θ(参数向量)。

损失函数 L(θ) 的定义方式与线性模型相同:衡量模型在给定参数 θ 下的预测值与真实值之间的总体差距。

优化目标仍然是找到一组参数 θ*,使得损失 L(θ) 最小。优化算法仍然使用梯度下降(Gradient Descent)

  1. 随机初始化参数向量 θ^0
  2. 计算损失函数 Lθ 的梯度(偏导数向量),记作 g = ∇L(θ)
  3. 更新参数:θ^1 = θ^0 - η * g,其中 η 是学习率(Learning Rate)。
  4. 重复步骤2和3,直到收敛。

在实际操作中,我们通常不会一次性使用所有数据计算梯度,而是采用小批量梯度下降(Mini-batch Gradient Descent)

  • 将所有训练数据随机分成若干小份,每一份称为一个批次(Batch)
  • 每次迭代只使用一个批次的数据计算损失和梯度,并更新参数。
  • 遍历完所有批次称为一个周期(Epoch)

激活函数:Sigmoid 与 ReLU

我们之前用 Sigmoid 函数来近似 Hard Sigmoid。实际上,还有其他函数可以作为神经元的“激活函数(Activation Function)”。另一个非常常见的是 ReLU(Rectified Linear Unit)

ReLU 函数的公式是:y = max(0, b + w * x)
它的形状是一条折线:当输入小于0时输出为0,当输入大于0时输出为输入值本身。

有趣的是,两个 ReLU 函数可以合成一个 Hard Sigmoid 函数。因此,在神经网络中,我们完全可以使用 ReLU 代替 Sigmoid。实际上,在深度学习中,ReLU 因其计算简单和训练中的良好性能,变得比 Sigmoid 更常用。

深度神经网络

我们可以将上述“输入-隐藏层-输出”的结构反复堆叠。

  • 第一层:输入 x 产生输出 a
  • 第二层:将 a 作为输入,通过新的权重和激活函数,产生输出 a'
  • 第三层:将 a' 作为输入,产生输出 a''
  • ……
  • 最后一层:输出最终预测 y

每增加一层,就引入了更多的参数和非线性变换。这种多层的神经网络结构被称为深度神经网络(Deep Neural Network),“深度”指的就是层数多。

实验表明,在一定范围内,增加网络层数(使用更多参数和更复杂的结构)可以在训练数据上获得更低的损失。但这也可能带来过拟合(Overfitting)问题:模型在训练数据上表现很好,但在未见过的新数据上表现变差。

总结

本节课中我们一起学习了深度学习的基本概念:

  1. 我们首先指出了简单线性模型的局限性(模型偏差),它无法表达复杂的非线性关系。
  2. 为了克服这个问题,我们引入了由多个 Sigmoid 函数组合而成的更复杂的模型。这些函数可以逼近分段线性曲线,进而逼近任何连续函数。
  3. 我们学习了模型的数学表示和直观的神经网络图示,包括输入层、隐藏层和输出层。
  4. 我们介绍了模型的训练过程,核心仍然是定义损失函数和使用梯度下降法优化参数,并了解了实际常用的小批量训练方式。
  5. 我们认识了两种重要的激活函数:Sigmoid 和 ReLU。
  6. 最后,我们了解了通过堆叠多个隐藏层可以构建深度神经网络,并简要提到了模型复杂度和过拟合之间的关系。

深度学习本质上就是使用包含多个隐藏层的神经网络,通过大量数据和梯度下降算法,学习输入与输出之间复杂的映射关系。在接下来的课程中,我们将深入探讨如何选择模型结构、避免过拟合以及更高效的训练技巧。

课程 P20:L13.3 - 自督导式学习3:BERT详解 🧠

在本节课中,我们将深入探讨BERT模型的工作原理,并解释它为何如此有效。我们将从最直观的解释入手,逐步分析其内部机制,并通过一些有趣的实验来揭示其更深层的特性。

BERT为何有效?🤔

上一节我们介绍了自督导学习的基本概念,本节中我们来看看BERT模型的核心思想。最常见的解释是:BERT能够为输入文本中的每个字或词生成一个对应的向量,这个向量被称为嵌入

这个嵌入向量的特别之处在于,它代表了输入字词的含义。例如,输入“台湾大学”,BERT会输出四个向量,分别代表“台”、“湾”、“大”、“学”的意思。

向量如何表示含义?

具体来说,如果我们将这些字词对应的向量可视化或计算它们之间的距离,会发现含义越相近的字词,其向量在空间中也越接近。

公式:对于两个词向量 v1v2,其相似度通常用余弦相似度衡量:
similarity = (v1 · v2) / (||v1|| * ||v2||)

例如,“苹果”和“橘子”都是水果,它们的向量会比较接近;而“苹果”和“电脑”的向量则可能相距较远。

处理一词多义

你可能会问,中文(以及许多其他语言)存在一词多义的问题。BERT可以很好地处理这一点,因为它考虑了上下文信息。同一个字,在不同的上下文中,其生成的嵌入向量是不同的。

代码示例(概念性):

# 伪代码:BERT根据上下文生成不同的嵌入
context1 = "吃苹果"
context2 = "苹果手机"
embedding_apple1 = BERT_encode(context1)["果"] # 与“水果”含义接近
embedding_apple2 = BERT_encode(context2)["果"] # 与“品牌”含义接近

因此,“吃苹果”中的“果”与“草”的向量可能更接近,而“苹果手机”中的“果”则可能与“电”更接近。

实证:BERT理解词义 📊

为了验证BERT是否真的能做到这一点,我们来看一个真实的例子。我们收集了包含“果”字的句子,并将其输入BERT。

以下是分析步骤:

  1. 收集句子(例如:“今天买了苹果来吃”、“苹果即将发表新款iPhone”)。
  2. 将每个句子输入BERT,获取其中“果”字对应的嵌入向量。
  3. 计算这些向量两两之间的余弦相似度。

分析结果会形成一个相似度矩阵。你会发现,代表“水果”含义的“果”的向量彼此相似度高,代表“苹果公司”含义的“果”的向量彼此相似度也高,但这两组向量之间的相似度则较低。这表明BERT确实能根据上下文区分词语的不同含义。

所以,在通过“填空”任务进行训练的过程中,BERT似乎学会了理解每个字词的含义。这使得它能够在后续的下游任务中表现得更好。

BERT能力的语言学基础 🗣️

那么,BERT为何拥有这种神奇的能力呢?这基于一个语言学假设:一个词的含义取决于它的上下文

这个观点由语言学家John Rupert Firth提出,即“You shall know a word by the company it keeps.”。例如,“苹果(水果)”的上下文常出现“吃”、“树”等词,而“苹果(公司)”的上下文则常出现“股价”、“专利”等词。

BERT在训练时所做的正是这件事:给定上下文(如W1, [MASK], W3, W4),它需要预测被遮盖的词(W2)。为了完成这个任务,模型必须从上下文中抽取关键信息。因此,它输出的嵌入向量,本质上是上下文的精华浓缩,用于预测目标词。

这种思想在BERT之前就已存在。例如,Word2Vec技术中的Skip-gram模型就做着类似的事情:预测给定中心词周围的上下文。BERT可以看作是它的“深度”版本,模型更复杂,并且能生成上下文相关的词嵌入

一个令人深思的实验 🧬

以上是文献中最常给出的解释。但这里我想分享一个我们实验室进行的、可能颠覆直觉的实验。

我们将原本在文本上预训练的BERT,直接用于DNA序列分类、蛋白质分类和音乐分类任务。以DNA分类为例:

实验步骤

  1. DNA由A、T、C、G四种碱基组成。
  2. 我们随机地将每个碱基映射到一个英文单词(例如,A->“we”, T->“you”)。
  3. 于是,一段DNA序列就变成了一段无意义的“英文”句子(如“AGAC” -> “we she we he”)。
  4. 我们将这个无意义的句子输入BERT(使用在英文文本上预训练的权重),然后接一个线性分类器来预测DNA类别。

令人惊讶的是,即使输入是毫无语义的乱码,使用预训练BERT的模型性能(红色部分)也比随机初始化的模型(蓝色部分)更好。

核心发现:这个实验表明,BERT的强大能力可能不完全源于其“理解语义”。它可能作为一种更好的参数初始化方法,其架构本身就更适合学习各种序列模式(无论是语言、DNA还是音乐)。这提醒我们,对于这些新模型为何有效,仍有巨大的研究空间。

多语言BERT的奇迹 🌍

接下来要介绍的是多语言BERT。它在预训练时使用了104种不同语言的文本进行“填空”训练。

其神奇之处在于:用英文问答数据微调后的多语言BERT,竟然能直接处理中文问答任务

实验数据

  • 在纯中文BERT上微调:在中文问答数据集DRCD上达到约89%的准确率。
  • 在多语言BERT上,仅用英文问答数据集SQuAD微调,然后直接在中文DRCD上测试:准确率达到了约78%,这与BERT出现之前最强的问答模型QANet性能相当。

它从未见过中文的问答数据,却能够回答中文问题。这是如何做到的?

探究原因:词向量对齐

一个合理的猜测是:多语言BERT在学习过程中,自动将不同语言中意思相同的词映射到了向量空间中相近的位置。例如,“兔子”和“rabbit”的向量很接近。

我们使用Mean Reciprocal Rank (MRR) 指标来衡量这种对齐效果,MRR越高,说明不同语言间同义词的向量越接近。实验发现,谷歌发布的104语言BERT的MRR值非常高。

为了探究成因,我们尝试自己训练多语言BERT。最初,每个语言只用20万句数据,训练出的模型无法实现良好的跨语言对齐。直到我们将每个语言的数据量增加到100万句,在训练了相当长时间后,模型才突然“学会”了对齐。

启示:许多神奇的能力(如跨语言迁移)可能需要海量的数据足够的计算资源才能显现出来,这在过去是无法观察到的。

语言信息藏于何处?

然而,这整件事仍有一个疑点:如果BERT认为不同语言的同义词没有区别,那它如何区分不同语言的句子并进行正确的填空呢?

我们发现,语言的差异信息并没有被完全抹去。通过计算所有英文词向量的平均值和所有中文词向量的平均值,我们可以得到一个代表“语言差异”的向量。

神奇实验:将一句英文的BERT嵌入向量,加上这个“中英文差异向量”,再让BERT做填空,它输出的竟然会是中文答案!

示例
输入英文:“There is no one who can help me.”
处理后的BERT输出:“無人能幫助我。”

这虽然不是一个完美的翻译,但说明多语言BERT在将语义空间对齐的同时,依然在内部保留了语言特征信息。


本节课总结
我们一起深入探讨了BERT模型。我们了解到,BERT通过“填空”预训练任务,学会了生成上下文相关的词嵌入,这些嵌入能有效表示词语的语义。其能力源于“词义取决于上下文”的语言学假设。同时,通过DNA分类和多语言BERT的实验,我们看到BERT的能力可能超越单纯的语义理解,其架构和预训练方式本身可能就是一种强大的特征提取器。最后,多语言BERT展现的跨语言迁移能力,揭示了大数据时代下模型涌现出的新特性,也留下了许多值得探索的奥秘。

课程 P21:L13.4 - 自监督学习4:GPT 🤖

在本节课中,我们将要学习GPT模型。这是一种与BERT不同的自监督学习方法,它通过预测下一个词元(token)来训练模型,并具备强大的文本生成能力。我们还将探讨GPT如何应用于下游任务,以及自监督学习在语音和图像领域的扩展。


GPT的核心任务:预测下一个词元 🎯

上一节我们介绍了BERT模型,它通过“填空”任务进行训练。本节中我们来看看GPT模型,它的核心训练任务与BERT不同。

GPT模型的任务是预测接下来会出现的词元是什么。这类似于一个语言建模任务。

假设训练数据中有一个句子是“台湾大学”。GPT在训练时会如何处理呢?以下是其训练过程:

  1. 首先,模型接收一个“句子开始”(Begin of Sentence)标记。
  2. GPT输出一个嵌入向量(embedding)。
  3. 使用这个嵌入向量去预测下一个应该出现的词元。根据训练数据,下一个词元是“台”。
  4. 模型的目标是让预测的分布与正确答案之间的交叉熵(cross entropy)越小越好。

这个过程可以用以下公式表示:

H → Linear Transform → Softmax → Distribution

其中,H 是模型输出的嵌入向量,经过线性变换和Softmax后得到一个概率分布,目标是最小化该分布与真实下一个词元之间的交叉熵损失。

接下来,这个过程会反复进行:

  • 输入“句子开始”和“台”,模型预测下一个词元应为“湾”。
  • 输入“句子开始”、“台”、“湾”,模型预测下一个词元应为“大”。
  • 以此类推。

在实际训练中,模型会使用海量的句子数据进行学习。GPT的强大之处在于,使用巨量数据训练了一个参数规模异常庞大的模型,从而展现出惊人的能力。


GPT的模型架构 🔧

这里需要说明的是,GPT的模型架构类似于Transformer的解码器部分。

我们知道Transformer包含编码器和解码器。GPT的架构类似于解码器,但移除了“编码器-解码器注意力”部分,只使用带掩码的自注意力机制。

这意味着:

  • 当模型根据“句子开始”预测“台”时,它看不到后面“湾”、“大”、“学”这些词元。
  • 当模型根据“台”预测“湾”时,它同样看不到后面“大”、“学”这些词元。

这种掩码机制确保了模型在预测时只能利用当前位置之前的信息,这与“预测下一个词元”的任务要求是一致的。


GPT的生成能力与应用实例 🦄

由于GPT能够预测下一个词元,因此它具备了文本生成能力。你可以让它不断预测下一个词元,从而生成完整的文章或段落。

GPT系列最著名的一个例子,就是它生成了一篇关于“在安第斯山脉发现独角兽”的假新闻。这篇文章活灵活现,以至于很多人提到GPT时,都会联想到这只“独角兽”。

为了让您更直观地了解GPT的运作,线上有一个演示网页叫“Talk to Transformer”。它使用了一个较小的GPT模型(最大的GPT模型并未公开),您可以输入一句话的开头,模型会自动将后续内容补全。


GPT如何用于下游任务?🧠

那么,这种“补全句子”的能力,如何应用到问答系统等下游任务中呢?GPT采用了一种与BERT不同的、更为“激进”的思路。

BERT的做法是:将预训练好的BERT模型拿出来,在后面接一个简单的线性分类器,然后在下游任务数据上进行微调。

GPT论文中提出了一个更接近人类学习方式的想法,称为情境学习

设想你参加托福听力考试:

  1. 首先,你会看到题目说明,告诉你这是选择题,并从A、B、C、D中选出答案。
  2. 接着,会给你一个示例,展示题目和正确答案。
  3. 最后,你看到新的问题,并期望你能举一反三开始作答。

GPT系列模型试图做同样的事情。例如,要让GPT做翻译任务:

  1. 先输入任务描述:“Translate English to French:”。
  2. 然后给几个示例:“sea otter => loutre de mer”、“plush giraffe => girafe peluche”。
  3. 最后给出新的输入:“cheese =>”,并让模型补全后面的部分。

这个想法之所以“激进”,是因为在训练时,GPT从未专门学习过翻译。它只学会了“根据前半段文字补全后半段”。现在,我们通过几个示例(情境)直接告诉它现在要做翻译,它就能尝试给出翻译结果。

这种学习方式在GPT文献中被称为 Few-Shot Learning,但它与通常的机器学习不同,完全没有使用梯度下降来调整模型参数。因此,GPT的研究者给这种方式起了一个特殊的名字:In-Context Learning

还有更具挑战性的设置:

  • One-Shot Learning:只给模型一个示例,就期望它学会任务。
  • Zero-Shot Learning:不给任何示例,只给任务描述(如“Translate English to French:”),就期望模型能执行任务。

GPT-3的性能与局限 ⚖️

GPT系列(特别是GPT-3)是否真的实现了强大的情境学习能力呢?这是一个见仁见智的问题。

根据GPT-3论文中的实验结果:

  • 它在42个不同的任务上进行了测试。
  • 在Few-Shot、One-Shot、Zero-Shot三种设置下,模型的表现随着参数量的增大(从1亿到1750亿参数)而提升。
  • 在Few-Shot设置下,平均正确率从20%多提升到了50%多。

50%多的平均正确率算成功吗?这取决于评判标准。目前看来:

  • 对于一些任务,如简单的加减法运算,GPT-3确实能够学会。
  • 但对于一些需要逻辑推理的任务,它的表现则非常糟糕。

因此,GPT-3展现出了令人印象深刻的少样本学习潜力,但其能力并不均衡,且距离通用人工智能仍有很大差距。


自监督学习不限于文字 🌈

到目前为止,我们的例子都围绕文本展开。但请不要误会,自监督学习的概念同样可以应用于语音和图像领域

事实上,自监督学习的技术非常多,我们讲解的BERT和GPT只是其中“预测”这一类方法。接下来我们简要了解其他领域的应用。

图像中的自监督学习 🖼️

以下是图像领域两种著名的自监督学习方法:

  • SimCLR:其核心思想是对同一张图像进行两种不同的数据增强,然后训练模型让这两个增强版本的表示向量尽可能接近,而与其他图像的表示向量远离。这个概念并不复杂,通过阅读论文可以理解。
  • BYOL:这是一个更令人惊奇的工作。它的想法在论文发表前,如果学生向我提出,我可能会认为存在巨大缺陷而难以成功。但事实上它不仅有效,还一度达到了顶尖水平。这再次说明了深度学习的奇妙之处。

语音中的自监督学习 🎤

在语音领域,完全可以运用自监督学习的概念:

  • 你可以训练语音版的BERT:例如,将一段音频的部分片段掩盖,让模型预测被掩盖的部分是什么(填空任务)。
  • 你也可以训练语音版的GPT:让模型根据已有的音频序列,预测接下来会出现的声音。

目前,语音领域相比文本领域,还缺乏一个像GLUE那样的统一的基准测试集。为了推动该领域发展,我们实验室与其他团队共同开发了一个语音版的“GLUE”,称为 SUPERB

SUPERB是一个语音理解通用性能基准测试,它包含了10个不同的任务,全面评估模型在语音内容识别、说话人识别、情感识别和语义理解等多方面的能力。它旨在全方位检测一个自监督学习模型在理解人类语音上的能力。


总结 📚

本节课中我们一起学习了:

  1. GPT模型的核心训练任务是预测下一个词元,这使其具备了强大的文本生成能力。
  2. GPT的模型架构类似于Transformer的解码器,并使用掩码自注意力机制。
  3. GPT应用于下游任务时,采用了一种创新的 “情境学习” 方式,通过提供任务描述和少量示例,让模型在不更新参数的情况下适应新任务。
  4. 最新的GPT-3模型在少样本学习上展现了潜力,但其能力并不全面,仍有局限性。
  5. 最后,我们了解到自监督学习是一个广阔的领域,其技术不仅适用于文本,在图像和语音处理中也有丰富且活跃的研究与应用,例如图像领域的SimCLR、BYOL,以及语音领域的SUPERB基准测试集。

自监督学习为我们提供了利用海量无标注数据训练强大模型的新范式,是当前人工智能研究的前沿方向之一。

课程 P22:L14.1 - 自编码器1:基本概念 🧠

在本节课中,我们将要学习自编码器的基本概念。自编码器是一种无监督学习模型,它能够学习数据的有效表示,是深度学习中的一个重要组成部分。

概述

自编码器可以被视为自监督学习的一种预训练方法。它的核心思想是让模型学习如何压缩数据,然后再重建数据,整个过程无需任何标注数据。

自编码器的工作原理

上一节我们介绍了自编码器属于自监督学习的范畴,本节中我们来看看它的具体工作原理。

自编码器包含两个主要部分:一个编码器和一个解码器。以下是它们的工作流程:

  1. 编码器接收输入数据(例如一张图片),并将其转换为一个低维度的向量表示。这个向量通常被称为嵌入表示代码
    • 公式表示:h = Encoder(x)
  2. 解码器接收这个向量,并尝试重建出与原始输入尽可能相似的数据。
    • 公式表示:x' = Decoder(h)
  3. 训练的目标是最小化原始输入 x 与重建输出 x' 之间的差异(例如均方误差)。
    • 目标函数:Loss = ||x - Decoder(Encoder(x))||^2

这个过程完全不需要标注数据,只需要大量未标注的数据即可进行训练。

自编码器的应用:降维与下游任务

理解了自编码器如何工作后,我们来看看它的实际用途。自编码器最常见的应用之一是降维

编码器将高维度的输入数据(例如一张数万维的图片)压缩成一个低维度的向量(例如100维)。这个中间的低维向量层被称为瓶颈层

以下是自编码器用于下游任务的典型方式:

  1. 使用大量无标签数据预训练一个自编码器。
  2. 将训练好的编码器部分固定下来。
  3. 对于新的下游任务(如图片分类),我们将输入图片通过这个编码器,得到其低维表示。
  4. 使用这个低维表示(而非原始高维像素)作为特征,来训练一个简单的分类器。

这样做的好处是,编码器学习到的低维表示可能捕捉到了数据最本质的特征,从而使得下游任务需要更少的标注数据就能获得良好的性能。

自编码器的变体:去噪自编码器

自编码器有许多变体,其中一个重要的变体是去噪自编码器。它的核心思想是让模型学习从带噪声的数据中恢复出干净的数据。

以下是其工作原理:

  1. 我们首先对原始输入数据 x 人为地添加一些噪声,得到带噪声的数据
  2. 输入编码器,得到编码 h
  3. 解码器根据 h 进行重建,目标是输出原始的干净数据 x,而不是带噪声的输入
  4. 训练目标是最小化重建输出与原始干净数据 x 之间的差异。

通过这种方式,模型被迫学习到数据中更鲁棒的特征,从而能够去除噪声。有趣的是,像 BERT 这样的现代自然语言处理模型,其掩码语言模型任务本质上就是一个针对文本的去噪自编码器

历史背景

自编码器并不是一个全新的概念,它拥有悠久的历史。例如,深度学习先驱 Geoffrey Hinton 在 2006 年发表于《科学》杂志的论文中就探讨了基于受限玻尔兹曼机的深层自编码器训练方法。早期的研究认为深层网络需要分层预训练,但随着技术的发展,人们发现端到端的训练方式更为有效。

总结

本节课中我们一起学习了自编码器的基本概念。我们了解到:

  • 自编码器是一种无监督/自监督学习模型,由编码器和解码器组成。
  • 其核心目标是学习数据的压缩表示,并能从该表示中重建数据。
  • 编码器学习到的低维表示(瓶颈层)可以用于数据降维,并作为下游任务的有效特征。
  • 去噪自编码器通过让模型学习去除噪声,能够学习到更鲁棒的数据表示。
  • 自编码器的思想历史悠久,并且与现代模型(如BERT)的核心思想一脉相承。

自编码器为我们提供了一种理解数据内在结构和进行特征学习的强大工具。

课程 P23:L14.2 - 自编码器2:领结变声器与更多应用 🎙️🔧

在本节课中,我们将继续探索自编码器的应用。上一节我们介绍了自编码器的基本概念和下游任务,本节中我们将深入了解特征解缠、离散潜在表示等高级概念,并探讨自编码器在语音转换、异常检测等领域的实际应用。

特征解缠 🧵

上一节我们介绍了自编码器如何将输入数据压缩为包含所有重要信息的编码。然而,这些信息通常是纠缠在一起的。本节中我们来看看特征解缠技术,它旨在将编码中不同维度的信息分离开来。

特征解缠的目标是解开原本纠缠在一起的特征。自编码器将输入(如图片)编码为一个向量,再解码回原始输入。这个向量包含了输入的所有关键信息。例如,在语音中,向量可能同时包含语音内容和说话人身份的信息;在文本中,可能同时包含句法和语义信息。但这些信息都混合在一个向量中,我们无法区分哪些维度对应哪些具体信息。

特征解缠技术试图在训练自编码器时,让编码的特定维度明确代表特定类型的特征。例如,一个100维的编码,可能前50维代表语音内容,后50维代表说话人特征。以下是实现这一目标可能带来的应用:

  • 语音转换:这项技术可以将一个人的声音转换为另一个人的声音,类似于动画中的“领结变声器”。传统方法需要成对的语音数据(两个人说相同的句子),而利用特征解缠,即使说话人使用不同语言或说不同句子,也有可能实现声音转换。

具体操作流程如下:首先,用大量语音数据训练一个具备特征解缠能力的自编码器。这样,编码器输出的向量中,代表“内容”和“说话人特征”的维度就被分开了。接着,将说话人A的语音编码,取出其“内容”部分;将说话人B的语音编码,取出其“说话人特征”部分。将这两部分拼接成一个新向量,输入解码器,就能得到具有B的声音特征、但说着A的内容的语音。这项技术在图像和自然语言处理中也有类似应用。

离散潜在表示 🔢

到目前为止,我们都假设编码是连续的实数向量。本节中我们来看看编码是否可以表示为其他形式,例如离散值。

将编码变为离散值(如二进制或独热编码)可能带来好处。二进制编码可以让每个维度明确表示某种特征的有或无。独热编码则意味着编码中只有一个维度为1,其余为0。如果强制编码为独热向量,或许可以实现无监督分类。例如,在手写数字识别中,如果编码是10维的独热向量,那么每种独热编码可能自动对应到一个数字(0-9)。

在离散表示技术中,最著名的是向量量化变分自编码器。它的工作原理是:编码器输出一个连续向量后,会与一个可学习的“码本”中的多个向量计算相似度,并选取最相似的向量作为离散表示,传递给解码器。在训练中,编码器、解码器和码本一同被学习。这样做的好处是,解码器的输入被限制为码本中的有限选项,从而实现了离散的潜在表示。例如,在语音上应用VQ-VAE,码本中的向量可能学会对应到基本的发音单位。

更广义的表示:文字与树结构 📝🌳

我们进一步思考,表示一定要是向量吗?本节中我们来看看能否使用更复杂的结构,如文字或树结构,作为编码。

以文字作为编码:在文本自编码器中,编码器读入一篇文章,输出一段文字(而非向量),解码器再将这段文字还原成原文。如果这段输出文字能通过解码器还原原文,那它很可能就是原文的精华——即摘要。这为实现无监督的自动摘要提供了可能。然而,直接训练这样的模型会遇到问题:编码器和解码器可能会发明一套人类无法理解的“暗号”进行通信。为了解决这个问题,可以引入对抗训练的思想,加入一个判别器来迫使编码器生成人类可读的句子。这本质上与循环生成对抗网络的思想相似。

以树结构作为编码:也有研究尝试将输入(如文本)编码为树形结构,再从这个树结构解码回文本。这为理解文本的层次化结构提供了新思路。

自编码器的其他应用 🛠️

除了上述应用,自编码器还有许多其他用途。本节中我们来看看其中几个重要的方向。

  • 作为生成器:自编码器的解码器本身就是一个生成器,它可以接受一个从某个分布(如高斯分布)中采样的向量,并生成数据(如图片)。变分自编码器正是利用了这一思想来构建生成模型。
  • 数据压缩:编码器可以将高维输入压缩为低维编码,这可以看作是一种有损压缩技术,类似于JPEG图像压缩。解码器则执行解压缩操作。
  • 异常检测:这是我们课程作业将重点应用的技术。其核心思想是:使用大量“正常”数据训练一个自编码器。在测试时,给模型输入新数据,如果该数据与训练数据相似(属于“正常”类),则自编码器能够较好地重构它,重构误差小;反之,如果数据是“异常”的,重构误差就会很大。通过计算重构损失,可以判断新数据是否异常。这种方法特别适用于难以获取异常样本的场景,也称为单类分类问题。异常检测在欺诈检测、网络入侵检测、医疗诊断等领域有广泛应用。

总结 📚

本节课我们一起深入学习了自编码器的多种高级应用。我们探讨了特征解缠技术如何分离编码中的不同信息,并实现了像语音转换这样的有趣应用。我们了解了离散潜在表示(如VQ-VAE)以及用文字甚至树结构作为编码的前沿思路。最后,我们还介绍了自编码器作为生成器、压缩工具以及在异常检测中的重要作用。自编码器作为一个基础而强大的框架,其灵活性和潜力在各种机器学习任务中不断得到展现。

课程 P28:L17 - 概述领域自适应 🎯

在本节课中,我们将要学习领域自适应的核心概念。我们将探讨当训练数据和测试数据分布不同时,如何让模型依然保持良好的性能。这是迁移学习中的一个重要环节,对于将实验室模型应用到真实场景中至关重要。


领域偏移问题

上一节我们介绍了领域自适应的背景,本节中我们来看看什么是领域偏移

到目前为止,我们已经训练了许多机器学习模型。训练一个分类器对大家来说已不是问题。假设要训练一个数字分类器,只要有训练数据,训练好模型后应用在测试数据上即可。

像数字识别这么简单的问题,在基准测试上可能轻松达到95%的正确率。但是,如果测试数据与训练数据的分布不同,会发生什么呢?

我们举一个简单的例子。假设训练时数字是黑白的,但测试时数字是彩色的。你可能认为,虽然一边是黑白一边是彩色,但对模型来说数字形状是一样的。它能在黑白图片上认出数字,在彩色图片上应该也可以。

但实际上并非如此。如果在黑白数字上训练一个模型,直接用在彩色数字上,得到的正确率会非常低,只有57%。这不能算是一个及格的分数。

因此,一旦训练数据与测试数据之间存在差异,即它们的分布不同,在训练数据上训练出的模型在测试数据上就可能失效。这种问题叫做领域偏移

在多数作业或基准测试中,我们都假设无视领域偏移问题,训练数据与测试数据往往有着相同的分布。这会给人们一个错误的印象,即人工智能在很多任务上都有极高的正确率。但实际上,当训练数据与测试数据存在差异时,机器能否做好就是一个未知数。

我们今天要讲的就是,当训练数据与测试数据存在差异时,有没有什么方法可以让我们做得比什么都不做更好。这就是领域自适应技术。

领域自适应技术也可以看作是迁移学习的一种。迁移学习是指在A任务上学到的技能可以被用在B任务上。对于领域自适应来说,训练数据来自一个领域,测试数据来自另一个领域。你要把一个领域学到的知识用在另一个领域上,所以它可以看作是迁移学习的一个环节。

在过去的上课录音中,有完整讲解迁移学习相关的技术。由于今天时间有限,我们只聚焦在领域自适应的部分。如果你有兴趣,可以再看一下过去的上课录音。

领域偏移其实有很多种不同的类型。我们刚才看到的只是其中一种,即模型输入数据的分布发生变化。输入分布变化是一种可能性。

其实还有另一种可能性,即输出的分布也可能变化。举例来说,在训练数据上,可能每个数字出现的概率都一样。但在测试数据上,可能每个数字输出的概率不同,某个数字出现的概率特别大。这也是有可能的,这也是一种领域偏移。

还有一种更罕见但并非完全不可能发生的状况是,输入和输出虽然分布可能一样,但它们之间的关系变了。也许在训练数据里,这种东西叫做“零”,但在测试数据里,这种东西叫做“一”。这也不是不可能的。有时可能发生输入和输出关系在训练和测试数据中不一样的状况。这又是另一种领域偏移。

我们今天只专注在输入数据不同的领域偏移上。

在接下来的课程里,测试数据我们称其来自目标领域,训练数据我们称其来自源领域。所以源领域是我们的训练数据,目标领域是我们的测试数据。


领域自适应的情境

在领域自适应中,我们的情境是这样的:我们有一堆训练数据。这边我们直接拿手写数字辨识来当例子。我们有一堆来自源领域的训练数据,而且这些数据是有标注的,我们知道每张图片对应的数字是什么。

我们希望用这些数据训练出一个模型,这个模型可以用在不一样的领域上。要把这个模型用在不一样的领域上,在训练时,我们就必须对另一个领域,即测试数据所在的目标领域,有一些了解。

随着了解的程度不同,我们就有不同的领域自适应方法。

了解最多的情况是,假设我们在目标领域上有一点数据,而且这些数据居然还有标签。那这是一种情况。

还有一种更好的状况是,也许你根本在目标领域上就有一大堆的数据,那些数据也都有标签,那你其实就不需要做领域自定了,直接拿目标领域的数据来训练就好。

所以,要做领域自定的情境,可能是你在目标领域有数据也有标注,但量非常少。在这种状况下怎么办呢?

这种状况还算是在领域自适应里比较容易处理的状况。如果你遇到的是有标注资料但资料量很少的情况,你可以用这些有标注的资料来微调你在源领域上训练出来的模型。这边所谓的微调,就跟你在做BERT时的行为很像,就是你已经有一个在源领域上训练好的模型,然后你拿目标领域数据只稍微跑两三个epoch就足够了。

在这种情境下,你需要注意的问题就是因为目标领域的数据量非常少,所以你要小心不要过拟合。也就是说你不要在目标领域的数据上跑太多的迭代。如果跑太多迭代可能会过拟合到这些少量的数据上,然后在你真正的测试集上就做不好。这是有可能的。

为了避免过拟合的情况,过去就有很多的解决方案,比如把学习率调小一点,让微调前和微调后的模型参数不要差很多,或者让微调前和微调后的模型,它的输入和输出的关系不要差很多等等。有很多不同的方法,这边我们就不细讲。

今天主要想跟大家分享的情境,也是我们作业要处理的情境是:我们在目标领域有大量的资料,但是这些资料是没有标注的。你的目标是有颜色的数字,你收集到了一大堆有颜色的数字图片,但是没有人标注每张图片里的数字是什么。

我们在作业里面要处理的就是遇到这种状况时,到底应该怎么解?像这种情境,其实是蛮符合你在真实系统上有可能会发生的情境。举例来说,你在实验室里训练了一个模型,想把它用在真实的场域里,你就把模型上线。确实有一些人来用,但你发现得到的结果很差,大家都嫌弃你的系统正确率很低。那怎么办?但这个时候你也许就可以用领域自适应的技术。因为你的系统已经上线,真的有人使用,所以你可以收集到一大堆的资料,只是这些资料是没有标注的。

现在的问题是,怎么用这些没有标注的资料,来帮助我们在源领域上训练出一个模型,让它可以用在目标领域上呢?


核心思想:特征提取器

这边最基本的想法是这个样子的:我们想要找一个特征提取器。这个特征提取器其实也是一个神经网络,它以一张图片作为输入,吐出一个特征向量。

虽然源领域和目标领域的图片表面上看起来不一样,但特征提取器会把它们不一样的部分拿掉,只抽取出它们共同的部分。所以,虽然从图片上看起来这两组图片(一个有颜色,一个没颜色)本来就很不一样,但我们期待这个特征提取器可以学到无视颜色这件事,把颜色的资讯滤掉。

今天不管是来自源领域的图片还是来自目标领域的图片,只要通过这个特征提取器后,它们得到的特征看起来是没有差异的,它们看起来有一样的分布。这样你就可以用这些特征训练一个模型,在源领域上训练一个模型,直接用在目标领域上。

接下来的问题就是,怎么找出这样一个特征提取器?

其实我们可以把一个一般的分类器分成特征提取器标签预测器两个部分。我们知道一个图像分类器就是输入一张图像,输出分类结果。假设这个图像分类器有10层,我们就可以说前5层算是特征提取器,后5层算是标签预测器。因为前5层,一张图像通过后输出就是一个向量(如果是CNN,输出其实是特征图,但特征图拉直也可以看作是一个向量)。这个向量再丢到标签预测器(后面5层),它会产生类别。

所以我们可以把前5层看作是特征提取器。你可能会问,为什么是前5层?为什么不是前4层、前3层、前2层、前1层?可以是前4、前3、前2、前1,这是你自己决定的。一个分类器里哪些部分算特征提取器,哪些部分算标签预测器,这是你自己决定的,这算是一个超参数,就跟神经网络架构要调一样。

如果你今天用领域对抗训练的方法(等一下会用的方法叫领域对抗训练),你要把分类器里的哪几层当作特征提取器,这个也要问你自己,这也是你自己要决定的。


领域对抗训练

我们现在要怎么训练这个特征提取器和标签预测器呢?

对于源领域的数据,源领域的数据是有标注的。我们就期待把源领域数据丢进去,跟训练一个一般的分类器一样,它通过特征提取器再通过标签预测器可以产生正确的答案。

但不一样的地方是,目标领域的这些数据,我们有一堆目标领域的数据,但这些数据是没有任何标注的。所以我们不能说把这些数据丢进去后,期待标签预测器输出什么数字,因为我们根本不知道标签预测器输出什么数字才是对的。

但是这些数据可以怎么被使用呢?这些数据的使用方式就是,我们把这些图片丢进这个图像分类器,然后我们把特征提取器的输出拿出来看。拿出来看以后,我们希望源领域的图片丢进去得到的特征,跟目标领域图片丢进去得到的特征,它们看起来要分不出差异。也就是说,源领域图片的特征我们用蓝色的点来表示,目标领域图片的特征我们用红色的点来表示,我们要这些蓝色的点跟这些红色的点分不出差异。

那怎么让蓝色的点跟红色的点分不出差异呢?这就要借由对抗训练的技术。等一下如果你觉得这一段讲得有点快也没有关系,等一下助教会再更详细地讲一次。

我们现在要做的事情就是训练一个领域分类器。这个领域分类器就是一个二元的分类器,它以特征提取器的输出作为输入。它要做的事情就是判断这个特征是来自于源领域还是来自于目标领域。

而特征提取器学习的目标就是要去想办法骗过这个分类器。听到“骗过”这件事,是不是让你脑中就浮现了GAN(生成对抗网络)?没错,领域对抗训练就非常像是GAN。你可以把特征提取器想成是生成器,把领域分类器想成是判别器。其实对抗训练最早的论文发表在2015年的ICML上,比那个GAN还要稍微晚一点点,不过他们几乎可以说是同时期的作品。在对抗训练那篇论文里是有引用到GAN那篇论文的,但那时候GAN那篇论文还没有上NeurIPS,所以只说“有一篇另外的论文提了个叫GAN的想法,他是技术报告放在网络上的,跟我的想法有点像”,所以他们算是一个同时期的作品。

但是讲到这边,领域对抗训练跟GAN还是有一点不一样的。因为在这个游戏里,对生成器(特征提取器)来说,它要骗过判别器(领域分类器)完全不需要花什么力气。有一个非常无脑的做法就是:你的特征提取器不管看到什么输入,永远都输出零向量就好了。看到什么输入,我都输出一个零向量。那对领域分类器来说,它完全不知道输入图像是什么,它永远都看到零向量,它就完全无法分辨这个向量来自于哪一个领域。但这显然不是我们要的状况。

如果特征提取器只会输出零向量,那样子等于根本就什么事都没有做是一样的。那这件事情会发生吗?其实这件事情是不会发生的。为什么?因为标签预测器也需要这个特征。标签预测器也需要这个特征让它可以去判断输入的图片属于哪一个类别。所以假设生成器(特征提取器)就直接“放大绝”,说今天不管输入什么样的图像,我输出都是零向量。那对于标签预测器来说,它就没有办法判断是哪一张图片。在这个情况下,因为特征提取器还是需要产生这个向量让标签预测器可以产生正确的图片,所以特征提取器就不能“放大绝”,它就不能看到什么东西永远都输出零向量。


数学形式化

这边我们用符号再稍微把我们刚才讲过的事情重新说得更清楚一点。

假设标签预测器的参数是 θ_y,领域分类器的参数是 θ_d,特征提取器的参数是 θ_f

源领域上的这些图像是有标签的,所以你可以算它们的交叉熵损失。根据它们的交叉熵损失定出一个损失函数 L_y

对于领域分类器而言,它要去想办法分辨源领域和目标领域的特征,它要去做一个二元的分类问题。这个分类问题有一个损失函数 L_d

我现在要去找一组参数 θ_y,它可以让 L_y 越小越好。我们要去找一组参数 θ_d,它可以让 L_d 越小越好。也就是说,标签预测器要做的事情就是让分类越正确越好;领域分类器做的事情就是让领域分类越正确越好。

特征提取器呢?特征提取器要做的事情是,它站在标签预测器这边,然后它要去“捅”领域分类器一刀,它要去做跟领域分类器相反的事情。所以这个特征提取器的损失是标签预测器的损失 L_y 去减掉领域分类器的损失 L_d。所以特征提取器的损失就是 L_y - L_d。你要去找一组参数 θ_f,它可以让 L_y - L_d 的值越小越好。

这个是最原始的领域对抗训练做法。但这真的是最好的做法吗?你可以想想看。详情我们就不细讲,这个留给大家自己思考、自己发掘。你想想看,假设领域分类器的工作是要把源领域和目标领域分开,是要看到这种特征知道它来自源领域,看到那种特征知道它来自目标领域。它要把这两组特征分开。而特征提取器如果它的损失是领域分类器损失直接加一个负号,那意味着什么?意味着说它要做的事情就是跟分类器相反:本来分类器看到这个图的特征说是源领域,现在特征提取器是要让分类器看到这个图以后,说是目标领域;看到那个图反过来要说是源领域。如果你这么做,不也是把两组特征分开了吗?我们说我们现在要做的事情是要让源领域和目标领域没有分别,但是你今天不管是用 L_d 还是负的 L_d,其实都是要把源和目标分开。你让 L_d 的值本来分类器让 L_d 越小越好,你现在是特征提取器要让 L_d 的值越大越好,其实也是把源和目标分开。所以这未必是最好的做法。至于怎么做可以做得更好,哎,这个留给大家慢慢思考。但这招是有用的。


原始论文结果

我们来看一下领域对抗训练最原始的论文,它做的结果怎么样呢?当年看到这个论文的时候,真的觉得结果非常惊人。

这边它做了4个任务。上半部是源领域的图片,这边其实都是数字辨识。下半部都是目标领域的图片。

如果今天是拿目标领域的图片来做训练,目标领域的图片来做测试,那结果像是这样,每个任务正确率都是90%以上。

但如果我们是源领域训练,目标领域测试,却在黑白的数字上训练,在彩色的数字上测试,结果直接“铲掉”(崩溃),没办法做了,结果直接“铲掉”。

如果加上领域对抗训练的话,结果怎么样呢?你会发现,本来如果只在黑白图片上训练,在彩色图片上测试,正确率57.5%。如果今天做了领域对抗训练,正确率就飙升到81%。在很多其他任务上进步量都挺明显的,59%到71%,74%到88.7%,进步量都是挺明显的。这个就是领域对抗训练。


领域对抗训练的局限与改进

刚才这整套想法还是有一个限制,有一个小小的问题。什么样小小的问题呢?我们来看看。

今天蓝色的圈圈跟蓝色的三角形代表源领域上的两个类别。我们当然可以找一个决策边界去把这两组类别分开来。对于目标领域上的数据,我们没有任何的标签,我们就只能用正方形来表示它。

我们今天训练的目标就是要让这些正方形(目标领域特征)的分布,跟圈圈三角形合起来(源领域特征)的分布越接近越好。但是什么叫做越接近越好呢?

左边这个情况,红色的点跟蓝色的点,它们也算是蛮“挨”在一起的,也算是分布蛮接近的。右边这个情况,红色的点跟蓝色的点,它们也算是分布蛮接近的。但是你觉得左边比较好,还是右边比较好呢?

大多数同学都觉得是右边。没错,很多人都觉得是右边。所以我们是不是应该要让右边的状况发生,而避免让左边的状况发生呢?怎么做呢?怎么让右边的状况发生,左边的状况不要发生呢?

也许一个可能的想法是,我们既然知道蓝色的圈圈跟蓝色的三角形的分界点在哪里,而这个分界点我们是知道的,那我们应该要让这些方形(虽然我们不知道它是哪一个类别)远离这个分界点。

怎么让方形远离这个分界点呢?在文献上就有很多不同的做法了。你可以参考一下文献,看看你觉得怎么做比较好。

举例来说,一个最简单的做法是说,今天我有很多无标签的图片。丢到特征提取器再丢到标签预测器以后,我不知道它是哪一个类别。但是我希望它离决策边界越远越好。那什么叫做离决策边界越远越好呢?如果今天输出的结果非常的集中,就叫做离边界远;如果今天输出的结果每一个类别都非常的接近,就叫做离边界近。所以我希望说把无标签的图像丢进特征提取器再丢进标签预测器,输出的结果它离决策边界越远越好,也就是说集中在某一个类别上。我们虽然不知道它应该算是哪一个类别,但至少应该集中在某一个类别上。那只是一种招数,并不是全部。

也可以参考一下文献,比如说有个知名的方法叫做 DIRT。这个DIRT,它论文里特别告诉你说这个要念“dirty”。大家都是模型命名大师,都会命名一个很有创意的名字。这个DIRTY是一个招数。还有另外一个招数叫 Maximum Classifier Discrepancy。如果你要在这个领域自适应作业里得到最好的结果的话,这些招数是不可或缺的。实际上这些招数怎么进行还挺复杂,这个就留给大家自己研究。


类别不一致问题

这边还有一个问题,什么样的问题呢?我们到目前为止,好像都假设说源领域跟目标领域它的类别都要是一模一样的。源领域假设是影像分类的问题,源领域有老虎、狮子跟狗,目标领域也应该要有老虎、狮子跟狗。但是真的一定会这样吗?目标领域是没有标签的,我们根本不知道目标领域里面有什么样的类别。

在这个图示里面,实心的圈圈代表源领域里面有的东西,虚线的圈圈代表目标领域里面有的东西。所以,有没有可能是源领域里面的东西比较多,目标领域里面的东西比较少呢?有没有可能是目标领域里面东西比较少,源领域东西比较多呢?有没有可能两者虽然有交集,但是各自都有独特的类别呢?这都是有可能发生的。

在这个前提之下,你说源领域和目标领域要把它们完全对齐在一起,听起来有点问题呀。因为举例来说,在这个情况里,你说你要让源领域的数据跟目标领域的数据,它们的特征完全匹配在一起,那意味着说你硬是要让老虎去变得跟狗像,或者是老虎硬是要变得跟狮子像,到时候你就分不出老虎这个类别了。听起来就是有问题的方法。

那怎么解决这个问题?怎么解决源领域跟目标领域它可能有不一样的标签的问题?那你可以参见 Universal Domain Adaptation 这篇文章。


特征空间的挑战

有同学问:如果特征提取器是CNN而不是线性层,那领域分类器的输入就是特征图拉直的向量。这样潜在空间学到的东西把两个领域分布抹平,会不会有影响?因为特征图本来就有空间关系,现在却硬是被拉直。

你说的非常对。真的,你说的非常对。就是特征提取器它是一个复杂的网络,然后我们硬是要把两个领域的东西拉在一起,会不会变成它

课程 P29:L18.1 - 强化学习三步概述 🧠

在本节课中,我们将学习强化学习的基本概念,并将其与我们熟悉的机器学习框架联系起来。我们将看到,尽管强化学习听起来很复杂,但它本质上仍然遵循“定义模型、定义损失、优化参数”这三个核心步骤。

强化学习是什么?

到目前为止,我们课程中讨论的几乎都是监督学习。在监督学习中,我们不仅需要告诉机器输入是什么,还需要告诉它正确的输出(标签)应该是什么。然而,强化学习面向的是另一类问题。

在强化学习中,当我们给机器一个输入时,我们并不知道最佳的输出应该是什么。例如,教机器学习下围棋。用监督学习的方法似乎也可以做:告诉机器看到当前棋盘时,下一步应该落在哪里。但问题是,哪一步才是最好的?人类可能也不知道。当你发现收集有标注的数据很困难,或者连人类都不知道正确答案是什么时,强化学习就可能派上用场。

在学习过程中,机器并非一无所知。虽然我们不知道正确答案,但机器会通过与环境的互动,得到一个称为“奖励”的信号,从而知道某个输出是“好”还是“不好”。通过这种互动和反馈,机器仍然可以学习到一个有效的模型。

强化学习的框架

在本课程一开始,我们就提到机器学习包含三个步骤。强化学习作为机器学习的一种,也遵循完全相同的三个步骤框架。

第一步:定义函数(模型)

在强化学习中,我们要找的函数被称为“智能体”或“策略”。这个函数的输入是环境给出的“观察”,输出是智能体要采取的“动作”。

公式表示:
动作 = 策略(观察)

这个策略函数可以是一个神经网络。例如,在玩太空入侵者游戏时,输入是游戏画面(像素),输出是三个可能动作(左移、右移、开火)的分数。这本质上与一个多类分类网络非常相似。

第二步:定义损失函数

在强化学习中,智能体与环境进行多轮互动。每采取一个动作,环境会给予一个即时“奖励”。我们将从游戏开始到结束所获得的所有奖励之和称为“总奖励”。

公式表示:
总奖励 R = r1 + r2 + ... + rT

我们的目标是最大化这个总奖励。在机器学习的语境下,我们通常最小化损失函数。因此,我们可以将 负的总奖励 (-R) 定义为我们的损失函数。

损失函数公式:
损失 L = -总奖励 R

第三步:优化参数

我们的优化目标是找到一组神经网络的参数,使得损失函数 L 最小化,即总奖励 R 最大化。

然而,强化学习的优化问题比标准的神经网络训练更复杂,主要因为:

  1. 智能体的输出具有随机性:动作是根据输出分数采样得到的,而非确定性的最大分数。
  2. 环境与奖励函数是“黑盒”:我们通常不知道环境内部的具体运作机制和奖励的计算细节,它们可能也具有随机性。

因此,我们不能直接使用标准的梯度下降法来优化参数。这就需要专门为强化学习设计的优化算法,例如我们接下来要介绍的策略梯度方法。

策略梯度方法的核心思想

在深入策略梯度之前,我们先思考如何控制一个智能体的行为。如何让智能体在看到特定观察时,采取或不采取某个特定动作?

这完全可以被视为一个分类问题。假设我们希望智能体在状态 S 下采取动作 A。我们可以将 S 视为输入,A 视为标签(正确答案),然后计算智能体输出与标签之间的交叉熵作为损失。通过最小化这个损失,我们就可以训练智能体在 S 下倾向于输出 A。

反之,如果我们希望智能体在状态 S 下避免动作 A,只需将损失定义为负的交叉熵,然后最小化它,这会使智能体的输出远离 A。

所以,只要我们能为每个“状态-动作”对分配一个分数,表明我们“多希望”智能体执行该动作,我们就可以像训练分类器一样训练智能体。

以下是定义损失函数的一般形式:

假设我们收集了 N 个训练数据 (s_i, a_i),并为每个数据对分配了一个分数 A_iA_i 为正表示鼓励该动作,为负表示不鼓励,其绝对值大小代表鼓励或不鼓励的程度。

损失函数公式(策略梯度的一种形式):
L = - (1/N) * Σ [ A_i * log( P(a_i | s_i) ) ]

其中,P(a_i | s_i) 是智能体在状态 s_i 下选择动作 a_i 的概率。

接下来的关键问题就变成了:

  1. 如何生成这些训练数据 (s_i, a_i)
  2. 如何为每个数据对设定合适的分数 A_i

这正是策略梯度等强化学习算法要解决的核心问题。

总结

本节课我们一起学习了强化学习的基本框架。我们了解到,强化学习与我们熟悉的机器学习三步骤一脉相承:首先定义一个参数化的策略函数(智能体),然后定义一个以总奖励为基础的损失函数,最后通过专门的优化方法(如策略梯度)来调整参数,使智能体获得更高的奖励。我们还初步探讨了策略梯度方法的思想,即通过为智能体在不同状态下采取的动作打分,来引导其学习更好的行为策略。在接下来的课程中,我们将深入探讨如何具体实现这些步骤。

机器学习任务攻略 🧭

在本节课中,我们将学习如何系统地分析和解决机器学习任务中常见的问题。课程将围绕一个核心攻略展开,帮助你诊断模型在训练和测试阶段表现不佳的原因,并提供相应的解决策略。

课程概述

机器学习任务通常遵循一个通用流程:使用包含输入X和输出Y的训练数据来训练模型,然后在只有输入X的测试数据上进行预测和评估。本攻略旨在帮助你在此流程中,当模型表现不理想时,能够有条理地定位问题并找到改进方向。

诊断与解决流程总览

当你在测试集(例如Kaggle排行榜)上的结果不满意时,不应直接针对测试集进行调整。正确的做法是遵循一个系统的诊断流程。

首先,你需要检查模型在训练数据上的损失(Loss)。这是所有诊断的起点。

第一步:检查训练损失

如果训练损失很大,说明模型在训练数据上就没有学好。这通常由两个原因导致:模型偏差(Model Bias)或优化失败(Optimization Issue)。

情况一:模型偏差 (Model Bias)

模型偏差意味着你的模型过于简单,其函数集合中根本不包含能够有效拟合数据的函数。

核心概念:你的模型是一个带参数θ的函数:f_θ(x)。通过调整θ,你可以得到一系列函数,构成一个函数集合。如果这个集合太小,其中可能没有一个函数的损失足够低。

解决方案

  • 增加输入特征(Feature)。
  • 使用更复杂的模型(例如,增加网络层数或神经元数量)。
  • 采用深度学习(Deep Learning)来增加模型弹性。

情况二:优化失败 (Optimization Issue)

优化失败意味着你的模型函数集合中存在表现好的函数,但梯度下降(Gradient Descent)等优化算法没能找到它。

核心概念:虽然存在一个参数θ*使得 f_θ*(x) 的损失很低,但优化过程卡在了局部最小值(Local Minima)或其他不利位置,最终找到的参数θ’ 对应的损失仍然很高。

如何判断是模型偏差还是优化失败?
一个有效的方法是进行模型对比

  1. 先训练一个较简单的模型(例如线性模型或浅层网络)。这些模型通常更容易优化。
  2. 再训练一个更复杂的模型(例如深层网络)。
  3. 如果复杂模型在训练集上的损失反而高于简单模型,那么很可能是优化出了问题。因为复杂模型的函数集合包含了简单模型的集合,理论上其性能下限不应比简单模型差。

解决方案:需要改进优化过程(例如,调整学习率、使用更好的优化器)。这部分内容将在后续课程中详细讲解。


上一节我们介绍了如何诊断和解决训练损失大的问题。接下来,我们假设训练损失已经足够小,来看看测试阶段的问题。

第二步:检查测试损失

当训练损失很小,但测试损失很大时,你很可能遇到了过拟合(Overfitting)

过拟合的原因:模型过于复杂(弹性太大),它不仅仅学到了数据中的普遍规律,还“记住”了训练数据中的噪声和特定细节。这导致它在训练集上表现完美,但在未见过的测试数据上表现糟糕。

想象一个例子:真实规律是一个二次曲线(虚线),训练数据(蓝点)是从曲线上采样得到的。一个非常复杂的模型可能会产生一条穿过所有蓝点但形状古怪的曲线(绿色实线),它在训练点上误差为0,但在测试点(橙点)上误差很大。

解决过拟合的方法
以下是几种常用的解决过拟合的策略:

  • 增加训练数据:这是最有效的方法。更多的数据可以限制模型的“自由发挥”,迫使它学习更通用的模式。
  • 数据增强 (Data Augmentation):在不能收集新数据时(如作业要求),可以根据领域知识对现有数据进行变换来创造新样本(例如,对图像进行左右翻转、裁剪)。
  • 给模型增加限制 (Reduce Model Complexity)
    • 使用更少的参数。
    • 共享参数(例如,使用卷积神经网络CNN而非全连接网络Fully Connected)。
    • 使用更少的特征。
    • 正则化 (Regularization):如L1/L2正则化,直接在损失函数中惩罚大的参数值。
    • 早停 (Early Stopping):在训练损失停止下降前停止训练。

注意:限制模型需要适度。如果限制过强(例如强制使用线性模型去拟合非线性数据),又会回到模型偏差的问题上,导致模型能力不足。


在解决了过拟合问题后,我们需要选择一个合适的模型。这引出了模型选择与评估的重要原则。

模型选择与交叉验证

模型复杂度与误差之间存在一个权衡。随着模型变复杂,训练误差会持续下降,但测试误差会先下降后上升(出现过拟合)。我们的目标是选择一个在测试集上误差最小的“中庸”模型。

关键问题:如何选择这个模型?绝对不要根据公开测试集(Public Test Set)上的分数直接选择模型!

为什么? 因为这会导致你“过拟合”公开测试集。即使是一个糟糕的模型,只要尝试次数足够多,也有可能在公开测试集上偶然得到一个好分数。但这并不能保证它在最终私有测试集(Private Test Set)上表现好,可能导致最终排名暴跌。

正确的做法是使用验证集 (Validation Set)

  1. 将原始训练数据划分为两部分:训练集(Training Set)和验证集(Validation Set)。课程代码中通常按90%/10%划分。
  2. 用训练集训练模型,用验证集评估模型表现。
  3. 根据验证集上的分数来选择最佳模型。
  4. 将选出的最佳模型在整个训练集(训练集+验证集)上重新训练,然后用于最终的测试集预测。

为了更稳定地评估,可以使用 N折交叉验证 (N-fold Cross Validation)

  1. 将训练数据平均分成N份。
  2. 依次将其中一份作为验证集,其余N-1份作为训练集,进行N次训练和验证。
  3. 计算每个模型在这N次验证中的平均分数,选择平均分数最高的模型。
  4. 用该模型在全部训练数据上重新训练,用于测试。


除了上述常见问题,还有一种特殊状况需要注意。

不匹配问题 (Mismatch)

不匹配是指训练数据和测试数据来自不同的分布。例如,用2020年的视频观看数据训练,预测2021年的数据,由于社会背景变化(如疫情),分布可能截然不同。

与过拟合的区别:对于不匹配问题,单纯增加更多训练数据(如果仍来自旧分布)并无帮助。

解决方案:需要深入理解数据产生过程,并采用专门处理领域自适应(Domain Adaptation)或分布偏移(Distribution Shift)的技术。这将在后续相关作业中探讨。

课程总结

本节课我们一起学习了机器学习任务的通用诊断攻略:

  1. 首要检查训练损失:若训练损失大,需判断是模型偏差(增加模型复杂度)还是优化失败(改进优化算法)。
  2. 再检查测试损失:若训练损失小但测试损失大,可能是过拟合。可通过增加数据、数据增强、正则化、降低模型复杂度等方法解决。
  3. 正确进行模型选择:使用验证集交叉验证来选择模型,避免根据公开测试集分数做决策,以防止过拟合公开测试集。
  4. 留意不匹配问题:当训练与测试数据分布不同时,需采用特殊处理方法。

这套“攻略”旨在帮助你建立系统化的问题排查思路,从而更有效地提升机器学习模型的性能。

🎮 强化学习课程 P30:L18.2 - Policy Gradient 与探索策略

在本节课中,我们将要学习强化学习中的策略梯度方法,并深入探讨如何评估一个动作的好坏,以及训练过程中的关键概念,如探索策略和On-policy/Off-policy学习。


📚 概述与核心概念

上一节我们介绍了强化学习的基本框架。本节中,我们来看看如何训练一个智能体,使其能够通过与环境互动来学习最优策略。

策略梯度方法的核心思想是直接优化策略本身。我们有一个参数化的策略网络,它接收状态 S,输出动作的概率分布。我们的目标是最大化智能体在整个互动过程中获得的累积奖励。

核心公式:策略梯度的目标函数是最大化期望累积奖励 J(θ)
J(θ) = E_τ~π_θ [Σ_t γ^t R_t]
其中 τ 代表一个轨迹(状态、动作、奖励的序列),π_θ 是我们的策略,γ 是折扣因子。


🔍 如何评估动作的好坏?

在监督学习中,我们有明确的标签。在强化学习中,我们需要自己定义“标签”,即评估每个动作 A 的好坏。以下是几种不同的评估方法。

版本0:即时奖励

最简单的评估方式是直接使用执行动作后获得的即时奖励 R_t 作为该动作的评分 A_t

  • A_t = R_t

问题:这种方法目光短浅,只考虑眼前利益,没有考虑动作对未来的长远影响。例如,在游戏中,移动瞄准可能没有即时奖励,但却是后续射击命中的关键。

版本1:累积奖励

更合理的方式是考虑动作对未来产生的所有影响。我们将执行动作 A_t 后获得的所有未来奖励加起来,得到累积奖励 G_t,并用它来评估动作。

  • G_t = R_t + R_{t+1} + ... + R_T
  • A_t = G_t

优点:解决了版本0的短视问题。例如,向右移动(R_t=0)后成功射击(获得正奖励),那么向右移动的累积奖励 G_t 也会是正的,从而被鼓励。

版本2:折扣累积奖励

在版本1中,遥远的奖励对当前动作的影响被等权看待。我们引入折扣因子 γ (0 < γ < 1),让越远的奖励权重越小。

  • G'_t = R_t + γ R_{t+1} + γ^2 R_{t+2} + ... + γ^{T-t} R_T
  • A_t = G'_t

公式G'_t = Σ_{n=t}^{T} γ^{n-t} R_n

版本3:标准化奖励

好坏是相对的。如果所有动作的累积奖励都是正数,那么即使某些动作相对较差,也会被鼓励。因此,我们需要进行标准化,让评分有正有负。

  • A_t = G'_t - b
    这里的 b 是一个基线,在强化学习文献中常称为 baseline。减去基线后,高于平均水平的动作得到正分,低于平均水平的得到负分。

🛠️ Policy Gradient 算法流程

以下是策略梯度方法的基本操作步骤:

  1. 随机初始化策略网络参数 θ_0
  2. 进入训练循环(假设进行 T 轮迭代):
    a. 收集数据:使用当前的策略 θ_i 与环境互动,记录下多个回合的状态 S 和动作 A
    b. 评估动作:使用上述任一版本(推荐版本2或3)计算每个动作的评分 A_t
    c. 定义损失:将评分 A_t 作为权重,定义损失函数。例如,对于采取的动作 a_t,其损失为 -log P(a_t|s_t) * A_t。目标是最大化好动作的概率,最小化坏动作的概率。
    d. 更新参数:计算损失关于参数 θ_i 的梯度,并使用梯度上升法更新一次参数,得到 θ_{i+1}
  3. 重复步骤2。

关键点:每次参数更新后,必须用新的策略重新收集数据。这是因为数据是由旧策略 θ_i 产生的,它只反映了旧策略的经验。新策略 θ_{i+1} 的行为模式可能不同,旧数据不一定适用于评估新策略。


🔄 On-policy 与 Off-policy 学习

根据用于训练的策略和用于收集数据的策略是否相同,可以分为两种学习方式。

On-policy 学习

  • 定义:用于与环境互动收集数据的策略(行为策略)和我们需要更新的策略(目标策略)是同一个
  • 特点:正如上述算法流程所示,每更新一次策略,就必须用新策略重新收集数据,训练效率较低。

Off-policy 学习

  • 定义:行为策略和目标策略是不同的。目标策略可以学习其他策略(如旧策略或探索性更强的策略)收集到的经验。
  • 优点:可以重复利用历史数据,大幅提升数据利用效率和训练速度。
  • 经典方法PPO (Proximal Policy Optimization) 是一种强大且常用的Off-policy方法。它的核心思想是,在利用旧策略数据更新新策略时,要对更新幅度加以约束,防止新策略偏离旧策略太远而导致训练不稳定。

比喻:向经验丰富的人(行为策略)学习,但要考虑自身条件(目标策略)的差异,不能完全照搬。


🧭 探索的重要性

在训练过程中,策略的随机性(探索)至关重要。

  • 为什么需要探索?:如果策略的探索性不足,某些动作可能永远不被尝试,我们就无法知道这些动作的好坏。例如,如果智能体从未尝试“开火”,它就永远学不会这个关键动作。
  • 如何促进探索?
    • 在策略网络的输出概率分布上,鼓励其更大(更均匀)。
    • 直接在策略网络的参数上添加噪声,使每次互动产生不同的行为。

只有充分探索环境,才能收集到多样化的数据,从而学习到全面而鲁棒的策略。


📝 总结

本节课中我们一起学习了强化学习的策略梯度方法。

  1. 我们首先探讨了如何评估动作好坏的几种方式,从简单的即时奖励到更合理的折扣累积奖励,并强调了标准化的重要性。
  2. 接着,我们梳理了 Policy Gradient 的基本算法流程,理解了其“收集数据 -> 评估 -> 更新 -> 重新收集”的循环特点,并解释了为何需要频繁重新收集数据。
  3. 然后,我们区分了 On-policy 和 Off-policy 学习,并介绍了PPO这类Off-policy方法能提高数据利用率。
  4. 最后,我们指出了探索在训练中的关键作用,没有充分的探索,智能体可能无法发现最优策略。

策略梯度为我们提供了一种直接优化策略的强大工具,是深度强化学习领域的基石之一。

强化学习课程 P31:L18.3 - Actor-Critic 概述 🎯

在本节课中,我们将学习强化学习中的 Actor-Critic 方法。我们将首先介绍 Critic 的概念及其作用,然后讲解如何训练 Critic,最后探讨如何将 Critic 与 Actor 结合,以更有效地训练智能体。


什么是 Critic?🤔

Critic 的核心任务是评估一个 Actor 的好坏。具体来说,给定一个 Actor(其参数为 θ),Critic 需要评估当该 Actor 观察到某个状态(例如游戏画面)时,预期能获得多少累积奖励。

Critic 有多种形式。有些 Critic 仅根据当前状态进行判断,有些则同时考虑状态和 Actor 采取的动作。为了更具体地理解,我们将介绍一个在实际作业中会用到的重要概念:价值函数(Value Function)

价值函数(Value Function)

价值函数用 V^θ(s) 表示。其输入是状态 s(例如当前游戏画面),输出是一个标量值。上标 θ 表示这个价值函数是针对参数为 θ 的特定 Actor 进行评估的。

这个标量值的含义是:当 Actor θ 观察到状态 s 后,预期能获得的 折现累积奖励(Discounted Cumulative Reward)。折现累积奖励的计算公式为:

G = R_t + γR_{t+1} + γ²R_{t+2} + ...

其中,γ 是折扣因子(0 ≤ γ ≤ 1),用于衡量未来奖励的当前价值。价值函数的目标是“未卜先知”,即在游戏未结束前,仅根据当前状态 s 来预测 Actor 的长期表现。

需要注意的是,价值函数的输出值与所评估的 Actor 密切相关。相同的状态,不同的 Actor 会得到不同的价值评估。


如何训练 Critic?🔧

训练价值函数主要有两种常用方法:蒙特卡洛方法(Monte Carlo, MC)时序差分方法(Temporal Difference, TD)

蒙特卡洛方法(MC)

MC 方法非常直观。我们让 Actor 与环境进行多轮互动,收集游戏记录。对于每一轮游戏中的每个状态 s_t,我们都能计算出实际获得的折现累积奖励 G_t。这些数据对 (s_t, G_t) 就构成了训练资料。训练目标是让价值函数的预测值 V^θ(s_t) 尽可能接近实际值 G_t

时序差分方法(TD)

TD 方法则不需要玩完整场游戏。它只需要观察到连续的两个状态 s_ts_{t+1},以及其间的即时奖励 r_t,就可以更新价值函数。

根据定义,V^θ(s_t)V^θ(s_{t+1}) 之间存在以下关系:

V^θ(s_t) = r_t + γ * V^θ(s_{t+1})

因此,我们可以构造训练目标:让 V^θ(s_t) - γ * V^θ(s_{t+1}) 尽可能接近观察到的即时奖励 r_t。这种方法特别适用于回合很长或永不结束的游戏。

MC 与 TD 的差异

MC 和 TD 方法基于不同的假设,即使对同一组数据,计算出的价值函数也可能不同。MC 严格依赖于观察到的具体结果,而 TD 则假设状态转移是独立的,更侧重于期望值。


如何将 Critic 用于训练 Actor?🤝

上一节我们介绍了 Actor 的训练方法:通过计算每个“状态-动作”对 (s_t, a_t) 的优势分数 A_t 来更新策略。A_t 衡量了在状态 s_t 下执行动作 a_t 的相对好坏。

一个关键问题是:如何设定基准值 b 来进行归一化?一个合理的选择是使用价值函数的输出,即设 b = V^θ(s_t)

优势函数(Advantage Function)

因此,优势分数 A_t 可以定义为:

A_t = G_t - V^θ(s_t)

  • G_t 是在 s_t 下执行 a_t 后实际获得的(采样)累积奖励。
  • V^θ(s_t) 是在 s_t 下,随机采取动作所能获得的(平均)期望奖励。

如果 A_t > 0,说明动作 a_t 优于平均动作;如果 A_t < 0,则说明劣于平均动作。

为了减少采样的方差,我们通常使用 TD 思想来定义优势函数:

A_t = r_t + γ * V^θ(s_{t+1}) - V^θ(s_t)

这个公式直接计算了执行动作 a_t 所带来的期望奖励增量,是 Actor-Critic 方法中常用的核心公式。


实用技巧:网络参数共享 💡

在实现 Actor-Critic 时,Actor 和 Critic 都是神经网络,且输入相同(都是状态 s)。因此,一个实用的技巧是让它们共享前面的网络层(例如用于处理图像输入的卷积层),只在最后的分支上产生不同的输出:

  • Actor 分支输出每个动作的概率分布。
  • Critic 分支输出一个标量价值 V^θ(s)

这样做可以有效减少参数量,并让特征提取更高效。


扩展与总结 📚

本节课我们重点介绍了 Actor-Critic 框架,它通过引入 Critic(价值函数)来更稳定、高效地评估和指导 Actor(策略)的学习。

值得注意的是,强化学习中还有一个重要的系列方法是基于 价值函数 直接选择动作,例如著名的 DQN(Deep Q-Network) 及其众多变体(如集成多种技巧的 Rainbow 算法)。这些内容我们将在其他课程中探讨。

本节课总结

在本节课中,我们一起学习了:

  1. Critic(价值函数) 的概念与作用:评估给定状态下 Actor 的预期回报。
  2. 训练 Critic 的两种方法:蒙特卡洛(MC)时序差分(TD)
  3. 如何利用 Critic 计算 优势函数(A_t),从而更有效地训练 Actor。
  4. Actor-Critic 的实用实现技巧:网络参数共享

通过结合 Actor 和 Critic,我们能够构建出更强大、更稳定的强化学习智能体。

强化学习课程 P32:L18.4 - 奖励塑形:当奖励稀少时怎么办?🚀

在本节课中,我们将要学习一个名为 奖励塑形 的重要概念。当强化学习任务中的奖励信号非常稀疏(例如,多数时候奖励为0,只有极少数关键步骤才有奖励)时,智能体将难以学习。本节课将探讨如何通过设计额外的奖励来引导智能体更有效地学习。

什么是奖励塑形?🤔

到目前为止,我们学习的方法是让智能体与环境互动,收集奖励,并利用这些奖励计算优势分数 A。有了优势分数,我们就可以更新策略,教导智能体该做什么、不该做什么。

然而,在强化学习中,我们可能会遇到一种棘手的情况:奖励非常稀疏。如果奖励几乎总是0,只有在极低概率下才能获得一个巨大的奖励,那该怎么办?

这意味着,无论智能体采取什么行动,得到的奖励都差不多(都是0)。因此,计算出的优势分数 A 对每个动作而言也几乎相同。既然执行任何动作都没有显著差异,智能体就无法有效地学习和改进策略。

稀疏奖励的挑战与实例 🎲

谈到稀疏奖励问题,有人可能会想到围棋。在围棋中,每落一子通常没有即时奖励,只有在整盘游戏结束时,赢了得到正奖励,输了得到负奖励。但相较于其他任务,围棋的奖励问题还算“温和”。

一个更典型的例子是教机械手臂拧螺丝。合理的奖励定义是:成功拧入螺丝获得正奖励,否则奖励为0。但问题在于,初始时机械手臂的参数是随机的,它只是在空中随意挥舞。除非它极其巧合地拿起螺丝并成功拧入,否则它做的任何动作得到的奖励都是0。这与围棋不同,围棋玩完一整局至少能获得明确的最终奖励。

那么,遇到这种状况时,我们该怎么办呢?

解决方案:奖励塑形 🛠️

一个有效的解法是:我们设法提供额外的奖励来引导智能体学习。也就是说,在原始的真实奖励(即我们希望智能体最大化的目标)之外,我们再定义一些额外的奖励。这些额外奖励旨在帮助智能体更顺畅地学习。这种做法就叫做奖励塑形

人类其实也非常擅长进行“奖励塑形”。例如,在教育中,我们不会只告诉学生“博士毕业才能获得奖励”。相反,我们会设置一系列中间目标:修完一门课得到鼓励,完成一个小项目得到表扬,发表一篇会议论文得到认可……通过这些逐步的“奖励”,最终引导学生达成获得博士学位这个终极目标。

实战案例:在《毁灭战士》中应用奖励塑形 🎮

接下来,我们看一个奖励塑形在强化学习中实际应用的例子,以第一人称射击游戏《毁灭战士》为例。

在《毁灭战士》的AI竞赛中,仅凭游戏内置的奖励(杀敌加分、被杀扣分)很难训练出强大的智能体。因此,当年的冠军队伍就使用了奖励塑形技术。他们定义了一系列额外的奖励来引导智能体:

以下是他们定义的部分额外奖励规则:

  • 扣血惩罚:在游戏中,扣血本身不会扣分,只有死亡才会。但为了让智能体更快地学会避免受伤,直接规定扣血就给予负奖励。
  • 弹药与医疗包:损失弹药扣分,捡到弹药或医疗包加分。这些行为在原始游戏中不影响分数。
  • 禁止原地不动:如果智能体总是待在原地,则扣分。这是为了防止智能体在初期因外出容易被杀而选择“躺平”,因为待在原地至少奖励为0。
  • 鼓励移动:智能体每移动一步,就给予一个非常小的正奖励(例如 9e-5)。
  • “活着扣分”:这是一个非常有趣的设定。智能体每存活一帧,就会被扣一点分。这听起来有违常理,但目的是防止智能体学会“边缘OB”(即一直躲藏、转圈、避免与敌人交战)。为了迫使智能体积极与敌人交战以结束游戏(从而停止扣分),必须加入这个奖励。

从这些例子可以看出,奖励塑形需要开发者基于对任务和环境的深刻理解来设计。它是一把双刃剑,设计得好可以大幅加速学习,设计得不好则可能引导智能体学习错误的行为。

奖励塑形的注意事项 ⚠️

再举一个机械臂插板的例子。任务目标是将蓝色板子插到棍子上。一个直觉的奖励塑形方法是:蓝色板子离棍子越近,奖励越大

但仔细思考后会发现,仅凭“距离近”是不够的。观察下图,右侧两种情况中,机械臂也让板子靠近了棍子,但却是从侧面接近或撞击棍子,这无法达成最终“插入”的目标。

# 伪代码示例:一个可能不够完善的奖励塑形
reward_shaping = -distance(blue_block, peg) # 距离越近,惩罚越小(奖励越大)

如果只用这个简单的距离作为额外奖励,智能体可能会学到一些奇怪但能“骗”到高奖励的策略,而不是我们真正想要的行为。因此,使用奖励塑形时必须谨慎,需要对问题有足够深入的理解。

进阶方法:基于好奇心的奖励塑形 🧐

在奖励塑形中,有一个特别知名且有趣的方法叫做 基于好奇心的奖励塑形。其核心思想是:给智能体加上“好奇心”,鼓励它去探索未知。

具体做法是,在原始奖励之外,增加一个奖励:如果智能体在探索过程中看到了新的、未曾预料到的事物,就给予它正奖励

这里有一个关键点:所谓的“新”必须是有意义的新,而不是无意义的噪声变化。例如,如果环境背景是电视雪花屏(不断随机变化),智能体可能会因为单纯“看雪花”而不断获得“看到新东西”的奖励,从而停止对真实环境的探索。因此,在实际算法中(如ICLR 2017的这篇论文),需要设计机制来过滤掉这种无意义的“新”。

该论文有一个令人印象深刻的演示:让智能体玩《超级马里奥》,甚至不告诉它“通关”是最终目标,只赋予它“好奇心”(探索新东西获得奖励)。仅凭这一点,智能体就学会了通过一些关卡。因为《超级马里奥》是横向卷轴游戏,要看到新场景就必须向右移动,这恰好与通关的目标方向一致。

总结 📚

本节课中,我们一起学习了奖励塑形这一重要技术。

  • 我们首先认识了稀疏奖励问题,它会导致智能体因缺乏学习信号而无法进步。
  • 接着,我们学习了奖励塑形的核心思想:通过设计额外的、引导性的奖励,来帮助智能体在稀疏奖励环境中更有效地学习。
  • 我们通过《毁灭战士》AI竞赛的实际案例,分析了如何具体设计这些额外奖励,并了解到这需要开发者对任务有深入理解。
  • 最后,我们介绍了一种特殊的奖励塑形方法——基于好奇心的奖励塑形,它通过鼓励探索来应对稀疏奖励,但需要注意区分“有意义的探索”和“无意义的噪声”。

奖励塑形是强化学习实践中一项强大的工具,它能将人类知识注入学习过程,引导智能体朝着我们希望的方向前进。然而,它也需要精心设计,以避免智能体学到“捷径”或错误行为。

课程 P33:L18.5 - 从示范中学习:逆向增强式学习 🧠

在本节课中,我们将要学习当增强式学习(Reinforcement Learning)环境中没有明确的奖励(Reward)时,如何通过专家的示范来训练智能体(Agent)。我们将重点介绍两种方法:行为克隆(Behavior Cloning)和逆向增强式学习(Inverse Reinforcement Learning)。


为何有时没有奖励?

在之前的课程中,我们假设环境会提供奖励信号,尽管有时奖励非常稀疏(Sparse),需要进行奖励塑形(Reward Shaping)。然而,在真实世界中,定义明确的奖励函数可能非常困难。

例如,在训练自动驾驶汽车时,如何量化奖励?礼让行人加100分还是1000分?闯红灯扣50分还是50000分?这些数值难以确定。此外,人为设计的奖励函数可能导致智能体出现意想不到的、甚至有害的行为,例如电影《机械公敌》中机器人将人类囚禁起来的“神逻辑”,或者训练机械臂摆盘子时,智能体为达成目标而摔碎盘子。

因此,当没有预定义奖励时,我们需要其他方法来指导智能体学习。


模仿学习(Imitation Learning)简介

在没有奖励的情况下,一种方法是模仿学习(Imitation Learning)。智能体仍然可以与环境互动,接收观测(Observation)并做出动作(Action),但不会从环境获得奖励。取而代之的是,我们拥有专家示范(Expert Demonstrations),通常来自人类专家与环境的互动记录。

例如:

  • 训练自动驾驶时,人类司机的行驶记录就是专家示范。
  • 训练机械臂时,人类手动引导机械臂完成一次倒水或摆盘动作,这也是专家示范。

我们记专家的示范轨迹为 \(\hat{\tau}\)。模仿学习的目标就是利用这些示范 \(\hat{\tau}\) 以及智能体与环境的互动来进行学习。


方法一:行为克隆(Behavior Cloning)

一个直观的想法是将其视为监督学习(Supervised Learning)问题:让智能体直接模仿专家的动作。

具体做法:
我们拥有数据集 \({(s_1, \hat{a}_1), (s_2, \hat{a}_2), ...}\),其中 \(s_t\) 是状态,\(\hat{a}_t\) 是专家在该状态下采取的动作。我们训练一个策略网络 \(\pi_\theta\),使其在输入状态 \(s_t\) 时,输出的动作 \(a_t\) 尽可能接近 \(\hat{a}_t\)。损失函数可以定义为:

loss = MSE(a_t, \hat{a}_t)  # 均方误差损失

行为克隆可能遇到的问题:

  1. 状态分布不匹配(State Distribution Mismatch):专家示范通常只包含“成功”的轨迹。智能体在训练中从未见过“接近失败”的状态(例如,汽车即将撞墙),因此当它自己在实践中遇到这些陌生状态时,可能不知道如何正确处理。
  2. 盲目模仿无关行为:智能体会模仿专家的所有行为,包括一些个人习惯或与任务无关的 idiosyncrasies(例如,老师讲课时习惯性的手势)。这可能导致效率低下或出现多余动作。
  3. 智能体能力有限:当智能体的能力(例如模型容量)无法完全复现专家所有行为时,它可能只学到部分特征。如果恰好学到的是无关特征(如“不修边幅”),而非核心技能(如“有创意”),则效果会很差。

上一节我们介绍了直接模仿专家行为可能带来的问题。接下来,我们看看一种更鲁棒的方法。


方法二:逆向增强式学习(Inverse Reinforcement Learning, IRL)

逆向增强式学习的核心思想是:我们不直接模仿专家的动作,而是尝试从专家的示范中反推出其背后隐含的奖励函数(Reward Function)

基本框架:

  1. 输入:环境(Environment)和专家的示范轨迹 \(\hat{\tau}\)
  2. 过程:运行逆向增强式学习算法,其目标是找到一个奖励函数 \(R\)。这个 \(R\) 需要满足一个关键条件:专家示范轨迹所获得的累计奖励,应高于智能体策略产生的任何其他轨迹
  3. 输出:学得的奖励函数 \(R\)
  4. 应用:得到 \(R\) 后,我们就可以使用标准的增强式学习算法(如PPO、DQN)来训练一个优化该奖励函数的智能体。

一个简单的奖励函数(如“生存”),也可能衍生出非常复杂和多样的智能体行为。


IRL 的算法流程

以下是逆向增强式学习的一个典型迭代流程:

  1. 初始化:随机初始化一个智能体策略 \(\pi\)
  2. 迭代以下步骤
    • a. 收集轨迹:让当前智能体 \(\pi\) 与环境互动,收集其轨迹 \(\tau\)
    • b. 更新奖励函数 \(R\):学习一个新的奖励函数 \(R\),使得:
      • \(R(\hat{\tau}) > R(\tau)\) (专家轨迹得分高于智能体轨迹)
    • c. 更新智能体策略 \(\pi\):使用标准RL算法,更新策略 \(\pi\) 以最大化新奖励函数 \(R\) 下的期望回报。
  3. 循环:重复步骤2,直到奖励函数 \(R\) 和策略 \(\pi\) 收敛。

图像化理解:
可以将智能体 \(\pi\) 看作生成器(Generator),奖励函数 \(R\) 看作判别器(Discriminator)。判别器 \(R\) 的任务是给专家数据 \(\hat{\tau}\) 打高分,给生成器数据 \(\tau\) 打低分;生成器 \(\pi\) 的任务是生成能骗过判别器(即获得高分)的轨迹。这形成了一个与生成对抗网络(GAN)非常相似的对抗学习框架。


IRL 的应用实例

逆向增强式学习在机器人操控领域特别有用,因为它避免了为复杂任务手工设计奖励函数的困难。

以下是其应用方式:

  1. 人类专家通过手动引导(如抓着机械臂)或遥控,演示20次“摆盘子”或“倒水”的任务。
  2. 系统使用IRL从这20次示范中,学习到完成该任务的隐含奖励标准(例如,盘子需平稳到达指定位置,水要倒入杯中)。
  3. 智能体基于学到的奖励函数,通过RL自我训练,最终学会完成任务,甚至可能比人类演示做得更快、更稳。

更前沿的研究甚至可以让智能体通过“想象”目标画面(自己创造目标),并练习达成这些目标,从而获得一种通用的“实现指定目标”的能力。


常见问题解答

Q: 使用IRL方法,智能体的表现能否超越人类专家?
A: 可以。因为IRL的本质是学习奖励函数,而非单纯模仿动作。我们可以在学到的奖励函数基础上,添加额外的优化目标(例如“速度更快”、“能耗更低”)。智能体在优化这个组合奖励函数时,就有可能找到比原始人类示范更优的策略,实现“青出于蓝而胜于蓝”。


总结 🎯

本节课中我们一起学习了在没有明确奖励函数的情况下进行增强式学习的两种主要方法:

  1. 行为克隆(Behavior Cloning):将问题简化为监督学习,直接模仿专家的状态-动作对。这种方法简单直接,但容易受到状态分布不匹配和盲目模仿等问题的影响。
  2. 逆向增强式学习(Inverse Reinforcement Learning, IRL):其核心思想是从专家示范中反推其遵循的奖励函数。它通过一个类似GAN的对抗过程,迭代地优化奖励函数和智能体策略。这种方法更鲁棒,能够学习任务背后的本质目标,并且有潜力让智能体表现超越专家。

通过这两种技术,我们可以让智能体通过观察和推理来学习复杂任务,大大降低了为真实世界任务设计奖励函数的门槛。

posted @ 2026-01-30 15:41  绝不原创的飞龙  阅读(2)  评论(0)    收藏  举报