pytorch模型构建、训练、测试及预测

一  神经网络的典型处理流程

1. 定义可学习参数的网络结构(堆叠各层和层的设计);继承 nn.Module 模块,改写 forward 方法。
2. 数据集输入;
3. 对输入进行处理(由定义的网络层进行处理),主要体现在网络的前向传播;
4. 计算loss ,由Loss层计算;
5. 反向传播求梯度;
6. 根据梯度改变参数值,最简单的实现方式(SGD)为: weight = weight - learning_rate * gradient

其中,torch.nn是用来构建神经网络每个层的,例如卷积层,全连接层等。torch.nn.functional用以引用各种数学函数,例如激活函数等。torch.optim是各种优化方法,例如SGD,ADAM等。

二 简单例子

1 定义网络

构建一个简单的CNN网络,两个 (卷积+激活+池化)的模块,接两层全连接层,然后是输出层。然后实例化对象net。

import torch.nn as nn
import torch.nn.functional as F


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

#实例化对象
net = Net()

2 定义损失函数和优化器

import torch.optim as optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

3 网络训练

为方便理解,只设置2个epoch,在每个 epoch 的循环中会遍历所有 trainloader 的数据。

每一次遍历时:

  1. 先通过 optimizer.zero_grad() 把梯度清理干净,防止受之前遗留梯度的影响。
  2. outputs = net(inputs), 前向传播,等价于net.forward(inputs) ,把输入数据输入到网络,得到预测结果。
  3. loss = criterion(outputs, labels), 计算当前 batch 的损失值。
  4. loss.backward(),执行链式求导,计算梯度。
  5. optimizer.step(),通过4中计算出来的梯度,更新每个可训练权重。
# 定义训练函数
def train(trainloader, model, criterion, optimizer):

    loss, current, n = 0.0, 0.0, 0
        for batch, data in enumerate(trainloader, 0):
            # get the inputs; data is a list of [inputs, labels]
            inputs, labels = data

            # zero the parameter gradients
            optimizer.zero_grad()

            # forward + backward + optimize
            outputs = net(inputs)
            cur_loss = criterion(outputs, labels)
            _, pred = torch.max(output, axis=1)
            cur_acc = torch.sum(labels==pred)/output.shape[0]
            
            loss.backward()
            optimizer.step()

            loss += cur_loss.item()
            current += cur_acc.item()
            n = n+1

        train_loss = loss / n      n个batch的平均?
        tran_acc = current /n
      

# 定义验证函数
def val(valloader, model, criterion):
    
    # 将模型转为验证模型
    model.eval()
    loss, current, n = 0.0, 0.0, 0
    with torch.no_grad():
        for batch, data in enumerate(valloader):
            inputs, labels = data
            output = net(inputs)
            cur_loss = crietrion(output, y)
            _, pred = torch.max(output, axis=1)
            cur_acc = torch.sum(y == pred) / output.shape[0]
            loss += cur_loss.item()
            current += cur_acc.item()
            n = n+1
 
        val_loss = loss / n
        val_acc = current / n

#开始训练

# 开始训练
loss_train = []
acc_train = []
loss_val = []
acc_val = []
 

min_acc = 0
for t in range(2):
    lr_scheduler.step()
    
    print(f"epoch{t+1}\n--------------")
    train_loss, train_acc = train(train_dataloader, model, crietrion, optimizer)
    val_loss, val_acc = val(val_dataloader, model, crietrion)
 
    loss_train.append(train_loss)
    acc_train.append(train_acc)
    loss_val.append(val_loss)
    acc_val.append(val_acc)
 
    # 保存最好的模型权重文件
    if val_acc > min_acc:
        folder = 'save_model'
        if not os.path.exists(folder):
            os.mkdir('save_model')
        min_acc = val_acc
        print(f'save best model,第{t+1}轮')
        torch.save(model.state_dict(), 'save_model/best_model.pth')
    # 保存最后的权重模型文件
    if t == epoch - 1:
        #使用 torch.save 将模型序列化保存在指定地址,方便后续调用,调用时使用torch.load
        torch.save(model.state_dict(), 'save_model/last_model.pth')
print('Done!')

其中,几个主要函数

optimizer.zero_grad():

该函数会遍历模型的所有参数,通过p.grad.detach_()方法截断反向传播的梯度流,再通过p.grad.zero_()函数将每个参数的梯度值设为0,即上一次的梯度记录被清空。因为训练的过程通常使用mini-batch方法,所以如果不将梯度清零的话,梯度会与上一个batch的数据相关,因此该函数要写在反向传播和梯度下降之前。

loss.backward():

PyTorch的反向传播(即tensor.backward())是通过autograd包来实现的,autograd包会根据tensor进行过的数学运算来自动计算其对应的梯度。具体来说,torch.tensor是autograd包的基础类,如果你设置tensor的requires_grads为True,就会开始跟踪这个tensor上面的所有运算,如果你做完运算后使用tensor.backward(),所有的梯度就会自动运算,tensor的梯度将会累加到它的.grad属性里面去。更具体地说,损失函数loss是由模型的所有权重w经过一系列运算得到的,若某个w的requires_grads为True,则w的所有上层参数(后面层的权重w)的.grad_fn属性中就保存了对应的运算,然后在使用loss.backward()后,会一层层的反向传播计算每个w的梯度值,并保存到该w的.grad属性中。如果没有进行tensor.backward()的话,梯度值将会是None,因此loss.backward()要写在optimizer.step()之前。

optimizer.step():

step()函数的作用是执行一次优化步骤,通过梯度下降法来更新参数的值。其使用的是参数空间(param_groups)中的grad,也就是当前参数空间对应的梯度,这也就解释了为什么optimzier使用之前需要zero清零一下,因为如果不清零,那么使用的这个grad就得同上一个mini-batch有关。因为梯度下降是基于梯度的,所以在执行optimizer.step()函数前应先执行loss.backward()函数来计算梯度。注意:optimizer只负责通过梯度下降进行优化,而不负责产生梯度,梯度是tensor.backward()方法产生的。

optimizer.step()放在每一个batch训练中,而不是epoch训练中,这是因为现在的mini-batch训练模式是假定每一个训练集就只有mini-batch这样大,因此实际上可以将每一次mini-batch看做是一次训练,一次训练更新一次参数空间,因而optimizer.step()放在这里。

scheduler.step()按照Pytorch的定义是用来更新优化器的学习率的,一般是按照epoch为单位进行更换,即多少个epoch后更换一次学习率,因而scheduler.step()放在epoch这个大循环下。

注意:1 验证集使用时,使用model.eval转换为验证模型,验证集不用来更新权重和梯度;2 验证集的作用:可以用在训练的过程中,经过几个epoch后,跑一次验证集看一下效果,可以及时发现模型或者参数的问题,主要用来调整超参数(如人为设定的初始学习率、层数、权值衰减系数、训练次数等);2 每个batch训练后更新梯度和权重。

4  预测

  • 4
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当你构建PyTorch模型训练完成后,需要把模型保存下来以备后续使用。这时你需要学会如何加载这个模型,以下是PyTorch模型加载方法的汇总。 ## 1. 加载整个模型 ```python import torch # 加载模型 model = torch.load('model.pth') # 使用模型进行预测 output = model(input) ``` 这个方法可以轻松地加载整个模型,包括模型的结构和参数。需要注意的是,如果你的模型是在另一个设备上训练的(如GPU),则需要在加载时指定设备。 ```python # 加载模型到GPU device = torch.device('cuda') model = torch.load('model.pth', map_location=device) ``` ## 2. 加载模型参数 如果你只需要加载模型参数,而不是整个模型,可以使用以下方法: ```python import torch from model import Model # 创建模型 model = Model() # 加载模型参数 model.load_state_dict(torch.load('model.pth')) # 使用模型进行预测 output = model(input) ``` 需要注意的是,这个方法只能加载模型参数,而不包括模型结构。因此,你需要先创建一个新的模型实例,并确保它的结构与你保存的模型一致。 ## 3. 加载部分模型参数 有时候你只需要加载模型的部分参数,而不是全部参数。这时你可以使用以下方法: ```python import torch from model import Model # 创建模型 model = Model() # 加载部分模型参数 state_dict = torch.load('model.pth') new_state_dict = {} for k, v in state_dict.items(): if k.startswith('layer1'): # 加载 layer1 的参数 new_state_dict[k] = v model.load_state_dict(new_state_dict, strict=False) # 使用模型进行预测 output = model(input) ``` 这个方法可以根据需要选择加载模型的部分参数,而不用加载全部参数。 ## 4. 加载其他框架的模型 如果你需要加载其他深度学习框架(如TensorFlow)训练模型,可以使用以下方法: ```python import torch import tensorflow as tf # 加载 TensorFlow 模型 tf_model = tf.keras.models.load_model('model.h5') # 将 TensorFlow 模型转换为 PyTorch 模型 input_tensor = torch.randn(1, 3, 224, 224) tf_output = tf_model(input_tensor.numpy()) pytorch_model = torch.nn.Sequential( # ... 构建与 TensorFlow 模型相同的结构 ) pytorch_model.load_state_dict(torch.load('model.pth')) # 使用 PyTorch 模型进行预测 pytorch_output = pytorch_model(input_tensor) ``` 这个方法先将 TensorFlow 模型加载到内存中,然后将其转换为 PyTorch 模型。需要注意的是,转换过程可能会涉及到一些细节问题,因此可能需要进行一些额外的调整。 ## 总结 PyTorch模型加载方法有很多,具体要根据实际情况选择。在使用时,需要注意模型结构和参数的一致性,以及指定正确的设备(如GPU)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值