#python #neural-network #pytorch
Вопрос:
Я работаю над проектом визуальных сетей, в котором пытаюсь отобразить несколько значений узла-края-узла в интерактивном графике.
У меня есть несколько нейронных сетей (это один из примеров):
import torch import torch.nn as nn import torch.optim as optim class Model(nn.Module): def __init__(self): super(Model, self).__init__() self.fc1 = nn.Linear(1, 2) self.fc2 = nn.Linear(2, 3) self.fc3 = nn.Linear(3, 1) def forward(self, x): x1 = self.fc1(x) x = torch.relu(x1) x2 = self.fc2(x) x = torch.relu(x2) x3 = self.fc3(x) return x3, x2, x1 net = Model()
Как я могу эффективно получить значения node-edge-node
( neuron-edge-neuron
) в сети? Некоторые из этих сетей имеют большое количество параметров. Обратите внимание, что для первого слоя это будет input-edge-neuron
скорее, чем neuron-edge-neuron
.
Я попытался сохранить значения каждого узла после fc
слоев (т. Е. x1,x2,x3
), чтобы мне не пришлось их пересчитывать, но я не уверен, как сделать ребра и эффективно сопоставить их с соответствующими нейронами.
Вывод, который я ищу, — это список списков node-edge-node
значений. Хотя это также может быть тензор тензоров, если это проще. Например, в приведенной выше сети с первого слоя у меня будет 2 тройки (1×2), со 2-го слоя у меня будет 6 из них (2×3), а в последнем слое у меня будет 3 тройки (3×1). Проблема заключается в эффективном сопоставлении значений узлов (т. е. нейронов) (одного из слоя n-1 и одного из слоя n) с соответствующими ребрами.
Комментарии:
1. В какой форме вы стремитесь к конечному результату и каков ваш текущий подход ?
2. «Вывод, который я ищу, — это список списков
node-edge-node
значений». Хотя это также может быть тензор тензоров, если это проще. Мой текущий подход состоит в том, чтобы теоретически перебиратьfc
матрицу каждого слоя и каким-то образом сопоставлять края с соответствующим начальным узлом (с предыдущего слоя) и конечным узлом (со следующего слоя), но я не смог заставить его работать (и я не уверен, что это эффективный способ сделать это3. Гарантируете ли вы, что в вашей сети есть только линейные слои, и они всегда каскадированы ?
4. .. а как насчет термина предвзятости ? входит ли это в вашу
node-edge-node
структуру ? Я так не думаю. Это важно ?5. @ayandas вы можете игнорировать предвзятость
Ответ №1:
Признание: Давайте начнем с того, что я немного изменил ваш код, чтобы сделать его удобным. Вы можете сделать все в том виде, в каком оно было изначально. Я также изменил определенное количество нейронов просто для игры (я уверен, что вы можете вернуть их обратно).
Я создал summary
объект (возвращаемый .forward()
функцией), который содержит всю трассировку выполнения сети, т. Е. (input, weight, output)
кортежи для *каждого слоя.
class Model(nn.Module): def __init__(self): super(Model, self).__init__() self.fc1 = nn.Linear(3, 5) self.fc2 = nn.Linear(5, 7) self.fc3 = nn.Linear(7, 2) def forward(self, x): summary = [] running_x = x for layer in self.children(): out = layer(running_x) # triplet of (input, weight, output) for each layer summary.append((running_x, layer.weight, out)) running_x = out return summary model = Model() batch_size = 32 X = torch.rand(batch_size, 3) summary = model(X)
Основная логика заключается только в этом
for L in summary: # iterate over the (ip, weight, out) tuple for each layer ip, weight, out = L # unpack them ip = ip[:, :, None, None].repeat(1, 1, out.shape[-1], 1) weight = weight.T[None, :, :, None].repeat(batch_size, 1, 1, 1) out = out[:, None, :, None].repeat(1, ip.shape[1], 1, 1) triplets = torch.cat([ip, weight, out], -1)
Таким triplets
образом, переменная (по одной для каждого слоя) — это все, что вы ищете. Он имеет размер
(batch_size, layer_in_dim, layer_out_dim, 3)
Давайте рассмотрим конкретно triplets
первый слой.
gt;gt; triplets.shape (32, 3, 5, 3)
Например, учитывая индекс выборки , индекс b = 12
входного нейрона i = 1
и индекс выходного нейрона j = 3
, у вас есть ровно node-edge-node
кортежи
gt;gt; triplets[b][i][j] tensor([0.7080, 0.3442, 0.7344], ...)
Проверка: Давайте вручную проверим правильность.
Размерность 12
1
st t-го образца равна
# Its the first layer we are looking, so input comes from user gt;gt; X[12][1] tensor(0.7080)
проверять.
Соединительный вес между 1
входным нейроном st и 3
выходным нейроном rd для первого слоя
gt;gt; model.fc1.weight.T[1][3] # weight matrix is transposed, so had to do .T tensor(0.3442, ...)
проверять.
Вывод 3
rd-нейрона для 12
t-го образца может быть получен из его тензора активации
gt;gt; _, _, out = summary[0] # first layer's output tensor gt;gt; out[12][3] tensor(0.7344, ...)
ТАКЖЕ ПРОВЕРЬТЕ.
Я надеюсь, что это то, чего ты хотел. Если вам нужна дополнительная информация/изменения, не стесняйтесь комментировать. Я не думаю, что это может быть более эффективным, чем это.
Комментарии:
1. Выглядит неплохо. Несколько вопросов: если бы я хотел также обучить этому, нужно ли мне возвращаться
running_x
вместе сsummary
этим ? Кроме того, вы упомянули , что тройняшки имеют размер(batch_size, layer_in_dim, layer_out_dim, 3)
, но разве он не должен быть больше этого? Если мы добавляем все тройки из всех слоев. Если только я чего-то не понял неправильно.2. Если вы хотите иметь правильный градиент w.r.t
triplets
, вам нужноrunning_x
.summary
уже включает в себя всеrunning_x
. Кроме того, у нас естьtriplets
для каждого слоя (я уже упоминал; см. Основной логическийfor
цикл). Мы не можем упаковать всеtriplets
для всех слоев, потому что они имеют разные размеры.3. .. таким образом, в основном мы получаем список (длина = # слоев) тензоров (т. Е.
triplets
). Я не создавал этот список явно в своем коде. Я уверен, что вы можете сделать это сами.4. Разные размеры? Каждая тройка имеет размер 3. Немного запуталась
5. Нет, но у вас разное количество таких тройняшек. Вы сами написали в вопросе, что «2 для первого слоя, 6 для 2-го слоя, 3 для третьего слоя».