获取噪声散点图
def synthetic_data(w,b,num_examples): #输入w,b, 返回带噪声的y=xw+b,num_examples为返回坐标的点数
"""
生成y=Xw+b的噪声
"""
X=torch.normal(0,1,(num_examples,len(w))) #生产高斯噪声(num_examples,len(w))为噪声的维度这里是输入w是维度2向量,len为2
print("X.shape:", X.shape) # 所以维度等于[num_examples,2]
y=torch.matmul(X,w)+b #[1000 2]* [2] w是维度[2]向量 得到y是维度1000向量
y+=torch.normal(0,0.01,y.shape) #获取y=xw+b后再加上等于y自身维度的高斯噪声 均值0 标准差0.01
print("y.shape", y.shape)
return X, y.reshape((-1,1)) #将y重塑成(1000,1)并返回
#*************调用synthetic_data获取带噪声的散点图**************/
true_w = torch.tensor([2, -3.4])
print(true_w.shape)
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
# print('features:',features,'\nlabel:',labels)
print('features:', features[0, 1], '\nlabel:', labels[0])
d2l.set_figsize()
d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1); # 绘制散点图
# features[:, 1].detach().numpy() 横坐标,detach()将features分离出计算图,numpy转换numpy数组,1:散点大小
d2l.plt.show() # 显示图片
设计迭代器
#迭代器:接收批量大小、特征矩阵和标签向量,生成大小为batchsize的小批量数据
def data_iter(batch_size,features,labels):
num_examples =len(features) #获取特征矩阵元素数量
indices =list(range(num_examples)) #生成从0-num_examples-1的列表
# print("indices type",type(indices))
# print("indices len", len(indices))
random.shuffle(indices)#打乱列表顺序
for i in range(0,num_examples, batch_size): #以batch_size为步长,从零遍历到num_examples
#print("i:", i)
batch_indices =torch.tensor(indices[i:min(i+batch_size,num_examples)]) #每一次遍历从i开始取batch_size个索引,min函数保证索引不超过最大值
yield features[batch_indices], labels[batch_indices]
#yield的生成迭代器办法可以帮助节省内存
#yield是一个定义生成器的关键字,生成器是一种特殊的函数,逐个产生一系列的值并返回
#而函数会保留当前转态,下次调用迭代器时,又会从当前yield处开始运行,返回下一批新的batch个数据
# 使用迭代器的办法用for循环
# for x,y in data_iter(batch_size,features,labels) 就会迭代循环调用这个迭代器直到迭代运行结束
#*************迭代器使用**************/
batch_size =10
for X,y in data_iter(batch_size,features,labels):
print('x:',X,'\n','y:',y)
break#只迭代运行一次迭代器就退出
训练
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 #均方损失, /2只是为了压缩
def sgd(params, lr,batch_size):
"""小批量随机梯度下降"""
with torch.no_grad(): #表示解下进行操作,不会自动取计算梯度信息
for param in params: #params是模型参数的集合,每个参数的对应的点都有对应的梯度信息,迭代每个参数更新梯度信息
param -= lr*param.grad/batch_size #之前是多个batch进行计算求梯度,梯度信息是累计的
#所以更新梯度时要取平均
param.grad.zero_() #每次进行梯度下降后,清除当前参数的梯度信息
#*************初始化模型参数**************/
w = torch.normal(0, 0.01, size=(2,1),requires_grad=True)#用高斯分布初始化w,shape为[2,1]
b = torch.zeros (1,requires_grad=True)
# *************训练**************/
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) #计算网络输出和实际y的损失
l.sum().backward() #更新梯度
sgd([w,b],lr,batch_size) #计算梯度信息后将网络参数、学习率、batchsize输入sgd 进行随机梯度下降
with torch.no_grad():
train_l= loss(net(features,w,b),labels) #计算所有数据的均方损失
print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
print("w:",w)
print("b:",b)
print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差: {true_b - b}')
#打印出输出发现求得的w,b与用于生成数据集的真实的true_w true_b非常接近
# true_w = torch.tensor([2, -3.4])
# print(true_w.shape)
# true_b = 4.2
完整代码(复制就能跑)
import random
import torch
from d2l import torch as d2l
#获取带噪声散点图
def synthetic_data(w,b,num_examples): #输入w,b, 返回带噪声的y=xw+b,num_examples为返回坐标的点数
"""
生成y=Xw+b的噪声
"""
X=torch.normal(0,1,(num_examples,len(w))) #生产高斯噪声(num_examples,len(w))为噪声的维度这里是输入w是维度2向量,len为2
print("X.shape:", X.shape) # 所以维度等于[num_examples,2]
y=torch.matmul(X,w)+b #[1000 2]* [2] w是维度[2]向量 得到y是维度1000向量
y+=torch.normal(0,0.01,y.shape) #获取y=xw+b后再加上等于y自身维度的高斯噪声 均值0 标准差0.01
print("y.shape", y.shape)
return X, y.reshape((-1,1)) #将y重塑成(1000,1)并返回
#迭代器:接收批量大小、特征矩阵和标签向量,生成大小为batchsize的小批量数据
def data_iter(batch_size,features,labels):
num_examples =len(features) #获取特征矩阵元素数量
indices =list(range(num_examples)) #生成从0-num_examples-1的列表
# print("indices type",type(indices))
# print("indices len", len(indices))
random.shuffle(indices)#打乱列表顺序
for i in range(0,num_examples, batch_size): #以batch_size为步长,从零遍历到num_examples
#print("i:", i)
batch_indices =torch.tensor(indices[i:min(i+batch_size,num_examples)]) #每一次遍历从i开始取batch_size个索引,min函数保证索引不超过最大值
yield features[batch_indices], labels[batch_indices]
#yield的生成迭代器办法可以帮助节省内存
#yield是一个定义生成器的关键字,生成器是一种特殊的函数,逐个产生一系列的值并返回
#而函数会保留当前转态,下次调用迭代器时,又会从当前yield处开始运行,返回下一批新的batch个数据
# 使用迭代器的办法用for循环
# for x,y in data_iter(batch_size,features,labels) 就会迭代循环调用这个迭代器直到迭代运行结束
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 #均方损失, /2只是为了压缩
def sgd(params, lr,batch_size):
"""小批量随机梯度下降"""
with torch.no_grad(): #表示解下进行操作,不会自动取计算梯度信息
for param in params: #params是模型参数的集合,每个参数的对应的点都有对应的梯度信息,迭代每个参数更新梯度信息
param -= lr*param.grad/batch_size #之前是多个batch进行计算求梯度,梯度信息是累计的
#所以更新梯度时要取平均
param.grad.zero_() #每次进行梯度下降后,清除当前参数的梯度信息
if __name__== "__main__":
#*************调用synthetic_data获取带噪声的散点图**************/
true_w = torch.tensor([2, -3.4])
print(true_w.shape)
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
# print('features:',features,'\nlabel:',labels)
print('features:', features[0, 1], '\nlabel:', labels[0])
d2l.set_figsize()
d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1); # 绘制散点图
# features[:, 1].detach().numpy() 横坐标,detach()将features分离出计算图,numpy转换numpy数组,1:散点大小
d2l.plt.show() # 显示图片
#*************迭代器使用**************/
batch_size =10
for X,y in data_iter(batch_size,features,labels):
print('x:',X,'\n','y:',y)
break#只迭代运行一次迭代器就退出
#*************初始化模型参数**************/
w = torch.normal(0, 0.01, size=(2,1),requires_grad=True)#用高斯分布初始化w,shape为[2,1]
b = torch.zeros (1,requires_grad=True)
# *************训练**************/
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) #计算网络输出和实际y的损失
l.sum().backward() #更新梯度
sgd([w,b],lr,batch_size) #计算梯度信息后将网络参数、学习率、batchsize输入sgd 进行随机梯度下降
with torch.no_grad():
train_l= loss(net(features,w,b),labels) #计算所有数据的均方损失
print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
print("w:",w)
print("b:",b)
print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差: {true_b - b}')
#打印出输出发现求得的w,b与用于生成数据集的真实的true_w true_b非常接近
# true_w = torch.tensor([2, -3.4])
# print(true_w.shape)
# true_b = 4.2