Не могу тренировать Re sNet, используя GPU с Pytorch - PullRequest
0 голосов
/ 14 апреля 2020

Я пытаюсь использовать gpu для обучения архитектуры Re sNet на наборе данных CIFAR10. Вот мой код для Re sNet:

import torch
import torch.nn as nn
import torch.nn.functional as F 
class ResNetBlock(nn.Module):

    def __init__(self, in_planes, planes, stride=1):
        super(ResNetBlock, self).__init__()
        self.stride = stride
        self.in_planes=in_planes
        self.planes = planes
        if stride!=1:

          self.fx = nn.Sequential(nn.Conv2d(in_planes, planes, 3, stride=2, 
                                            padding=1),
                                  nn.ReLU(), 
                                  nn.Conv2d(planes, planes,3, padding=1))


        else:
          self.fx = nn.Sequential(nn.Conv2d(planes, planes, 3, padding = 1),
                                  nn.ReLU(), 
                                  nn.Conv2d(planes, planes,3, padding=1))



    def forward(self, x):

      if self.stride ==1:
        fx = self.fx(x)
        id = nn.Sequential()
        out = fx + id(x)
        relu = nn.ReLU()
        return relu(out)

      else:

        fx = self.fx(x)
        id = nn.Conv2d(self.in_planes, self.planes, 2, stride = 2)
        out = fx + id(x)
        relu = nn.ReLU()
        return relu(out)

class ResNet(nn.Module):

  def __init__(self, block, num_blocks, num_classes=10, num_filters=16, input_dim=3):
      super(ResNet, self).__init__()
      self.in_planes = num_filters

      self.conv1 = nn.Conv2d(input_dim, num_filters, kernel_size=3, stride=1, padding=1, bias=False)
      self.bn1 = nn.BatchNorm2d(num_filters)

      layers = []
      plane = num_filters 

      for nb in num_blocks:

        layer = self._make_layer(block,plane ,nb,2)
        layers.append(layer)
        plane*=2

      self.layers = nn.Sequential(*layers)




      self.linear = nn.Linear(2304, num_classes)

  def _make_layer(self, block, planes, num_blocks, stride):
      layers = []
      block1 = ResNetBlock(planes, 2*planes, stride = 2)
      planes *=2
      layers.append(block1)

      for i in range(1,num_blocks):
        block = ResNetBlock(planes, planes, stride =1)
        layers.append(block)

      return nn.Sequential(*layers)

  def forward(self, x):
      out = F.relu(self.bn1(self.conv1(x)))
      out = self.layers(out)

      out = F.avg_pool2d(out, 4)
      out = out.view(out.size(0), -1)
      out = self.linear(out)
      return out


# (1 + 2*(1 + 1) + 2*(1 + 1) + 2*(1 + 1) + 2*(1 + 1)) + 1 = 18
def ResNet18():
    return ResNet(ResNetBlock, [2,2,2,2])

Затем я обучаю сеть, используя gpu:


net = ResNet18()
net = net.to('cuda')
train2(net, torch.optim.Adam(net.parameters(), lr=0.001), trainloader, criterion, n_ep=3)

И я получаю ошибку:

RuntimeError: Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same

, что раздражает, потому что мои веса должны быть также cuda из-за re snet .cuda ().

В другой сети функция поезда работает хорошо, поэтому она должна исходить из классов, упомянутых выше.

Также next (re snet .parameters ()). Is_cuda возвращает True.

Обновление: вот моя функция тренировки.


def train(net, optimizer, trainload, criterion, n_ep=10, cuda = True):
  if cuda:
    net = net.to('cuda')


  for epoch in range(n_ep):
    for data in trainload:

      inputs, labels = data
      if cuda:
        inputs = inputs.type(torch.cuda.FloatTensor)
        labels = labels.type(torch.cuda.LongTensor)


      optimizer.zero_grad()

      print(next(net.parameters()).is_cuda)
      ## this actually prints "True" ! 



      outputs = net.forward(inputs)
      loss = criterion(outputs, labels)
      loss.backward()
      optimizer.step()

  return net

Дело в том, что эта обучающая функция хорошо работает с другим типом net. Например, используется этот (Ale xNet):

class AlexNet(nn.Module):

    def __init__(self, num_classes=1000):
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(nn.Conv2d(3,64,11), nn.ReLU(),nn.MaxPool2d(2, stride = 2), nn.Conv2d(64,192,5),
                                     nn.ReLU(), nn.MaxPool2d(2, stride = 2), nn.Conv2d(192,384,3),
                                     nn.ReLU(),nn.Conv2d(384,256,3), nn.ReLU(), nn.Conv2d(256,256,3), nn.ReLU())
        self.avgpool = nn.AdaptiveAvgPool2d((6, 6))
        self.classifier = nn.Sequential(
            nn.Dropout(),
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Linear(4096, num_classes),)

    def forward(self, x):
        x = self.features(x)
        x = self.avgpool(x)
        x = x.view(x.size(0), 256 * 6 * 6)
        x = self.classifier(x)
        return x

, и с этим тренировка GPU работает хорошо.

Есть еще кое-что, чего я не понимаю. Я пытался обучить сеть, которую я перешел на GPU (используя .cuda ()), с данными обучения, которые я не перемещал в GPU (специально). И на этот раз я получаю сообщение об ошибке, что тип веса - torch.cuda, а тип данных - нет.

EDIT: я думал, что это связано с использованием nn.ModuleList вместо обычных python списков. Однако я попробовал это, и это не решило проблему.

Ответы [ 2 ]

1 голос
/ 14 апреля 2020

Нам понадобится фрагмент вашего обучения l oop, чтобы лучше определить вашу ошибку.

Я предполагаю, что где-то в этом l oop у вас есть несколько строк кода, которые выполняют следующее:

for data, label in CifarDataLoader:
     data, label = data.to('cuda'), label.to('cuda')

Моим первым предположением было бы добавить строку непосредственно перед l oop ->

resnet = resnet.to('cuda')

Дайте мне знать, если это работает, если нет, мне нужно больше Ваш код, чтобы найти ошибку.

0 голосов
/ 17 апреля 2020

Хорошо, я наконец понял.

Я определял некоторые объекты nn.Module в функции forward класса ResNetBlock. Я предполагаю, что их нельзя было перенести в gpu, потому что pytorch ищет только такие объекты в функции init. Я немного изменил свою реализацию, чтобы определить объекты в функции init , и это сработало.

Спасибо за помощь :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...