如何进行神经网络的模型训练(视频代码中的知识点记录)

发布于:2025-09-07 ⋅ 阅读:(19) ⋅ 点赞:(0)

视频链接:详解神经网络是如何训练的——细节到每个参数(👉戳右边合集观看最新Transformer相关教程)_哔哩哔哩_bilibili

1.nn.Parameter()

在 PyTorch 中,nn.Parameter() 是一个特殊的类(torch.nn.Parameter),用于定义神经网络中可学习的参数(如权重、偏置等)。它是 torch.Tensor 的子类,核心作用是:当把 Parameter 对象赋值给 nn.Module 类(或其子类,如自定义模型、层)的属性时,会自动被注册为模型的参数,并参与训练时的梯度计算和更新。

  • nn.Parameter 会被自动纳入模型的参数管理,是 “可学习参数” 的官方标记方式。
    import torch
    from torch import nn
    class Model(nn.Module):
        def __init__(self):
            super().__init__()
            self.w=nn.Parameter(torch.randn(2,3))
            self.b=nn.Parameter(torch.zeros(2))
        
        def forward(self,x):
            return x@self.w.t()+self.b
    model=Model()
    for name,param in model.named_parameters():
        print(f"参数名:{name},形状:{param.shape}")
        
    
    
    
    
            
    

    注意:在 PyTorch 中,torch.randn(4, 3) 会生成一个形状为 (4, 3) 的张量,其元素是服从标准正态分布(均值为 0,标准差为 1)的随机数。因此,self.w 的具体数值是随机生成的,每次运行代码都会得到不同的结果。

2.损失函数标准差的计算

其中data_train.iloc[i:i+4, :-1]是panda中按位置提取数据的操作,是一个panda_DataFrame对象,要求变量名不能有空格,由此命名为data_train。i:i+4表示选取从索引 i 到 i+3 的连续 4 行数据,:-1表示选取除最后一列之外的所有列。而只有-1表示选取最后一列。

3.self的用法

不是所有的类中的函数(方法)都有self参数,类的方法有实例化方法,类方法,静态方法。

实例化方法要求第一个参数是self,self 代表调用该方法的实例对象本身。

类方法:用 @classmethod 装饰,第一个参数必须是 cls(代表类本身),不需要 self
作用:操作类的属性或创建实例(与类相关,不依赖具体实例)。

静态方法:用 @staticmethod 装饰,既不需要 self,也不需要 cls,本质上是定义在类命名空间中的普通函数。
作用:提供与类相关的工具功能,不依赖类或实例的状态。

4.pyTorch模型训练步骤

初始化模型 → 2. 初始化优化器(依赖模型参数,需在模型之后)→ 3. 准备数据 → 4. 循环训练(多轮 Epoch)

每轮训练:梯度清零 → 前向传播(算 y_pred)→ 计算损失 → 反向传播(算梯度)→ 优化器更新参数(用梯度调参)

import torch
from torch import nn
import numpy as np
import pandas as pd
from torch.optim import AdamW

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.w = nn.Parameter(torch.tensor([
            [0.1,0.2],
            [0.2,0.3],
            [0.1,0.3]

        ]))  # 权重:(1,2),对应2个特征
        self.b = nn.Parameter(torch.tensor([0.0,0.1,0.2]))     # 偏置:
        self.softmax=nn.Softmax(-1)
    
    def forward(self, x):
        # 修正:用squeeze()将输出从(3,1)转为(3,),与y的形状完全匹配
        return self.softmax((x @ self.w.t() + self.b).squeeze()  )
    
    @staticmethod
    def loss(y_pred, y):
        return ((y_pred - y) ** 2).mean()  # MSE损失

if __name__ == '__main__':
    # 1. 初始化模型
    model = Model()
    print(model.w) 
    print(model.b)
    # 2. 初始化优化器(必须在模型之后)
    optimizer = AdamW(
        params=model.parameters(),
        lr=0.1  # 学习率
    )

    # 3. 准备训练数据
    data_list = [
        [1, 2, 3, 4],   # x取前2列[1,2],y取最后1列[4]
        [2, 3, 4, 5],   # x取[2,3],y取[5]
        [3, 4, 5, 6]    # x取[3,4],y取[6]
    ]
    data_train = pd.DataFrame(data_list)

    # 4. 训练循环(核心修正部分)
    epochs = 10  # 训练轮次
    for epoch in range(epochs):  # 外部epoch循环:用epoch而非i,避免变量冲突
        # 关键1:每个epoch重置损失列表,不累积历史损失
        epoch_loss_list = []  
        # 关键2:内部数据循环用j,避免与外部epoch变量冲突(原代码用i覆盖)


        for j in range(0, len(data_train), 4):  #核心作用是从 data_train 的第 0 个元素开始,每间隔 4 个元素取一个索引 j,通常用于 批量处理数据(比如每次处理 4 个样本,即批量大小为 4)
            # 提取特征x:前2列,形状(3,2)(3个样本,每个样本2个特征)
            x = torch.tensor(np.array(data_train.iloc[j:j+3, :-2]), dtype=torch.float32)
            # 提取标签y:最后1列,形状(3,)(3个样本,每个样本1个标签)
            y = torch.tensor(np.array(data_train.iloc[j:j+3, -1]), dtype=torch.float32)
            
            # 前向传播:得到y_pred(形状(3,))
            y_pred = model(x)
            # 计算当前批次损失
            batch_loss = Model.loss(y_pred, y)
            # 收集当前epoch的批次损失
            epoch_loss_list.append(batch_loss)


        # 5. 反向传播与参数更新(关键修正:顺序和梯度清零)
        optimizer.zero_grad()  # 关键3:先清零梯度,再反向传播(原代码顺序颠倒)
        total_epoch_loss = sum(epoch_loss_list)  # 当前epoch的总损失(不累积历史)
        total_epoch_loss.backward()  # 对当前epoch的总损失反向传播
        optimizer.step()  # 更新参数

        # 6. 打印训练日志(观察损失下降和参数更新)
        print(f"Epoch: {epoch+1:2d} | Total Loss: {total_epoch_loss.item():.4f}")
        print(model.w)
        print(model.b)
    y_preds=[torch.round(y_pre) for y_pre in y_pred]
    print('#########',y_preds)

    accuracy=(np.array(y_pred)==(np.array(y))).mean()
    print('Accaracy:',accuracy)


    

5,前向传播和反向传播的区别

6.nn.Linear()

nn.Linear 是 PyTorch(torch.nn 模块)中实现线性变换的核心层类,本质是对输入数据执行「矩阵乘法 + 偏置加法」操作,公式为:
y = x · Aᵀ + b
其中:x 是输入,A 是层的权重矩阵,b 是偏置向量(可选),y 是输出。它是神经网络中构建全连接层、输入输出层的基础组件。

import torch
from torch import nn
torch.random.manual_seed(42)

class F1(nn.Module):
    def __init__(self):
        super().__init__()
        self.softmax=nn.Softmax(-1)
        self.linear=nn.Linear(4,3)
    def forward(self,x):
        return self.softmax(self.linear(x))
    
f=F1()
X=torch.tensor([
    [1.2,2.1,3.3,4.5],
    [2.3,3.4,4.5,5.1]
])

y_pred=f(X)
print(y_pred)
print(f.linear.weight)
print(f.linear.bias)

7.密集张量与稀疏张量的区别

密集张量存储全部元素(包括大量无意义的零值 / 无效值),稀疏张量仅存储 “有意义的非零 / 有效元素” 及其位置,二者适用于不同数据场景。

稀疏张量: 例如一个3×4 的表格,若只有 2 个非零值,只需记录这 2 个值的 “行号、列号” 和 “值本身”,无需记录其他零值。

密集张量:比如一个 3×4 的表格,即使大部分单元格是 0,也会把每个单元格的内容(包括 0)都记录下来。

8.TensorFlow,Pytorch和Transfrom的关系

TensorFlow 和 PyTorch 是 “平行的深度学习工具”,都能将 “Transformer 这个序列建模方案” 转化为可训练、可运行的模型;Transformer 依赖这两个框架(或其他框架)实现,而两个框架则通过支持 Transformer,拓展了自身处理序列任务的能力。


网站公告

今日签到

点亮在社区的每一天
去签到