使用pytorch训练模型报错

报错如下

Traceback (most recent call last):
  File "C:\Users\17122\Desktop\segnet\train.py", line 56, in <module>
    train(epoch)
  File "C:\Users\17122\Desktop\segnet\train.py", line 41, in train
    for batch_idx, data in enumerate(data123, 0):
  File "C:\Users\17122\anaconda3\lib\site-packages\torch\utils\data\dataset.py", line 53, in __getitem__
    raise NotImplementedError
NotImplementedError
ERROR conda.cli.main_run:execute(47): `conda run python C:\Users\17122\Desktop\segnet\train.py` failed. (See above for error)

data123这个变量对应的类继承父类Dataset的时候没有实现相应的__getitem__接口

img

  • 你可以看下这个问题的回答https://ask.csdn.net/questions/7692662
  • 这篇博客也不错, 你可以看下pytorch常用预训练模型下载网址
  • 同时,你还可以查看手册:pytorch 单机模型并行的最佳实践 中的内容
  • 除此之外, 这篇博客: 使用Pytorch识别字符验证码中的 搭建模型 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 之前使用Keras做字符验证码识别的时候,得到的经验就是针对这种比较简单的字符验证码,无需过于复杂的模型,几层CNN就够了。

    import torch
    from torch import nn
    from torch import optim
    
    import os
    
    
    class NeuralNetWork(nn.Module):
        def __init__(self, channel, num_classes):
            """
            :param channel: 输入图片的channel
            :param num_classes: 分类数量
            """
            super(NeuralNetWork, self).__init__()
            self.convin = nn.Sequential(
                nn.Conv2d(channel, 64, kernel_size=(3, 3), padding=1, bias=False),
                nn.ReLU(),
                nn.Conv2d(64, 64, kernel_size=(3, 3), padding=1, bias=False),
                nn.ReLU(),
                nn.MaxPool2d(2, 2),
                nn.Dropout(0.25)
            )
            self.convall = nn.Sequential(
                nn.Conv2d(64, 64, kernel_size=(3, 3), padding=1, bias=False),
                nn.ReLU(),
                nn.Conv2d(64, 64, kernel_size=(3, 3), padding=1, bias=False),
                nn.ReLU(),
                nn.MaxPool2d(2, 2),
                nn.Dropout(0.25)
            )
            # 承接卷积层和fc层
            self.fc1 = nn.Sequential(
                nn.Linear(64*5*11, 1024),  # 这个输入值需要计算,根据输入图像的尺寸决定(本次输入图像尺寸为40*90)
                nn.ReLU(),
                nn.Dropout(0.5)
            )
            self.dense1 = nn.Sequential(
                nn.Linear(1024, 512),
                nn.ReLU(),
                nn.Linear(512, num_classes),
                # nn.LogSoftmax()
            )
            self.dense2 = nn.Sequential(
                nn.Linear(1024, 512),
                nn.ReLU(),
                nn.Linear(512, num_classes),
                # nn.LogSoftmax()
            )
            self.dense3 = nn.Sequential(
                nn.Linear(1024, 512),
                nn.ReLU(),
                nn.Linear(512, num_classes),
                # nn.LogSoftmax()
            )
           
        
       def forward(self, n_input):
            # 进行卷积、激活和池化操作
            feature = self.convin(n_input)
            feature = self.convall(feature)
            feature = self.convall(feature)
    
            # 对特征层(Tensor类型)进行维度变换,变成两维
            feature = feature.view(n_input.size(0), -1)  # size(0)是批次大小
    
            # 进行全连接操作
            feature = self.fc1(feature)
            out_put1 = self.dense1(feature)
            out_put2 = self.dense2(feature)
            out_put3 = self.dense3(feature)
            # 每个样本有三个输出值
            return [out_put1, out_put2, out_put3]
    

    关于模型代码,有以下几点说明:

    1. 使用几层卷积、卷积核的数量、池化操作和dropout等并不是固定的,这要根据你的训练情况逐步调整;

    2. 全连接层的地方的输入值是需要计算的,是由输入到全连接层的输出通道数量x你的图片经过你的卷积和池化层后得到的尺寸,比如这里输出通道数量为64,原始输入图片尺寸为40x90,经过padding=1的卷积层尺寸不变,经过三次(2, 2)的池化层,变为5x11

      40x90 --> 20x45 --> 10x22 --> 5x11

      并且在全连接层之前要把feature转换为(batch, )形状的二维tensor。

    3. 如何控制每个样本有3个输出值,这里是我遇到的难题,因为之前学习都是每个样本一个类型。

      这里经过咨询有经验的同事得知,实际上就是利用相同的线性层计算得到三个值,同时返回。

      不过需要注意的是,即使这三个输出值是经过了相同的线性层,就像这里的

      nn.Sequential(
          nn.Linear(1024, 512),
          nn.ReLU(),
          nn.Linear(512, num_classes),
      )
      

      但是一定是三个独立定义的层(层名称无所谓),如果均使用同一个层,那么输出的这三个值永远都是一样的(亲身踩坑)

  • 您还可以看一下 七月在线老师的PyTorch入门与实战课程中的 自然语言分类任务小节, 巩固相关知识点
  • 以下回答由chatgpt基于相关博客总结生成:

    解决方法:

    该问题是由于GPU内存不足导致的,可以采取以下方法解决:

    1.减小batch size

    可以通过减小batch size来减小显存占用,具体方法是在训练代码中将batch size减小为一个较小的值,如16或32等。代码如下:

    train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16)
    

    2.释放显存

    可以通过PyTorch提供的torch.cuda.empty_cache()函数来释放显存,代码如下:

    import torch
    if hasattr(torch.cuda, 'empty_cache'):
      torch.cuda.empty_cache()
    

    3.降低模型复杂度

    在不影响模型精度的情况下,可以考虑降低模型的复杂度,比如减少模型中的参数数量,或者通过使用预训练的模型来减少训练所需的时间和内存占用。

    4.使用分布式训练

    如果有多个GPU可以使用,可以考虑使用分布式训练来减小单个GPU内存的压力。具体方法是使用PyTorch提供的torch.nn.parallel.DistributedDataParallel来实现分布式训练,代码如下:

    import torch
    import torch.nn as nn
    import torch.nn.parallel
    import torch.backends.cudnn as cudnn
    import torch.distributed as dist
    import torch.optim
    import torch.utils.data
    import torch.utils.data.distributed
    
    # 初始化进程组
    dist.init_process_group(backend='nccl', world_size=4, init_method='...')
    # 使用 DistributedSampler 作为数据加载器,保证每个进程都可以访问到不同的数据切片
    train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset)
    train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, sampler=train_sampler)
    
    # 将模型复制到多个GPU上
    model = nn.parallel.DistributedDataParallel(model)
    

    以上是常见的解决方法,可以根据自己的实际情况进行选择和尝试。