• Pytorch深度学习——线性回归实现 04(未完)


    1 问题假设

    假设我们的基础模型就是y = wx+b,其中w和b均为参数,我们使用y = 3x+0.8来构造数据x、y,所以最后通过模型应该能够得出w和b应该分别接近3和0.8。

    2 步骤

    1. 准备数据: x就是随机生成的数,y=3*x+0.8 得到的数据。(也就是说,这里使用的y真实值 是无噪声的,那么可以知道只要epoch次数够就能训练出比较真实的值)
    2. 初始化要训练的参数
    3. 带入参数计算,并且用均方差代表loss
    4. 梯度清零反向传播tensor.grad中保存的是梯度,更新参数
    import torch
    
    learning_rate = 0.01
    # 1 准备数据
    # y = 3x+0.8
    
    x = torch.rand([500, 1])  # 500行1列的随机数,范围是0-1
    y_true = x*3 + 0.8
    
    # 初始化两个要训练的参数
    w = torch.rand([1, 1], requires_grad=True)  # 1行1列
    b = torch.zeros(1, requires_grad=True)
    # 或者写成这样: b = torch.tensor(0, requires_grad=True, dtype=torch.float32)
    
    print(w, b)
    # 4 通过循环,反向传播,更新参数
    
    for i in range(2500):
    	# 2 通过模型计算y_pred
        # 3 计算loss
        y_predict = torch.matmul(x, w) + b
        loss = (y_true - y_predict).pow(2).mean()  # 均方误差
    
        if w.grad is not None:
            w.grad.data.zero_()  # 归零 (就地修改)
        if b.grad is not None:
            b.grad.data.zero_()
    
        loss.backward()  # 反向传播
        w.data = w.data - learning_rate * w.grad
        b.data = b.data - learning_rate * b.grad
        print("w, b, loss", w.item(), b.item(), loss.item())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    以上代码就是一个模型训练的过程,训练模型的本质就是训练了参数w和b

    输出如下:(因为输出有2500行+,所以只截取最后的结果)
    在这里插入图片描述
    可以看到,最后w收敛到了2.95517635345459, b最后收敛到了0.823337733745575,非常接近w=3b=0.8

    3 学习使用Pytorch的API来搭建模型

    3.1 nn.Model

    nn.Model 是torch.nn 提供的一个类,是Pytorch中 微我们自定义网络的一个基类,在这个类中定义了很多有用的方法,让我们在继承这个类 定义网路的时候非常简单。

    1. __init__ 需要 调用super方法,继承附列的属性和方法。
    2. forward方法必须实现,用来定义我们的网络的前向计算的过程。
    • 用y = wx+b 的模型举例如下:
    import torch
    from torch import nn
    
    class Lr(nn.Module):
        def __init__(self):
            super(lr, self).__init__()  # 继承父类的init的参数
            self.linear = nn.Linear(1, 1)
        
        def forward(self, x):
            out = self.linear(x)
            return out       
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其中:这一行代码是固定的。

     super(lr, self).__init__()  # 继承父类的init的参数
    
    • 1
    1. nn.Linear 为 torch 预定好的线性模型,也被称为全连接层,传入的参数为输入的数量和输出的数量(in_features, out_features),是不算(batch_size)的列数的。
    2. nn.Module 定义了 __call__方法,即类Lr的实例,实现的就是调用forward方法,能够直接被传入参数调用,实际上调用的是forward方法并传入参数。

    示例:

    model = Lr()  # 实例化模型
    pred = model(x)  # 传入数据,计算结果
    
    • 1
    • 2

    3.2 优化器类

    优化器(optimizer),可以理解为pytorch中封装好了的用来更新参数的方法,比如常见的随机下降(SGD)和Adam。

    • 优化器都是由torch.optim提供的:
    torch.optim.SGD(参数,学习率)
    
    • 1
    torch.optim.Adam(参数,学习率)
    
    • 1
    1. 参数可以使用model.parameters() 来获取,获取模型中所有 requires_grad=True 的参数。
    2. 优化器使用方法:
      ①实例化
      ②所有参数的梯度置零
      ③反向传播计算梯度
      ④更新参数值
    optimizer = optim.SGD(model.parameters(), lr=1e-3)  # 1. 实例化
    optimizer.zero_grad()  # 2. 梯度置零
    loss.backward()  # 3. 计算梯度
    optimizer.step()  # 4. 更新参数的值
    
    • 1
    • 2
    • 3
    • 4
    • 写代码——调用API来实现线性模型
    import torch
    import torch.nn as nn
    from torch.optim import SGD
    
    
    # 0. 准备数据
    x = torch.rand([500, 1])
    y_true = 3*x + 0.8
    
    
    # 1. 定义模型
    class MyLinear(nn.Module):
        def __init__(self):
            super(MyLinear, self).__init__()
            self.linear = nn.Linear(1, 1)
    
        def forward(self, x):
            out = self.linear(x)
            return out
    
    
    # 2. 实例化模型,优化器实例化,loss实例化
    my_linear = MyLinear()
    optimizer = SGD(my_linear.parameters(), 0.001)
    loss_fn = nn.MSELoss()
    
    
    # 3. 循环,进行梯度下降,参数的更新
    for i in range(5000):
    
        # 得到预测值
        y_predict = my_linear(x)
        loss = loss_fn(y_predict, y_true)
    
        # 梯度置零
        optimizer.zero_grad()
    
        # 反向传播
        loss.backward()
    
        # 参数更新
        optimizer.step()
    
        if i%200 == 0:
            print(loss.item(), list(my_linear.parameters()))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这里插入图片描述

    可以看到,用API来实现线性回归的收敛效果没有手动实现的好。(不知道为啥)

    3.3 评估模式和训练模式

    model.eval()  # 表示设置模型为评估模式,即预测模式
    model.train(mode=True)  # 表示设置模型为训练模式
    
    • 1
    • 2

    在目前的线性模型中上述没有什么区别,但是在一些训练和预测时参数不同的模型中,比如说是Dropout, BatchNorm 等存在时,就需要告诉模型是训练还是在预测。

    3.4 使用GPU

    1. 判断GPU是否可用: torch.cuda.is_available()
    torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    
    print(device)
    >> device(type='cuda', index=0)  # 使用GPU
    >> device(type='cpu')  # 使用CPU
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 把模型参数和 input数据转换为cuda的支持类型 ( 要转的话要一起转,不能一个在cpu上跑 一个在GPU上跑)
    model.to(device)
    x_true.to(device)
    
    • 1
    • 2
    1. 在GPU上计算结果也为cuda的数据类型,需要转化为numpy或者cpu的tensor类型(就是说 要把gpu上的值转到cpu上进行一些求均值等等的操作)
    predict = predict.cpu().detach().numpy()
    
    • 1

    detach() 的作用相当于 data,但是detach()是深拷贝,data是取值是浅拷贝。

    • 总结:模型放到GPU,那么输入x和输出y_true也要放在GPU,模型的参数也要GPU(如果是内部参数就不需要),最后得到的输出 y_predict 也是GPU类型的。

    在GPU上执行程序:
    (1)自定义的参数和数据,需要转化为cuda支持的tensor
    (2)model需要转化为cuda支持的model
    (3)执行的结果需要和cpu的tensor进行计算的时候:
    a. tensor.cpu() 把cuda的tensor转化为CPU的tensor

    data和item的区别

    .data返回的是一个tensor
    .item()返回的是一个具体的数值。
    注意:对于元素不止一个的tensor列表,使用item()会报错

    list(my_linear.parameters()
    
    • 1
  • 相关阅读:
    Linux源码安装MySQL
    MapReduce——01MapReduce编程规范
    【矩阵论】4. 矩阵运算——广义逆——广义逆的计算
    Visopsys 0.92 发布
    12.1 使用键盘鼠标监控钩子
    【一文秒懂——Profile配置】
    java并发面试题
    一个关于wait/notify与锁关系的探究
    家常菜中的黄焖鸡
    IPython Jupyter NumPy Pandas Matplotlib Scikit-Learn statsmodels
  • 原文地址:https://blog.csdn.net/weixin_42521185/article/details/126829055