图 5.3 我们未知的数据可能遵循线性模型
注意
我们知道线性模型是正确的,因为问题和数据都是捏造的,但大家不要在意这一点。这是一个很好的例子,可以帮助我们理解PyTorch在幕后的所作所为。
2.4 选择线性模型作为第一次尝试
在缺乏进一步知识的情况下,我们假设两组测量值之间转换的最简单模型,就像开普勒可能做的那样。这两者可能是线性相关的,也就是说,乘以一个因子,再加上一个常数,我们可以得到摄氏度的温度(直到我们忽略的误差):
这是合理的假设吗?可能;我们来看看最终模型的效果如何。我们选择将权重和偏差命名为w和b,这是线性标度和加法常数的两个非常常见的术语。
好的,现在我们需要基于我们的数据估计我们模型中的参数w和b。这样做的目的是使我们通过模型运行未知温度t_u得到的温度接近我们实际测量的摄氏温度。如果这听起来像是通过一组测量来拟合一条线,那么,是的,因为这正是我们正在做的。我们将使用PyTorch来学习这个简单的例子,并认识到训练神经网络基本上需要将模型更改为稍微复杂一点的模型,并增加几个(或很多个)参数。
让我们再回顾一下:我们有一个模型,其中有一些未知参数,我们需要估计这些参数,以便预测输出和测量值之间的误差尽可能小。我们注意到我们仍然需要精确地定义误差的度量。我们称之为损失函数,如果误差很高,则损失函数应该很高,理想情况下应该尽可能低以获得完美匹配。因此,我们的优化过程应该以找到w和b为目标,以使损失函数最小。
3. 我们想要的是更小的误差损失函数(或代价函数)是一个计算单个数值的函数,学习过程将试图最小化该数值。损失的计算通常涉及一些训练样本的期望输出与模型在输入这些样本时实际产生的输出之间的差值。在我们的例子中,这将是我们的模型输出的预测温度t_p和实际测量值之间的差异,也就是t_p–t_c。
我们需要确保损失函数在t_p大于或小于真实t_c时使损失都为正,因为目标是t_p与t_c匹配。我们有几个选择,最直接的是| t_p–t_c |和(t_p–t_c)^2.根据我们选择的数学表达式,我们可以强调或忽略某些错误。从概念上讲,损失函数是一种优先考虑从训练样本中修复哪些错误的方法,因此我们的参数更新会导致对高权重样本的输出进行调整,而不是对其他一些损失较小的样本的输出进行更改。
这两个例子损失函数在0处都有一个明显的最小值,并且随着预测值向任一方向远离真值而单调增长,因为增长的陡度也随着远离最小值而单调增长,所以这两个函数都被称为凸函数。由于我们的模型是线性的,因此作为w和b的函数的损失也是凸的,当损失是模型参数的凸函数时,通常很难处理,因为我们可以通过专门的算法非常有效地找到最小值。但是,我们将在本章中使用功能较弱但更普遍适用的方法。我们这样做是因为对于我们最终感兴趣的深层神经网络,损失不是输入的凸函数。
对于我们的两个损失函数| t_p–t_c |和(t_p–t_c)^2,如图5.4所示,我们注意到差的平方在最小值附近表现得更为良好:当t_p等于t_c时,误差平方损失对t_p的导数为零。另一方面,绝对值在我们想要收敛的地方有一个未定义的导数。这在实践中并不像看上去那样是一个问题,但我们将暂时坚持使用平方差。
图 5.4 绝对差与平方差
值得注意的是,平方差比绝对差对错误结果的惩罚更大。通常,有更多的轻微错误的结果要比有几个严重错误的结果好,平方差有助于根据需要优先考虑这些结果。
3.1 从问题回到PyTorch我们已经计算出了模型和损失函数,也已经计算出了图5.2中高级图的一部分。现在我们需要启动学习过程,并向它提供实际数据。另外,数学符号也足够了;让我们换成PyTorch来实现吧,毕竟,我们解决这个问题仅仅是为了好玩。
我们已经创建了数据张量,现在让我们将模型写成Python函数:
t_u、w和b分别是输入张量、权重参数和偏差参数。在我们的模型中,参数将是PyTorch标量(又称零维张量),乘积运算将使用广播产生返回的张量。不管怎样,是时候定义我们的损失了: