参考: 李沐老师
代码如下
import random
import torch
from d2l import torch as d2l
def data(w,b,num_exam):
#从(0,1)标准正态分布中找num_exam个列数是w的样本,s
x = torch.normal(0,1,(num_exam,len(w)))
#y=x×w后+偏差b
y = torch.matmul(x,w)+b
#往公式y中加入随机噪音, 均值为0, 方差为0.01, 形状与y一样
y+=torch.normal(0,0.01,y.shape)
# 将x与y做成列向量后返回, reshape中-1表示自动计算行,1代表为1列
return x,y.reshape((-1,1))
def data_lter(batch_size,features,labels):
# num_examples代表取x的第一列的个数
num_examples = len(features)
#indices代表以x的数目形成的数列
indices = list(range(num_examples))
#这些样本是随机读取的, 没有特定的顺序
random.shuffle(indices)
#打乱数列indices的数据
for i in range(0,num_examples,batch_size):
batch_indices = torch.tensor(indices[i:min(i+batch_size,num_examples)])
#从indices中选取不定长的数据,最长为indices的长度
yield features[batch_indices],labels[batch_indices]
#从x和y中随机选取值输出
def linreg(x,w,b):
#执行矩阵乘法, 返回的是预测
return torch.matmul(x,w)+b
#定义损失函数
def squared_loss(y_hat,y):
#均方损失
#将y定义为与y_hat同行同列
return ((y_hat-y.reshape(y_hat.shape))**2)/2
#定义优化算法
#params代表参数, lr代表学习率
def sgd(params,lr,batch_size):
with torch.no_grad():#不采用梯度计算
for param in params:
#/batch_size代表求均值, w与b在减去各自的梯度后乘lr再除batch_size, 将结果见赋到新的w, b
param-=lr*param.grad/batch_size
#将梯度设为0
param.grad.zero_()
#y=wx+b相当于向量之间做点积后再相加
true_w = torch.tensor([2,-3.4])
true_b=4.2
teatures,labels = data(true_w,true_b,1000)#随机取出一定长度的数据
lr = 0.01
batch_size=10
num_epochs =3#代表将数据扫3遍
net = linreg#net代表一个模型, 此时net代表y=wx+b
loss = squared_loss
#选取2个期望为0, 方差为0.01, 个数为2, 列数为1的样本, requires_grad代表需要计算梯度
w = torch.normal(0,0.01,(2,1),requires_grad=True)
#zeros创建1行1列的向量
b = torch.zeros((1),requires_grad=True)
for epoch in range(num_epochs):
#从结果中随机取出一定数据赋于x,y
for x,y in data_lter(batch_size,teatures,labels):
l=loss(net(x,w,b),y)#计算损失函数, 最终目的是求w与b, 此时先随机定义一个w与b
l.sum().backward()#将损失函数求和后算梯度
sgd([w,b],lr,batch_size)
with torch.no_grad():
train_1 = loss(net(teatures,w,b),labels)
print("epoch",epoch+1,",","loss",float(train_1.mean()))
print("w的误差",true_w-w.reshape(true_w.shape))
运行结果如下