动手学深度学习
写在前面:
本文采用的教程为00 预告【动手学深度学习v2】_哔哩哔哩_bilibili
参考书籍为《动手学深度学习》李沐著
感谢上述作者做出的贡献
线性神经网络
线性回归
引入模型
在提到线性回归之前,我们先引入一个简化模型
如果现在你要买一套房子
假设1:影响房价的关键因素是卧室的个数,卫生间个数和居住面积,记为
假设2:成交价是关键因素的加权和
我们将上述概念抽象成一个线性模型
给定一个
维输入 线性模型有一个n维权重和一个标准偏差
- 输出是输入的加权和
注:我们可以将线性模型看作是一个单层神经网络
抽象出线性模型后,我们进行预估价值的衡量
- 比较真实值和预估值,例如房屋售价和估价
- 假设
是真实值, 是估计值,我们可以比较
我们把上述公式叫做平方损失(最小二乘法)
注:机器学习的目标就是找到损失函数(代价函数)的最小
训练数据
例如我们可以收集一些数据点来决定参数值(权重和偏差),例如过去6个月卖的房子。我们把这些数据称之为训练数据,通常越多越好
参数学习
- 训练损失
- 最小化损失来学习参数
显示解

由上述内容我们可知
- 线性回归是对n维输入的加权,外加偏差
- 使用平方损失来衡量预测值和真实值之间的差异
- 线性回归有显示解(能明确用数学表达出来的解)
- 线性回归可以看作是单层神经网络
梯度下降算法

线性回归的从零开始实现
我们将从零开始优化整个方法,包括数据流水线、模型、损失函数和小批量随机梯度下降优化器
首先我们导入一些程序需要的包
%matplotlib inline
import random
import torch
from d2l import torch as d2l本文使用带有噪声的线性模型构造一个人造数据集。 任务是使用这个有限样本的数据集来恢复这个模型的参数。,我们将使用低维数据,这样可以很容易地将其可视化。
我们使用线性模型参数
def synthetic_data(w, b, num_examples): #@save
"""生成y=Xw+b+噪声"""
X = torch.normal(0, 1, (num_examples, len(w)))#每个元素从均值为0、标准差为1的正态分布中随机采样
y = torch.matmul(X, w) + b
y += torch.normal(0, 0.01, y.shape)
return X, y.reshape((-1, 1))
#定义线性模型的真实权重和偏差
true_w = torch.tensor([2, -3.4])
true_b = 4.2
#生成1000个样本的合成数据
features, labels = synthetic_data(true_w, true_b, 1000)生成好数据集后,我们对数据集进行读取。训练模型时要对数据集进行遍历,每次抽取一小批量样本,并使用它们来更新我们的模型。 由于这个过程是训练机器学习算法的基础,所以有必要定义一个函数, 该函数能打乱数据集中的样本并以小批量方式获取数据。
def data_iter(batch_size, features, labels):
num_examples = len(features)
indices = list(range(num_examples))
# 这些样本是随机读取的,没有特定的顺序
random.shuffle(indices)
for i in range(0, num_examples, batch_size):
batch_indices = torch.tensor(
#切片操作,获取当前批次的索引范围。如果 i + batch_size 超过了总样本数,则取到末尾。
indices[i: min(i + batch_size, num_examples)])
yield features[batch_indices], labels[batch_indices]在开始用小批量随机梯度下降优化我们的模型参数之前, 我们需要先有一些参数。 在下面的代码中,我们通过从均值为0、标准差为0.01的正态分布中采样随机数来初始化权重, 并将偏置初始化为0。
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)我们必须定义模型,将模型的输入和参数同模型的输出关联起来。
def linreg(X, w, b): #@save
"""线性回归模型"""
return torch.matmul(X, w) + b因为需要计算损失函数的梯度,所以我们应该在计算梯度之前先定义损失函数。
def squared_loss(y_hat, y): #@save
"""均方损失"""
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2优化算法我们选用小批量随机梯度下降算法。在每一步中,使用从数据集中随机抽取的一个小批量,然后根据参数计算损失的梯度。 接下来,朝着减少损失的方向更新我们的参数。 下面的函数实现小批量随机梯度下降更新。 该函数接受模型参数集合、学习速率和批量大小作为输入。每 一步更新的大小由学习速率
def sgd(params, lr, batch_size): #@save
"""小批量随机梯度下降"""
with torch.no_grad():
for param in params:
param -= lr * param.grad / batch_size
param.grad.zero_()在准备好模型训练的所有需要的元素后,便可以开始实现主要的训练部分了。在每次迭代中,我们读取一小批量训练样本,并通过我们的模型来获得一组预测。 计算完损失后,我们开始反向传播,存储每个参数的梯度。 最后,我们调用优化算法

lr = 0.03
num_epochs = 3
net = linreg
loss = squared_loss
for epoch in range(num_epochs):#主循环,遍历每一个训练轮次
for X, y in data_iter(batch_size, features, labels):#遍历每个小批量数据
l = loss(net(X, w, b), y) # 计算当前批次的损失
l.sum().backward()#计算损失的梯度,并反向传播
sgd([w, b], lr, batch_size) # 使用参数的梯度更新参数
with torch.no_grad():
train_l = loss(net(features, w, b), labels)# 计算整个数据集上的损失
print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')