zl程序教程

您现在的位置是:首页 >  后端

当前栏目

机器学习经典实例:使用pytorch 完成线性回归分析

实例机器经典学习PyTorch 分析 完成 回归
2023-09-14 09:13:19 时间

机器学习经典实例:使用pytorch 完成线性回归分析


0.总结

Get to the points first. The article comes from LawsonAbs!
  • pytorch中相关函数的使用
  • 线性回归、梯度下降的理解与计算

1.要求

  • 使用随机生成的模拟数据去训练一个函数模型
  • 数据集是点对,呈现的是一次线性函数关系

2.主要思路

这个案例带有 “验证” 的味道,即我们事先定义好一个函数模型,并根据这个模型随机生成一些数据,然后给这些数据集加点儿噪声,最后得到的数据集就是通常所说的训练集。根据训练集训练一个一维函数模型,并使用随机生成的数据测试模型的效果如何,最后用matplotlib 展现拟合效果。

  • step1.事先定义一个函数,即我们的原始数据服从这个函数模型,然后在其中加点儿噪声就得到训练的数据集了;
  • step2.【因为这里是一维函数模型,所以我们就设一次线性函数为这个问题的模型】令函数模型为y=w*x+b。并随机初始化w,b的值;
  • step3.事先定义好学习率 lr = 0.001
  • step4.采用梯度下降的方法更新参数,这里没有调用Autograd中的方法,而是自己计算梯度并更新;
  • step5.每训练完一批数据之后,就开始进行一次模拟验证【对应if ii % 10 == 0:中的部分】

3.代码

from __future__ import print_function
import torch as t
import numpy as np
from matplotlib import pyplot as plt
from IPython import display

t.manual_seed(1000)  # 设置随机数种子,保证任何机器运行都相同
def get_fake_data(batch_size=8):
    # 从均匀分布[0,1) 中抽出8*1的数据,并放大20倍【这里的放大倍数是没有影响的】
    x = t.rand(batch_size, 1) * 20;
    # print(x) # 其类似一个8行1列的向量
    
    # 添加随机噪声
    # 这里的 1+t.randn(batch_size,1) 会在[8,1]这个tensor中每个位置都加1。举例如下:
    """
	tensor([[-0.9596],
        [ 0.3518],
        [-0.4039],
        [ 1.7584],
        [-0.4145],
        [ 0.8561],
        [-0.4429],
        [ 1.4079]])
tensor([[0.0404],
        [1.3518],
        [0.5961],
        [2.7584],
        [0.5855],
        [1.8561],
        [0.5571],
        [2.4079]])
	"""
    y = x * 2 + (1 + t.randn(batch_size, 1)) * 3  
    return x, y

x, y = get_fake_data()
# 只不过是将tensor 转换为numpy
#plt.scatter(x.squeeze().numpy(), y.squeeze().numpy())

# 随机初始化参数
w = t.rand(1, 1) # => w是个tensor
b = t.zeros(1, 1) # => b也是个tensor
lr = 0.001  # learning rate


'''01.这里的意思就是生成一个具有20000个数据对作为样本,然后用这20000个数据对去训练一个函数模型出来'''
for ii in range(20000):
    x, y = get_fake_data() # 模拟出假的数据
    # forward: 计算loss
    #print(x.size()) # torch.Size([8, 1])
    #print(w.size()) # torch.Size([1, 1])
    y_pred = x.mm(w) + b.expand_as(y)
    loss = 0.5 * (y_pred - y) ** 2  # 均方误差
    loss = loss.sum() # Returns the sum of all elements in the input tensor

    # backward: 手动计算梯度
    dloss = 1 # dloss是什么?
    dy_pred = dloss * (y_pred - y)
    # print(x.size()) # torch.Size([8, 1])
    # print(dy_pred.size()) # torch.Size([8, 1])

    '''    
    01.dw = x.t().mm(dy_pred) 里为什么有个x.t()操作? 是什么意思?
    02.mm函数计算的是两个tensor的乘积,但是如果要做矩阵乘积,显然是无法相乘的。
    所以就需要转换【转置】。
    这里的x.t()就是将x进行转置操作。
    03.结合learning rate 调整参数
    '''
    dw = x.t().mm(dy_pred)
    db = dy_pred.sum()
    w.sub_(lr * dw)
    b.sub_(lr * db)

    # 每训练100次就查看训练的效果到底怎么样了
    if ii % 10 == 0:
        # 清空输出 Clear the output of the current cell receiving output
        display.clear_output(wait=True)
        x = t.arange(0, 20).view(-1, 1)
        # print(x.dtype) # torch.int64 所以需要显式的调用.float()将其转换成float型
        # 其根本原因在于t.arange(0,20)是根据默认1为步长来分配的,导致会出现int64
        # print(w.dtype)

        '''
        01.这里再生成一批数据,就相当于测试集。让这个测试集去表示训练模型的具体效果如何
        02.plot是画出直线,scatter是画出离散的点。这样就可以直观地看出拟合的效果了
        03.为了图形更好看,所以设置了一下长度的限制。
        04.为了不直接跳出图形界面,暂缓了0.5s
        05.最后输出了w,b的两个参数值
        '''
        y = x.float().mm(w)+ b.expand_as(x)
        plt.plot(x.numpy(), y.numpy())  # predicted
        x2, y2 = get_fake_data(batch_size=20) # 这里生成的数据是20个
        plt.scatter(x2.numpy(), y2.numpy())  # true data
        plt.xlim(0, 20) # 设置x轴,y轴的最大值
        plt.ylim(0, 41)
        plt.show()
        print("w=",w.item(), "b=",b.item())

上面这段代码在pycharm中的执行结果就是:

  • 屏幕上会弹出若干幅图形,这些图形由两部分构成:
    (1)训练得到的函数模型
    (2)真实数据(其实就是我们模拟生成的数据)的一个个参数点坐标
  • 底部会打印出参数w,b的值。

运行结果和一部分的参数展示:
在这里插入图片描述

4.难点分析

  • tensor【其实就是矩阵】间的相互运算
  • pytorch函数的学习
    这里我都在文章中的代码中进行了详细的注释。
  • 梯度下降的理解与计算
4.1 看看到底是怎么运算?

我觉得新手最容易怀疑的问题就是:y=w*x+b,这个乘与加的过程到底是什么样的?这里我就把数据拿出来,专门做个解释。

  • 函数模型
    y = x*w + b

  • 数据

x = tensor([[ 8.8605],
        [13.1534],
        [ 8.5220],
        [ 6.9218],
        [13.6363],
        [16.2603],
        [ 4.5726],
        [12.9265]])
w = tensor([[0.3915]])

我们手动相乘一下,就得到了如下的结果:

x*w = tensor([[3.46888575],
[5.1495561],
[]...
])

实际计算机运算得到的x*w值如下:

tensor([[3.4685],
        [5.1490],
        [3.3360],
        [2.7096],
        [5.3380],
        [6.3652],
        [1.7900],
        [5.0602]])

然后再加上b的值【这里是0矩阵】,最后就成了y_pred的值【即y的预测值】。可以发现二者是相同的。【计算机应该不会算错的】

而此时生成的y的值为:

y = tensor([[24.2896],
        [23.1069],
        [21.5958],
        [12.2041],
        [35.8736],
        [36.4838],
        [14.5665],
        [28.4940]])

可以看到他们的之间的loss太大了,现在的问题就是调整这个w,b去减少loss。这是后话,不说了。

4.2 具体函数的使用
  • expand_as()
    把一个tensor变成和函数括号内一样形状的tensor,用法与 expand()类似
    具体实例:
>>> import torch as t
>>> x=t.rand(3,4)
>>> print(x.size())
torch.Size([3, 4])
>>> print(x)
tensor([[0.7740, 0.1354, 0.3477, 0.7286],
        [0.3327, 0.4944, 0.3491, 0.1855],
        [0.3790, 0.8667, 0.6716, 0.2647]])
>>> b=t.zeros(1,1)
>>> print(b)
tensor([[0.]])
>>> print(b.size())
torch.Size([1, 1])
>>> b=b.expand_as(a)
>>> print(b.size())
torch.Size([2, 3])
>>> print(b)
tensor([[0., 0., 0.],
        [0., 0., 0.]])
  • 平方运算【**2
    这里我们在loss函数中用到了平方运算。是将(y_pred-y)**2,这里的y是一个tensor,相当于一个8行一列的数组,其平方运算就是直接将tensor的每位直接对应相乘,然后得到的结果。示例如下:
import torch as t
x=t.rand(8,1) * 10
print("x=",x)
y=x**2
print("y=(x**2)=",y)

在这里插入图片描述当二维或者更加高维的tensor去验证也可以发现的确就是这样运算方法。