Изменение тензорной формы PyTorch от (C, B, H) до (B, C * H) - PullRequest
0 голосов
/ 26 ноября 2018

С учетом входного тензора формы (C, B, H) torch.Size([2, 5, 32]) некоторых слоев нейронной сети, где

  • channels = 2
  • batch_size =5
  • hidden_size = 32

Цель состоит в том, чтобы сгладить каналы и манипулировать входным тензором в форме (B, C * H) torch.Size([5, 2 * 32]), где:

  • batch_size = 5
  • hidden_size = 32 * 2

Я пытался сделать следующее:

import torch

t = torch.rand([2, 5, 32])

# Changed from (channels, batch_size, hidden_size) 
# -> (batch_size, channels, hidden_size)
t = t.permute(1, 0, 2)

# Reshape using view(), where batch_size is t.size(0) 
# and -1 is to flatten the left over values to the other dimension.
z = t.contiguous().view(t.size(0), -1)

print(z.shape)
print(z)

[out]:

torch.Size([5, 64])
tensor([[0.3911, 0.9586, 0.2104, 0.3937, 0.9976, 0.3378, 0.0630, 0.6676, 0.0806,
         0.9311, 0.5219, 0.1697, 0.7442, 0.5162, 0.2555, 0.0826, 0.5502, 0.9700,
         0.3375, 0.5012, 0.9025, 0.8176, 0.1465, 0.1848, 0.3460, 0.9999, 0.7892,
         0.7577, 0.6615, 0.2620, 0.6868, 0.2003, 0.4840, 0.8354, 0.9253, 0.3172,
         0.9516, 0.8962, 0.1272, 0.2268, 0.6510, 0.5166, 0.6772, 0.9616, 0.9826,
         0.5254, 0.9191, 0.4378, 0.7048, 0.8808, 0.0299, 0.1102, 0.9710, 0.8714,
         0.7256, 0.9684, 0.6117, 0.1957, 0.8663, 0.4742, 0.2843, 0.6548, 0.9592,
         0.1559],
        [0.2333, 0.0858, 0.5284, 0.2965, 0.3863, 0.3370, 0.6940, 0.3387, 0.3513,
         0.1022, 0.3731, 0.3575, 0.7095, 0.0053, 0.7024, 0.4091, 0.3289, 0.5808,
         0.5640, 0.8847, 0.7584, 0.8878, 0.9873, 0.0525, 0.7731, 0.2501, 0.9926,
         0.5226, 0.0925, 0.0300, 0.4176, 0.0456, 0.4643, 0.4497, 0.5920, 0.9519,
         0.6647, 0.2379, 0.4927, 0.9666, 0.1675, 0.9887, 0.7741, 0.5668, 0.7376,
         0.4452, 0.7449, 0.1298, 0.9065, 0.3561, 0.5813, 0.1439, 0.2115, 0.5874,
         0.2038, 0.1066, 0.3843, 0.6179, 0.8321, 0.9428, 0.1067, 0.5045, 0.9324,
         0.3326],
        [0.6556, 0.1479, 0.9288, 0.9238, 0.1324, 0.0718, 0.6620, 0.2659, 0.7162,
         0.7559, 0.7564, 0.2120, 0.3943, 0.9497, 0.7520, 0.8455, 0.4444, 0.4708,
         0.8371, 0.6365, 0.3616, 0.0326, 0.1581, 0.4973, 0.6701, 0.9245, 0.8274,
         0.3464, 0.7044, 0.5376, 0.0441, 0.5210, 0.8603, 0.7396, 0.2544, 0.3514,
         0.5686, 0.3283, 0.7248, 0.4303, 0.9531, 0.5587, 0.8703, 0.1585, 0.9161,
         0.9043, 0.9778, 0.4489, 0.9463, 0.8655, 0.5576, 0.1135, 0.1268, 0.3424,
         0.1504, 0.2265, 0.1734, 0.1872, 0.3995, 0.1191, 0.0532, 0.6109, 0.1662,
         0.6937],
        [0.6342, 0.1922, 0.1758, 0.4625, 0.7654, 0.6509, 0.2908, 0.1546, 0.4768,
         0.3779, 0.2490, 0.0086, 0.6170, 0.5425, 0.6953, 0.4730, 0.5834, 0.8326,
         0.0165, 0.8236, 0.0023, 0.7479, 0.5621, 0.9894, 0.5957, 0.0857, 0.6087,
         0.5667, 0.5478, 0.8197, 0.9228, 0.7329, 0.4434, 0.5894, 0.9860, 0.6133,
         0.2395, 0.4718, 0.8830, 0.6361, 0.6104, 0.6630, 0.5084, 0.7604, 0.7591,
         0.3601, 0.6888, 0.6767, 0.9178, 0.5291, 0.0591, 0.4320, 0.7875, 0.5038,
         0.4419, 0.0319, 0.3719, 0.5843, 0.0334, 0.3525, 0.0023, 0.1205, 0.4040,
         0.7908],
        [0.0989, 0.8436, 0.0425, 0.6247, 0.6091, 0.4778, 0.2692, 0.4785, 0.9217,
         0.9604, 0.6355, 0.4686, 0.9414, 0.7722, 0.8013, 0.1660, 0.6578, 0.6414,
         0.6814, 0.6212, 0.4124, 0.7102, 0.7416, 0.7404, 0.9842, 0.6542, 0.0106,
         0.3826, 0.5529, 0.8079, 0.9855, 0.3012, 0.2341, 0.9353, 0.6597, 0.7177,
         0.8214, 0.1438, 0.4729, 0.6747, 0.9310, 0.4167, 0.3689, 0.8464, 0.9395,
         0.9407, 0.8419, 0.5486, 0.1786, 0.1423, 0.9900, 0.9365, 0.3996, 0.1862,
         0.6232, 0.7547, 0.7779, 0.4767, 0.6218, 0.9079, 0.6153, 0.1488, 0.5960,
         0.4015]])

Хотя permute() + view() достигают желаемого результата, есть ли другие способы выполнить ту же операцию?Есть ли лучший способ напрямую изменить форму, не переставляя сначала порядок формы?

Ответы [ 2 ]

0 голосов
/ 30 июня 2019

Einops позволяет выполнять такие перестановки элементов в одну (читаемую) строку

from einops import rearrange
import torch

t = torch.rand([2, 5, 32])
y = rearrange(t, 'c b h -> b (c h)')
y.shape  # prints torch.Size([5, 64])
0 голосов
/ 27 декабря 2018

Давайте посмотрим "за занавесом" и посмотрим, почему один должен иметь оба permute / transpose и view для перехода от C - B - H к B - C*H:

Элементы тензоров сохраняются как длинный непрерывный векторв памяти.Например, если вы посмотрите на тензор 2-3-4, он содержит 24 элемента, которые хранятся в 24 последовательных местах в памяти.Этот тензор также имеет «заголовок», который указывает pytorch обрабатывать эти 24 значения как тензор 2 на 3 на 4.Это делается путем сохранения не только size тензора, но и «шагов»: на какой «шаг» нужно прыгнуть, чтобы перейти к следующему элементу по каждому измерению.В нашем примере size=(2,3,4) и strides=(12, 4, 1) (вы можете проверить это сами, и вы можете узнать больше об этом здесь ).

Теперь, если вы хотите изменить size на 2-(3*4), вам не нужно перемещать какой-либо элемент тензора в памяти, только для обновления «заголовка» тензора.Установив size=(2, 12) и strides=(12, 1), все готово!

В качестве альтернативы, если вы хотите «транспонировать» тензор в 3-2-4, это немного сложнее, но вы все равно можете сделать это, манипулируя шагами.Установка size=(3, 2, 4) и strides=(4, 12, 1) дает вам именно то, что вы хотите без перемещения любых реальных тензорных элементов в памяти.

Однако, как только вы манипулируете шагами, вы не можете тривиально изменитьразмер тензора - потому что теперь вам нужно иметь два разных значения "шага" для одного (или нескольких) измерений.Вот почему вы должны позвонить contiguous() в этот момент.

Сводка
Если вы хотите перейти от фигуры (C, B, H) к (B, C*H), выдолжны иметь операции permute, contiguous и view, в противном случае вы просто зашифруете записи вашего тензора.

Небольшой пример с тензором 2-3-4:

a = 
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]],

       [[12, 13, 14, 15],
        [16, 17, 18, 19],
        [20, 21, 22, 23]]])

Есливы просто меняете view полученного тензора

a.view(3,8) 
array([[ 0,  1,  2,  3,  4,  5,  6,  7],
       [ 8,  9, 10, 11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20, 21, 22, 23]])

Что означает , а не , что вы хотите!
Вам нужно иметь

a.permute(1,0,2).contiguous().view(3, 8)
array([[ 0,  1,  2,  3, 12, 13, 14, 15],
       [ 4,  5,  6,  7, 16, 17, 18, 19],
       [ 8,  9, 10, 11, 20, 21, 22, 23]])
...