Logo
Section 1 / 5

线性回归的局限性

在本节课中,探讨线性回归的局限性。

导入

线性回归的局限性

在本节课中,探讨线性回归的局限性。

在上一章中,我们编写了一段能够学习的代码。然而,如果这段代码被计算机科学家审查,他们会认为它存在不足。特别是,他们会对 train() 函数提出异议:按照严格的计算机科学标准,这段代码或许在这个简单示例中尚可运行,但无法扩展到真实世界的问题中。

在本章中,我们将从两个方面来解决这些问题:

  • 第一,我们不再让计算机科学家来审查我们的代码;
  • 第二,我们将分析当前 train() 实现的缺陷,并引入机器学习中的一个核心思想——梯度下降(gradient descent)算法,来解决这些问题。

和我们当前的 train() 代码一样,梯度下降也是一种寻找损失函数最小值的方法,但它比上一章的代码更快、更精确,也更具通用性。梯度下降不仅仅适用于我们这个小型程序;事实上,在机器学习中,没有梯度下降我们将寸步难行。以不同形式出现的这一算法,将贯穿本章始终。

让我们先从梯度下降旨在解决的问题说起。

我们的算法

我们的程序已经能成功预测披萨销量,但这只是一个起点。我们还可以预测更多其他场景,例如尝试用类似代码预测股票市场走势。

然而,如果我们试图将线性回归程序应用于其他问题,就会遇到障碍。当前代码基于一个简单的直线模型,仅包含两个参数:权重 ww 和偏置 bb。而大多数现实问题需要更加复杂的模型,涉及更多的参数。举例来说,本课程第一阶段的目标是构建一个图像识别系统。图像远比单个数值复杂得多,因此所需的模型参数数量也远远超过披萨销量预测器。

不幸的是,如果我们简单地为模型增加更多参数,性能将急剧下降。为了理解原因,让我们回顾上一章中的 train() 函数:

1def train(X, Y, iterations, lr): 2 w = b = 0 3 for i in range(iterations): 4 current_loss = loss(X, Y, w) 5 print("Iteration %4d => Loss: %.6f" % (i, current_loss)) 6 7 if loss(X, Y, w + lr) < current_loss: 8 w += lr 9 elif loss(X, Y, w - lr) < current_loss: 10 w -= lr 11 elif loss(X, Y, w, b + lr) < current_loss: 12 b += lr 13 elif loss(X, Y, w, b - lr) < current_loss: 14 b -= lr 15 else: 16 return w, b 17 18 raise Exception("Couldn't converge within %d iterations" % iterations)

在每一次迭代中,该算法会单独调整 ww 或 bb,试图找到使损失最小的参数值。这种方法的一个潜在问题是:当我们调整 ww 时,可能会无意中增大由 bb 引起的损失,反之亦然。为了避免这个问题,并尽可能接近最小损失,我们应该同时调整两个参数。参数越多,越需要同时调整所有参数。若要同时调整 ww 和 bb,就必须尝试所有可能的调整组合:

  • 增加 ww 和 bb;
  • 增加 ww,减少 bb;
  • 增加 ww,保持 bb 不变;
  • 减少 ww,等等。

通过数学计算可知,总的调整组合数(包括所有参数都不变的情况)等于 3 的“参数数量”次方。当有两个参数时,共有 32=93^2 = 9 种组合。

每次迭代调用 9 次 loss() 函数似乎不算严重问题,但如果参数增加到 10 个,组合数就变成 3103^{10},即每次迭代需要近 6 万次损失函数调用。你可能觉得 10 个参数过于夸张,但实际上并非如此。

在后续课程中,我们会使用拥有数十万个参数的模型。面对如此庞大的模型,任何试图穷举所有参数组合的算法都完全不可行。

此外,当前 train() 的实现还有一个更紧迫的问题:它以等于学习率的固定步长来调整参数。如果学习率 lrlr 较大,参数变化快,训练速度加快,但最终结果精度较低,因为每个参数只能是该较大步长的整数倍;若要提高精度,则需使用较小的学习率,但这又会导致训练速度进一步变慢。我们不得不在速度与精度之间做权衡,而实际上我们两者都需要。

正因如此,我们当前的代码本质上是一种权宜之计(hack)。我们需要用一种更好的算法来替代它,使得 train() 既能快速收敛,又能保证高精度。

分类器的工作原理

梯度下降