计算机系统应用教程网站

网站首页 > 技术文章 正文

python pytorch 深度学习神经网络 线性回归学习笔记

btikc 2024-12-22 14:30:48 技术文章 49 ℃ 0 评论

#暑期创作大赛#

深度学习网络,是由多层神经元组成的,上一层的输出是下一层的输入,线性神经网络可以作为深度学习中的一层神经元。由于线性神经网络的结构简单,可以作为单层使用,非常适合用他来学习神经网络的构架和了解训练过程。

线性回归一般用于,给定一个值来预测结果,想预测一个结果就是回归问题。想要预测数据,首先要有历史数据和结果数据,所以他是有监督学习。通过历史数据和历史结果数据计算出w权重和b偏移量,给出一个预测值x就可以通过线性回归模型公式,计算出一个接近历史结果数据y的值。当然我们希望越接近越好。

下图是深度学习网络单次训练的流程图

以深度学习为框架,架构线性回归层和训练流程

由于线性回归网络可以单独使用。可以单独放到深度学习框架中,也可以在深度学习框架中配合其他网络层一起使用。为了能更好的学习如何构建深度学习网络框架,所以只在深度学习框架内只放一个线性回归网络层。

  • 1、准备数据
  • 把数据转换成pytorch的数据结构tensor,并转换成训练集。
  • 把数据集输入到深度学习网络中
  • 2、把线性回归网络层放到深度学习框架中。并初始化w和b的值
  • 3、线性回归网络层架构
  • 损失函数,用于计算损失值
  • 用损失值计算梯度
  • 优化算法根据梯度来更新w和b的值
  • 4、进行训练
  • 首先初始化w和b和值,把数据输入到深度学习网络中,深度学习网络框架会把训练集交给线性回归层,进行训练,这是一次训练。如果损失值在理想状态下应该是一个接近0的值,如果损失值非常大的话就非常不理想,就要第二次把训练集输入到深度学习网络中,第二次训练所用的w和b的值是上次根据梯度更新后的值,如果损失值还不理想就再次训练,直到损失值到达一个合理值,训练完成。

线性回归神经网络模型

线性回归基础模型公式 y=wx+b

  • y 因变量
  • x 变量
  • w 权重
  • b 偏移量

线性回归神经网络,通过给出的数据集,数据集包含样本x,目标值y,通过训练计算出w和b的值。这样就可以在给出x的时候通过模型计算出的w和b的值得出一个接近于因变量y的值。

多个变量,一个因变量。

  • w1,w2,w3······wn 各个变量的权重 线性回归求出的w为多个权重。
  • A,B,C······Z 各变量。

x为一个张量对象,下标为张量索引,模型公式为:

转换成pytorch代码为:

y=torch.matmul(x,w)+b

用python 代码 pytorch 库 构建深度学习线性回归网络

一、准备训练数据

1、线性回归的数据特点

从名字就能看出,线性就是直线,回归后就是一条直线。所以线性回归对训练数据是有要求的,训练数据中的历史数据和历史结果的关系要存在线性关系,如果是离散的话,其离散也要趋于一条直线,如果离散度越大就预测偏差值就越大。如果只有一个x的,x和y是一维关系,两个x和y是三维关系,多个x和y是多维关系。x和y的关系如果是条曲线,线性回归是不能拟合曲线的。

从以下图就能看出,线性回归能够拟合什么样的数据了。

左侧是x,y在坐标系中的关系图,右侧是y值的坐标图。

蓝色是训练集数据坐标,橘色是通过线性神经网络计算出来的w和b值计算出y值的坐标数据图,也就是拟合坐标。

只有一个x变量的坐标图

  • 训练数据离散区域过大,预测数值和实际数据过大
  • 训练数据离散重叠区域趋于一条直线,预测数据接近实际数值
  • 训练数据一条直线,预测数据与实际数据高度拟合
  • 训练数据是曲线,线性回归不能与曲线拟合

有两个x变量的坐标图

  • 离散过大,拟合误差大
  • 离散趋于一条直线,高度拟合

2、构建训练数据

构建一个由两个变量历史数据,和一个历史结果数据

import matplotlib.pyplot as plt
import torch
from torch.utils import data
weight=torch.tensor([2,-3.4]) #虚构一个w权重
bias=4.2#偏移量
x=torch.normal(0,1,(1000,2))#由一个平均值为0偏差值为1的正态分布中随机取值,生成一个大小为[1000,2]的张量,作为线性回归中的x
y=torch.matmul(x,w)+b#通过线性回归公式生成y值
y+=torch.normal(0,1,y.shape)#为y增加噪音,增加离散区域的大小,
y=y.reshape(-1,1)#转换张量形状[1000,1] 

打印x和y关系的坐标图

xs=x[:,0]
zs=x[:,1]
ys=y
plt.rcParams['figure.dpi']=200
fig=plt.figure()
ax=fig.add_subplot(projection='3d')
ax.scatter(xs,zs,ys)
plt.show()

3、打包成训练集并分批训练

把数据先转换成训练集,为了以后能够利用gpu并行能力,在把训练集进行分批打乱顺序后构造成一个迭代器。

dataset = data.TensorDataset(*(x,y))#对x和y打包成数据集
iterdata=data.DataLoader(dataset, batch_size=10, shuffle=True)#生成一个数据集迭代器,shuffle参数True随机打乱数据,每份10行数据

4、构建深度学习网络框架

为了能对以后学习深度学习,先要学会怎么用pytorch构架深度学习框架,pytorch给我们提供了Sequential类,Sequential类提供了把多个层连接起来的功能,这样我们只要关心使用那些层,而不需要考虑怎样把要使用到的层串连起来。这里我们只使用了一个线性回归构架层,pytorch给我们提供了全连接层Linear类,这个类实现了线性回归模型。

net = nn.Sequential(nn.Linear(2, 1))#由于只使用了一个线性回归层,所以内部只有一个nn.Linear
#第一个参数指定了数据集的输入x形状,数据集x每行有2个变量所以输入2
#第二个参数指定数据集的输出形状y的形状,数据集y输出每行只有一个所以填1

5、初始化参数

线性回归层需要初始化w和b两个值,主要初始化第一次训练使用的参数。

nn.init.normal_(net[0].weight,0,0.1)
#nn.init.normail_ 从一个平均值为0,偏差值为0.1的正态分布中随机抽取一个值作为深度学习构架中下标为0也就是第一层weight权重的初始值
nn.init.zeros_(net[0].bias) 
#nn.init.zeros_用0初始化第一层bias偏移量

6、构建损失函数和优化算法

pytorch给我们提供了很多损失函数,这里使用MSELoss损失函数,其原理是计算(训练集中y值)和(用初始化或者之前计算出来的w、b和训练集中x通过线性模型公式计算出的y值)的均方差。

torch.optim优化类中提供了很多优化算法,这里使用SGD算法。SGD梯度下降算法。

mloss = nn.MSELoss()#损失函数 因变量y和预测值的差值平方的均值 均方差 
sgd = torch.optim.SGD(net.parameters(), lr=0.03)#lr为学习率,这个需要根据训练效果需要随时调整,选择一个最优值

7、构建训练代码并开始训练

train=5#整个训练集的训练次数
for epoch in range(train):
    for X, Y in iterdata:#把迭代器内的数据迭代分批训练。
        l = mloss(net(X) ,Y)#通过初始化的weight和bias,第二个循环开始使用的是更新后的weight和bisa值计算出损失值
        sgd.zero_grad()#清除上一次计算出来的损失函数的梯度梯度结果
        l.backward()#对损失函数求导,计算当前模型关于损失函数的梯度,根据梯度下降调整模型参数,让损失函数逐渐减少。
        #只计算当前数据集的损失函数梯度,但不更新参数。
        sgd.step()#根据计算出的梯度,确定模型参数的方向,并更新模型weight和bias参数。
    l = mloss(net(x), y)#根据整个训练集的weight和bias的结果,计算出损失值。
    print(f'训练第 {epoch + 1}次, 损失值 {l:f},最后一次更新weight值:{net[0].weight.data},bias值{net[0].bias.data}')
   #输出结果
  '''
训练第 1次, 损失值 1.008016,最后一次更新weight值:tensor([[ 1.9366, -3.3241]]),bias值tensor([4.1218])
训练第 2次, 损失值 0.996908,最后一次更新weight值:tensor([[ 1.9744, -3.3236]]),bias值tensor([4.1910])
训练第 3次, 损失值 0.996160,最后一次更新weight值:tensor([[ 1.9696, -3.3895]]),bias值tensor([4.2113])
训练第 4次, 损失值 0.996013,最后一次更新weight值:tensor([[ 1.9595, -3.3662]]),bias值tensor([4.2179])
训练第 5次, 损失值 1.015133,最后一次更新weight值:tensor([[ 1.9609, -3.2403]]),bias值tensor([4.1481])
'''

输出坐标图

w1 = net[0].weight.data.reshape(weight.shape)#返回计算出的weight
b1 = net[0].bias.data#返回最后一次计算出的bias
ays=torch.matmul(x,w1)+b1#利用线性回归模型公式计算出对原数据集x的预测值y
fig1=plt.figure()
axd2=fig1.add_subplot(2,2,1,projection='3d')
axd2.scatter(xs,zs,ys)
axd2.scatter(xs,zs,ays)
axd3=fig1.add_subplot(2,2,2)
axd3.plot(ys[:20])#右侧图形蓝色曲线原训练集中的y值
axd3.plot(ays[:20])#橘色曲线预测值y
plt.show()

8、调整训练参数

训练参数的调整主要分为两个方面

1、训练集的值

当训练集中的数值过大的时候,会发生梯度爆炸,导致损失值、weight和bias的值为nan

训练第 1次, 损失值 nan,最后一次更新weight值:tensor([[nan, nan]]),bias值tensor([nan])
训练第 2次, 损失值 nan,最后一次更新weight值:tensor([[nan, nan]]),bias值tensor([nan])
训练第 3次, 损失值 nan,最后一次更新weight值:tensor([[nan, nan]]),bias值tensor([nan])
训练第 4次, 损失值 nan,最后一次更新weight值:tensor([[nan, nan]]),bias值tensor([nan])
训练第 5次, 损失值 nan,最后一次更新weight值:tensor([[nan, nan]]),bias值tensor([nan])

解决办法是在训练的时候使用梯度裁剪torch.nn.utils.clipgradnorm_

train=5#整个训练集的训练次数
for epoch in range(train):
    for X, Y in iterdata:
        l = mloss(net(X) ,Y)
        sgd.zero_grad()#清除上一次计算出来的损失函数的梯度梯度结果
        l.backward()#对损失函数求导,计算当前模型关于损失函数的梯度,根据梯度下降调整模型参数,让损失函数逐渐减少。
        #只计算当前数据集的损失函数梯度,但不更新参数。
        torch.nn.utils.clip_grad_norm_(net[0].parameters(), max_norm=0.5)#梯度裁剪
        sgd.step()#根据计算出的梯度,确定模型参数的方向,并更新模型参数。
    l = mloss(net(x), y)
    print(f'训练第 {epoch + 1}次, 损失值 {l:f},最后一次更新weight值:{net[0].weight.data},bias值{net[0].bias.data}')
 #输出结果
'''
训练第 1次, 损失值 319.293274,最后一次更新weight值:tensor([[ 1.3146, -2.8752]]),bias值tensor([0.0125])
训练第 2次, 损失值 17.654533,最后一次更新weight值:tensor([[ 2.0027, -3.4051]]),bias值tensor([0.1564])
训练第 3次, 损失值 16.013952,最后一次更新weight值:tensor([[ 2.0080, -3.4273]]),bias值tensor([0.4045])
训练第 4次, 损失值 14.341454,最后一次更新weight值:tensor([[ 1.9820, -3.3744]]),bias值tensor([0.6388])
训练第 5次, 损失值 12.398740,最后一次更新weight值:tensor([[ 2.0072, -3.4132]]),bias值tensor([0.8739])'''

还有一个就是一定要注意训练集的维度问题,如果出现如下错误提示,并且损失值居高不下就要考虑一下是不是训练集的维度发生了问题。

''' UserWarning: Using a target size (torch.Size([1000])) that is different to the input size (torch.Size([1000, 1])). This will likely lead to incorrect results due to broadcasting. Please ensure they have the same size.
  return F.mse_loss(input, target, reduction=self.reduction)
训练第 1次, 损失值 19.514772,最后一次更新weight值:tensor([[-0.1906,  0.1064]]),bias值tensor([2.6184])
训练第 2次, 损失值 17.487070,最后一次更新weight值:tensor([[ 0.0346, -0.1404]]),bias值tensor([3.5679])
训练第 3次, 损失值 17.279388,最后一次更新weight值:tensor([[ 0.1057, -0.2999]]),bias值tensor([3.9379])
训练第 4次, 损失值 17.240051,最后一次更新weight值:tensor([[ 0.1480, -0.2928]]),bias值tensor([4.1017])'''

2、训练参数的调整

一个是调整训练次数和优化器的lr值

lr值不是越小越好,过小意味着训练次数的增加,lr值大的话能够快速增加回归速度,减少训练次数。其主要看每次训练后输出的损失函数的值是否在一个稳定的区间小幅度波动

#训练10次 lr值0.05的输出结果
训练第 1次, 损失值 4.533952,最后一次更新weight值:tensor([[ 1.2099, -2.5944]]),bias值tensor([2.7105])
训练第 2次, 损失值 1.415053,最后一次更新weight值:tensor([[ 1.7015, -3.1076]]),bias值tensor([3.6767])
训练第 3次, 损失值 1.000105,最后一次更新weight值:tensor([[ 1.8819, -3.2986]]),bias值tensor([4.0383])
训练第 4次, 损失值 0.951717,最后一次更新weight值:tensor([[ 1.9329, -3.3693]]),bias值tensor([4.1621])
训练第 5次, 损失值 0.946102,最后一次更新weight值:tensor([[ 1.9620, -3.3960]]),bias值tensor([4.1906])
训练第 6次, 损失值 0.944928,最后一次更新weight值:tensor([[ 1.9684, -3.4111]]),bias值tensor([4.2119])
训练第 7次, 损失值 0.944754,最后一次更新weight值:tensor([[ 1.9765, -3.4007]]),bias值tensor([4.2189])
训练第 8次, 损失值 0.944785,最后一次更新weight值:tensor([[ 1.9749, -3.3981]]),bias值tensor([4.2294])
训练第 9次, 损失值 0.944757,最后一次更新weight值:tensor([[ 1.9707, -3.3997]]),bias值tensor([4.2216])
训练第 10次, 损失值 0.944762,最后一次更新weight值:tensor([[ 1.9825, -3.4071]]),bias值tensor([4.2249])

从上面就结果看出从第5次训练开始损失值就已经趋于稳定了

结束,如上面总结的有错误请大家多多指正,谢谢。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表