在学习深度神经网络之前,需要了解神经网络训练的基础知识。 包括:定义简单的神经网络架构、数据处理、指定损失函数和如何训练模型。 为了更容易学习,从经典算法————线性神经网络开始,了解神经网络的基础知识。
线性回归基于几个简单的假设:
首先,假设自变量 x 和因变量 y 之间的关系是线性的, 即 y 可以表示为 x 中元素的加权和,这里通常允许包含观测值的一些噪声; 其次,我们假设任何噪声都比较正常,如噪声遵循正态分布。
我们以一个非常经典的根据房屋的面积(平方米)和房龄(年)来估算房屋价格的模型为例。
首先,我们需要准备训练数据集(training data set) 或训练集(training set)
,包括真实的房屋价格,面积和房龄。
我们把试图预测的目标(比如预测房屋价格)称为标签(label)或目标(target)
。 预测所依据的自变量(面积和房龄)称为特征(feature)或协变量(covariate)
。
根据最开始我们的线性假设,我们的预测目标(房屋价格)可以表示为(面积和房龄)的加权和,用一个数学表达式来表示如下:
这个表达式可以看作输入特征的一个
仿射变换(affine transformation)
。 仿射变换的特点是通过加权和对特征进行线性变换(linear transformation)
, 并通过偏置项来进行平移(translation)
。
warea 和 wage 称为权重(weight)
,权重决定了每个特征对我们预测值的影响。
b 称为偏置(bias)、偏移量(offset)或截距(intercept)
。(表述成截距可能更熟悉)可以很清楚的看到,b可以表示当所有特征都取0时,预测值为多少。即使现实中不会有任何房子的面积是0或房龄正好是0年,我们仍然需要偏置项。 如果没有偏置项,我们模型的表达能力将受到限制。
在机器学习中,我们通常使用的是高维数据集,很多个特征(feature)的输入
所以用线性代数的方式,用向量来表示会更方便,同时向量的点积可以表示加权和,就会简化成如下形式:
表示完这种数学模型之后,就可以发现,表达式中有两个模型参数(model parameters)
w 和 b ,接下来就是确定这两个参数,我们就引入了另外两个概念:
损失函数
:一种模型质量的度量方式随机梯度下降
:一种能够更新模型以提高模型预测质量的方法。损失函数(loss function)能够量化目标的实际值与预测值之间的差距。
通常我们会选择非负数作为损失,且数值越小表示损失越小,完美预测时的损失为0。
回归问题中最常用的损失函数是平方误差函数。 当样本 i 的预测值为 y^(i) ,其相应的真实标签为 y(i) 时, 平方误差可以定义为以下公式
常数 1/2 不会带来本质的差别,但这样在形式上稍微简单一些 (因为当我们对损失函数求导后常数系数为1)。
由于平方误差函数中的二次方项, 估计值 y^(i) 和观测值 y(i) 之间较大的差异将导致更大的损失。 为了度量模型在整个数据集上的质量,我们需计算在训练集 n 个样本上的损失均值(也等价于求和)
在训练模型时,我们希望寻找一组参数( w∗,b∗ ), 这组参数能最小化在所有训练样本上的总损失。
梯度下降(gradient descent)
, 这种方法几乎可以优化所有深度学习模型。 它通过不断地在损失函数递减的方向上更新参数来降低误差。
梯度下降最简单的用法是计算损失函数关于模型参数的导数(在这里也可以称为梯度)。
但实际中的执行可能会非常慢:因为在每一次更新参数之前,我们必须遍历整个数据集。 因此,我们通常会在每次需要计算更新的时候随机抽取一小批样本, 这种变体叫做小批量随机梯度下降(minibatch stochastic gradient descent)
算法步骤:
(1)初始化模型参数的值,如随机初始化;
(2)从数据集中随机抽取小批量样本,计算小批量的平均损失关于模型参数的导数(也可以称为梯度)。 最后,我们将梯度乘以一个预先确定的正数 η ,并从当前参数的值中减掉。并不断迭代这一步骤。
| B| 表示每个小批量中的样本数,这也称为
批量大小(batch size)
。 η表示学习率(learning rate)
。 批量大小和学习率的值通常是手动预先指定,而不是通过模型训练得到的。 这些可以调整但不在训练过程中更新的参数称为超参数(hyperparameter)
。
调参(hyperparameter tuning)
是选择超参数的过程。 超参数通常是我们根据训练迭代结果来调整的, 而训练迭代结果是在独立的验证数据集(validation dataset)上评估得到的。
例如对对于平方损失中的w和B:
线性回归恰好是一个在整个域中只有一个最小值的学习问题。 但是对于像深度神经网络这样复杂的模型来说,损失平面上通常包含多个最小值。 需要花费大力气寻找这样一组参数,使得在训练集上的损失达到最小。 事实上,更难做到的是找到一组参数,这组参数能够在我们从未见过的数据上实现较低的损失, 这一挑战被称为泛化(generalization)。
其实简单来说就是利用线性代数库,而不是在for循环,来简化运算过程。对两个向量用两种方式相加的过程进行计时,来表示他们之间的效率差异
n = 100000 a = torch.ones(n) b = torch.ones(n)
一个常用的计时器:
class Timer: #@save """记录多次运行时间""" def __init__(self): self.times = [] self.start() def start(self): """启动计时器""" self.tik = time.time() def stop(self): """停止计时器并将时间记录在列表中""" self.times.append(time.time() - self.tik) return self.times[-1] def avg(self): """返回平均时间""" return sum(self.times) / len(self.times) def sum(self): """返回时间总和""" return sum(self.times) def cumsum(self): """返回累计时间""" return np.array(self.times).cumsum().tolist()
第一种:使用for循环,每次执行一位的加法:
c = torch.zeros(n) timer = Timer() for i in range(n): c[i] = a[i] + b[i] f'{timer.stop():.5f} sec'
输出时长:
'0.76498 sec'
第二种:使用重载的+运算符来计算按元素的和。
timer.start() d = a + b f'{timer.stop():.5f} sec'
输出时长:
'0.00100 sec'
结果很明显,第二种方法比第一种方法快得多。 矢量化代码通常会带来数量级的加速。 另外,我们将更多的数学运算放到库中,而无须自己编写那么多的计算,从而减少了出错的可能性。
正态分布和线性回归之间的关系很密切。 正态分布(normal distribution)
,也称为高斯分布(Gaussian distribution)
其正态分布概率密度函数如下:
下面我们定义一个Python函数来计算正态分布。
def normal(x, mu, sigma): p = 1 / math.sqrt(2 * math.pi * sigma**2) return p * np.exp(-0.5 / sigma**2 * (x - mu)**2)
进行可视化:
# 再次使用numpy进行可视化 x = np.arange(-7, 7, 0.01) # 均值和标准差对 params = [(0, 1), (0, 2), (3, 1)] d2l.plot(x, [normal(x, mu, sigma) for mu, sigma in params], xlabel='x', ylabel='p(x)', figsize=(4.5, 2.5), legend=[f'mu {mu}, sigma {sigma}' for mu, sigma in params])
如图,就是对正态分布的理解:改变均值(mu)会产生沿 x 轴的偏移,增加方差(sigma)将会分散分布、降低其峰值。
均方损失可以用于线性回归的一个原因是: 我们假设了观测中包含噪声,其中噪声服从正态分布。 噪声正态分布如下式:
可以写出通过给定的 x 观测到特定 y 的似然(likelihood):
根据极大似然估计法,参数 w 和 b 的最优值是使整个数据集的似然最大的值
根据极大似然估计法选择的估计量称为极大似然估计量。 虽然使许多指数函数的乘积最大化看起来很困难,我们可以通过概率论中计算最大化似然对数来简化。 由于历史原因,优化通常是说最小化而不是最大化。 我们可以改为最小化负对数似然 −logP(y∣X) 。
现在我们只需要假设 σ 是某个固定常数就可以忽略第一项, 因为第一项不依赖于 w 和 b 。 现在第二项除了常数 1/σ2 外,其余部分和前面介绍的均方误差是一样的。
因此,在高斯噪声的假设下,最小化均方误差等价于对线性模型的极大似然估计。
尽管神经网络涵盖了更多更为丰富的模型,我们依然可以用描述神经网络的方式来描述线性模型, 从而把线性模型看作一个神经网络, 该图只显示连接模式,即只显示每个输入如何连接到输出,隐去了权重和偏置的值。
图中,输入为 x1,…,xd , 因此输入层中的输入数(或称为特征维度,feature dimensionality)
为 d 。 网络的输出为 o1 ,因此输出层中的输出数是1。 需要注意的是,输入值都是已经给定的,并且只有一个计算神经元。
由于模型重点在发生计算的地方,所以通常我们在计算层数时不考虑输入层。 所以图中神经网络的层数为1。 我们可以将线性回归模型视为仅由单个人工神经元组成的神经网络,或称为单层神经网络。
对于线性回归,每个输入都与每个输出(在本例中只有一个输出)相连, 我们将这种变换( 图3中的输出层) 称为全连接层(fully-connected layer)或称为稠密层(dense layer)
。