线性回归的过程是已知数据点,需要通过一条直线来拟合这些点,这条直线对应的参数 都是通过线性回归求得
例子:假设y = X × w + b y是一个房子的价格 X是一个向量[X1,X2],X1是面积,X2是位置,是影响y的因素,w是X中对应的权重[w1,w2]T, b 是偏差
y=w1 × X1+ w2 × X2+b 通过梯度下降寻找不断更新参数以得到最优解
代码是指定w为 [2, 3.4]T b为4.2 构造一个随机数据集
通过梯度下降 线性回归去用一条直线近似生成的点集 在最后查看近似求得的w b与真实的w b的差距
#线性回归
import torch
import random
from d2l import torch as d2l
from matplotlib import pyplot as plt
def synthetic_data(w, b, num_expamples): # 构建人造数据集 w=[2 ,-3.4]T b=4.2 以及一个噪声项d y= Xw + b + d
X = torch.normal(0, 1, (num_expamples, len(w))) # 生成均值为0 方差为1的随机数 num_expamples个样本 len(w) 列数
y = torch.matmul(X, w) + b # y = X * w + b matmul矩阵乘法
y += torch.normal(0, 0.01, y.shape) # 噪声
return X, y.reshape((-1, 1)) # reshape(-1,1)转换成1个列向量
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000) # 生成 1000个样本 每个样本两列
d2l.set_figsize()
d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1) # 将X的第一列与lable画散点图 可看出二者之间存在线性关系
plt.show()
# 随机获得一组 features[] labels[]
def data_iter(batch_size, features, labels):
num_emamples = len(features) # 获取样本数量
indices = list(range(num_emamples)) # 生成每个样本的index range(n)--- 0到n-1
random.shuffle(indices) # 将index 随机打乱 shuffle只能用于list
for i in range(0, num_emamples, batch_size):
batch_indices = torch.tensor(indices[i:min(i + batch_size, num_emamples)]) # 避免超出list的范围所以用了min()
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
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True) # 需要更新 所以要计算梯度
b = torch.zeros(1, requires_grad=True)
def linear_regression(X, w, b): # 定义模型
return torch.matmul(X, w) + b
def square_loss(y_hat, y):
# 均方损失
return (y_hat - y.reshape(y_hat.shape))**2 / 2
def sgd(params, lr, batch_size): # params是一个list 给定所以参数 lr 学习率
# 小批量随机梯度下降
with torch.no_grad(): # 不需要计算梯度, 更新值时 才需要计算
for param in params:
param -= lr * param.grad / batch_size # param.grad 参数梯度值 /batch_size 损失函数中未求均值 在这边除以batch_size
param.grad.zero_() # 不会自动设0 手动将梯度设置为0
lr = 0.03 # 给定超参数
num_epochs = 10
net = linear_regression
loss = square_loss
# 训练模型
for epoch in range(num_epochs):
for X, y in data_iter(batch_size, features, labels): # 将一个batch_size大小features和labels赋给 X 和 y
l = loss(net(X, w, b), y) # net(X, w, b)相当于linear_regression(X, w, b) 计算小批量损失
# l 形状是 [batch_size, 1]
l.sum().backward() # 求和算梯度
sgd([w, b], lr, batch_size) # 使用上面计算的梯度对w b进行更新
with torch.no_grad():
train_l = loss(net(features, w, b), labels) # 计算整个features和整个labels的loss
print(f'epoch {epoch +1}, loss {float(train_l.mean()):f}')
print(f'w的估计误差:{true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差:{true_b - b}')