Объект Pytorch 'Tensor' не вызывается

Я пытаюсь применить фильтр Собела к своей сети. Я получаю эту ошибку: «Объект Tensor не вызывается» Вот мой код:

class SobelFilter(nn.Module):
    def __init__(self):
        super(SobelFilter, self).__init__()

        kernel1=torch.Tensor([[1, 0, -1],[2,0,-2],[1,0,-1]])
        kernela=kernel1.expand((1,1,3,3))

        kernel2=torch.Tensor([[1, 2, 1],[0,0,0],[-1,-2,-1]])
        kernelb=kernel2.expand((1,1,3,3))

        inputs = torch.randn(1,1,64,128)

        self.conv1 = F.conv2d(inputs,kernela,stride=1,padding=1)
        self.conv2 = F.conv2d(inputs,kernelb,stride=1,padding=1)

    def forward(self, x ):

        print(x.shape)
        G_x = self.conv1(x)    %GIVES ERROR AT THIS LINE
        G_y = self.conv2(x)
        out = torch.sqrt(torch.pow(G_x,2)+ torch.pow(G_y,2))

        return out
class EXP(nn.Module):
    def __init__(self, maxdisp):
        super(EXP, self).__init__()
        self.device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
        self.SobelFilter = SobelFilter()

    def forward(self, im):
        % just think "im" to be [1,32,64,128]

        for i in range(im.shape[1]):
            out1= im[:,i,:,:].unsqueeze(1)
            im[:,i,:,:] = self.SobelFilter(out1)

что может вызвать проблему? Спасибо!


person a-f-a    schedule 05.04.2020    source источник


Ответы (1)


Я думаю, ваша проблема в том, что вы используете torch.nn.functional, а не просто torch. Назначение функционального API - выполнять операции (в данном случае conv2d) напрямую, без создания экземпляра класса и последующего вызова его метода пересылки. Следовательно, оператор self.conv1 = F.conv2d(inputs,kernela,stride=1,padding=1) уже выполняет свертку между input и kernela, и то, что у вас есть в self.conv1, является результатом такой свертки. Здесь есть два подхода к решению проблемы. Используйте torch.Conv2d внутри __init__, где inputs - это канал ввода, а не тензор той же формы, что и ваш реальный ввод. И второй подход - придерживаться функционального API, но переместить его в метод forward(). Чего вы хотите достичь, можно сделать, изменив форвард на:

def forward(self, x ):
  print(x.shape)
  G_x = F.conv2d(x,self.kernela,stride=1,padding=1)
  G_y = F.conv2d(x,self.kernelb,stride=1,padding=1)
  out = torch.sqrt(torch.pow(G_x,2)+ torch.pow(G_y,2))
  return out

Обратите внимание, что я сделал атрибуты классов kernela и kernelb. Таким образом, вы также должны изменить __init__() на

def __init__(self):
  super(SobelFilter, self).__init__()

  kernel1=torch.Tensor([[1, 0, -1],[2,0,-2],[1,0,-1]])
  self.kernela=kernel1.expand((1,1,3,3))

  kernel2=torch.Tensor([[1, 2, 1],[0,0,0],[-1,-2,-1]])
  self.kernelb=kernel2.expand((1,1,3,3))
person Manuel Lagunas    schedule 05.04.2020
comment
Спасибо! это сработало. Я также добавил self.inputs вместо просто input - person a-f-a; 05.04.2020
comment
Код работал, но результат - не то, что мне нужно. Вывод выглядит как смешанные случайные величины. Я хотел применить фильтр Собела, чтобы получить края ... :( - person a-f-a; 06.04.2020
comment
Я обновил форвард, убедитесь, что вы добавили переменную x внутри F.conv2d() call. Дайте мне знать, если это сработает сейчас :) - person Manuel Lagunas; 07.04.2020
comment
теперь он говорит RuntimeError: тип ввода (torch.cuda.FloatTensor) и тип веса (torch.FloatTensor) должны быть одинаковыми - person a-f-a; 07.04.2020
comment
Сама ошибка кажется довольно понятной. Один из тензоров был перемещен в GPU посредством вызова .cuda(), а другой остался в CPU. Убедитесь, что оба находятся в процессоре или графическом процессоре. - person Manuel Lagunas; 07.04.2020
comment
Я работаю с GPU, однако класс sobelFilter был создан в CPU (когда я нажимаю тензор на CPU, он работает). Вопрос в том, как я могу передать класс sobelfilter на GPU? Кстати спасибо :) - person a-f-a; 07.04.2020
comment
OK. Я добавил .cuda() в конце kernel1=torch.Tensor([[1, 0, -1],[2,0,-2],[1,0,-1]]), тогда это сработало :) - person a-f-a; 07.04.2020
comment
вы можете добавить метод внутри класса def to(self, device, dtype=None): и внутри этого метода вызвать self.kernela = self.kernela.to(device, dtype) (сделайте то же самое с kernelb). Затем, после того, как вы создадите класс SF = SobelFilter(...), выполните SF.to(device, dtype) с device и dtype устройством и типом по вашему выбору. - person Manuel Lagunas; 09.04.2020