import math
import time
import numpy as np
import torch
import random
from d2l import torch as d2l
# 生成数据 wx+b=y, n是case数量
def gen_data(w, b, n):
x = torch.normal(0, 1, (n, len(w)))
y = torch.matmul(x, w) + b
y += torch.normal(0, 1, y.shape)
return x, y.reshape(-1, 1)
# 对于features/labels,每次随机抽batch_size的数据用作训练
def data_iter(features, labels, batch_size):
ndim = len(features)
idx = [i for i in range(ndim)]
idx = random.shuffle(idx)
for i in range(ndim):
st, ed = i, min(i+batch_size, ndim)
yield features[st:ed], labels[st:ed]
# 预测值与真实值的 R2 距离
def squared_loss(y_predict, y):
return (y - y_predict.reshape(y.shape))**2 / 2
# 根据w,b计算预测值 (线性回归)
def linreg(X, w, b):
return torch.matmul(X, w) + b
# 随机梯度下降
def sgd(params, lr, batch_size):
with torch.no_grad():
for param in params:
down_grad = lr * param.grad / batch_size
# print("param: ", param, "down_grad: ",down_grad)
param -= down_grad
param.grad.zero_()
w_real = torch.Tensor([2.0, -2])
b_real = -5
features, labels = gen_data(w_real, b_real, 100)
w = torch.zeros((2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
#print(w)
lr = 0.001 # learning rate
epochs = 50
net = linreg # 线性回归
loss = squared_loss #均方损失
batch_size = 10
epoch_ = []
loss_ = []
for epoch in range(epochs):
for X, y in data_iter(features, labels, batch_size):
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)
real_loss = float(train_l.mean())
#print(f'epoch {epoch + 1}, loss {real_loss:f}')
epoch_.append(epoch)
loss_.append(real_loss)
d2l.plt.plot(epoch_, loss_)
print(f'w估计误差: {w_real - w.reshape(w_real.shape)}')
print(f'b估计误差: {w_real - w.reshape(w_real.shape)}')
print(w_real, b_real)
print(w, b)