当前位置: 首页 > article >正文

人工智能之深度学习_[3] -PyTorch自动微分模块和构建线性回归模型

自动微分模块

自动微分就是自动计算梯度值,也就是计算导数。

  • 什么是梯度
    • 对函数求导的值就是梯度
  • 什么是梯度下降法
    • 是一种求最优梯度值的方法,使得损失函数的值最小
  • 梯度经典语录
    • 对函数求导得到的值就是梯度 (在数值上的理解)
      • 在某一个点上,对函数求导得到的值就是该点的梯度
      • 没有点就无法求导,没有梯度
    • 梯度就是上山下山最快的方向 (在方向上理解)
    • 在平面内,梯度就是某一点上的斜率
      • y = 2x^2 某一点x=1的梯度,就是这一点上的斜率
    • 反向传播传播的是梯度
      • 反向传播利用链式法则不断的从后向前求导,求出来的值就是梯度,所以大家都经常说反向传播传播的是梯度
    • 链式法则中,梯度相乘,就是传说中的梯度传播

训练神经网络时,最常用的算法就是反向传播。在该算法中,参数(模型权重)会根据损失函数关于对应参数的梯度进行调整。为了计算这些梯度,PyTorch内置了名为 torch.autograd 的微分模块。它支持任意计算图的自动梯度计算:在这里插入图片描述
接下来我们使用这个结构进行自动微分模块的介绍,我们使用 backward 方法、grad 属性来实现梯度的计算和访问。

9.1 梯度基本计算

  • pytorch不支持向量张量对向量张量的求导,只支持标量张量对向量张量的求导
    • x如果是张量,y必须是标量(一个值)才可以进行求导
  • 计算梯度: y.backward(), y是一个标量
  • 获取x点的梯度值: x.grad, 会累加上一次的梯度值
  • 标量张量梯度计算

    # 定义一个标量张量(点)
    # requires_grad=:默认为False,不会自动计算梯度;为True的话是将自动计算的梯度值保存到grad中
    x = torch.tensor(10, requires_grad=True, dtype=torch.float32)
    print("x-->", x)
    
    # 定义一个曲线
    y = 2 * x ** 2
    print("y-->", y)
    # 查看梯度函数类型,即曲线函数类型
    print(y.grad_fn)
    
    # 计算x点的梯度
    # 此时y是一个标量,可以不用使用y.sum()转换成标量
    print("y.sum()-->", y.sum())
    # y'|(x=10) = (2*x**2)'|(x=10) = 4x|(x=10) = 40
    y.sum().backward()
    
    # 打印x的梯度值
    print("x的梯度值是:", x.grad)
    
  • 向量张量梯度计算

    # 定义一个向量张量(点)
    x = torch.tensor([10, 20], requires_grad=True, dtype=torch.float32)
    print("x-->", x)
    
    # 定义一个曲线
    y = 2 * x ** 2
    print("y-->", y)
    
    # 计算梯度
    # x和y都是向量张量,不能进行求导,需要将y转换成标量张量-->y.sum()
    # y'|(x=10) = (2*x**2)'|(x=10) = 4x|(x=10) = 40
    # y'|(x=20) = (2*x**2)'|(x=20) = 4x|(x=20) = 80
    y.sum().backward()
    
    # 打印x的梯度
    print("x.grad-->", x.grad)
    

9.2 梯度下降法求最优解

  • 梯度下降法公式: w = w - r * grad (r是学习率, grad是梯度值)

  • 清空上一次的梯度值: x.grad.zero_()

    # 求 y = x**2 + 20 的极小值点 并打印y是最小值时 w的值(梯度)
    # 1 定义点 x=10 requires_grad=True  dtype=torch.float32
    # 2 定义函数 y = x**2 + 20
    # 3 利用梯度下降法 循环迭代1000 求最优解
    # 3-1 正向计算(前向传播)
    # 3-2 梯度清零 x.grad.zero_()
    # 3-3 反向传播
    # 3-4 梯度更新 x.data = x.data - 0.01 * x.grad
    
    
    # 1 定义点x=10 requires_grad=True  dtype=torch.float32
    x = torch.tensor(10, requires_grad=True, dtype=torch.float32)
    
    # 2 定义函数 y = x ** 2 + 20
    y = x ** 2 + 20
    print('开始 权重x初始值:%.6f (0.01 * x.grad):无 y:%.6f' % (x, y))
    
    # 3 利用梯度下降法 循环迭代1000 求最优解
    for i in range(1, 1001):
    
        # 3-1 正向计算(前向传播)
        y = x ** 2 + 20
    
        # 3-2 梯度清零 x.grad.zero_()
        # 默认张量的 grad 属性会累加历史梯度值 需手工清零上一次的提取
        # 一开始梯度不存在, 需要做判断
        if x.grad is not None:
            x.grad.zero_()
    
        # 3-3 反向传播
        y.sum().backward()
     
        # 3-4 梯度更新 x.data = x.data - 0.01 * x.grad
        # x.data是修改原始x内存中的数据,前后x的内存空间一样;如果使用x,此时修改前后x的内存空间不同
        x.data = x.data - 0.01 * x.grad  # 注:不能 x = x - 0.01 * x.grad 这样写
    
        print('次数:%d 权重x: %.6f, (0.01 * x.grad):%.6f y:%.6f' % (i, x, 0.01 * x.grad, y))
            
    print('x:', x, x.grad, 'y最小值', y)
    

9.3 梯度计算注意点

  • 不能将自动微分的张量转换成numpy数组,会发生报错,可以通过detach()方法实现

    # 定义一个张量
    x1 = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)
    
    # 将x张量转换成numpy数组
    # 发生报错,RuntimeError: Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.
    # 不能将自动微分的张量转换成numpy数组
    # print(x1.numpy())
    
    # 通过detach()方法产生一个新的张量,作为叶子结点
    x2 = x1.detach()
    # x1和x2张量共享数据,但是x2不会自动微分
    print(x1.requires_grad)
    print(x2.requires_grad)
    # x1和x2张量的值一样,共用一份内存空间的数据
    print(x1.data)
    print(x2.data)
    print(id(x1.data))
    print(id(x2.data))
    
    # 将x2张量转换成numpy数组
    print(x2.numpy())
    

9.4 自动微分模块应用

import torch

# 输入张量 2*5
x = torch.ones(2, 5)
# 目标值是 2*3    
y = torch.zeros(2, 3)
# 设置要更新的权重和偏置的初始值
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
# 设置网络的输出值
z = torch.matmul(x, w) + b  # 矩阵乘法
# 设置损失函数,并进行损失的计算
loss = torch.nn.MSELoss()
loss = loss(z, y)
# 自动微分
loss.backward()
# 打印 w,b 变量的梯度
# backward 函数计算的梯度值会存储在张量的 grad 变量中
print("W的梯度:", w.grad)
print("b的梯度", b.grad)

10 PyTorch构建线性回归模型

我们使用 PyTorch 的各个组件来构建线性回归模型。在pytorch中进行模型构建的整个流程一般分为四个步骤:

  • 准备训练集数据
  • 构建要使用的模型
  • 设置损失函数和优化器
  • 模型训练

在这里插入图片描述
要使用的API:

  • 使用 PyTorch 的 nn.MSELoss() 代替平方损失函数
  • 使用 PyTorch 的 data.DataLoader 代替数据加载器
  • 使用 PyTorch 的 optim.SGD 代替优化器
  • 使用 PyTorch 的 nn.Linear 代替假设函数
import torch
from torch.utils.data import TensorDataset  # 构造数据集对象
from torch.utils.data import DataLoader  # 数据加载器
from torch import nn  # nn模块中有平方损失函数和假设函数
from torch import optim  # optim模块中有优化器函数
from sklearn.datasets import make_regression  # 创建线性回归模型数据集
import matplotlib.pyplot as plt


plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号


# 构造数据集
def create_dataset():
    x, y, coef = make_regression(n_samples=100,
                                 n_features=1,
                                 noise=10,
                                 coef=True,
                                 bias=14.5,
                                 random_state=0)

    # 将构建数据转换为张量类型
    x = torch.tensor(x)
    y = torch.tensor(y)

    return x, y, coef


# 训练模型
def train():
    # 构造数据集
    x, y, coef = create_dataset()

    # 构造数据集对象
    dataset = TensorDataset(x, y)

    # 构造数据加载器
    # dataset=:数据集对象
    # batch_size=:批量训练样本数据
    # shuffle=:样本数据是否进行乱序
    dataloader = DataLoader(dataset=dataset, batch_size=16, shuffle=True)

    # 构造模型
    # in_features指的是输入的二维张量的大小,即输入的[batch_size, size]中的size
    # out_features指的是输出的二维张量的大小,即输出的[batch_size,size]中的size
    model = nn.Linear(in_features=1, out_features=1)

    # 构造平方损失函数
    criterion = nn.MSELoss()

    # 构造优化函数
    # params=model.parameters():训练的参数,w和b
    # lr=1e-2:学习率, 1e-2为10的负二次方
    print("w和b-->", list(model.parameters()))
    print("w-->", model.weight)
    print("b-->", model.bias)
    optimizer = optim.SGD(params=model.parameters(), lr=1e-2)

    # 初始化训练次数
    epochs = 100
    # 损失的变化
    epoch_loss = [] 
    total_loss=0.0 
    train_sample=0.0

    for _ in range(epochs):
        for train_x, train_y in dataloader:
            # 将一个batch的训练数据送入模型
            y_pred = model(train_x.type(torch.float32))
            # 计算损失值
            loss = criterion(y_pred, train_y.reshape(-1, 1).type(torch.float32))
            total_loss += loss.item() 
            train_sample += len(train_y)
            # 梯度清零
            optimizer.zero_grad()
            # 自动微分(反向传播)
            loss.backward()
            # 更新参数
            optimizer.step()
        # 获取每个batch的损失 
        epoch_loss.append(total_loss/train_sample)
        
    # 打印回归模型的w
    print(model.weight)
    # 打印回归模型的b
    print(model.bias)
    
    # 绘制损失变化曲线 
    plt.plot(range(epochs), epoch_loss) 
    plt.title('损失变化曲线') 
    plt.grid() 
    plt.show()

    # 绘制拟合直线
    plt.scatter(x, y)
    x = torch.linspace(x.min(), x.max(), 1000)
    y1 = torch.tensor([v * model.weight + model.bias for v in x])
    y2 = torch.tensor([v * coef + 14.5 for v in x])
    plt.plot(x, y1, label='训练')
    plt.plot(x, y2, label='真实')
    plt.grid()
    plt.legend()
    plt.show()


if __name__ == '__main__':
    train()

在这里插入图片描述
在这里插入图片描述


http://www.kler.cn/a/508087.html

相关文章:

  • unity学习18:unity里的 Debug.Log相关
  • WebSocket实现分布式的不同方案对比
  • Linux命令行工具-使用方法
  • XML序列化和反序列化的学习
  • 【2024年华为OD机试】 (C卷,100分)- 小明找位置(Java JS PythonC/C++)
  • 网站收录入口提交的方法有哪些(网站收录的方式都有哪些)
  • 1.1初探大模型:起源与发展
  • 如何将数据库字符集改为中文,让今后所有的数据库都支持中文
  • 二十三种设计模式-代理模式
  • IF=24.5! 综述:机器人纹理识别触觉感知和机器学习进展
  • 请求响应-
  • 【算法】差分
  • python爬取Boss直聘,分析北京招聘市场
  • Android-V lmkd 中的那些属性值
  • WORD转PDF脚本文件
  • 如何攻击一个服务器(仅用于教育及娱乐实验目的)
  • 从零用java实现 小红书 springboot vue uniapp (10)系统消息模块 接收推送消息优化
  • 浅谈计算机网络04 | 现代网络需求与技术支撑
  • C++内存分布
  • C++异常处理详解
  • P6周:VGG-16算法-Pytorch实现人脸识别
  • 深度学习 Pytorch 张量的索引、分片、合并以及维度调整
  • 【优选算法】四数之和(双指针算法)
  • 3D扫描仪在文博行业的应用有哪些?
  • 当设置dialog中有el-table时,并设置el-table区域的滚动,看到el-table中多了一条横线
  • 【golang学习之旅】使用VScode安装配置Go开发环境