# 其它形式的学习

## 10.1 度量学习（Metric Learning)

我曾提到过衡量两个特征向量之间相似性（或差异）最常用的度量是欧氏距离和余弦相似性。这种度量选择似乎是符合逻辑，但实际上是随意的，就像在线性回归中选择平方误差一样。事实上，一个指标可以比另一个指标性能更好，取决于特定的数据集。也就是说，没有一种指标是永远完美的。

您可以创建更适合您的数据集的指标。然后可以将您的度量标准集成到任何需要度量标准的学习算法中，例如 k-means 或 kNN。您如何在不尝试所有可能性的情况下知道哪个方程式是一个好的度量标准？您可以用数据训练您的度量标准。

比如两个向量 x 和 x` 间的欧氏距离：

$$
d\left(\mathbf{x}, \mathbf{x}^{\prime}\right) \stackrel{\mathrm{def}}{=} \sqrt{\left(\mathbf{x}-\mathbf{x}^{\prime}\right)^{2}}=\sqrt{\left(\mathbf{x}-\mathbf{x}^{\prime}\right)\left(\mathbf{x}-\mathbf{x}^{\prime}\right)}
$$

我们可以稍微修改此指标以使其可参数化，然后从数据中学习这些参数。
请考虑以下修改:

$$ d_{\mathbf{A}}\left(\mathbf{x},\mathbf{x}^{\prime}\right)=\left\|\mathbf{x}-\mathbf{x}^{\prime}\right\| \mathbf{A} \stackrel{\mathrm{def}}{=} \sqrt{\left(\mathbf{x}-\mathbf{x}^{\prime}\right)^{\top} \mathbf{A}\left(\mathbf{x}-\mathbf{x}^{\prime}\right)} $$

其中 A 是 D× D 矩阵。假设 D = 3.如果我们让 A 为单位矩阵，

$$
\mathbf{A} \stackrel{\operatorname{def}}{=}\left[\begin{array}{lll}{1} & {0} & {0} \\ {0} & {1} & {0} \\ {0} & {0} & {1}\end{array}\right]
$$

则 dA 为欧几里德距离。如果我们有一个通用的对角矩阵，像这样，

$$
\mathbf{A} \stackrel{\operatorname{def}}{=}\left[\begin{array}{lll}{2} & {0} & {0} \\ {0} & {8} & {0} \\ {0} & {0} & {1}\end{array}\right]
$$

那么不同的维度在度量标准中具有不同的重要性。（在上面的例子中，第二个维度是度量计算中最重要的。）更一般地说，为了表示一个度量，两个变量的函数必须满足三个条件:

$$
\begin{array}{ll}{\text { 1. } d\left(\mathbf{x}, \mathbf{x}^{\prime}\right) \geq 0} & {\text { nonnegativity }} \\ {\text { 2. } d\left(\mathbf{x}, \mathbf{x}^{\prime}\right) \leq d\left(\mathbf{x}, \mathbf{x}^{\prime}\right)+d\left(\mathbf{x}^{\prime}, \mathbf{z}\right)} & {\text { triangle inequality }} \\ {\text { 3. } d\left(\mathbf{x}, \mathbf{x}^{\prime}\right)=d\left(\mathbf{x}^{\prime}, \mathbf{x}\right)} & {\text { symmetry }}\end{array}
$$

为了满足前两个条件，矩阵必须是半正定的。你可以看到一个半正定矩阵作为非负实数对矩阵的概念的推广。任何半正定矩阵 M 满足：

$$
\mathbf{z}^{\top} \mathbf{M z} \geq 0
$$

上述性质遵循半正定矩阵的定义。可以在本书的配套网站上找到半正定矩阵满足第二个条件证明。
为了满足第三个条件，我们可以简单地计算  $\left(d\left(\mathbf{x}, \mathbf{x}^{\prime}\right)+d\left(\mathbf{x}^{\prime}, \mathbf{x}\right)\right) / 2$

假设我们有一个未标注数据集 $\mathcal{X}=\left\{\mathbf{x}_{i}\right\}_{i=1}^{N}$。为了构建我们的度量学习问题的训练数据，我们手动创建两组。第一个数据集 S 包含这样的样本 $\left(\mathbf{x}_{i}, \mathbf{x}_{k}\right)$ ，其中 $x_{i}$ 和 $x_{k}$ 相似（从我们的主观角度来看）。第二个数据集 D 包含样本（xi，xk），其中 $x_{i}$ 和 $x_{k}$ 不相似。

为了从数据中训练参数矩阵 A，我们希望找到一个半正定矩阵 A 来解决以下优化问题：

$$
\min _{\mathbf{A}} \sum_{\left(\mathbf{x}_{i}, \mathbf{x}_{k}\right) \in \mathcal{S}}\left\|\mathbf{x}-\mathbf{x}^{\prime}\right\|_{\mathbf{A}}^{2} \text { such that } \sum_{\left(\mathbf{x}_{i}, \mathbf{x}_{k}\right) \in \mathcal{D}}\left\|\mathbf{x}-\mathbf{x}^{\prime}\right\| \mathbf{A} \geq c
$$

c 为正常数（可以是任何数）。

这种优化问题的解决方案是通过梯度下降和修改来确定的，确保找到的矩阵A是半正定的。本书未提及具体的算法描述，以供进一步阅读。您应该知道还有许多其他方法可以学习度量，包括非线性和基于核的方法。但是，本书中介绍的方法可以为大多数实际问题提供良好的结果。

![10-1](https://github.com/apachecn/ml-book-100-zh/blob/master/doc/img/10-1.png)

## 10.2 排序学习（Learning to Rank)

排序学习是一个有监督的学习问题。其中，使用排序学习的一个常见问题是搜索引擎为查询返回的搜索结果的优化。在搜索结果排名优化中，N 个样本的训练集中一个带标签的样本 $\mathcal{X}_{i}$ 是关于文档大小 $r_{i}$ 的排序集合（标签是文档的排名）。一个特征向量表示集合中的每个文档。学习的目标是确定排序函数，其输出的值可用于对文档进行排名。对于每个训练样本，一个理想的函数的输出应该根据给出的标签包含相同排名的文档。

 每个样本 $\mathcal{X}_{i}$， i = 1，...，N， 是一个带标签的特征向量：$\mathcal{X}_{i}=\left\{\left(\mathbf{x}_{i, j}, 3 i, j\right)\right\}_{j=1}^{r} .$  特征向量 $\mathbf{x}_{i, j}$ 代表着文档  $j=1, \ldots, r_{i}$ 。比如， $\mathbf{x}_{i, j}^{(1)}$ 可以表示文本的近期情况， $\mathbf{x}_{i, j}^{(2)}$ 将反映是否可以在文档标题中找到查询的单词， $\mathbf{x}_{i, j}^{(1)}$ 代表着文档的大小，等等。而标签 $y_{i, j}$ 代表着排名 $\left(1,2, \ldots, r_{i}\right)$ 或分数。例如，分数越低，文档应该排名越高。

 解决这种学习问题有三种主要方法：单文档方法（Pointwise），文档对方法（Pairwise），文档列表方法（Listwise）。

 单文档方法将每个样本转化为多个样本：每个文档对应一个样本。学习问题是标准的监督学习问题，无论是线性回归还是逻辑回归。单文档方法中的每个样本 $(\mathbf{x}, y)$ ，X 是一些文档的特征向量，y 是初始分数（如果 $y_{i, j}$ 是分数）或从排名中获得的合成分数（排名越高，合成分数越低）。在这种情况下可以使用任何监督学习算法。解决方案通常是不完美的。原则上，这是因为每个文档被孤立地考虑，而原始排名（由原始训练集的标签 $y_{i, j}$ 给出）会优化其在整个文档集的位置。例如，如果我们已经在某些文档集合中给予某个维基百科页面高排名，我们就不会对同一查询的另一个维基百科页面给出高排名。

文档对方法中存在的问题也是将文档孤立地考虑，然而，在这种情况下，每次会考虑一对文档。给定一对文档 $\left(\mathrm{x}_{i}, \mathrm{x}_{k}\right)$ ，我们想要建立一个模型 f，将给定 $\left(\mathrm{x}_{i}, \mathrm{x}_{k}\right)$ 作为输入，如果 $\mathrm{x}_{i}$ 要比 $\mathrm{x}_{k}$ 排名更高,则输出接近 1 的值。否则，f 输出一个接近 0 的值。在测试时，给定一个模型，通过聚合 X 中所有文档对的预测获得未标记的样本 X 的最终排名。这种方法比单文档方法更好，但仍远非完美。

最先进的排序学习算法，例如 LambdaMART，实现了文档列表方法。在列表方法中，我们尝试直接在一些反映出排名质量的度量上优化模型。评估搜索结果排名有各种指标，包括精确度和召回率。将精确度和召回率相结合的一种常用度量称为平均精度（MAP）。

要定义 MAP，让我们让评委（谷歌称那些人是 rankers ）检查查询的搜索结果集合，并为每个搜索结果分配相关性标签。标签可以是二进制的（1 表示“相关”，0 表示“不相关”）或某种尺度，例如 1 到 5：值越高，文档与搜索查询的相关性越高。让我们的评委为 100 个查询的集合构建相关标签。现在，让我们测试一下这个系列的排名模型。我们的模型对某些查询的精度由下式给出：

$$
\text { precision }=\frac{ |\{\text { relevant documents }\} \cap\{\text { retrieved documents }\} |}{ |\{\text { retrieved documents }\} |}
$$

这里的 |·| 代表数量。

平均精度度量标准 AveP 定义为搜索引擎为查询 q 返回的排序文档集合：

$$
\operatorname{AveP}(q)=\frac{\sum_{k=1}^{n}(P(k) \times \operatorname{rel}(k))}{ |\{\text { relevant documents }\} |}
$$

其中 n 是检索到的文档的数量。

$P(k)$ 表示由我们的查询排名模型返回的前 k 个搜索结果计算的精度，如果排名 k 的是相关文档（根据评判），则 $rel(k)$ 是等于 1 的指标函数，否则，函数值为零。最后，给出大小为 Q 的搜索查询集合的 MAP，

$$
\mathrm{MAP}=\frac{\sum_{q=1}^{Q} \operatorname{AveP}(\mathrm{q})}{Q}
$$

现在我们回到 LambdaMART。该算法实现了文档对方法，并使用梯度增强来训练排序函数 $h(k)$。预测文档 $\mathbf{x}_{i}$ 是否具有比文档 $\mathbf{x}_{k}$ 更高的等级（对于相同的搜索查询）的二进制模型 $f\left(\mathbf{x}_{i}, \mathbf{x}_{k}\right)$ 由具有超参数 α 的 sigmoid 函数给，

$$
f\left(\mathbf{x}_{i}, \mathbf{x}_{k}\right) \stackrel{\mathrm{def}}{=} \frac{1}{1+\exp \left(\left(h\left(\mathbf{x}_{\mathbf{i}}\right)-h\left(\mathbf{x}_{\mathbf{k}}\right)\right) \alpha\right.}
$$

 同样，与许多预测概率的模型一样，使用模型 f 对代价函数进行交叉熵计算。在梯度提升中，我们通过尝试最小化 cost 来组合多个回归树来构建函数 h。请记住，在梯度提升中，我们向模型添加树以减少当前模型对训练数据的误差。对于分类问题，我们计算了代价函数的导数，用这些导数代替训练样例的实际标签。LambdaMART 的工作方式类似，只有一个例外。它使用梯度和取决于度量的另一个因子（例如 MAP）的组合来替换实际梯度。该因子通过增加或减少原始梯度来修改原始梯度，从而提高度量值。

 这是一个非常明智的想法，并不是很多监督学习算法可以直接提升他们的优化度量( matric )。优化度量是我们真正想要的，但我们在典型监督学习算法中所做的是优化代价 ( cost ) 而不是度量(matric)。通常，在监督学习中，一旦我们找到优化代价函数的模型，我们就会尝试调整超参数以提高度量的值。而 LambdaMART 直接优化度量标准

 剩下的问题是我们如何基于模型 f 的预测来构建排序的结果列表，模型 f 预测其第一个输入是否必须高于第二个输入。它通常是计算上难以解决的问题，并且存在多种能够将文档对比较转换为排序列表的工具。最直接的方法是使用现有的排序算法。

排序算法按递增或递减顺序对数字集合进行排序。（最简单的排序算法称为冒泡排序，工程学院中通常会教授它。）通常，排序算法迭代地比较集合中的一对数字，并根据比较结果更改列表中的位置。如果我们将函数 f 插入到排序算法中以执行此比较，则排序算法将对文档而不是数字进行排序。

![10-2](https://github.com/apachecn/ml-book-100-zh/blob/master/doc/img/10-2.png)

## 10.3 推荐学习（Learning to Recommend）

推荐学习是一种构建推荐系统的方法。通常，我们有一个消费某些内容的用户。我们有消费历史，我们希望向用户推荐用户想要的新内容。它可能是 Netflix 上的一部电影或亚马逊上的一本书。

传统上，有两种方法用于提供推荐：基于内容的过滤（content-based ﬁltering）和协作过滤（collaborative ﬁltering）。

基于内容的过滤通过基于他们消费的内容的描述来学习用户喜欢什么。例如，如果新闻网站的用户经常阅读有关科学和技术的新闻文章，那么我们会向该用户建议更多关于科学和技术的文献。更一般地，我们可以为每个用户创建一个训练集，并将新闻文章添加到该数据集作为特征向量 x 以及用户最近是否将该新闻文章作为标签 y 阅读。然后我们构建每个用户的模型，并定期检查每个新内容以确定特定用户是否会读取它。

基于内容的方法有许多限制。例如，用户可能被困在所谓的过滤泡沫中：系统将始终向该用户建议看起来与用户已经消费的非常相似的信息。这可能导致用户完全隔离不同于他们的观点或扩展他们的信息。在更实际的方面，用户可能只是获得他们已经知道的项目的推荐，这是不合需要的。

协作过滤相对于基于内容的过滤具有显着优势：对一个用户的推荐是基于其他用户消费或评价的内容计算的。例如，如果两个用户对相同的十个电影给予高评价，那么用户 1 更可能会欣赏基于用户 2 的品味而推荐的新电影，反之亦然。这种方法的缺点是忽略了推荐项目的内容。

在协作过滤中，关于用户偏好的信息以矩阵形式组织。每行对应一个用户，每列对应一个用户评价或消费的内容。通常，这个矩阵非常庞大且非常稀疏，这意味着它的大部分单元都没有填充（或填充为零）。这种稀疏性的原因是大多数用户仅消耗或评估可用内容项的一小部分。基于这样的稀疏数据很难做出有意义的推荐。

大多数现实中的推荐系统使用混合方法：它们结合了基于内容和协作过滤模型获得的推荐。

我已经提到过基于内容的推荐模型可能是使用分类或回归模型构建，该模型预测用户是否会根据内容的特征来喜欢内容。特征的示例可以包括用户喜欢的书籍或新闻文章中的词语，价格，内容的新近度，内容作者的身份等等。

两种有效的协同过滤学习算法是 因子分解机 （FM）和去噪自动编码器（DAE）。

### 10.3.1 因子分解机 （Factorization Machines）

因子分解机是一种相对较新的算法。它是为稀疏数据集而设计的。让我们来解释这个问题。

![图 1：稀疏特征向量 x 及其各自标签 y 的示例](https://github.com/apachecn/ml-book-100-zh/blob/master/doc/img/10-3-1.png)

在图 1，您会看到带标签的稀疏特征向量的示例。每个特征向量表示有关一个特定用户和一个特定电影的信息。蓝色部分中的功能代表用户。用户被编码为独热矢量 （one-hot vectors）。绿色部分中的功能代表电影。电影也被编码为独热矢量。黄色部分中的功能表示绿色用户对其评级的每部电影的分数。特征 $x_{99}$ 表示特定用户观看的电影与奥斯卡的比例。特征 $x_{100}$ 表示​​用户在以绿色评分电影之前以蓝色观看的电影的百分比。目标 y 表示用户以蓝色给予电影的绿色分数。

在真正的推荐系统中，用户数量可以达到数百万，所以矩阵就可以了。1 将计数数亿行。功能的数量可能达到数十万，具体取决于内容选择的覆盖范围以及作为数据分析师在特征工程中的创造性。特征 $x_{99}$ 和 $x_{100}$ 是在特征工程过程中手工制作的，我只是为了说明的目的而展示了两个特征。

如果对这样一个非常稀疏的数据集进行回归或分类模型，实际上会导致泛化性非常差。因子分解机以不同的方式解决这个问题。

因子分解机模型的定义如下：

$$
f(\mathbf{x}) \stackrel{\mathrm{def}}{=} b+\sum_{i=1}^{D} w_{i} x_{i}+\sum_{i=1}^{D} \sum_{j=i+1}^{D}\left(\mathbf{v}_{i} \mathbf{v}_{j}\right) x_{i} x_{j}
$$

其中 $b$ 和 $w_{i}, i=1, \ldots, D$ 是与标准回归相似的标量参数。向量 $v_{i}, i=1, \ldots, D$ ，是因子的 k 维向量。k 是一个超参数，通常比 D 小得多。表达式 $\left(\mathbf{v}_{i} \mathbf{v}_{j}\right)$ 是因子的第 i 个和第 j 个向量的点积。正如您所看到的，我们不是试图找到一个宽的参数向量，而是由于稀疏性而能够反映出特征之间的不良交互，我们通过适用于特征之间的成对交互 $x_{i} x_{j}$ 的附加参数来完成它。然而，我们不是为每个交互设置一个参数 $w_{i, j}$，而是为模型添加了大量的新参数（注：更确切地说，我们将添加 D(D-1) 个参数 $w_{i, j}$，我们仅将满足 $D k \ll D(D-1)$ 的参数添加到模型来将 $w_{i, j}$ 分解为 $v_{i} v_{j}$ 。

根据问题，损失函数可以是平方误差损失（用于回归）或铰链损失（hinge loss）。对于 $y \in\{-1,+1\}$ 的回归问题，在铰链损失或 logistic 损失的情况下，预测为 $y=\operatorname{sign}(f(x))$。 logistic 损失定义为，

$$
\operatorname{loss}(f(\mathbf{x}), y)=\frac{1}{\ln 2} \ln \left(1+e^{-y f(\mathbf{x})}\right)
$$

梯度下降可用于优化平均损失。在图 1 中的示例中，标签为 { 1, 2, 3, 4, 5} ，所以这是一个多类问题。我们可以使用一个与休息策略将这个多类问题转换成五个二分类问题。

### 10.3.2 去噪自动编码器（Denoising Autoencoders）

在第 7 章，您就知道去噪自动编码器是什么：它是一个从瓶颈层重建其输入的神经网络。事实上，输入被噪声破坏，而输出不受影响，使得自动编码器成为理想的建模工具。

这个想法非常简单：用户喜欢的新电影被视为因为一些错误过程从完整的电影数据集中移除的。去噪自动编码器的目标是重建那些被移除的项目。

要为我们的去噪自动编码器准备训练集，请从图 1 训练集中删除蓝色和绿色特征。因为现在一些例子重复，只保留唯一的例子。

在训练时，使用零随机替换输入向量中的一些非零黄色要素。训练自动编码器以重建未损坏的输入。

在预测时，为用户构建特征向量。特征向量将包括未破坏的黄色特征以及 $x_{99}$ 和 $x_{100}$ 等手工制作的特征。使用训练有素的 DAE 模型重建未损坏的输入。推荐用户在模型输出中得分最高的电影。

另一种有效的协同过滤模型是具有两个输入和一个输出的前馈神经网络。还记得第8章中说，神经网络善于处理多个同时输入。这里的训练样本是三元组（u，m，r）。输入向量 u 是用户的独热码。第二输入向量 m 是电影的独热码。输出层可以是 sigmoid（在这种情况下标签 r 在 [0,1] 中）或 ReLU，在这种情况下 r 可以在某些特殊范围内，例如 [1,5]。

![10-3](https://github.com/apachecn/ml-book-100-zh/blob/master/doc/img/10-3.png)

## 10.4 自监督学习：词嵌入 （Word Embeddings）

我们已经在第7章讨论过 Word Embeddings。回想一下，词嵌入向量是单词的特征向量。它们具有一种特性：相似单词具有相似单词向量。您可能想问的问题是这些词嵌入向量来自何处。答案是：从数据中学习它们。

学习 Word Embeddings 有很多算法。在这里，我们只详细介绍其中一个：skip-gram（word2vec的一个特定版本），在实践中效果很好。可以在线下载多种语言的预训练 word2vec 嵌入模型。

在单词嵌入学习中，我们的目标是构建一个模型，我们可以使用该模型将单词的独热码（one-hot）转换为词嵌入。假如我们的字典包含 10000 个单词。每个单词的一个独热码向量是一个 10000 维向量的全零向量，除了一个包含 1 的维度。不同的单词在不同的维度上为 1。

考虑一句话：“I almost ﬁnished reading the book on machine learning.” 现在，考虑一下我们删除了一些单词的相同句子，比如 “book.” 我们的句子变成：“I almost ﬁnished reading the · on machine learning.”  现在让我们只保留 “ · ”之前三个单词和在它之后的三个词：“ﬁnished reading the · on machine learning.”看着这个七字窗口，如果我要求你猜猜 “ · ” 代表什么，你可能会说：“book,” “article,” 或者 “paper.” 这就是上下文单词如何让你预测它们所包围的单词。这也是机器如何发现 “book,” “article,” 或者 “paper.” 这几个词的含义相似：因为它们在多个文本中共享相似的语境。

它也可以反向工作的：一个词可以预测它上下文环境。“ﬁnished reading the · on machine learning” 这一部分被称为具有窗口大小为 7（3 + 1 + 3）的 skip-gram。通过使用 Web 上提供的文档，我们可以轻松创建数亿个 skip-gram。

让我们用这样的skip-gram表示单词：$\left[\mathbf{X}_{-3}, \mathbf{X}_{-2}, \mathbf{X}_{-1}, \mathbf{X}, \mathbf{X}_{+1}, \mathbf{X}_{+2}, \mathbf{X}_{+3}\right]$。在我们上面的例句中，$\mathbf{X}_{-3}$ 是 “ﬁnished,” 的独热矢量，$\mathbf{X}_{-2}$ 对应于 “reading,” $\mathbf{X}$ 是跳过的单词（·），$\mathbf{X}_{+1}$ 是 “on” ，依此类推。窗口大小为 5 的 skip-gram 将如下所示：$\left[\mathbf{X}_{2}, \mathbf{X}_{-1}, \mathbf{X}, \mathbf{X}_{+1}, \mathbf{X}_{+2}\right]$。

具有窗口大小 5 的 skip-gram 模型如图 2 所示。它是一个全连接的网络，就像多层感知机一样。输入单词是我们的 skip-gram 中表示为 · 的单词。神经网络必须学会在给定中心词的情况下预测 skip-gram 的上下文单词。

![图 2：窗口大小为 5 的 skip-gram 模型和 300 个单元的嵌入层。](https://github.com/apachecn/ml-book-100-zh/blob/master/doc/img/10-4-1.png)

您现在可以明白为什么这种学习被称为自监督：标记的样本从未标记的数据（如文本）中提取。

输出层中使用的激活函数是 softmax。cost 函数是负对数似然（negativelog-likelihood）。当给出该单词的独热码作为模型的输入时，获得单词的嵌入向量作为嵌入层的输出。

由于 word2vec 模型中有大量参数，因此可以使用两种技术使计算更加高效：hierarchical softmax（计算 softmax 的一种有效方法，包括将 softmax 的输出表示为二叉树的叶）和负采样（基本上，这个想法只是为每次迭代下降迭代更新所有输出的随机样本）。我们留下这些以供进一步阅读。

![10-4](https://github.com/apachecn/ml-book-100-zh/blob/master/doc/img/10-4.png)
