目录
一、线性模型
1.1 模型的数学表示
- 输入:
- 权重:,决定每个特征对预测值的英雄
- 偏差:,决定特征都为0时,预测值应为多少。
- 输出为输入的加权和:
- 向量形式的输出:
线性模型可以看作单层神经网络。
1.2 衡量预估质量
衡量预估的质量就是比较真实值和预估值,假设是真实值,是估计值,可以有多种形式衡量两者的差距,例如平方损失:
1.3 训练数据的表示
通常我们会收集一些数据点包括训练样本和对应的真实值,记为:
其中是列向量,代表每一个样本数据。这样的每一行就是一个样本。
这样所有样本的预测值就可以表示为:
1.4 参数学习
训练的损失带入1.2中提到的平方损失公式。
通过令最小,找到对应的参数和。
1.5 线性模型求解
为了便于计算,令,,在的最右侧添加全一的列,在的下面添加标量。这样就可以直接计算
带入损失函数:
由于损失函数是凸函数,所以最优解满足梯度为0,可以解得
1.6 线性回归的从零实现
(1)导入包
import random
import torch
from d2l import torch as d2l # pip install d2l
(2)构造数据集
创建一个带有噪声的人造数据集,使用真实的和生成数据集及标签。
def synthetic_data(w, b, num_examples):
"""生成 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) # 添加均值为0,方差为0.01的噪声
return X, y.reshape((-1, 1))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
features的每一行都包含一个二维数据样本,labels中的每一行都包含一个标签值。
(3)读取批量
def data_iter(batch_size, features, labels):
num_examples = len(features) # 样本数量
indices = list(range(num_examples)) # 生成每个样本的index
random.shuffle(indices) # 将index随机打乱
for i in range(0, num_examples, batch_size): # 步长为batch_size
# 获取i到i+batch_size的下标
batch_indices = torch.tensor(indices[i:min(i + batch_size, num_examples)])
# 每次yield返回一个值,下次调用从上次的yield开始
yield features[batch_indices], labels[batch_indices]
batch_size = 10
for X, y in data_iter(batch_size, features, labels):
print(X, '\n', y)
break
(4)初始化模型参数
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
(5)定义模型
def linreg(X, w, b):
"""线性回归模型。"""
return torch.matmul(X, w) + b
(6)定义损失函数
def squared_loss(y_hat, y):
"""均方损失。"""
return (y_hat - y.reshape(y_hat.shape))**2 / 2
(7)定义优化算法
def sgd(params, lr, batch_size):
"""小批量随机梯度下降。"""
with torch.no_grad():
for param in params:
param -= lr * param.grad / batch_size
param.grad.zero_()
(8)训练过程
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}')
1.7 线性回归的简单实现
(1)导入包
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
true_w = torch.tensor([2, -3.4])
true_b = 4.2
# 利用人工数据合成函数,生成样本和标签
features, labels = d2l.synthetic_data(true_w, true_b, 1000)
(2)调用框架中现有的API读取数据
def load_array(data_arrays, batch_size, is_train=True):
"""构造一个PyTorch数据迭代器。"""
# 把输入的两类数据一一对应
dataset = data.TensorDataset(*data_arrays)
# 重新排序后返回
return data.DataLoader(dataset, batch_size, shuffle=is_train)
batch_size = 10
data_iter = load_array((features, labels), batch_size)
# 下面代码用于在屏幕显示读取到的数据,打包成iter迭代器,然后依次读取
next(iter(data_iter))
(3)定义模型
from torch import nn
# 将线性层放到Sequential容器中
net = nn.Sequential(nn.Linear(2, 1)) # 指定输入维度2,输出维度1
net[0].weight.data.normal_(0, 0.01) # 第0层线性层 -> 权重w -> 数据 -> 使用正态分布替换data
net[0].bias.data.fill_(0) # 第0层线性层 -> 偏差b -> 数据 -> 填充0
(4)均方误差
loss = nn.MSELoss()
(5)随机梯度下降
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
(6)训练过程
num_epochs = 3
for epoch in range(num_epochs):
for X, y in data_iter:
l = loss(net(X), y)
trainer.zero_grad()
l.backward()
trainer.step()
l = loss(net(features), labels)
print(f'epoch {epoch + 1}, loss {l:f}')
二、基础优化方法——梯度下降
当一个模型没有显式解时,一般通过这种方法求解。
- 挑选一个初始值
- 在训练中重复迭代参数:(:学习率)
也就是说让沿梯度方向(数值下降最快的方向)进行参数更新来找到最优解。类似于下山时一直找坡度最陡的方向走,最终到达山脚(最优解)。
(1)超参数1:学习率
其中的学习率代表每一次参数更新的大小,学习率太小参数更新很慢,学习率太大模型会震荡找不到最优解。
(2)超参数2:批量大小
由于在整个训练集上计算梯度时间消耗太大,可能需要数分钟乃至数个小时。
因此通常随机采样个样本来近似训练集的损失。
同样批量大小不能太大,也不能太小。如果批量太小,不适合并行计算利用GPU资源,如果批量太大,内存消耗增加,浪费计算。
三、Softmax回归
上面提到的回归,目的是估计一个连续值。而分类问题是用来预测一个离散类别。Softmax回归虽然名字叫回归,但其实是一个分类问题。
常见的分类问题包括:手写数字识别、自然物体分类、蛋白质显微镜图片分类、恶意软件分类、恶意评论分类。
对比回归与分类
| 回归 | 分类 |
|---|---|
| 单连续值数值输出 | 多个输出 |
| 跟真实值的区别作为损失 | 输出i是预测i的置信度 |
1.1 如何将分类问题转化为回归问题
(1)类别编码
对于n个类别,可以用一维有效编码来编码。那么标号就是长为n的向量,每个类别的标号向量分别是。
其中第i个类别的标号是,其中只有第i个元素是1,其余元素都是0。
(2)确定损失函数
在Softmax中可以选择使用均方损失函数训练。
(3)进行预测
其中是每个类别的置信度,是置信度最大的类别的索引。这样就能找到置信度最大的那个类别。
进行检测的关键是使对于正确类的置信度远大于其它类别。通常需要保证
(4)置信度转换为概率
我们获得了所有类别的置信度。
但是置信度只是预测的物体与每个类别的匹配程度,而非识别为该物体的概率,具体转换方法如下:
这样就实现了置信度的所有元素非负,且和为1。
然后将真实的概率与的区别作为损失。

评论