22.7. 最大似然
在 Colab 中打开 Notebook
在 Colab 中打开 Notebook
在 Colab 中打开 Notebook
在 Colab 中打开 Notebook
在 SageMaker Studio Lab 中打开 Notebook

机器学习中最常遇到的思想之一是最大似然观点。这个概念是,当处理具有未知参数的概率模型时,使数据具有最高概率的参数是最有可能的参数。

22.7.1. 最大似然原则

这有一个贝叶斯解释,有助于思考。假设我们有一个带参数 \(\boldsymbol{\theta}\) 的模型和一组数据样本 \(X\)。具体来说,我们可以想象 \(\boldsymbol{\theta}\) 是一个单一的值,表示硬币抛掷时正面朝上的概率,而 \(X\) 是一系列独立的硬币抛掷结果。我们稍后将深入研究这个例子。

如果我们想为我们的模型找到最可能的参数值,这意味着我们想找到

(22.7.1)\[\mathop{\mathrm{argmax}} P(\boldsymbol{\theta}\mid X).\]

根据贝叶斯定理,这等同于

(22.7.2)\[\mathop{\mathrm{argmax}} \frac{P(X \mid \boldsymbol{\theta})P(\boldsymbol{\theta})}{P(X)}.\]

表达式 \(P(X)\),一个与参数无关的生成数据的概率,完全不依赖于 \(\boldsymbol{\theta}\),因此可以在不改变 \(\boldsymbol{\theta}\) 的最佳选择的情况下被丢弃。同样,我们现在可以假设我们对哪组参数比其他参数更好没有先验假设,所以我们可以声明 \(P(\boldsymbol{\theta})\) 也不依赖于 \(\theta\)!这在我们的抛硬币例子中是有意义的,其中正面朝上的概率可以是 \([0,1]\) 中的任何值,而没有任何先验信念认为它是公平的还是不公平的(这通常被称为*无信息先验*)。因此,我们看到,我们对贝叶斯定理的应用表明,我们对 \(\boldsymbol{\theta}\) 的最佳选择是 \(\boldsymbol{\theta}\) 的最大似然估计

(22.7.3)\[\hat{\boldsymbol{\theta}} = \mathop{\mathrm{argmax}} _ {\boldsymbol{\theta}} P(X \mid \boldsymbol{\theta}).\]

作为一个常用术语,给定参数下数据的概率(\(P(X \mid \boldsymbol{\theta})\))被称为*似然*。

22.7.1.1. 一个具体的例子

让我们来看一个具体的例子。假设我们有一个单一参数 \(\theta\),表示抛硬币正面朝上的概率。那么,得到反面的概率是 \(1-\theta\),所以如果我们观察到的数据 \(X\) 是一个有 \(n_H\) 次正面和 \(n_T\) 次反面的序列,我们可以利用独立概率相乘的事实,看到

(22.7.4)\[P(X \mid \theta) = \theta^{n_H}(1-\theta)^{n_T}.\]

如果我们抛掷 \(13\) 次硬币,得到序列“HHHTHTTHHHHHT”,其中有 \(n_H = 9\) 次正面和 \(n_T = 4\) 次反面,我们看到

(22.7.5)\[P(X \mid \theta) = \theta^9(1-\theta)^4.\]

这个例子的一个好处是,我们事先就知道答案。的确,如果我们口头说,“我抛了13次硬币,9次是正面,我们对硬币正面朝上的概率的最佳猜测是什么?”,每个人都会正确地猜出是 \(9/13\)。这种最大似然方法将给我们一种从基本原理中得到这个数字的方法,这种方法将推广到更复杂得多的情况。

在我们的例子中,\(P(X \mid \theta)\) 的图像如下

%matplotlib inline
import torch
from d2l import torch as d2l

theta = torch.arange(0, 1, 0.001)
p = theta**9 * (1 - theta)**4.

d2l.plot(theta, p, 'theta', 'likelihood')
../_images/output_maximum-likelihood_907113_3_0.svg
%matplotlib inline
from mxnet import autograd, np, npx
from d2l import mxnet as d2l

npx.set_np()

theta = np.arange(0, 1, 0.001)
p = theta**9 * (1 - theta)**4.

d2l.plot(theta, p, 'theta', 'likelihood')
[22:07:56] ../src/storage/storage.cc:196: Using Pooled (Naive) StorageManager for CPU
../_images/output_maximum-likelihood_907113_6_1.svg
%matplotlib inline
import tensorflow as tf
from d2l import tensorflow as d2l

theta = tf.range(0, 1, 0.001)
p = theta**9 * (1 - theta)**4.

d2l.plot(theta, p, 'theta', 'likelihood')
../_images/output_maximum-likelihood_907113_9_0.svg

它的最大值在我们预期的 \(9/13 \approx 0.7\ldots\) 附近。为了看它是否正好在那里,我们可以求助于微积分。注意到在最大值处,函数的梯度是平的。因此,我们可以通过找到导数为零的 \(\theta\) 值,并找到给出最高概率的那个值来找到最大似然估计 (22.7.1)。我们计算

(22.7.6)\[\begin{split}\begin{aligned} 0 & = \frac{d}{d\theta} P(X \mid \theta) \\ & = \frac{d}{d\theta} \theta^9(1-\theta)^4 \\ & = 9\theta^8(1-\theta)^4 - 4\theta^9(1-\theta)^3 \\ & = \theta^8(1-\theta)^3(9-13\theta). \end{aligned}\end{split}\]

这有三个解:\(0\)\(1\)\(9/13\)。前两个显然是最小值,而不是最大值,因为它们为我们的序列分配的概率为 \(0\)。最后一个值*没有*为我们的序列分配零概率,因此必须是最大似然估计 \(\hat \theta = 9/13\)

22.7.2. 数值优化和负对数似然

前面的例子很好,但如果我们有数十亿的参数和数据样本怎么办?

首先,请注意,如果我们假设所有数据样本都是独立的,我们就不能再实际地考虑似然本身,因为它是许多概率的乘积。实际上,每个概率都在 \([0,1]\) 之间,比如说典型值约为 \(1/2\),而 \((1/2)^{1000000000}\) 的乘积远低于机器精度。我们无法直接处理这个问题。

然而,回想一下,对数可以将乘积转化为和,在这种情况下

(22.7.7)\[\log((1/2)^{1000000000}) = 1000000000\cdot\log(1/2) \approx -301029995.6\ldots\]

这个数字甚至可以完美地容纳在一个单精度 \(32\) 位浮点数中。因此,我们应该考虑*对数似然*,即

(22.7.8)\[\log(P(X \mid \boldsymbol{\theta})).\]

由于函数 \(x \mapsto \log(x)\) 是递增的,最大化似然与最大化对数似然是同一回事。实际上,在 第 22.9 节 中,我们将看到在处理朴素贝叶斯分类器的具体例子时应用了这种推理。

我们经常处理损失函数,我们希望最小化损失。我们可以通过取 \(-\log(P(X \mid \boldsymbol{\theta}))\),即*负对数似然*,将最大似然转化为最小化损失。

为了说明这一点,考虑之前的抛硬币问题,并假装我们不知道闭式解。我们可以计算出

(22.7.9)\[-\log(P(X \mid \boldsymbol{\theta})) = -\log(\theta^{n_H}(1-\theta)^{n_T}) = -(n_H\log(\theta) + n_T\log(1-\theta)).\]

这可以写成代码,并且即使对于数十亿次硬币抛掷也可以自由优化。

# Set up our data
n_H = 8675309
n_T = 256245

# Initialize our paramteres
theta = torch.tensor(0.5, requires_grad=True)

# Perform gradient descent
lr = 1e-9
for iter in range(100):
    loss = -(n_H * torch.log(theta) + n_T * torch.log(1 - theta))
    loss.backward()
    with torch.no_grad():
        theta -= lr * theta.grad
    theta.grad.zero_()

# Check output
theta, n_H / (n_H + n_T)
(tensor(0.9713, requires_grad=True), 0.9713101437890875)
# Set up our data
n_H = 8675309
n_T = 256245

# Initialize our paramteres
theta = np.array(0.5)
theta.attach_grad()

# Perform gradient descent
lr = 1e-9
for iter in range(100):
    with autograd.record():
        loss = -(n_H * np.log(theta) + n_T * np.log(1 - theta))
    loss.backward()
    theta -= lr * theta.grad

# Check output
theta, n_H / (n_H + n_T)
[22:07:57] ../src/base.cc:48: GPU context requested, but no GPUs found.
(array(0.9713101), 0.9713101437890875)
# Set up our data
n_H = 8675309
n_T = 256245

# Initialize our paramteres
theta = tf.Variable(tf.constant(0.5))

# Perform gradient descent
lr = 1e-9
for iter in range(100):
    with tf.GradientTape() as t:
        loss = -(n_H * tf.math.log(theta) + n_T * tf.math.log(1 - theta))
    theta.assign_sub(lr * t.gradient(loss, theta))

# Check output
theta, n_H / (n_H + n_T)
(<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.9713101>,
 0.9713101437890875)

数值便利性不是人们喜欢使用负对数似然的唯一原因。还有其他几个原因使其更受青睐。

我们考虑对数似然的第二个原因是简化了微积分规则的应用。如上所述,由于独立性假设,我们在机器学习中遇到的大多数概率都是单个概率的乘积。

(22.7.10)\[P(X\mid\boldsymbol{\theta}) = p(x_1\mid\boldsymbol{\theta})\cdot p(x_2\mid\boldsymbol{\theta})\cdots p(x_n\mid\boldsymbol{\theta}).\]

这意味着如果我们直接应用乘法法则来计算导数,我们会得到

(22.7.11)\[\begin{split}\begin{aligned} \frac{\partial}{\partial \boldsymbol{\theta}} P(X\mid\boldsymbol{\theta}) & = \left(\frac{\partial}{\partial \boldsymbol{\theta}}P(x_1\mid\boldsymbol{\theta})\right)\cdot P(x_2\mid\boldsymbol{\theta})\cdots P(x_n\mid\boldsymbol{\theta}) \\ & \quad + P(x_1\mid\boldsymbol{\theta})\cdot \left(\frac{\partial}{\partial \boldsymbol{\theta}}P(x_2\mid\boldsymbol{\theta})\right)\cdots P(x_n\mid\boldsymbol{\theta}) \\ & \quad \quad \quad \quad \quad \quad \quad \quad \quad \quad \vdots \\ & \quad + P(x_1\mid\boldsymbol{\theta})\cdot P(x_2\mid\boldsymbol{\theta}) \cdots \left(\frac{\partial}{\partial \boldsymbol{\theta}}P(x_n\mid\boldsymbol{\theta})\right). \end{aligned}\end{split}\]

这需要 \(n(n-1)\) 次乘法和 \((n-1)\) 次加法,因此与输入的二次方时间成正比!足够巧妙地对项进行分组可以将其减少到线性时间,但这需要一些思考。对于负对数似然,我们有

(22.7.12)\[-\log\left(P(X\mid\boldsymbol{\theta})\right) = -\log(P(x_1\mid\boldsymbol{\theta})) - \log(P(x_2\mid\boldsymbol{\theta})) \cdots - \log(P(x_n\mid\boldsymbol{\theta})),\]

然后得到

(22.7.13)\[- \frac{\partial}{\partial \boldsymbol{\theta}} \log\left(P(X\mid\boldsymbol{\theta})\right) = \frac{1}{P(x_1\mid\boldsymbol{\theta})}\left(\frac{\partial}{\partial \boldsymbol{\theta}}P(x_1\mid\boldsymbol{\theta})\right) + \cdots + \frac{1}{P(x_n\mid\boldsymbol{\theta})}\left(\frac{\partial}{\partial \boldsymbol{\theta}}P(x_n\mid\boldsymbol{\theta})\right).\]

这只需要 \(n\) 次除法和 \(n-1\) 次求和,因此与输入的线性时间成正比。

考虑负对数似然的第三个也是最后一个原因是与信息论的关系,我们将在 第 22.11 节 中详细讨论。这是一个严谨的数学理论,它提供了一种衡量随机变量中信息或随机性程度的方法。该领域的核心研究对象是熵,即

(22.7.14)\[H(p) = -\sum_{i} p_i \log_2(p_i),\]

它衡量了一个源的随机性。请注意,这不过是平均 \(-\log\) 概率,因此,如果我们取负对数似然并除以数据样本的数量,我们会得到熵的一个亲戚,称为交叉熵。仅这个理论解释就足以促使我们将数据集上的平均负对数似然作为衡量模型性能的一种方式。

22.7.3. 连续变量的最大似然

到目前为止,我们所做的一切都假设我们正在处理离散随机变量,但如果我们想处理连续随机变量呢?

简而言之,什么都没有改变,只是我们用概率密度替换了所有的概率。回想一下,我们用小写 \(p\) 来表示密度,这意味着例如我们现在说

(22.7.15)\[-\log\left(p(X\mid\boldsymbol{\theta})\right) = -\log(p(x_1\mid\boldsymbol{\theta})) - \log(p(x_2\mid\boldsymbol{\theta})) \cdots - \log(p(x_n\mid\boldsymbol{\theta})) = -\sum_i \log(p(x_i \mid \theta)).\]

问题变成了,“为什么这样可以?” 毕竟,我们引入密度的原因是因为获得特定结果本身的概率为零,那么对于任何参数集,生成我们数据的概率不也为零吗?

的确如此,理解为什么我们可以转向密度,是一个追踪 epsilon 会发生什么的过程。

让我们首先重新定义我们的目标。假设对于连续随机变量,我们不再想要计算得到精确值的概率,而是匹配到某个范围 \(\epsilon\) 内的概率。为简单起见,我们假设我们的数据是独立同分布随机变量 \(X_1, \ldots, X_N\) 的重复观测 \(x_1, \ldots, x_N\)。正如我们之前看到的,这可以写成

(22.7.16)\[\begin{split}\begin{aligned} &P(X_1 \in [x_1, x_1+\epsilon], X_2 \in [x_2, x_2+\epsilon], \ldots, X_N \in [x_N, x_N+\epsilon]\mid\boldsymbol{\theta}) \\ \approx &\epsilon^Np(x_1\mid\boldsymbol{\theta})\cdot p(x_2\mid\boldsymbol{\theta}) \cdots p(x_n\mid\boldsymbol{\theta}). \end{aligned}\end{split}\]

因此,如果我们对这个式子取负对数,我们得到

(22.7.17)\[\begin{split}\begin{aligned} &-\log(P(X_1 \in [x_1, x_1+\epsilon], X_2 \in [x_2, x_2+\epsilon], \ldots, X_N \in [x_N, x_N+\epsilon]\mid\boldsymbol{\theta})) \\ \approx & -N\log(\epsilon) - \sum_{i} \log(p(x_i\mid\boldsymbol{\theta})). \end{aligned}\end{split}\]

如果我们检查这个表达式,\(\epsilon\) 唯一出现的地方是在加性常数 \(-N\log(\epsilon)\) 中。这根本不依赖于参数 \(\boldsymbol{\theta}\),所以 \(\boldsymbol{\theta}\) 的最优选择不依赖于我们对 \(\epsilon\) 的选择!无论我们要求四位还是四百位精度,\(\boldsymbol{\theta}\) 的最佳选择都保持不变,因此我们可以自由地丢弃 epsilon,看到我们想要优化的是

(22.7.18)\[- \sum_{i} \log(p(x_i\mid\boldsymbol{\theta})).\]

因此,我们看到最大似然观点可以像处理离散随机变量一样轻松地处理连续随机变量,只需用概率密度替换概率即可。

22.7.4. 总结

  • 最大似然原则告诉我们,对于给定数据集,最佳拟合模型是那个以最高概率生成数据的模型。

  • 人们通常使用负对数似然,原因有多种:数值稳定性、将乘积转换为和(以及由此简化的梯度计算),以及与信息论的理论联系。

  • 虽然在离散情况下最容易进行论证,但它也可以自由地推广到连续情况,通过最大化分配给数据点的概率密度。

22.7.5. 练习

  1. 假设你知道一个非负随机变量的密度是 \(\alpha e^{-\alpha x}\),对于某个值 \(\alpha>0\)。你从该随机变量中获得了一个观测值,数字是 \(3\)。对于 \(\alpha\) 的最大似然估计是多少?

  2. 假设你有一个从未知均值但方差为 \(1\) 的高斯分布中抽取的样本数据集 \(\{x_i\}_{i=1}^N\)。均值的最大似然估计是什么?