使用相同模型相同数据集,为什么每次运行得到的损失值都不一样?

今天小编在学习 PyTorch 时,突然发现咋每次运行所得损失绘制的曲线都不一样呢?即使小编使用torch.manual_seed()函数固定 torch 的随机数种子每次运行的结果还是不一样,因此小编就写一篇文章记录一下。

数据集

本次使用的数据集是小编自定义的小型数据集:

x1x2x3x4x5x6x7x8x9x10y
464113572142224454321
395519562351303035560
423314352953305133591
512518232728243921300
365820422649285121361
603016412658282326411
282612582346514154270
453710502626272732541
474916372049203744280
465512592638222043561
562713262026452653341

注:

  1. 表格中xi 表示样本特征(输入),而y表示值(输出)。
  2. 制作数据集时,需要先将样本数据导入excel表格,再将文件保存为.csv格式的文件,最后再使用函数np.loadtxt(DATASETS_PATH + “文件名.csv”, delimiter=“,”, dtype=np.float32, skiprows=1)即可完成数据导入。

源码与分析

首先使用 numpy 加载数据集,并且将模型的输入与输出值分别取出。

def dataLoader():
    """
    加载数据集
    """
    xy = np.loadtxt(DATASETS_PATH + "/my_test/my_test.csv", delimiter=",", dtype=np.float32, skiprows=1)
    x_data = torch.from_numpy(xy[:, :-1])
    y_data = torch.from_numpy(xy[:, [-1]])

    return x_data, y_data

定义模型,在这个模型的最初输入是 10 维数据,输出是 1 维数据。

class my_model(nn.Module):
    def __init__(self):
        super(my_model, self).__init__()
        self.network = nn.Sequential(
            nn.Linear(10, 5),
            nn.ReLU(),
            nn.Linear(5, 2),
            nn.ReLU(),
            nn.Linear(2, 1)
        )

    def forward(self, x):
        y_pred = self.network(x)
        return y_pred

网络结构self.network是一个由多个层组成的序列,使用nn.Sequential来组织。这意味着数据将按照定义的顺序依次通过这些层。

  • 第一层:nn.Linear(10, 5),这是一个全连接层,将输入特征从10维减少到5维。
  • 第二层:nn.Sigmoid(),这是一个激活函数,将第一层的输出通过Sigmoid函数,输出值范围在0到1之间,通常用于二分类问题。
  • 第三层:nn.Linear(5, 2),又一个全连接层,将特征从5维减少到2维。
  • 第四层:nn.Sigmoid(),再次使用Sigmoid激活函数。
  • 第五层:nn.Linear(2, 1),将特征从2维减少到1维,这通常意味着模型的输出是一个单一的值。
  • 第六层:nn.Sigmoid(),最后一层也是Sigmoid激活函数。

前向传播forward方法定义了数据通过模型的方式。输入x将通过self.network,即上面定义的序列,最终得到预测值y_pred
输出:模型的输出是一个经过Sigmoid函数的单一值。这意味着无论输入特征如何,模型的输出都将是一个介于0和1之间的值,这通常用于二元分类问题,其中输出可以解释为属于某个类别的概率。
模型训练有六个步骤:数据集加载、模型定义、损失函数定义、优化器定义、训练模型、测试模型。一般情况下数据加载时会得到两部分数据:训练集与测试集,训练集通常用于模型训练或作为测试集的一部分,测试集用于测试所得到模型的准确度也可提高模型的泛化能力。
下面是模型训练的代码,此次训练直接使用所有测试集,且并未添加测试集。

def train():
    # step1 数据加载
    x_data, y_data = dataLoader()
    # step2 模型定义
    model = my_model()

    # step3 损失函数定义
    loss = nn.MSELoss()
    # step4 优化器定义
    optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
    # step5 训练
    loss_list = []
    for i in range(5):
        _loss_list = []
        for epoch in range(100):
            # 前向传播
            y_pred = model(x_data)
            # 计算损失
            loss_value = loss(y_pred, y_data)
            _loss_list.append(loss_value.item())
            # 反向传播
            optimizer.zero_grad()
            loss_value.backward()
            # 更新参数
            optimizer.step()
        loss_list.append(_loss_list)
    # 绘制损失曲线
    draw_liners((range(len(loss_list[0])), loss_list[0], '-', 'liner1'),
                (range(len(loss_list[1])), loss_list[1], '--', 'liner2'),
                (range(len(loss_list[2])), loss_list[2], '-.', 'liner3'),
                (range(len(loss_list[3])), loss_list[3], ':', 'liner4'),
                (range(len(loss_list[4])), loss_list[4], 'solid', 'liner5'),
                labels=['epoch', 'loss vale'], img_name="loss liners0",
                is_display=False, is_save=True, imgs_path=IMAGES_PATH)

未添加随机数种子时,得到结果:
跑.png
添加随机数种子后得到结果
p1.png
在 pytorch 中可使用torch.manual_seed(11) 添加随机数种子,添加随机数种子用于初始化随机数生成器的状态,能够确保实验的可重复性。

问题阐述与分析

好!那么问题来了。

  • 上述八张图片中曲线的线型大致一致,均为单调减函数,同一个 liner 相差并不是特别大,但不同 liner 数值上相差非常大。
  • 未添加随机数种子时,每次训练所得到的曲线虽然线型一致,但是值存在一定的误差。
  • 而添加随机数种子后,每次重新训练每个单独的 liner 都一样,但是不同 liner 值却不一样。

询问 AI 后,看 AI 的结果:

使用相同模型和数据集进行训练时,每次运行得到的损失值可能会不同,这可能是由以下几个因素导致的:

  1. 初始化权重的差异:神经网络在训练前需要初始化权重,不同的初始化方法或随机种子会导致权重初始化值不同,从而影响最终的损失值 。
  2. 学习率设置:如果学习率过大,可能会导致损失值突然变得很大,即模型训练出现“跑飞”的情况 。
  3. 数据集的划分和顺序:即使是相同的数据集,不同的数据划分和读取顺序也可能导致每次训练损失值波动 。
  4. 优化器的选择和配置:不同的优化器(如SGD、Adam等)或其配置参数(如动量、衰减率等)会影响模型训练的动态过程,进而影响损失值 。
  5. 正则化策略:正则化项的加入和参数(如L1、L2正则化的系数)会影响损失函数的值,不同的正则化设置可能导致损失值的变化 。
  6. 梯度消失或爆炸问题:在深度学习中,梯度消失或爆炸问题可能导致模型训练不稳定,从而影响损失值的稳定下降 。
  7. 训练过程中的随机性:如Dropout等引入随机性的操作,每次执行时都可能不同,进而影响损失值 。
  8. 数据预处理:数据的标准化、归一化等预处理步骤的不同,也可能导致损失值的波动 。
  9. 模型结构设计:模型结构的不同,如层数、神经元数量等,也会影响损失值的最终结果 。
  10. 损失函数的选择:不同的损失函数可能对模型训练过程中的损失值有不同的影响,特别是在分类问题中,交叉熵损失函数的选择会对损失值产生影响 。

小编的想法:

  • 计算精度:因为计算机内部参与运算的数据大小会受到一定的限制,这就有可能会造成最终结果产生一定误差。在控制台中打印每次 loss 得到结果loss_value.item()=0.2310512214899063,个人猜测这种可能性较小。
  • 模型的随机性:神经网络算法具有一定的随机性,如初始化随机权重,因此用同样的数据训练同一个网络会得到不同的结果。模型定义时,可使用下面这段代码查看模型参数。
self.linear = nn.Linear(in_features, out_features)
for name, p in self.linear.named_parameter():
    print(name, ": ", p)
  • 第三方库的随机性:在本模型中,并未引入任何第三方库,因此小编认为此种情况不符合这个实例。

【Python 】数据可视化入门:使用 Matplotlib、Numpy 和 SciPy 绘制精美曲线曲面图

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值