【问题标题】:How to use k channels in CNN for k FC Layers如何将 CNN 中的 k 个通道用于 k 个 FC 层
【发布时间】:2021-04-24 17:51:52
【问题描述】:

我有一个编码器,它输出一个形状为(bn, c * k, 32, 32) 的张量。我现在想要生成形状为(bn, k, 1, 2) 的 k 均值。所以手段是二维坐标。为此,我想使用 k 个 FC 层,而对于每个均值 k_i 我只想使用 c 个通道。

所以我的想法是,我将编码器输出 out 重塑为形状为 (bn, k, c, 32, 32) 的 5d 张量。然后我可以使用扁平化的 out[:, 0] ... out[:, k] 作为 k 个线性层的输入。

简单的解决方案是手动定义线性层:

self.fc0 = nn.Linear(c * 32 * 32, 2)
...
self.fck = nn.Linear(c * 32 * 32, 2)

然后我可以如下定义每个均值的前向传播:

mean_0 = self.fc0(out[:, 0].reshape(bn, -1))
...
mean_k = self.fck(out[:, k].reshape(bn, -1))

有没有更有效的方法来做到这一点?

【问题讨论】:

  • 不太确定,但你不能使用跨步卷积来做到这一点吗?
  • 我不认为这就是我想要的。提供更多关于背景的信息:我想找到输入图像的关键点/地标。这个想法是,我为每个关键点 k 分配了一些特征图 c。这就是为什么编码器的输出具有(bn, k, c, 32, 32) 的形状。现在我想要那些 c 特征图来预测它的关键点,这是一个 2-dim 坐标。本质上,我希望每个关键点都有一个单独的 fc 层。

标签: python deep-learning neural-network pytorch


【解决方案1】:

我相信您正在寻找分组卷积。你可以让axis=1k*c 张量,所以输入形状是(bn, k*c, 32, 32)。然后使用带有2*k 过滤器的nn.Conv2d 卷积层并设置为接收k 组,因此它不是完全连接的通道(仅kc 映射:卷积c 一次。

>>> bn = 1; k = 5; c = 3
>>> x = torch.rand(bn, k*c, 32, 32)
>>> m = nn.Conv2d(in_channels=c*k, out_channels=2*k, kernel_size=32, groups=k)

>>> m(x).shape
torch.Size([4, 10, 1, 1])

然后你可以根据自己的喜好重新塑造。


就参数数量而言。 nn.Conv2d 的典型用法是:

>>> m = nn.Conv2d(in_channels=c*k, out_channels=2*k, kernel_size=32)
>>> sum(layer.numel() for layer in m.parameters())
153610

这正是c*k*2*k*32*32 权重加上2*k 偏差。

在你的情况下,你会

>>> m = nn.Conv2d(in_channels=c*k, out_channels=2*k, kernel_size=32, groups=k)
>>> sum(layer.numel() for layer in m.parameters())
30730

这正是c*2*k*32*32 权重加上2*k 偏差。 k 比上一层少。给定的过滤器只有c 层(不是k*c),这意味着它将具有c 通道的输入(包含k 组之一的c 映射)

【讨论】:

  • 但是这种方法在计算均值时不是共享权重吗?我希望,平均 k_0 的预测完全取决于分配给该特定关键点的 c 特征图,即通道 x[:, 0]。不过我可能会误解你的概念。
  • 查看我的编辑,我添加了一些说明。分组卷积不会完全连接通道方面。给定 2D 输出的结果将仅取决于输入张量的 c 通道
  • 啊,很有趣!我不知道nn.Conv2d 中的组参数。是的,这似乎也有效。我认为这里的两个答案都达到了我的目标。我想知道哪种方法更适合!你有什么想法吗?
  • 无法击败单行!另外我认为使用卷积会更有效,因为整个操作将一次性发生, k 单独的nn.Linear 调用。
  • 我会去重塑 (bn, k, c, 32, 32) (我认为它是一批 k c-channel 32x32 地图)
【解决方案2】:

你可以使用 nn.ModuleList 来做这样的事情:

import torch
import torch.nn as nn
import torch.nn.functional as F

class fclist(nn.Module):
    def __init__(self, k):
        super().__init__()
        '''
        k: no. of clusters
        '''
        self.k = k
        '''
        .
        .
        .
        Other previous layers
        .
        .
        '''

        c = 1

        self.out_layers = nn.ModuleList()
        for i in range(k):
            self.out_layers.append(nn.Linear(c*32*32, 2))

    def forward(self, x):
        '''
        .
        .
        .
        pass throgh previous layers
        .
        .
        '''
        x = [layer(x) for layer in self.out_layers]
        return x

样本输出:

>>> net =  fclist(k=3)
>>> inp = torch.randn(1, 1*32*32)
>>> net(inp)
[tensor([[-0.7319, -0.2686]], grad_fn=<AddmmBackward>), tensor([[-0.6248,  0.9180]], grad_fn=<AddmmBackward>), tensor([[0.2532, 0.1387]], grad_fn=<AddmmBackward>)]

【讨论】:

  • 不确定这是否是 OP 所说的 “更有效的方法?”
  • 谢谢,我想这正是我想要的! :)
猜你喜欢
  • 2011-07-24
  • 1970-01-01
  • 2017-10-24
  • 2015-12-08
  • 1970-01-01
  • 2017-12-25
  • 2014-09-15
  • 2019-06-24
  • 1970-01-01
相关资源
最近更新 更多