【发布时间】:2021-01-21 13:32:45
【问题描述】:
所以,我已经阅读了大约一半的原始 ResNet 论文,并且正在尝试弄清楚如何为表格数据制作我的版本。
我已经阅读了一些关于它在 PyTorch 中如何工作的博客文章,并且我看到大量使用 nn.Identity()。现在,该论文还经常使用术语身份映射。但是,它只是指以元素方式将层堆栈的输入添加到同一堆栈的输出。如果输入和输出维度不同,那么论文会讨论用零填充输入或使用矩阵W_s 将输入投影到不同的维度。
这是我在一篇博文中找到的残差块的抽象:
class ResidualBlock(nn.Module):
def __init__(self, in_channels, out_channels, activation='relu'):
super().__init__()
self.in_channels, self.out_channels, self.activation = in_channels, out_channels, activation
self.blocks = nn.Identity()
self.shortcut = nn.Identity()
def forward(self, x):
residual = x
if self.should_apply_shortcut: residual = self.shortcut(x)
x = self.blocks(x)
x += residual
return x
@property
def should_apply_shortcut(self):
return self.in_channels != self.out_channels
block1 = ResidualBlock(4, 4)
还有我自己对虚拟张量的应用:
x = tensor([1, 1, 2, 2])
block1 = ResidualBlock(4, 4)
block2 = ResidualBlock(4, 6)
x = block1(x)
print(x)
x = block2(x)
print(x)
>>> tensor([2, 2, 4, 4])
>>> tensor([4, 4, 8, 8])
所以最后,x = nn.Identity(x) 我不确定它的用途,除了模仿原始论文中的数学术语。我确信情况并非如此,而且它有一些我还没有看到的隐藏用途。会是什么?
编辑这是另一个实现残差学习的例子,这次是在 Keras 中。它只是按照我上面的建议做的,只是保留输入的副本以添加到输出中:
def residual_block(x: Tensor, downsample: bool, filters: int, kernel_size: int = 3) -> Tensor:
y = Conv2D(kernel_size=kernel_size,
strides= (1 if not downsample else 2),
filters=filters,
padding="same")(x)
y = relu_bn(y)
y = Conv2D(kernel_size=kernel_size,
strides=1,
filters=filters,
padding="same")(y)
if downsample:
x = Conv2D(kernel_size=1,
strides=2,
filters=filters,
padding="same")(x)
out = Add()([x, y])
out = relu_bn(out)
return out
【问题讨论】:
-
我在这里看到了答案:github.com/pytorch/pytorch/issues/9160。如果没有人先这样做,我会在几天内将其扩展为答案。
标签: python neural-network pytorch deep-residual-networks