我正在尝试在 cifar10 数据集上使用 3d conv(只是为了好玩(。我看到我们通常输入的文档是 5d 张量 (N,C,D,H,W(。我真的必须传递 5 维数据吗?
我持怀疑态度的原因是,3D 卷积只是意味着我的卷积在 3 个维度/方向上移动。所以从技术上讲,我可以有 3d 4d 5d 甚至 100d 张量,然后只要它至少是 3d 张量,就应该都可以工作。这不对吗?
我很快就尝试了一下,它确实给出了一个错误:
import torch
def conv3d_example():
N,C,H,W = 1,3,7,7
img = torch.randn(N,C,H,W)
##
in_channels, out_channels = 1, 4
kernel_size = (2,3,3)
conv = torch.nn.Conv3d(in_channels, out_channels, kernel_size)
##
out = conv(img)
print(out)
print(out.size())
##
conv3d_example()
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-3-29c73923cc64> in <module>
15
16 ##
---> 17 conv3d_example()
<ipython-input-3-29c73923cc64> in conv3d_example()
10 conv = torch.nn.Conv3d(in_channels, out_channels, kernel_size)
11 ##
---> 12 out = conv(img)
13 print(out)
14 print(out.size())
~/anaconda3/lib/python3.7/site-packages/torch/nn/modules/module.py in __call__(self, *input, **kwargs)
491 result = self._slow_forward(*input, **kwargs)
492 else:
--> 493 result = self.forward(*input, **kwargs)
494 for hook in self._forward_hooks.values():
495 hook_result = hook(self, input, result)
~/anaconda3/lib/python3.7/site-packages/torch/nn/modules/conv.py in forward(self, input)
474 self.dilation, self.groups)
475 return F.conv3d(input, self.weight, self.bias, self.stride,
--> 476 self.padding, self.dilation, self.groups)
477
478
RuntimeError: Expected 5-dimensional input for 5-dimensional weight 4 1 2 3, but got 4-dimensional input of size [1, 3, 7, 7] instead
交叉发布:
- https://discuss.pytorch.org/t/how-does-one-use-3d-convolutions-on-standard-3-channel-images/53330
- 如何在标准 3 通道图像上使用 3D 卷积?
请考虑以下方案。您有一个 3 通道 NxN 映像。此映像在 pytorch 中的大小为 3xNxN(暂时忽略批处理维度(。
假设您将此图像传递到无偏差的 2D 卷积层,内核大小为 5x5,填充为 2,输入/输出通道分别为 3 和 10。
当我们将此层应用于输入图像时,实际发生了什么?
你可以这样想...
对于 10 个输出通道中的每一个,都有一个大小为 3x5x5 的内核。使用此内核将3D卷积应用于 3xNxN 输入图像,该内核在第一维中可以被认为是未填充的。这种卷积的结果是一个1xNxN的特征图。
由于有 10 个输出层,因此有 10 个 3x5x5 内核。应用所有内核后,输出将堆叠成单个 10xNxN 张量。
所以实际上,在经典意义上,2D卷积层已经在执行3D卷积。
同样,对于 3D 卷积层,它实际上是在执行 4D 卷积,这就是您需要 5 维输入的原因。
让我们回顾一下我们所知道的,对于 3D 卷积,我们需要解决这些问题:
N For mini batch (or how many sequences do we want to feed at one go)
Cin For the number of channels in our input (if our image is rgb, this is 3)
D For depth or in other words the number of images/frames in one input sequence (if we are dealing videos, this is the number of frames)
H For the height of the image/frame
W For the width of the image/frame
因此,既然我们知道需要什么,那么应该很容易做到这一点。
在您的示例中,您缺少输入中的深度,- 并且由于您有一个 rgb 图像,因此输入的深度或时间维度为 1。
- 你也有一个错误的
in_channels
. 它的 C(在你的例子 3 中,因为你似乎有 rgb 图像( - 您还需要修复内核维度,因为它的深度维度也错误。 同样,由于我们处理的是单个图像而不是图像序列,因此深度为 1。 如果你的输入深度为 k,那么你可以选择内核中的任何值
1<=n<=k
.
现在你应该能够成功运行你的代码段。
def conv3d_example():
# for deterministic output only
torch.random.manual_seed(0)
N,C,D,H,W = 1,3,1,7,7
img = torch.randn(N,C,D,H,W)
##
in_channels = C
out_channels = 4
kernel_size = (1,3,3)
conv = torch.nn.Conv3d(in_channels, out_channels, kernel_size)
##
out = conv(img)
print(out)
print(out.size())
结果为 :
In [3]: conv3d_example()
tensor([[[[[ 0.9368, -0.6973, 0.1359, 0.2023, -0.3149],
[-0.4601, 0.2668, 0.3414, 0.6624, -0.6251],
[-1.0212, -0.0767, 0.2693, 0.9537, -0.4375],
[ 0.6981, -0.1586, -0.3076, 0.1973, -0.2972],
[-0.0747, -0.8704, 0.1757, -0.4161, -0.3464]]],
[[[-0.4710, -0.7841, -1.1406, -0.6413, 0.9183],
[-0.2473, 0.2532, -1.0443, -0.8634, -0.8797],
[ 0.5243, -0.4383, 0.1375, -0.7561, 0.7913],
[-1.1216, -0.4496, 0.5481, 0.1034, -1.0036],
[-0.0941, -0.1458, -0.1438, -1.0257, -0.4392]]],
[[[ 0.5196, 0.3102, 0.5299, -0.0126, 0.7945],
[ 0.3721, -1.3339, -0.5849, -0.2701, 0.4842],
[-0.2661, 0.9777, -0.3328, -0.1730, -0.6360],
[ 0.4960, 0.2348, 0.5183, -0.2935, 0.1777],
[-0.2672, 0.0233, -0.5573, 0.8366, 0.6082]]],
[[[-0.1565, -1.7331, -0.2015, -1.1708, 0.3099],
[-0.3667, 0.1985, -0.4940, 0.4044, -0.8000],
[ 0.2814, -0.6172, -0.4466, -0.6098, 0.0983],
[-0.5814, -0.2825, -0.1321, 0.5536, -0.4767],
[-0.3337, 0.3160, -0.4748, -0.7694, -0.0705]]]]],
grad_fn=<SlowConv3DBackward0>)
torch.Size([1, 4, 1, 5, 5])