线性回归
%matplotlib inline
import random
import torch
import matplotlib.pyplot as plt
from d2l import torch as d2l
生成数据集
我们使⽤线性模型参数w = [2, −3.4]⊤、b = 4.2 和噪声项ϵ⽣成数据集及其标签
def synthetic_data(w,b,num_examples):
x = torch.normal(0,1,(num_examples,len(w)))#生成一个均值为0,方差为1,有n个样本,大小为w列的长度
#torch.normal(means, std, out=None)
#·means (Tensor) – 均值
#·std (Tensor) – 标准差
#· out (Tensor) – 可选的输出张量
y = torch.matmul(x,w)+b
#torch.mul(a, b)是矩阵a和b对应位相乘,a和b的维度必须相等,比如a的维度是(1, 2),b的维度是(1, 2),返回的仍是(1, 2)的矩阵;
#torch.mm(a, b)是矩阵a和b矩阵相乘,比如a的维度是(1, 2),b的维度是(2, 3),返回的就是(1, 3)的矩阵。
#torch.matmul()没有强制规定维度和大小,可以用利用广播机制进行不同维度的相乘操作
y +=torch.normal(0,0.01,y.shape)#均值为0,方差为1,形状大小与y相同
return x,y.reshape((-1,1))#将x和y作为一个列向量来进行返回
true_w = torch.tensor([2,-3.4])
true_b=4.2
features ,labels = synthetic_data(true_w,true_b,1000)
#d2l.synthetic_data用来生成人工合成数据
# x
# y
features中的每⼀⾏都包含⼀个⼆维数据样本,labels中的每⼀⾏都包含⼀维标签值(⼀个标量)
print(features.shape)
print(labels.shape)
plt.plot(features[:, 0], features[:, 1], '.')
d2l.set_figsize()
d2l.plt.scatter(features[:,1].detach().numpy(),
labels.detach().numpy(),1);
#detach函数将torch内部数据传给numpy,由numpy来输出
构造函数读取数据
#构造生成读取数据的数据集,该函数接收批量⼤小、特征矩阵和标签向量作为输⼊,⽣成⼤小为batch_size的小批量
def data_iter(batch_size,features,labels):
num_examples = len(features)
# print(num_examples)
indices = list(range(num_examples))#生成每个样本的index,转化成list
random.shuffle(indices)#shuffle() 方法将序列的所有元素随机排序。
#随机顺序来访问样本
for i in range(0,num_examples,batch_size):#从0开始访问,一直到num_examples,间隔为batch_size
batch_indices = torch.tensor(
indices[i:min(i+batch_size,num_examples)]
#从0开始进行拿取数据,如果数据批量拿取时不足,就会取一个最小值
)
yield features[batch_indices],labels[batch_indices]#每一次产生随机顺序的特征和标号
#return:在程序函数中返回某个值,返回之后函数不在继续执行,彻底结束。
#yield: 带有yield的函数是一个迭代器,函数返回某个值时,会停留在某个位置,返回函数值后,会在前面停留的位置继续执行,直到程序结束
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)
#需要进行梯度计算,参数需要设置 requires_grad=True
b = torch.zeros(1,requires_grad=True)
定义模型
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
#防止y_hat 和 y 不能相减,所以把y的reshape成y_hat的reshape
定义优化算法
def sgd(params , lr , batch_size):#params是给定的list,其中包括w和b,lr是学习率
"""小梯度随机梯度下降"""
with torch.no_grad():
for param in params:
param -= lr * param.grad /batch_size
param.grad.zero_()
训练模型
lr = 0.03
num_epochs = 10 #扫描数据次数
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) # X和y的⼩批量损失
#将参数x , w , b ,放入net模型当中来进行预测,将预测的y~ 与真实的y做损失
# 因为l形状是(batch_size,1),⽽不是⼀个标量。l中的所有元素被加到⼀起,
# 并以此计算关于[w,b]的梯度
l.sum().backward()
#对损失先进行求和,之后再来计算梯度
sgd([w, b], lr, batch_size) # 使⽤参数的梯度更新参数
with torch.no_grad():
train_l = loss(net(features, w, b), labels)
#net(features, w, b)预测的参数与labels做损失
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}')