Подтвердить что ты не робот

Как работает метод просмотра в PyTorch?

Я запутался в методе view() в следующем фрагменте кода.

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()

Моя путаница касается следующей строки.

x = x.view(-1, 16*5*5)

Что делает tensor.view()? Я видел его использование во многих местах, но я не могу понять, как он интерпретирует свои параметры.

Что произойдет, если я передам отрицательные значения в качестве параметров функции view()? Например, что произойдет, если я позвоню tensor_variable.view(1, 1, -1)?

Кто-нибудь может объяснить основной принцип функции view() на некоторых примерах?

4b9b3361

Ответ 1

Функция view предназначена для изменения тензора.

Скажем, у вас есть тензор

import torch
a = torch.range(1, 16)

a является тензором, который имеет 16 элементов от 1 до 16 (включительно). Если вы хотите изменить этот тензор, чтобы сделать его тензор 4 x 4 то вы можете использовать

a = a.view(4, 4)

Теперь будет a 4 x 4 тензором. Обратите внимание, что после изменения формы общее количество элементов должно оставаться неизменным. Изменение формы тензора a до тензора 3 x 5 не подходит.

Что означает параметр -1?

Если есть ситуация, когда вы не знаете, сколько строк вы хотите, но уверены в количестве столбцов, вы можете указать это с помощью -1. (Обратите внимание, что вы можете распространить это на тензоры с большим количеством измерений. Только одно из значений оси может быть -1). Это способ сказать библиотеке: "дайте мне тензор с таким количеством столбцов, и вы вычисляете соответствующее количество строк, необходимое для этого".

Это можно увидеть в коде нейронной сети, который вы дали выше. После строки x = self.pool(F.relu(self.conv2(x))) в функции forward у вас будет 16 карт глубины. Вы должны сгладить это, чтобы дать это полностью связанному слою. Таким образом, вы указываете pytorch изменить форму полученного вами тензора, чтобы он имел определенное количество столбцов, и предлагаете ему самостоятельно определять количество строк.

Рисуя сходство между NumPy и Pytorch, view похож на функцию NUMPY изменение формы.

Ответ 2

Давайте сделаем несколько примеров, от простых до более сложных.

  1. Метод view возвращает тензор с теми же данными, что и self тензор (что означает, что возвращенный тензор имеет такое же количество элементов), но с другой формой. Например:

    a = torch.arange(1, 17)  # a shape is (16,)
    
    a.view(4, 4) # output below
      1   2   3   4
      5   6   7   8
      9  10  11  12
     13  14  15  16
    [torch.FloatTensor of size 4x4]
    
    a.view(2, 2, 4) # output below
    (0 ,.,.) = 
    1   2   3   4
    5   6   7   8
    
    (1 ,.,.) = 
     9  10  11  12
    13  14  15  16
    [torch.FloatTensor of size 2x2x4]
    
  2. Предполагая, что -1 не является одним из параметров, когда вы умножаете их вместе, результат должен быть равен числу элементов в тензоре. Если вы сделаете: a.view(3, 3), он вызовет RuntimeError потому что shape (3 x 3) недопустим для ввода с 16 элементами. Другими словами: 3 x 3 не равно 16, но 9.

  3. Вы можете использовать -1 качестве одного из параметров, передаваемых функции, но только один раз. Все, что происходит, - это то, что метод сделает для вас математику о том, как заполнить это измерение. Например, a.view(2, -1, 4) эквивалентно a.view(2, 2, 4). [16/(2 x 4) = 2]

  4. Обратите внимание, что возвращенный тензор имеет те же данные. Если вы вносите изменения в "представление", вы изменяете исходные тензорные данные:

    b = a.view(4, 4)
    b[0, 2] = 2
    a[2] == 3.0
    False
    
  5. Теперь для более сложного варианта использования. В документации говорится, что каждое новое измерение представления должно быть либо подпространством исходного измерения, либо охватывать только d, d + 1,..., d + k, которые удовлетворяют следующему условию смежности, которое для всех i = 0,..., k - 1, шаг [i] = шаг [i + 1] x размер [i + 1]. В противном случае, contiguous() необходимо вызвать перед просмотром тензора. Например:

    a = torch.rand(5, 4, 3, 2) # size (5, 4, 3, 2)
    a_t = a.permute(0, 2, 3, 1) # size (5, 3, 2, 4)
    
    # The commented line below will raise a RuntimeError, because one dimension
    # spans across two contiguous subspaces
    # a_t.view(-1, 4)
    
    # instead do:
    a_t.contiguous().view(-1, 4)
    
    # To see why the first one does not work and the second does,
    # compare a.stride() and a_t.stride()
    a.stride() # (24, 6, 2, 1)
    a_t.stride() # (24, 2, 1, 6)
    

    Обратите внимание, что для a_t, шага [0]! = Шага [1] х размер [1], так как 24! = 2 х 3

Ответ 3

Я понял, что x.view(-1, 16 * 5 * 5) эквивалентно x.flatten(1), где параметр 1 указывает, что процесс сглаживания начинается с 1-го измерения (без сглаживания измерения 'sample') ) Как видите, последнее использование семантически более понятно и проще в использовании, поэтому я предпочитаю flatten().

Ответ 4

weights.reshape(a, b) вернет новый тензор с теми же данными, что и веса с размером (a, b), так как он копирует данные в другую часть памяти.

weights.resize_(a, b) возвращает тот же тензор с другой формой. Однако, если новая форма приводит к меньшему количеству элементов, чем исходный тензор, некоторые элементы будут удалены из тензора (но не из памяти). Если новая форма приводит к большему количеству элементов, чем исходный тензор, новые элементы будут неинициализированы в памяти.

weights.view(a, b) вернет новый тензор с теми же данными, что и веса с размером (a, b)

Ответ 5

Что означает параметр -1?

Вы можете прочитать -1 как динамическое число параметров или "что угодно". Из-за этого в view() может быть только один параметр -1.

Если вы спросите x.view(-1,1) это выведет тензорную форму [anything, 1] зависимости от количества элементов в x. Например:

import torch
x = torch.tensor([1, 2, 3, 4])
print(x,x.shape)
print("...")
print(x.view(-1,1), x.view(-1,1).shape)
print(x.view(1,-1), x.view(1,-1).shape)

Будет выводить:

tensor([1, 2, 3, 4]) torch.Size([4])
...
tensor([[1],
        [2],
        [3],
        [4]]) torch.Size([4, 1])
tensor([[1, 2, 3, 4]]) torch.Size([1, 4])