线性回归模型
基础优化算法——梯度下降
梯度是上升最快的方向,负梯度是下降最快的方向
代码实现
先在之前安装好的pytorch中安装d2l,在Anaconda Prompt中先activate pytorch,再执行pip install -U d21安装d21包
conda activate pytorch
pip install -U d2l
在Pycharm上面编程,想要看到图像需要加上d2l.plt.show(),pycharm不支持%matplotlib inline ,删去
import random #用于随机化生成的数据
import torch #框架
from d2l import torch as d2l #我们引入的包
def synthetic_data(w ,b ,num_examples):
'y = wX+ b+ 噪音项'
X = torch.normal(mean=0,std=1,size=(num_examples,len(w))) #构造x,从标准正态分布N~(0,1),提取一个num_examplesxW的矩阵
y = torch.matmul(X,w) +b #matul函数作矩阵乘法
y+=torch.normal(mean=0,std=0.01,size=(y.shape)) #加入噪音项
return X,y.reshape((-1,1))
true_w = torch.tensor([1,3.8])
true_b = 4.2
features,labels = synthetic_data(w = true_w,b=true_b,num_examples=1000)
# 我们将数据可视化,以查看数据是否生成正确
d2l.set_figsize((4,4 ))
d2l.plt.scatter(x=features[:, 1].numpy(),y=labels.numpy(),s=1,c='r') # s → 散点的面积
d2l.plt.show()
运行结果:
手动实现线性回归完整代码如下:
import random #用于随机化生成的数据
import torch #框架
from d2l import torch as d2l #我们引入的包
def synthetic_data(w ,b ,num_examples):#生成数据的函数
'y = wX+ b+ 噪音项'
X = torch.normal(mean=0,std=1,size=(num_examples,len(w))) # 生成一个(样本数,特征数)
y = torch.matmul(X,w) +b#matmul矩阵乘法
y+=torch.normal(mean=0,std=0.01,size=(y.shape))
return X,y.reshape((-1,1))#变成nX1维,固定列为1列,不知道多少行,即一个列向量
true_w = torch.tensor([1,3.8])#torch.Tensor()使用List创建,含小数代表数据类型为浮点数
true_b = 4.2
features,labels = synthetic_data(w = true_w,b=true_b,num_examples=1000)#调函数生成数据
# 我们将数据可视化,以查看数据是否生成正确
d2l.set_figsize((4,4 ))
d2l.plt.scatter(x=features[:, 1].numpy(),y=labels.numpy(),s=1,c='r') # s → 散点的面积
d2l.plt.show()
#读取数据 调用框架中现有的API来读取数据
def data_iter(batch_size , features , labels):#labels存着实际真实值y
num_examples = len(features) # len(features) -》1000 返回的是 行的数量
indexes = list(range(num_examples))
#shuffle my Data
random.shuffle(indexes)
for i in range(0, num_examples, batch_size):#range(0, 30, 5) 步长为 5,此处步长为batch_size
batch_indexes = torch.tensor(
indexes[i: min(i + batch_size, num_examples)])#min为了不越界
yield features[batch_indexes],labels[batch_indexes]#yield:return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始
next(data_iter(10,features,labels)) # 只取第一次的数据 表明我的data迭代器没有任何问题,接下来就可以设置一个梯度下降了
#定义模型
def linerRegression(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
def sgd(params,lr,batch_size):
'''随机批量梯度下降'''
with torch.no_grad():#类似try...finally,torch.no_grad即更新的时候不参与梯度计算
for param in params:
param -= lr*param.grad / batch_size
param.grad.zero_()
#初始化模型参数
w = torch.normal(mean=0,std=1,size=(2,1),requires_grad=True)
b = torch.tensor(4.2,requires_grad=True)
lr = 0.03
num_epochs = 3
batch_size = 10
net = linerRegression#函数实例化?
loss = squared_loss
for epoch in range(num_epochs):
for X,y in data_iter(batch_size=batch_size,features=features,labels=labels):#读取数据
l = loss(y_hat=net(X=X,w=w,b=b),y=y) # 一个样本的均方误差
l.sum().backward() # loss function求和算梯度
sgd([w, b], lr, batch_size) # 使用参数的梯度更新参数,使用sgd对w和b进行更新
with torch.no_grad():#在使用pytorch时,并不是所有的操作都需要进行计算图的生成,只是想要网络结果的话就不需要后向传播 ,如果你想通过网络输出的结果去进一步优化网络的话 就需要后向传播了。
train_l = loss(net(features, w, b), labels)
print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
运行结果如下:
epoch 1, loss 0.020302
epoch 2, loss 0.000120
epoch 3, loss 0.000047
简洁版利用库函数实现线性回归完整代码如下:
import torch
import torch.nn#nn是神经网络的缩写,里面有很多定义好的层
import numpy as np
from torch.utils import data
from d2l import torch as d2l
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)
# 用两个问号查询函数相关信息 发现这个函数是来自我们本地的函数
# 我们将数据可视化,以查看数据是否生成正确
d2l.set_figsize((4,4 ))
d2l.plt.scatter(x=features[:, 1].numpy(),y=labels.numpy(),s=1,c='r') # s → 散点的面积
d2l.plt.show()
#读取数据并且分割成批量大小返回
def load_array(data_arrays,batch_size,is_train=True):
'''构造一个Python的迭代器类似于我们之前的data_iter+'''
dataset = data.TensorDataset(*data_arrays) # (1)创建数据集,或者说封装数据集,可以传入多个参数
return data.DataLoader(dataset=dataset,batch_size=batch_size,shuffle=is_train)#shuffle=is_train需要随机打乱
batch_size = 10
data_iter = load_array((features, labels), batch_size) # 传入(features,labels)
next(iter(data_iter))#转为python的iter,通过next得到一个x、y
#定义模型
net = torch.nn.Sequential(torch.nn.Linear(2, 1))# Sequential是个容器,功能是把layer按顺序放在一起
# 在PyTorch中,全连接层在Linear类中定义。值得注意的是,我们将两个参数传递到nn.Linear中。
#第一个指定输入特征形状,即2,第二个指定输出特征形状,输出特征形状为单个标量,因此为1。
#定义损失函数
loss = torch.nn.MSELoss()# 均方误差是MSE
#定义优化算法
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
#算法实现
num_epochs = 3 # 迭代的次数
for epoch in range(num_epochs):
for X, y in data_iter:
l = loss(net(X) ,y) # 我们之前定义的在optim模块中的MSEloss()算法
trainer.zero_grad() # 每次调用SGD之后都要清空 ,因为我们进行的是小批量梯度下降
l.backward() # 在前面我们进行了前向传播,现在进行反向传播更新我们的参数
trainer.step()#子模型更新
l = loss(net(features), labels) # 完成一次迭代之后查看我们的损失函数的值
print(f'epoch {epoch + 1}, loss {l:f}')
运行结果如下:
epoch 1, loss 0.000208
epoch 2, loss 0.000097
epoch 3, loss 0.000097