提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

这段代码是一个简单的线性回归模型训练过程,主要步骤包括数据生成、数据提供器、预测函数、损失函数、优化算法以及训练和可视化结果。下面详细解释每一部分的作用:


提示:以下是本篇文章正文内容,下面案例可供参考

一、导入必要的库

import os
from contourpy.util import data
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
import torch
import matplotlib.pyplot as plt #画图的
import random   #随机

这些库分别用于环境配置数据处理绘图随机数生成
oscontourpy.util.data 相关的导入在这里没有实际用途,可以忽略。这里主要是解决某个本地配置的重名问题。
torch: PyTorch 库,用于深度学习模型的构建和训练。
matplotlib.pyplot: 用于绘制图表。
random: 用于生成随机数。

二、生成数据

def create_data(w, b, data_num):    #生成数据
    x = torch.normal(0, 1, (data_num, len(w)))
    y = torch.matmul(x, w) + b      #matmul矩阵相乘

    noise = torch.normal(0, 0.01, y.shape ) #噪声要加到y上
    y += noise

    return x, y

num = 500
true_w = torch.tensor([8.1, 2, 2, 4])
true_b = torch.tensor(1.1)

X, Y = create_data(true_w, true_b, num)

create_data 函数用于生成模拟数据集。这里我们生成了500个样本,每个样本有四个特征,并且这些样本遵循一个线性关系 y=Xw+b 加上一些噪声

  • x = torch.normal(0, 1, (data_num, len(w))): 生成一个均值为0、标准差为1的正态分布随机数张量,形状为 (data_num, len(w)),即每个样本有四个特征。这里表示行数为data_num,列数为len(w)
  • y = torch.matmul(x, w) + b: 计算目标变量 y,其中 torch.matmul(x, w) 表示矩阵乘法 y=Xw ,然后加上偏置 b
  • noise = torch.normal(0, 0.01, y.shape): 生成一个均值为0、标准差为0.01的正态分布噪声张量,形状与 y 相同(形状说明直接用的y.shape)。

num = 500: 设置生成的数据样本数量为500。
true_w = torch.tensor([8.1, 2, 2, 4]): 定义真实的权重参数。
true_b = torch.tensor(1.1): 定义真实的偏置参数。
X, Y = create_data(true_w, true_b, num): 调用 create_data 函数生成数据集 X 和 Y。

三、绘制散点图

plt.scatter(X[:, 0], Y, 1)
plt.show()

使用matplotlib库绘制第一个特征与目标变量之间的散点图,以便初步观察数据分布情况。
plt.scatter(X[:, 0], Y, 1): 使用 Matplotlib 绘制第一个特征与目标变量之间的散点图。

  • X[:, 0]: 提取所有样本的第一个特征。
  • Y: 提供对应的目标变量。
  • 1: 设置散点的大小。

plt.show(): 显示图形。

四、定义数据提供器

def data_provider(data, label, batchsize):          #每次访问这个函数,就能提供一批数据
    length = len(data)  #length:500
    indices = list(range(length))       #0~500的一个列表
    #我不能按顺序取    把数据打乱
    random.shuffle(indices)

    for  each in range(0, length, batchsize):
        get_indices = indices[each:each+batchsize]      #batchsize步长为16,即16个数据为一组
        get_data = data[get_indices]
        get_label = label[get_indices]

        yield get_data, get_label   #有存档点的return    即会保留上一次循环的数据

batch_size = 16

data_provider 是一个生成器函数,它每次返回一个批次的数据(这里是16个样本),并且在每次调用时都会打乱数据顺序以减少过拟合的风险。

  • length = len(data): 获取数据集的长度(这里是500)。
  • indices = list(range(length)): 创建一个索引列表 [0, 1, …, 499]。
  • random.shuffle(indices): 打乱索引列表,确保每次获取的数据顺序不同。
  • for each in range(0, length, batchsize): 按照 batchsize 分割数据集。
  • get_indices = indices[each:each+batchsize]: 获取当前批次的索引。
  • get_data = data[get_indices]: 根据索引获取当前批次的数据。
  • get_label = label[get_indices]: 根据索引获取当前批次的标签。
  • yield get_data, get_label: 返回当前批次的数据和标签,并暂停执行,等待下一次调用。

batch_size = 16: 设置每个小批量的数据量为16。

五、定义预测函数

def fun(x, w, b):
    pred_y = torch.matmul(x, w) + b
    return pred_y

fun 函数用于计算给定输入特征 x 和参数 w、b 下的目标值预测

  • pred_y = torch.matmul(x, w) + b: 计算预测值 y’=Xw+b。
  • return pred_y: 返回预测值。

六、定义损失函数

def maeLoss(pre_y, y):
    return torch.sum(abs(pre_y - y)) / len(y)

maeLoss 计算均绝对误差(MAE),这是一种常用的回归任务损失函数,衡量预测值与真实值之间的差异。
torch.sum(abs(pre_y - y)): 计算预测值与真实值之间绝对误差的总和。
/ len(y): 将总和除以样本数量,得到平均值。

七、定义优化算法

def sgd(paras, lr):     #随机梯度下降,更新参数
    with torch.no_grad(): #属于这句代码的部分,不计算梯度
        for para in paras:
            para -= para.grad * lr   #lr为学习率    不能写成para =  para - para.grad*lr(这会新创一个para)
            para.grad.zero_()   #使用过的梯度,归0

sgd 实现了随机梯度下降法来更新模型参数。通过减去学习率乘以参数梯度来调整权重,并清空梯度以备下次迭代使用。

  • with torch.no_grad(): 在此上下文中,禁用梯度计算,防止在更新参数时影响后续的梯度计算
  • for para in paras: 遍历所有需要更新的参数(这里是权重 w 和偏置 b)。
  • para -= para.grad * lr: 更新参数,通过减去学习率乘以参数的梯度(不可以para = para - lr*para.grad,因为会新创一个para)。
  • para.grad.zero_(): 清空参数的梯度,以便下次迭代重新计算。

八、初始化参数并开始训练

lr = 0.03	
w_0 = torch.normal(0, 0.01, true_w.shape, requires_grad=True)   #这个w需要计算梯度
b_0 = torch.tensor(0.01, requires_grad=True)
print(w_0, b_0)

epochs = 50  #要训练的轮数

for epoch in range(epochs):
    data_loss = 0
    for batch_x, batch_y in data_provider(X, Y, batch_size):
        pred_y = fun(batch_x, w_0, b_0)
        loss = maeLoss(pred_y, batch_y)     #pred_y是预测值 batch_y是真实值
        loss.backward()           #梯度回传
        sgd([w_0, b_0], lr)

        data_loss += loss
    print("epoch %03d: loss: %.6f"%(epoch, data_loss))

初始化权重 w_0 和偏置 b_0,然后进行多轮训练(这里选择50轮)。每一轮中,从数据提供器获取一个小批量数据,计算预测值和损失,并通过反向传播更新参数。最后打印出每轮的总损失。
初始化参数:

  • w_0 = torch.normal(0, 0.01, true_w.shape, requires_grad=True): 初始化权重 w_0,设置其形状与真实权重相同,并启用梯度计算。
  • b_0 = torch.tensor(0.01, requires_grad=True): 初始化偏置 b_0,并启用梯度计算。
  • print(w_0, b_0): 打印初始化后的权重和偏置。

开始训练:

  • data_loss = 0: 初始化本轮的总损失。
  • for batch_x, batch_y in data_provider(X, Y, batch_size): 从数据提供器获取一个小批量数据。
  • pred_y = fun(batch_x, w_0, b_0): 计算预测值。
  • loss = maeLoss(pred_y, batch_y): 计算损失。
  • loss.backward(): 反向传播,计算梯度
  • sgd([w_0, b_0], lr): 使用 SGD 更新参数。
  • data_loss += loss: 累加当前批次的损失。
  • print(“epoch %03d: loss: %.6f”%(epoch, data_loss)): 打印每轮的总损失。

九、输出真实的参数和训练得到的参数

print("真实的函数值是", true_w, true_b)
print("训练得到的参数值是", w_0, b_0)

分别打印真实的和训练得到的权重和偏置

十、可视化结果

idx = 0 #取第一列(行)
plt.plot(X[:,idx].detach().numpy(), X[:,idx].detach().numpy()*w_0[idx].detach().numpy() + b_0.detach().numpy())
plt.scatter(X[:, idx], Y, 1)
plt.show()

最后,根据训练得到的参数绘制一条直线,表示模型学到的关系,并与原始数据点一起显示出来,以便直观地评估模型性能。
idx = 0: 设置要可视化的特征列为第一个特征。

plt.plot(X[:,idx].detach().numpy(), X[:,idx].detach().numpy()*w_0[idx].detach().numpy() + b_0.detach().numpy()): 绘制训练得到的线性回归模型的拟合直线。

  • X[:,idx].detach().numpy(): 提取第一个特征并转换为 NumPy 数组。
  • X[:,idx].detach().numpy()*w_0[idx].detach().numpy() + b_0.detach().numpy(): 计算对应的预测值。

plt.scatter(X[:, idx], Y, 1): 绘制原始数据点。
plt.show(): 显示图形

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐