在神经网络中获取 "neuron-edge-neuron" 值的有效方法

Efficient way to get "neuron-edge-neuron" values in a neural network

我正在从事可视化网络项目,我试图在交互式图表中绘制多个节点-边缘-节点值。

我有几个神经网络(这是一个例子):

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 个三元组 (1x2),第二层有 6 个 (2x3),最后一层有 3 个三元组 (3x1)。问题是以有效的方式将节点(即神经元)值(一个来自第 n-1 层,一个来自第 n 层)与相应的边匹配。

忏悔:首先说一下我修改了你的代码,方便点。你可以按照原来的形式做任何事情。我还更改了神经元的具体数量,只是为了玩玩(我相信你可以将它们还原)。

我创建了一个 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

>> triplets.shape
(32, 3, 5, 3)

例如,给定样本索引 b = 12、输入神经元索引 i = 1 和输出神经元索引 j = 3,您正好有 node-edge-node 个元组

>> triplets[b][i][j]
tensor([0.7080, 0.3442, 0.7344], ...)

验证:让我们手动验证正确性。

12 个样本的第 1 个维度是

# Its the first layer we are looking, so input comes from user
>> X[12][1]
tensor(0.7080) 

检查。

第一层第1个输入神经元和第3个输出神经元之间的连接权重

>> model.fc1.weight.T[1][3] # weight matrix is transposed, so had to do .T
tensor(0.3442, ...)

检查。

12 个样本的第 3 个神经元的输出可以从其激活张量中检索

>> _, _, out = summary[0] # first layer's output tensor
>> out[12][3]
tensor(0.7344, ...)

还要检查。


希望这就是您想要的。如果还需要 info/changed,请随时发表评论。我认为没有比这更有效的了。