机器学习编程:从编码到深度学习
上QQ阅读APP看书,第一时间看更新

3.1 算法的缺陷

我们的程序可以成功地预测比萨销量,但为什么仅止步于此呢?或许我们可以使用同样的代码来预测一些其他问题,比如用于股市预测之类的。或许我们可以由此一夜暴富(剧透警告:其实这是行不通的)!

事实上,如果我们试图使用当前代码解决另外一个不同的问题,那么就可能会遇到一些障碍。这段代码基于一个非常简单的模型,模型中只有两个参数,即权重w和偏置b。然而,现实生活中大多数问题都需要使用包含更多参数的复杂模型。例如,别忘了本书第一部分的目标,我们希望构建一个图像识别系统。图像数据要比单一数值复杂得多,因此建立一个图像识别系统需要一个参数数量比比萨预测器的参数数量多得多的模型。

不幸的是,如果我们向现有的这个模型中添加更多的参数,那么就会扼杀模型的性能。要究其原因,就让我们回顾一下前一章中的train()函数:

在每次迭代过程中,该算法通过调整w或b的值来寻找最小的损失。这里有一种可能的出错方式:当调整w时,就有可能增加b造成的损失,反之亦然。为避免出现这个问题并使得损失尽可能地变小,我们应该同时调整这两个参数。模型中包含的参数越多,对这些参数进行同时调整就越重要。

要同时调整参数w和b,就必须尝试参数w和b所有可能的调整组合:增加w和增加b;增加w和减少b;增加w和保持b不变;减少w……嗯,你应该明白我的意思了吧。计算一下,你就会发现调整组合的总数,包括所有参数保持不变的组合,是3的参数个数次方幂。如果有两个参数,那组合数就是32,也就是说,有9种组合。

每次迭代中调用9次loss()函数乍一听并不是很难。然而,如果将参数的数量增加到10,则会得到310个组合。这就意味着每次迭代要调用几乎60 000次loss()函数。你可能认为模型中不太可能有10个参数,但事实并非如此。我们将会在本书后面的内容中使用具有成千上万个参数的数学模型。对于如此庞大的模型,一个尝试所有参数组合的算法显然永远不会成功,我们应该把这种慢速代码消灭在萌芽状态。

当前train()函数的实现还有一个更为紧迫的问题:该函数使用与学习率lr相等的增量来实现对参数的调整。如果lr值很大,那么参数的变化就很快,此时就加快了训练速度,但最终结果就会不那么精确。因为每个参数都必须是那个较大lr的倍数。为了提高准确率,就需要一个较小的lr值,但这样会导致训练速度变慢。我们虽然可以通过牺牲速度来换取准确率,但是二者其实是不可或缺的。

因此,我们现有的代码基本上是不能用了。我们应该使用一个更好的算法来替代它——一个让train()函数既快速又精确的算法。