模型训练(以LeNet为例)

在上面一篇文章,我介绍了LeNet的一些基本知识,下面我们来看如何训练这个网络,后续的训练基本上就是按照这个套路来就可以

首先上代码,代码取自《dive into deep learning》


def train(net, train_iter, test_iter, num_epochs, lr, device):
    # 首先初始化权重,使用nn.init.xavier_uniform_初始化函数
    def init_weights(m):
        if type(m) == nn.Linear or type(m) == nn.Conv2d:
            nn.init.xavier_uniform_(m.weight)
    # 经过初始化的权重应用到网络中,用于初始化模型的权重    
    net.apply(init_weights)
    # 下面是要将模型进行部署,这里是要部署到GPU上
    print('training on', device)
    net.to(device)
    # 定义优化器更新模型参数
    optimizer = torch.optim.SGD(net.parameters(), lr=lr)
    # 交叉熵损失    
    loss = nn.CrossEntropyLoss()
    animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
                            legend=['train loss', 'train acc', 'test acc'])
    timer, num_batches = d2l.Timer(), len(train_iter)
    for epoch in range(num_epochs):
        # 训练损失之和,训练准确率之和,样本数
        metric = d2l.Accumulator(3)
        net.train()
        for i, (X, y) in enumerate(train_iter):
            timer.start()
            optimizer.zero_grad()
            X, y = X.to(device), y.to(device)
            y_hat = net(X)
            l = loss(y_hat, y)
            l.backward()
            optimizer.step()
            with torch.no_grad():
                metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
            timer.stop()
            train_l = metric[0] / metric[2]
            train_acc = metric[1] / metric[2]
            if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
                animator.add(epoch + (i + 1) / num_batches,
                             (train_l, train_acc, None))
        test_acc = evaluate_accuracy_gpu(net, test_iter)
        animator.add(epoch + 1, (None, None, test_acc))
    print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, '
          f'test acc {test_acc:.3f}')
    print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec '
          f'on {str(device)}')

下面对这段代码进行解释,如有不当敬请指出

  • def train(net, train_iter, test_iter, num_epochs, lr, device):
    定义了一个函数 train,接受模型 net、训练集迭代器 train_iter、测试集迭代器 test_iter、迭代的轮数 num_epochs、学习率 lr 和设备类型 device 作为输入参数。

  • def init_weights(m):
    定义了一个内部函数 init_weights,这个函数在后面的代码中被用来对模型的权重进行初始化。

  • if type(m) == nn.Linear or type(m) == nn.Conv2d:
    在 init_weights 函数中,如果 m 是 nn.Linear 或者 nn.Conv2d 类型的模块,则执行下面的语句。

  • nn.init.xavier_uniform_(m.weight)
    用 Xavier 初始化方法对模块 m 的权重进行初始化。Xavier 初始化是一种常用的权重初始化方法,旨在解决深度神经网络中梯度消失和梯度爆炸的问题。这个方法假设前一层的输入和后一层的输出具有相等的方差,从而使得信息能够在网络中保持相对稳定。nn.init.xavier_uniform_()是一个就地操作,它会直接修改所传入张量的值,而不会返回一个新的张量。这意味着无需重新分配内存,可以直接在原地初始化权重。

  • net.apply(init_weights)
    调用 apply 方法,将 init_weights 函数应用到 net 模型的所有模块的权重上,用于初始化模型的权重。

  • print(‘training on’, device)
    打印当前训练所使用的设备类型。

  • net.to(device)
    将模型 net 移动到指定的设备上,以便在该设备上进行训练。

  • optimizer = torch.optim.SGD(net.parameters(), lr=lr)
    创建一个随机梯度下降(SGD)优化器对象 optimizer,用于更新模型的参数。传入的参数是模型 net 的可学习参数和学习率 lr。
    优化器这里后面开一篇新的帖子记录。

  • loss = nn.CrossEntropyLoss()
    创建一个交叉熵损失函数对象 loss,用于计算模型的输出与真实标签之间的损失。

  • animator = d2l.Animator(xlabel=‘epoch’, xlim=[1, num_epochs], legend=[‘train loss’, ‘train acc’, ‘test acc’])
    创建一个动画显示对象 animator,用于在训练过程中可视化训练损失、训练准确率和测试准确率的变化。xlabel 参数表示横轴标签为 “epoch”,xlim 参数为横轴的范围,legend 参数表示图例标签。

  • timer, num_batches = d2l.Timer(), len(train_iter)
    创建一个计时器对象 timer,用于计算训练每个 epoch 所需的时间,并且获取训练集迭代器 train_iter 的长度作为总批次数 num_batches。

  • for epoch in range(num_epochs):
    开始迭代训练的轮数,从 0 到 num_epochs-1。

  • metric = d2l.Accumulator(3)
    创建一个累加器对象 metric,用于累计训练损失之和、训练准确率之和和样本数量。

  • net.train()
    把模型设置为训练模式,这会启用 dropout 和批量归一化等层的训练行为。

  • for i, (X, y) in enumerate(train_iter):
    迭代训练集数据,获取每个批次的图像数据 X 和标签数据 y。

  • optimizer.zero_grad()
    清零所有模型参数的梯度。

  • X, y = X.to(device), y.to(device)
    将输入数据 X 和标签数据 y 移动到指定的设备上。

  • y_hat = net(X)
    使用当前模型 net 对输入数据 X 进行前向传播得到预测值 y_hat。

  • l = loss(y_hat, y)
    计算预测值 y_hat 和真实标签 y 之间的损失值。

  • l.backward()
    反向传播,计算损失相对于模型参数的梯度。

  • optimizer.step()
    根据计算得到的梯度更新模型参数。

  • with torch.no_grad():
    在上下文中,禁用梯度计算。

  • metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
    使用累加器 metric 分别累加当前批次的训练损失、训练准确率和样本数量。

  • timer.stop()
    停止计时器。

  • train_l = metric[0] / metric[2]
    计算平均训练损失。

  • train_acc = metric[1] / metric[2]
    计算平均训练准确率。

  • (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
    如果迭代达到每个 epoch 的五分之一进度(包括最后一次迭代),执行下面的语句。

  • animator.add(epoch + (i + 1) / num_batches, (train_l, train_acc, None))
    添加当前训练损失、训练准确率和 None(表示未知测试准确率)到动画显示对象 animator 中。

  • test_acc = evaluate_accuracy_gpu(net, test_iter)
    使用 evaluate_accuracy_gpu 函数计算在 GPU 上测试集的准确率 test_acc。

  • nimator.add(epoch + 1, (None, None, test_acc))
    添加当前 epoch 的测试准确率到动画显示对象 animator 中。

  • print(f’loss {train_l:.3f}, train acc {train_acc:.3f}, test acc {test_acc:.3f}')
    打印当前 epoch 的训练损失、训练准确率和测试准确率。

  • print(f’{metric[2] * num_epochs / timer.sum():.1f} examples/sec on {str(device)}')
    打印每秒处理的样本数量,即训练过程中的平均速度。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值