Cómo funciona el método view() para tensor en torch


Tengo confusión sobre el método view() en el siguiente fragmento de código.

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

Mi confusión se refiere a la siguiente línea.

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

¿Qué hace la función tensor.view()? He visto su uso en muchos lugares, pero no puedo entender cómo interpreta sus parámetros.

¿Qué sucede si doy valores negativos como parámetros a la función view()? Por ejemplo, ¿qué sucede si llamo, tensor_variable.view(1, 1, -1)?

¿Puede alguien explicar el principio principal de la función view() con algunos ejemplos?

Author: fritzo, 2017-02-27

2 answers

La función view está destinada a remodelar el tensor.

Digamos que tienes un tensor

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

a es un tensor que tiene 16 elementos del 1 al 16(incluidos). Si desea remodelar este tensor para convertirlo en un tensor 4 x 4, puede usar

a = a.view(4, 4)

Ahora a será un tensor 4 x 4.(Tenga en cuenta que después de la remodelación, el número total de elementos debe permanecer igual. Remodelar el tensor a a un tensor 3 x 5 no sería apropiado)

¿Cuál es el significado de parámetro -1?

Si hay alguna situación en la que no sabe cuántas filas desea pero está seguro del número de columnas, puede mencionarlo como -1(puede extender esto a tensores con más dimensiones. Solo uno de los valores del eje puede ser -1). Esta es una forma de decirle a la biblioteca; dame un tensor que tenga estas muchas columnas y calculas el número apropiado de filas que es necesario para que esto suceda.

Esto se puede ver en el código de red neuronal que tiene given above. Después de la línea x = self.pool(F.relu(self.conv2(x))) en la función forward, tendrá un mapa de entidades de 16 profundidades. Tienes que aplanar esto para darle a la capa completamente conectada. Así que le dices a Pytorch que remodele el tensor que obtuviste para tener un número específico de columnas y le dices que decida el número de filas por sí mismo.

Dibujando una similitud entre numpy y pytorch, viewes similar a la función reshape de numpy.

 100
Author: Kashyap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-27 16:34:41

Vamos a hacer algunos ejemplos, de más simple a más difícil.

  1. El método view devuelve un tensor con los mismos datos que el tensor self (lo que significa que el tensor devuelto tiene el mismo número de elementos), pero con una forma diferente. Por ejemplo:

    a = torch.arange(1, 17)  # a's 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. Suponiendo que -1 no es uno de los parámetros, cuando se multiplican juntos, el resultado debe ser igual al número de elementos en el tensor. Si lo haces: a.view(3, 3), se levantará un RuntimeError porque shape (3 x 3) no es válido para entradas con 16 elementos. En otras palabras: 3 x 3 no es igual a 16 sino a 9.

  3. Puede usar -1 como uno de los parámetros que pasa a la función, pero solo una vez. Todo lo que sucede es que el método hará las matemáticas para usted sobre cómo llenar esa dimensión. Por ejemplo a.view(2, -1, 4) es equivalente a a.view(2, 2, 4). [16 /(2 x 4) = 2]

  4. Observe que el tensor devuelto comparte los mismos datos. Si usted hace un cambio en la "vista" está cambiando los datos del tensor original:

    b = a.view(4, 4)
    b[0, 2] = 2
    a[2] == 3.0
    False
    
  5. Ahora, para un caso de uso más complejo. La documentación dice que cada nueva dimensión de vista debe ser un subespacio de una dimensión original, o solo span d, d + 1, ..., d + k que satisfacen la siguiente condición de contigüidad que para todos i = 0, ..., k - 1, zancada[i] = zancada [i + 1] x tamaño[i + 1]. De lo contrario, contiguous() necesita ser llamado antes de que el tensor pueda ser ver. Por ejemplo:

    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)
    

    Observe que para a_t, zancada[0] != zancada[1] x tamaño[1] desde 24 != 2 x 3

 9
Author: Jadiel de Armas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-06 21:53:59