2.3.5 定义损失函数

Gluon 中,损失函数通过 loss 模块提供。在这个例子中,我们使用的是 L2损失(也叫 均方误差(MSE)),它衡量的是模型预测值与真实标签之间的差异。

loss = gluon.loss.L2Loss()
  • L2Loss:计算预测值和真实值之间的平方差并返回该值作为损失。适用于回归任务,尤其是线性回归模型中。

2.3.6 定义优化算法

优化算法是训练模型的关键部分,负责调整模型参数,使得损失函数的值最小化。小批量随机梯度下降SGD)是最常用的优化方法之一,Gluon 提供了 Trainer 类来处理不同的优化算法及其超参数。

在实例化 Trainer 时,我们需要指定:

  • 模型参数:通过 net.collect_params() 获取。
  • 优化算法:在本例中是 'sgd',即小批量随机梯度下降。
  • 超参数字典:包含如 学习率(learning_rate 等优化超参数。
from mxnet import gluon

trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.03})
  • learning_rate:设置学习率,这决定了每次更新参数的步长。这里设为 0.03。

2.3.7 训练

通过高层API,训练过程可以相对简洁。我们不再需要手动管理梯度计算、损失计算等细节。训练过程通常分为以下几个步骤:

  1. 前向传播:通过 net(X) 生成预测值,并计算损失 l
  2. 反向传播:通过 l.backward() 计算损失对参数的梯度。
  3. 参数更新:通过 trainer.step(batch_size) 更新模型参数。

每个训练周期,我们都会遍历一次数据集,并从中获取一个小批量的数据(X)和标签(y)。对于每一个小批量,执行上述三个步骤。

num_epochs = 3
for epoch in range(num_epochs):
    for X, y in data_iter:
        with autograd.record():
            l = loss(net(X), y)  # 前向传播
        l.backward()  # 反向传播
        trainer.step(batch_size)  # 更新模型参数
        
    # 打印当前周期的损失值
    l = loss(net(features), labels)
    print(f'epoch {epoch + 1}, loss {l.mean().asnumpy():f}')

例如,训练过程中,损失值会随着训练的进行逐渐下降:

epoch 1, loss 0.025140
epoch 2, loss 0.000089
epoch 3, loss 0.000051

2.3.8 模型参数与真实值对比

训练完成后,我们可以检查模型的参数,并与真实的参数进行对比。在这个例子中,我们查看的是模型的权重(w)和偏置(b)。

w = net[0].weight.data()  # 获取权重
print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')

b = net[0].bias.data()  # 获取偏置
print(f'b的估计误差: {true_b - b}')

输出示例:

w的估计误差: [ 0.00055146 -0.0003221 ]
b的估计误差: [0.00057793]

可以看到,训练获得的参数与生成数据的真实参数非常接近。

2.3.9 小结

  • 我们使用 Gluon 提供的高层API,简化了模型定义、损失函数定义和优化算法的实现。
  • data 模块 提供了数据处理工具,nn 模块 定义了许多神经网络层,loss 模块 提供了常见的损失函数。
  • MXNetinitializer 模块为模型参数提供了多种初始化方式。
  • 通过 autogradTrainer,可以简化反向传播和参数更新的过程,轻松实现高效的训练。

2.3.10 练习

  1. 问题: 如果我们用 l = loss(output, y).mean() 替换 l = loss(output, y),为了使代码的行为相同,需要将 trainer.step(batch_size) 更改为 trainer.step(1),这是为什么?

    解答:
    在使用 loss(output, y).mean() 时,我们计算的是批量损失的平均值。这会导致损失值的标量形式,因此需要将 trainer.step(batch_size) 改为 trainer.step(1),以确保每次更新的梯度基于单个样本而非整个批次。

  2. 问题: 查看 MXNet 文档,了解模块 gluon.lossinit 中提供了哪些损失函数和初始化方法。用 Huber损失 来代替。

    解答:
    MXNet 中,gluon.loss 模块提供了多个常用的损失函数,例如 L2Loss, SoftmaxCrossEntropyLoss, HuberLoss 等。我们可以通过以下代码使用 Huber损失

    loss = gluon.loss.HuberLoss()
    
  3. 问题: 你如何访问 dense.weight 的梯度?

    解答:
    通过以下方式可以访问 Dense 层的权重梯度:

    grad_w = net[0].weight.grad()
    print(grad_w)
    

    这将输出 Dense 层权重的梯度。
    在这里插入图片描述

Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐