概念
首先,让我们先了解一下什么是线性回归
它利用线性回归方程(函数)对一个或多个自变量(特征值)和因变量(目标值)之间的关系进行建模。这种函数是由一个或多个称为回归系数的模型参数的线性组合构成的。当只有一个自变量时,称为单变量回归或简单回归;当多于一个自变量时,则称为多元回归。
顺序结构实现梯度下降拟合线性回归
准备工作
import torch
import matplotlib.pyplot as plt
# 准备数据集
x=torch.tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
y=torch.tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
定义参数
w=torch.tensor([[10]],requires_grad=True,dtype=torch.float32)
b=torch.tensor([0],requires_grad=True,dtype=torch.float32)
lr=0.5
epoch=5000
更新参数(代码核心部分)
for i in range(epoch):
# 模型的正向传播,torch.matual()矩阵相乘,来计算预测值y_pre,相当于y_pre=w*x+b
y_pre=torch.matmul(x,w)+b
# 计算均方误差作为损失函数
# pow()函数:计算两个张量或一个张量与一个标量的指数计算结果,返回一个张量
loss=(y-y_pre).pow(2).mean()
# 对w与b的梯度进行归零,防止梯度累加
if w.grad is not None:
w. grad.data.zero_()
if b.grad is not None:
b.grad.data.zero_()
# 模型反向传播,得到w,b的梯度
loss.backward()
# 更新权值 w,b
w.data=w.data-lr*w.grad
b.data=b.data-lr*b.grad
print("w,b,loss:",w.item(),b.item(),loss.item(),i)
最终结果
print("最终的:w,b,loss",w.item(),b.item(),loss.item(),i)
可视化
plt.figure()
# scatter中,x,y为散点的坐标,s为大小,c为颜色
plt.scatter(x,y,20,'r')
y_pre=torch.matmul(x,w)+b
# detach()使 requires_grad=False
# plt.plot以括号中的第一个数为x轴,第二个数为y轴
plt.plot(x,y_pre.detach().numpy())
plt.show()
""" plt.plot(x,y_pre.detach().numpy()) detach就是把网络中的一部分分量从反向传播的流程中拿出来,使之requires_grad=False 但是拿出来的时候,还是指向原向量的地址,所以对拿出来的向量进行操作的时候,也会影响原向量。 t.numpy()将Tensor变量转换为ndarray变量,其中t是一个Tensor变量,可以是标量,也可以是向量, 转换后dtype与Tensor的dtype一致 """
完整代码
import torch
import matplotlib.pyplot as plt
# 准备数据集
x=torch.tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
y=torch.tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
# 定义参数
w=torch.tensor([[10]],requires_grad=True,dtype=torch.float32)
b=torch.tensor([0],requires_grad=True,dtype=torch.float32)
lr=0.5
epoch=5000
# 更新 w,b参数
for i in range(epoch):
# 模型的正向传播,torch.matual()矩阵相乘,来计算预测值y_pre,相当于y_pre=w*x+b
y_pre=torch.matmul(x,w)+b
# 计算均方误差作为损失函数
# pow()函数:计算两个张量或一个张量与一个标量的指数计算结果,返回一个张量
loss=(y-y_pre).pow(2).mean()
# 对w与b的梯度进行归零,防止梯度累加
if w.grad is not None:
w. grad.data.zero_()
if b.grad is not None:
b.grad.data.zero_()
# 模型反向传播,得到w,b的梯度
loss.backward()
# 更新权值 w,b
w.data=w.data-lr*w.grad
b.data=b.data-lr*b.grad
print("w,b,loss:",w.item(),b.item(),loss.item(),i)
print("最终的:w,b,loss",w.item(),b.item(),loss.item(),i)
plt.figure()
# scatter中,x,y为散点的坐标,s为大小,c为颜色
plt.scatter(x,y,20,'r')
y_pre=torch.matmul(x,w)+b
# detach()使 requires_grad=False
# plt.plot以括号中的第一个数为x轴,第二个数为y轴
plt.plot(x,y_pre.detach().numpy())
plt.show()
封装类实现梯度下降拟合线性回归
导包
import torch
import matplotlib.pyplot as plt
定义模型类
class Model():
# 构造函数初始化
def __init__(self,lr):
self.w=torch.tensor([[10]],requires_grad=True,dtype=torch.float32)
self.b=torch.tensor([0],requires_grad=True,dtype=torch.float32)
self.lr=lr
self.loss=None
__init__
: 构造函数,用于初始化模型的权重w
、偏置b
、学习率lr
和损失loss
。self.w
和self.b
: 模型的权重和偏置,初始值分别为10和0,且设置为需要计算梯度。self.lr
: 学习率,用于控制梯度下降时的步长
前馈函数
# 前馈函数forward。对父类函数中的overwrite
def forward(self,x,y):
# 调用linear中的call(),以利用父类forward()计算wx+b
y_pre=torch.matmul(x,self.w)+self.b
self.loss=(y_pre-y).pow(2).mean()
return y_pre
与顺序结构不同的是,封装类在前馈函数中定义损失函数loss和预测值y_pre
但是二者的定义是相同的
反向传播和更新参数
def backward(self):
if self.w.grad is not None:
self.w.grad.data.zero_()
if self.b.grad is not None:
self.b.grad.data.zero_()
self.loss.backward()
self.w.data=self.w.data-self.lr*self.w.grad
self.b.data=self.b.data-self.lr*self.b.grad
在类封装中,梯度清零和参数更新是一起在backword反向传播函数中的
打印最终结果
print("最终的:w,b,loss",self.w.item(),self.b.item(),self.loss.item())
定义万模型之后,我们就可以利用模型来实现拟合线性回归了
准备数据集和训练模型
x=torch.tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
y=torch.tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
epoch=5000
model=Model(lr=0.5)
for i in range(epoch):
model.forward(x,y)
model.backward()
model = Model(lr=0.5)实例化模型,顺便传入学习率lr
数据可视化
plt.figure()
plt.scatter(x, y, 20, 'r')
y_pre = model.forward(x, y)
plt.plot(x, y_pre.detach().numpy())
plt.show()
""" plt.plot(x,y_pre.detach().numpy()) detach就是把网络中的一部分分量从反向传播的流程中拿出来,使之requires_grad=False 但是拿出来的时候,还是指向原向量的地址,所以对拿出来的向量进行操作的时候,也会影响原向量。 t.numpy()将Tensor变量转换为ndarray变量,其中t是一个Tensor变量,可以是标量,也可以是向量, 转换后dtype与Tensor的dtype一致 """
完整代码
import torch
import matplotlib.pyplot as plt
class Model():
# 构造函数初始化
def __init__(self,lr):
self.w=torch.tensor([[10]],requires_grad=True,dtype=torch.float32)
self.b=torch.tensor([0],requires_grad=True,dtype=torch.float32)
self.lr=lr
self.loss=None
# 前馈函数forward。对父类函数中的overwrite
def forward(self,x,y):
# 调用linear中的call(),以利用父类forward()计算wx+b
y_pre=torch.matmul(x,self.w)+self.b
self.loss=(y_pre-y).pow(2).mean()
return y_pre
def backward(self):
if self.w.grad is not None:
self.w.grad.data.zero_()
if self.b.grad is not None:
self.b.grad.data.zero_()
self.loss.backward()
self.w.data=self.w.data-self.lr*self.w.grad
self.b.data=self.b.data-self.lr*self.b.grad
print("最终的:w,b,loss",self.w.item(),self.b.item(),self.loss.item())
x=torch.tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
y=torch.tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
epoch=5000
model=Model(lr=0.5)
for i in range(epoch):
model.forward(x,y)
model.backward()
plt.figure()
plt.scatter(x,y,20,'r')
y_pre=model.forward(x,y)
plt.plot(x,y_pre.detach().numpy())
plt.show()
继承类实现梯度下降拟合线性回归
导包
import torch
import matplotlib.pyplot as plt
定义模型
class LModel(torch.nn.Module):
# 构造函数初始化
def __init__(self):
# 调用父类的 init
super(LModel,self).__init__()
# 定义模型 torch.nn.Linear(输入值的维度,输出值的维度,bias=True)
self.linear=torch.nn.Linear(1,1)
# 前馈函数的forward,对父类函数中的overwrite
def forward(self,x):
# 调用 linear中的 call(),以利用父类 forward()计算 wx+b
y_pre=self.linear(x)
return y_pre
LModel
继承自 torch.nn.Module
,这是定义神经网络模型的基类
-
__init__
方法是类的构造函数,当创建LModel
的实例时,它会被调用。这里,我们首先调用父类torch.nn.Module
的__init__
方法,这是PyTorch的约定。然后,我们定义了一个线性层self.linear
,它接受一个输入特征并产生一个输出特征。
super:python中的super,名为超类,可以简单的理解为执行父类的__init__函数。
我们定义了一个线性层self.linear
,它接受一个输入特征并产生一个输出特征。
torch.nn.Linear(1, 1)可以理解为y=w*x+b
在前馈函数foward中,用y_pre来接收linear函数
让我们来看看它是如何调用forward的
最后我们就得到了y_pre
定义数据集
# 定义数据集
x=torch.Tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
y=torch.Tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
初始化模型、损失函数和优化器
# 定义模型
model=LModel()
# 构造 均方差 损失函数
criterion=torch.nn.MSELoss(size_average=False)
# 使用随机梯度下降法进行优化
optimizer=torch.optim.SGD(model.parameters(),lr=0.05)
criterion
是均方误差损失函数,用于计算模型预测值和目标值之间的误差。optimizer
是随机梯度下降优化器,用于根据损失函数的梯度更新模型的参数。
我们只需要了解一下记下来就可以了
训练模型
# 迭代更新模型权值
for epoch in range(5000):
y_pre=model(x) # 前向传播计算y_pre
loss=criterion(y_pre,y) # 前馈计算损失函数loss
optimizer.zero_grad() # 梯度清零
loss.backward() # 梯度反向传播,计算图清零
optimizer.step() # 根据传播的梯度以及学习率更新参数
print(loss)
y_pre=model(x)
是将x传到forward中,得到模型的预测值。loss=criterion(y_pre,y)
计算预测值和目标值之间的损失。optimizer.zero_grad()
清零梯度。loss.backward()
反向传播,计算梯度。optimizer.step()
根据梯度更新模型参数。
输出模型权值和预测值
# 输出模型权值
print("w=",model.linear.weight.item())
print("b=",model.linear.bias.item())
# 预测值
x_t=torch.Tensor([[4.0]])
y_t=model(x_t )
print("y_pre=",y_t.data)
4.0为参数,我们训练模型就是训练参数
使用模型对新的输入 x_t
进行预测,并输出预测值 y_t
。
可视化
plt.figure()
plt.scatter(x,y,20,'r')
y_pre=model(y)
plt.plot(x,y_pre.detach().numpy())
plt.show()
完整代码
import torch
import matplotlib.pyplot as plt
# Module 类是 torch.nn 模块里提供的一个模型构造类(nn.Module),是所有神经网网络模块的基类,我们可以继承它来定义我们想要的模型。
# 固定继承于Module
class LModel(torch.nn.Module):
# 构造函数初始化
def __init__(self):
# 调用父类的 init
super(LModel,self).__init__()
# 定义模型 torch.nn.Linear(输入值的维度,输出值的维度,bias=True)
self.linear=torch.nn.Linear(1,1)
# 前馈函数的forward,对父类函数中的overwrite
def forward(self,x):
# 调用 linear中的 call(),以利用父类 forward()计算 wx+b
y_pre=self.linear(x)
return y_pre
# 定义数据集
x=torch.Tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
y=torch.Tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
# 定义模型
model=LModel()
# 构造 均方差 损失函数
criterion=torch.nn.MSELoss(size_average=False)
# 使用随机梯度下降法进行优化
optimizer=torch.optim.SGD(model.parameters(),lr=0.05)
# 迭代更新模型权值
for epoch in range(5000):
y_pre=model(x) # 前向传播计算y_pre
loss=criterion(y_pre,y) # 前馈计算损失函数loss
optimizer.zero_grad() # 梯度清零
loss.backward() # 梯度反向传播,计算图清零
optimizer.step() # 根据传播的梯度以及学习率更新参数
print(loss)
# 输出模型权值
print("w=",model.linear.weight.item())
print("b=",model.linear.bias.item())
# 预测值
x_t=torch.Tensor([[4.0]])
y_t=model(x_t )
print("y_pre=",y_t.data)
plt.figure()
plt.scatter(x,y,20,'r')
y_pre=model(y)
plt.plot(x,y_pre.detach().numpy())
plt.show()
总结
其实这三种梯度下降拟合线性回归本质上是差不多的,只要理解了其中最基本的一种,我们就可以很好的掌握另外两种。
我们可以从最基础的梯度下降来进行理解
python深度学习--梯度下降算法(附完整代码)-CSDN博客
这篇文章可以帮助我们更好理解