对于深度学习,非常推荐李沐老师的课程,受益匪浅
课程视频08 线性回归 + 基础优化算法【动手学深度学习v2】_哔哩哔哩_bilibili
这里对源码做一些注释,希望大家可以更好理解这里面的意思
有基础的也可以直接看代码,来加深理解
若有差错,请与我联系探讨pwp
%matplotlib inline
import random
import torch
# 生成随机特征值和标签,即features和labels当作训练和验证集;这里的features的shape为(num_examples, len(w));labels为torch.matmul(X, w)
def synthetic_data(w, b, num_examples):
"""生成 y = Xw + b + 噪声。"""
X = torch.normal(0, 1, (num_examples, len(w)))
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
features, labels = synthetic_data(true_w, true_b, 1000)
# 这里的features是(1000,2),这里w是(2,),是一维张量,所以可以当成(2,1)去进行matmul。
# 这里是分类器,把数据分为一组一组的形式
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(indices[i:min(i +
batch_size, num_examples)])
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
# torch.normal 是正态分布中提取的随机数张量,平均数为0,方差为0.01,shape为(2,1);b是全零,一个1维张量
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
# return y,y=wx+b
def linreg(X, w, b):
"""线性回归模型。"""
return torch.matmul(X, w) + b
# MSE (features - y)的平方/2,这里是按组算的,所以这里没除大小有点问题,但不大
def squared_loss(y_hat, y):
"""均方损失。"""
return (y_hat - y.reshape(y_hat.shape))**2 / 2
# 梯度下降,params是参数,lr是学习率,核心是梯度下降靠:参数减去导数与学习率的积,这里是按组来的,因为
# 后面梯度算的时候是sum()后再backward所以这里还要除一个batch_size,别忘了用完梯度后梯度清零
def sgd(params, lr, batch_size):
"""小批量随机梯度下降。"""
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是一个含10个值的向量,或者说是一个(10,1)的矩阵,所以这里要sum()
# 这里先sum在backward要清楚什么是反向传播,他记住了你的计算模式,所以反向传播最后一步是把梯度全部加一起
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}')