动手深度学习 线性回归从零开始实现实例
🎈 作者:Linux猿
🎈 简介:CSDN博客专家🏆,华为云享专家🏆,Linux、C/C++、云计算、物联网、面试、刷题、算法尽管咨询我,关注我,有问题私聊!
🎈 欢迎小伙伴们点赞👍、收藏⭐、留言💬
# random 模块 调用 random() 方法返回随机生成的一个实数,值在[0,1)范围内
import random
# 机器学习框架 pythorch,类似于 TensorFlow 和 Keras
import torch
# 线性回归函数 y = Xw + b + e(噪音)
'''
一系列封装的函数
'''
# 批量获取数据函数
def synthetic_data(w, b, num_examples): #@save
# 生成 y=Xw+b+噪声
'''
返回一个张量,张量里面的随机数是从相互独立的正态分布中随机生成的
参与 1: 均值
参与 2: 标准差
参数 3: 张量的大小 [num_examples, len(w)]
'''
X = torch.normal(0, 1, (num_examples, len(w)))
# torch.matmul 两个张量元素相乘
y = torch.matmul(X, w) + b
# 加上噪声
y += torch.normal(0, 0.01, y.shape)
return X, y.reshape((-1, 1))
# 随机批量取数据函数
def data_iter(batch_size, features, labels):
num_examples = len(features)
# 生成存储值 0 ~ num_examples 值的列表,不重复
indices = list(range(num_examples))
# 在原列表 indices 中随机打乱所有元素
random.shuffle(indices)
# range() 第三个参数是步长
for i in range(0, num_examples, batch_size):
batch_indices = torch.tensor(
indices[i: min(i + batch_size, num_examples)])
# yield 相当于不断的 return 的作用
yield features[batch_indices], labels[batch_indices]
# 计算预测值
def linreg(X, w, b):
# 线性回归模型
return torch.matmul(X, w) + b
# 计算损失
def squared_loss(y_hat, y):
# 均方损失
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
# 梯度更新
def sgd(params, lr, batch_size):
# 小批量随机梯度下降
with torch.no_grad():
for param in params:
param -= lr * param.grad / batch_size
param.grad.zero_() # 清除 param 的梯度值为 0
'''
1. 生成数据集:包含 1000 条数据,每条 [x1, x2]
'''
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
# features: [1000, 2], labels: [1000, 1]
'''
2. 初始化 w 和 b, w: 2 x 1, b: 标量
'''
# requires_grad 在计算中保留梯度信息
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
# 初始化张量为全零
b = torch.zeros(1, requires_grad=True)
'''
3. 开始训练
'''
# 超参数学习率
lr = 0.03
# 训练批次/迭代周期
num_epochs = 3
# 每次训练的数据量
batch_size = 10
net = linreg
loss = squared_loss
for epoch in range(num_epochs): # num_epochs 个迭代周期
for X, y in data_iter(batch_size, features, labels): # 每次随机取 10 条数据一起训练
l = loss(net(X, w, b), y) # X 和 y 的小批量损失,计算损失
l.sum().backward() # 损失求和后,根据构建的计算图,计算关于[w,b]的梯度
sgd([w, b], lr, batch_size) # 使用参数的梯度更新参数
# 不自动求导
with torch.no_grad():
train_l = loss(net(features, w, b), labels) # 使用更新后的 [w, b] 计算所有训练数据的 loss
print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}') # 通过 mean 函数取平均值
'''
整体的思路:
1. 生成数据集;
2. 初始化 w 和 b;
3. 训练数据,更新 w 和 b;
'''
'''
with torch.no_grad():
在使用 pytorch 时,并不是所有的操作都需要进行计算图的生成(计算过程的构建,以便梯度反向传播等操作)。
而对于 tensor 的计算操作,默认是要进行计算图的构建的,在这种情况下,可以使用 with torch.no_grad():,
强制之后的内容不进行计算图构建。
'''