《动手学深度学习》笔记整理3:线性神经网络

378 阅读10分钟

线性回归的基本元素

回归(regression)是能为一个或多个自变量与因变量之间关系建模的一类方法。

1.线性模型

线性假设是指目标(房屋价格)可以表示为特征(面积和房龄)的加权和,如下面的式子:

image.png

而在机器学习领域,我们通常使用的是高维数据集,建模时采用线性代数表示法会比较方便。 当我们的输入包含d个特征时,我们将预测结果y^ (通常使用“尖角”符号表示y的估计值)表示为:

image.png

我们可以用点积形式来简洁地表达模型:

image.png

在开始寻找最好的模型参数(model parameters)w和b之前, 我们还需要两个东西: (1)一种模型质量的度量方式; (2)一种能够更新模型以提高模型预测质量的方法。

2.损失函数(模型质量的度量方式)

损失函数(loss function)能够量化目标的实际值与预测值之间的差距。 通常我们会选择非负数作为损失,且数值越小表示损失越小,完美预测时的损失为0。 回归问题中最常用的损失函数是平方误差函数。

image.png

3.随机梯度下降(更新模型以提高模型预测质量的方法)

我们用到一种名为梯度下降(gradient descent)的方法, 这种方法几乎可以优化所有深度学习模型。 它通过不断地在损失函数递减的方向上更新参数来降低误差。梯度下降最简单的用法是计算损失函数(数据集中所有样本的损失均值) 关于模型参数的导数(在这里也可以称为梯度)。 但实际中的执行可能会非常慢:因为在每一次更新参数之前,我们必须遍历整个数据集。 因此,我们通常会在每次需要计算更新的时候随机抽取一小批样本, 这种变体叫做小批量随机梯度下降

每次迭代中,我们首先随机抽样一个小批量B, 它是由固定数量的训练样本组成的。 然后,我们计算小批量的平均损失关于模型参数的导数(也可以称为梯度)。 最后,我们将梯度乘以一个预先确定的正数n,并从当前参数的值中减掉。

我们用下面的数学公式来表示这一更新过程:

image.png

4.用模型进行预测

这样子一个过程我们就完成了一个线性模型的构建,现在我们就可以让我们的线性模型通过房屋面积x1和房龄x2来估计一个(未包含在训练数据中的)新房屋价格。

矢量化加速

我们可以通过numpy,pandas库等等,来避免for循环,从而大大提高我们的运行速度,到达矢量化加速的效果。

正态分布与平方损失

image.png

image.png

因此,在高斯噪声的假设下,最小化均方误差等价于对线性模型的极大似然估计。

从线性回归到深度网络

image.png 当今大多数深度学习的研究几乎没有直接从神经科学中获得灵感。 我们援引斯图尔特·罗素和彼得·诺维格在他们的经典人工智能教科书 Artificial Intelligence:A Modern Approach 中所说的:虽然飞机可能受到鸟类的启发,但几个世纪以来,鸟类学并不是航空创新的主要驱动力。 同样地,如今在深度学习中的灵感同样或更多地来自数学、统计学和计算机科学。

线性回归的代码实现

在这里我们主要使用random,torch,d2l这三个库,主要用random来构建两个函数帮助我们生成训练数据并通过shuffle打乱数据形成数据块,然后用torch,d2l进行模型的搭建首先初始化超参,定义线性模型函数,定义损失函数,定义优化函数,最后通过调用这些函数实现模型的训练。训练完再和真实值相减进行模型的评估。具体的代码可以到下面我的GitHub地址找到。

线性回归的简洁实现

上面我们是通过定义函数实现各个功能,下面我们将介绍如何通过使用深度学习框架来简洁地实现中的线性回归模型。

import numpy as np

import torch

from torch.utils import data

from d2l import torch as d2l

上面就是所有要用到的包,然后首先我们的数据是通过构造一个PyTorch数据迭代器来获取,初始化超参,我们不再定义线性模型函数,定义损失函数,定义优化函数,而是直接通过torch调用这些函数,接下来就一样了写出主函数通过调用这些函数实现模型的训练。训练完再和真实值相减进行模型的评估。具体的代码可以到下面我的GitHub地址找到。

softmax回归

回归可以用于预测多少的问题。 比如预测房屋被售出价格,或者棒球队可能获得的胜场数,又或者患者住院的天数。

事实上,我们也对分类问题感兴趣:不是问"多少",而是问"哪一个":

  • 某个电子邮件是否属于垃圾邮件文件夹?
  • 某个用户可能注册或不注册订阅服务?
  • 某个图像描绘的是驴、狗、猫、还是鸡?
  • 某人接下来最有可能看哪部电影?

统计学家很早以前就发明了一种表示分类数据的简单方法:独热编码(one-hot 编码)。

softmax回归就是用来处理这类分类的问题的,其实他也是一个单层神经网络,我们可以和上面比较其实就是输出层的参数变多了,不再是单一的输出。

image.png

社会科学家邓肯·卢斯于1959年在选择模型(choice model)的理论基础上 发明的softmax函数正是这样做的: softmax函数能够将未规范化的预测变换为非负数并且总和为1,同时让模型保持 可导的性质。 为了完成这一目标,我们首先对每个未规范化的预测求幂,这样可以确保输出非负。 为了确保最终输出的概率值总和为1,我们再让每个求幂后的结果除以它们的总和。如下式:

image.png

image.png

同时要将输出视为概率,我们必须保证在任何数据上的输出都是非负的且总和为1。 此外,我们需要一个训练的目标函数,来激励模型精准地估计概率。例如, 在分类器输出0.5的所有样本中,我们希望这些样本是刚好有一半实际上属于预测的类别。 这个属性叫做校准(baselibration)。

image.png

现在让我们考虑整个结果分布的情况,即观察到的不仅仅是一个结果。 对于标签现在让我们考虑整个结果分布的情况,即观察到的不仅仅是一个结果。 对于标签,我们可以使用与以前相同的表示形式。 唯一的区别是,我们现在用一个概率向量表示,如, 而不是仅包含二元项的向量。我们使用 来定义损失, 它是所有标签分布的预期损失值。此损失称为(交叉熵 loss),它是分类问题最常用的损失之一。 本节我们将通过介绍信息论基础来理解交叉熵损失。 如果想了解更多信息论的细节,请进一步参考 。,我们可以使用与以前相同的表示形式。 唯一的区别是,我们现在用一个概率向量表示,如, 而不是仅包含二元项的向量。我们使用 来定义损失, 它是所有标签分布的预期损失值。此损失称为(交叉熵 loss),它是分类问题最常用的损失之一。

在训练softmax回归模型后,给出任何样本特征,我们可以预测每个输出类别的概率。 通常我们使用预测概率最高的类别作为输出类别。 如果预测与实际类别(标签)一致,则预测是正确的。 在接下来的实验中,我们将使用精度(accuracy)来评估模型的性能。 精度等于正确预测数与预测总数之间的比率。

softmax回归总结

  • softmax运算获取一个向量并将其映射为概率。
  • softmax回归适用于分类问题,它使用了softmax运算中输出类别的概率分布。
  • 交叉熵是一个衡量两个概率分布之间差异的很好的度量,它测量给定模型编码数据所需的比特数。

用softmax回归处理MNIST数据集代码实现

MNIST数据集是图像分类中广泛使用的数据集之一,但作为基准数据集过于简单。 我们将使用类似但更复杂的Fashion-MNIST数据集。Fashion-MNIST由10个类别的图像组成, 每个类别由训练数据集(train dataset)中的6000张图像 和测试数据集(test dataset)中的1000张图像组成。 因此,训练集和测试集分别包含60000和10000张图像。Fashion-MNIST中包含的10个类别,分别为T恤、裤子、套头衫(套衫)、连衣裙、外套(外套)、凉鞋(凉鞋)、衬衫(衬衫)、运动鞋(运动鞋)、包(包)和脚踝 boot(短靴)。

%matplotlib inline
import torch
import torchvision
from torch.utils import data
from torchvision import transforms
from d2l import torch as d2l

d2l.use_svg_display()

这些是我们用到的包,和上面训练线性回归模型非常相似:先读取数据,再定义模型和损失函数,然后使用优化算法训练模型。大多数常见的深度学习模型都有类似的训练过程。只不过这里的函数由线性模型变为softmax模型,损失函数由均分误差变为交叉熵,优化函数是小批量随机梯度下降来优化模型的损失函数,设置学习率为0.1,不过我们需要先计算分类精度。具体的代码可以到下面我的GitHub地址找到。

softmax回归处理MNIST数据集代码的简洁实现

这里跟上面线性模型一样,基本上就一个地方要改就是模型改为softmax模型。

  • 使用深度学习框架的高级API,我们可以更简洁地实现softmax回归。
  • 从计算的角度来看,实现softmax回归比较复杂。在许多情况下,深度学习框架在这些著名的技巧之外采取了额外的预防措施,来确保数值的稳定性。这使我们避免了在实践中从零开始编写模型时可能遇到的陷阱。

具体的代码可以到下面我的GitHub地址找到。

HeteroCat-blog/动手学深度学习代码 at main · HeteroCat/HeteroCat-blog (github.com)