1), 1) test_eq(Identity()(
层级
基本操作和大小调整
模块
module (*flds, **defaults)
使用 f
作为 forward
方法创建 nn.Module
的装饰器
恒等
Identity ()
什么都不做
Lambda
Lambda (func)
为简单的 func
创建 PyTorch 层的一种简单方法
def _add2(x): return x+2
= Lambda(_add2)
tst = torch.randn(10,20)
x +2)
test_eq(tst(x), x= pickle.loads(pickle.dumps(tst))
tst2 +2)
test_eq(tst2(x), x tst
Lambda(func=<function _add2>)
PartialLambda
PartialLambda (func)
应用 partial(func, **kwargs)
的层
def test_func(a,b=2): return a+b
= PartialLambda(test_func, b=5)
tst +5) test_eq(tst(x), x
展平
Flatten (full=False)
将 x
展平为单个维度,例如 在模型末尾。full
用于秩为 1 的张量
= Flatten()
tst = torch.randn(10,5,4)
x 10,20])
test_eq(tst(x).shape, [= Flatten(full=True)
tst 200]) test_eq(tst(x).shape, [
ToTensorBase
ToTensorBase (tensor_cls=<class 'fastai.torch_core.TensorBase'>)
将 x 转换为 TensorBase 类
= ToTensorBase()
ttb = TensorImage(torch.rand(1,3,32,32))
timg type(ttb(timg)), TensorBase) test_eq(
View
View (*size)
将 x
重塑为 size
= View(10,5,4)
tst 10,5,4]) test_eq(tst(x).shape, [
ResizeBatch
ResizeBatch (*size)
将 x
重塑为 size
,同时保持批处理维度大小不变
= ResizeBatch(5,4)
tst 10,5,4]) test_eq(tst(x).shape, [
调试器
Debugger ()
用于在模型内部调试的模块。
sigmoid_range
sigmoid_range (x, low, high)
范围为 (low, high)
的 Sigmoid 函数
= tensor([-10.,0.,10.])
test assert torch.allclose(sigmoid_range(test, -1, 2), tensor([-1.,0.5, 2.]), atol=1e-4, rtol=1e-4)
assert torch.allclose(sigmoid_range(test, -5, -1), tensor([-5.,-3.,-1.]), atol=1e-4, rtol=1e-4)
assert torch.allclose(sigmoid_range(test, 2, 4), tensor([2., 3., 4.]), atol=1e-4, rtol=1e-4)
SigmoidRange
SigmoidRange (low, high)
范围为 (low, high)
的 Sigmoid 模块
= SigmoidRange(-1, 2)
tst assert torch.allclose(tst(test), tensor([-1.,0.5, 2.]), atol=1e-4, rtol=1e-4)
池化层
AdaptiveConcatPool1d
AdaptiveConcatPool1d (size=None)
拼接 AdaptiveAvgPool1d
和 AdaptiveMaxPool1d
的层
AdaptiveConcatPool2d
AdaptiveConcatPool2d (size=None)
拼接 AdaptiveAvgPool2d
和 AdaptiveMaxPool2d
的层
如果输入是 bs x nf x h x h
,如果没有传递 size,输出将是 bs x 2*nf x 1 x 1
,或者 bs x 2*nf x size x size
= AdaptiveConcatPool2d()
tst = torch.randn(10,5,4,4)
x 10,10,1,1])
test_eq(tst(x).shape, [= torch.max(x, dim=2, keepdim=True)[0]
max1 = torch.max(max1, dim=3, keepdim=True)[0]
maxp 5], maxp)
test_eq(tst(x)[:,:5:], x.mean(dim=[2,3], keepdim=True))
test_eq(tst(x)[:,= AdaptiveConcatPool2d(2)
tst 10,10,2,2]) test_eq(tst(x).shape, [
PoolType
PoolType ()
初始化 self。请参阅 help(type(self)) 获取准确的签名。
adaptive_pool
adaptive_pool (pool_type)
PoolFlatten
PoolFlatten (pool_type='Avg')
结合 nn.AdaptiveAvgPool2d
和 Flatten
。
= PoolFlatten()
tst 10,5])
test_eq(tst(x).shape, [=[2,3])) test_eq(tst(x), x.mean(dim
BatchNorm 层
BatchNorm
BatchNorm (nf, ndim=2, norm_type=<NormType.Batch: 1>, eps:float=1e-05, momentum:Optional[float]=0.1, affine:bool=True, track_running_stats:bool=True, device=None, dtype=None)
具有 nf
特征和 ndim
的 BatchNorm 层,根据 norm_type
进行初始化。
InstanceNorm
InstanceNorm (nf, ndim=2, norm_type=<NormType.Instance: 5>, affine=True, eps:float=1e-05, momentum:float=0.1, track_running_stats:bool=False, device=None, dtype=None)
具有 nf
特征和 ndim
的 InstanceNorm 层,根据 norm_type
进行初始化。
kwargs
被传递给 nn.BatchNorm
,可以是 eps
、momentum
、affine
和 track_running_stats
。
= BatchNorm(15)
tst assert isinstance(tst, nn.BatchNorm2d)
15))
test_eq(tst.weight, torch.ones(= BatchNorm(15, norm_type=NormType.BatchZero)
tst 15))
test_eq(tst.weight, torch.zeros(= BatchNorm(15, ndim=1)
tst assert isinstance(tst, nn.BatchNorm1d)
= BatchNorm(15, ndim=3)
tst assert isinstance(tst, nn.BatchNorm3d)
= InstanceNorm(15)
tst assert isinstance(tst, nn.InstanceNorm2d)
15))
test_eq(tst.weight, torch.ones(= InstanceNorm(15, norm_type=NormType.InstanceZero)
tst 15))
test_eq(tst.weight, torch.zeros(= InstanceNorm(15, ndim=1)
tst assert isinstance(tst, nn.InstanceNorm1d)
= InstanceNorm(15, ndim=3)
tst assert isinstance(tst, nn.InstanceNorm3d)
如果 affine
为 false,则 weight 应为 None
15, affine=False).weight, None)
test_eq(BatchNorm(15, affine=False).weight, None) test_eq(InstanceNorm(
BatchNorm1dFlat
BatchNorm1dFlat (num_features:int, eps:float=1e-05, momentum:Optional[float]=0.1, affine:bool=True, track_running_stats:bool=True, device=None, dtype=None)
nn.BatchNorm1d
,但首先展平前面的维度
= BatchNorm1dFlat(15)
tst = torch.randn(32, 64, 15)
x = tst(x)
y = x.mean(dim=[0,1])
mean 0*0.9 + mean*0.1)
test_close(tst.running_mean, = (x-mean).pow(2).mean(dim=[0,1])
var 1*0.9 + var*0.1, eps=1e-4)
test_close(tst.running_var, -mean)/torch.sqrt(var+1e-5) * tst.weight + tst.bias, eps=1e-4) test_close(y, (x
LinBnDrop
LinBnDrop (n_in, n_out, bn=True, p=0.0, act=None, lin_first=False)
组合了 BatchNorm1d
、Dropout
和 Linear
层的模块
如果 bn=False
,则跳过 BatchNorm
层;如果 p=0.
,则跳过 dropout。可选地,您可以在线性层之后使用 act
添加激活函数。
= LinBnDrop(10, 20)
tst = list(tst.children())
mods len(mods), 2)
test_eq(assert isinstance(mods[0], nn.BatchNorm1d)
assert isinstance(mods[1], nn.Linear)
= LinBnDrop(10, 20, p=0.1)
tst = list(tst.children())
mods len(mods), 3)
test_eq(assert isinstance(mods[0], nn.BatchNorm1d)
assert isinstance(mods[1], nn.Dropout)
assert isinstance(mods[2], nn.Linear)
= LinBnDrop(10, 20, act=nn.ReLU(), lin_first=True)
tst = list(tst.children())
mods len(mods), 3)
test_eq(assert isinstance(mods[0], nn.Linear)
assert isinstance(mods[1], nn.ReLU)
assert isinstance(mods[2], nn.BatchNorm1d)
= LinBnDrop(10, 20, bn=False)
tst = list(tst.children())
mods len(mods), 1)
test_eq(assert isinstance(mods[0], nn.Linear)
初始化
sigmoid
sigmoid (input, eps=1e-07)
与 torch.sigmoid
相同,加上限制在 `(eps,1-eps)` 范围内
sigmoid_
sigmoid_ (input, eps=1e-07)
与 torch.sigmoid_
相同,加上限制在 `(eps,1-eps)` 范围内
vleaky_relu
vleaky_relu (input, inplace=True)
斜率为 0.3 的 F.leaky_relu
init_default
init_default (m, func=<function kaiming_normal_>)
使用 func
初始化 m
的权重并将 bias
设置为 0。
init_linear
init_linear (m, act_func=None, init='auto', bias_std=0.01)
卷积
ConvLayer
ConvLayer (ni, nf, ks=3, stride=1, padding=None, bias=None, ndim=2, norm_type=<NormType.Batch: 1>, bn_1st=True, act_cls=<class 'torch.nn.modules.activation.ReLU'>, transpose=False, init='auto', xtra=None, bias_std=0.01, dilation:Union[int,Tuple[int,int]]=1, groups:int=1, padding_mode:str='zeros', device=None, dtype=None)
创建一个卷积层(从 ni
到 nf
)、ReLU 层(如果 use_activ
为 true)和 norm_type
层的序列。
卷积使用 ks
(核大小)、stride
、padding
和 bias
。padding
将默认为适当的值(如果不是转置卷积,则为 (ks-1)//2
),如果 norm_type
是 Spectral
或 Weight
,bias
将默认为 True
;如果是 Batch
或 BatchZero
,则默认为 False
。请注意,如果您不希望进行任何归一化,应传递 norm_type=None
。
这定义了一个具有 ndim
(1,2 或 3)的卷积层,如果 transpose=True
,它将是 ConvTranspose。act_cls
是要使用的激活函数的类(在内部实例化)。如果您不希望使用激活函数,请传递 act=None
。如果您想快速更改默认激活函数,可以修改 defaults.activation
的值。
init
用于初始化权重(bias 初始化为 0),xtra
是一个可选层,可以添加到末尾。
= ConvLayer(16, 32)
tst = list(tst.children())
mods len(mods), 3)
test_eq(1].weight, torch.ones(32))
test_eq(mods[0].padding, (1,1)) test_eq(mods[
= torch.randn(64, 16, 8, 8)#.cuda() x
#Padding is selected to make the shape the same if stride=1
64,32,8,8]) test_eq(tst(x).shape, [
#Padding is selected to make the shape half if stride=2
= ConvLayer(16, 32, stride=2)
tst 64,32,4,4]) test_eq(tst(x).shape, [
#But you can always pass your own padding if you want
= ConvLayer(16, 32, padding=0)
tst 64,32,6,6]) test_eq(tst(x).shape, [
#No bias by default for Batch NormType
assert mods[0].bias is None
#But can be overridden with `bias=True`
= ConvLayer(16, 32, bias=True)
tst assert first(tst.children()).bias is not None
#For no norm, or spectral/weight, bias is True by default
for t in [None, NormType.Spectral, NormType.Weight]:
= ConvLayer(16, 32, norm_type=t)
tst assert first(tst.children()).bias is not None
#Various n_dim/tranpose
= ConvLayer(16, 32, ndim=3)
tst assert isinstance(list(tst.children())[0], nn.Conv3d)
= ConvLayer(16, 32, ndim=1, transpose=True)
tst assert isinstance(list(tst.children())[0], nn.ConvTranspose1d)
#No activation/leaky
= ConvLayer(16, 32, ndim=3, act_cls=None)
tst = list(tst.children())
mods len(mods), 2)
test_eq(= ConvLayer(16, 32, ndim=3, act_cls=partial(nn.LeakyReLU, negative_slope=0.1))
tst = list(tst.children())
mods len(mods), 3)
test_eq(assert isinstance(mods[2], nn.LeakyReLU)
# #export
# def linear(in_features, out_features, bias=True, act_cls=None, init='auto'):
# "Linear layer followed by optional activation, with optional auto-init"
# res = nn.Linear(in_features, out_features, bias=bias)
# if act_cls: act_cls = act_cls()
# init_linear(res, act_cls, init=init)
# if act_cls: res = nn.Sequential(res, act_cls)
# return res
# #export
# @delegates(ConvLayer)
# def conv1d(ni, nf, ks, stride=1, ndim=1, norm_type=None, **kwargs):
# "Convolutional layer followed by optional activation, with optional auto-init"
# return ConvLayer(ni, nf, ks, stride=stride, ndim=ndim, norm_type=norm_type, **kwargs)
# #export
# @delegates(ConvLayer)
# def conv2d(ni, nf, ks, stride=1, ndim=2, norm_type=None, **kwargs):
# "Convolutional layer followed by optional activation, with optional auto-init"
# return ConvLayer(ni, nf, ks, stride=stride, ndim=ndim, norm_type=norm_type, **kwargs)
# #export
# @delegates(ConvLayer)
# def conv3d(ni, nf, ks, stride=1, ndim=3, norm_type=None, **kwargs):
# "Convolutional layer followed by optional activation, with optional auto-init"
# return ConvLayer(ni, nf, ks, stride=stride, ndim=ndim, norm_type=norm_type, **kwargs)
AdaptiveAvgPool
AdaptiveAvgPool (sz=1, ndim=2)
用于 ndim
的 nn.AdaptiveAvgPool 层
MaxPool
MaxPool (ks=2, stride=None, padding=0, ndim=2, ceil_mode=False)
用于 ndim
的 nn.MaxPool 层
AvgPool
AvgPool (ks=2, stride=None, padding=0, ndim=2, ceil_mode=False)
用于 ndim
的 nn.AvgPool 层
嵌入
trunc_normal_
trunc_normal_ (x, mean=0.0, std=1.0)
截断正态初始化(近似)
Embedding
Embedding (ni, nf, std=0.01)
使用截断正态初始化的嵌入层
截断正态初始化限制分布以避免出现大值。对于给定的标准差 std
,边界大致为 -2*std
、2*std
。
= 0.02
std = Embedding(10, 30, std)
tst assert tst.weight.min() > -2*std
assert tst.weight.max() < 2*std
0, 1e-2)
test_close(tst.weight.mean(), 0.1) test_close(tst.weight.std(), std,
自注意力
SelfAttention
SelfAttention (n_channels)
用于 n_channels
的自注意力层。
在 Self-Attention Generative Adversarial Networks 中引入的自注意力层。
最初,不对输入进行任何更改。这由一个名为 gamma
的可训练参数控制,因为我们返回 x + gamma * out
。
= SelfAttention(16)
tst = torch.randn(32, 16, 8, 8)
x test_eq(tst(x),x)
然后,在训练过程中,gamma
可能会改变,因为它是一个可训练参数。让我们看看当它获得非零值时会发生什么。
1.)
tst.gamma.data.fill_(= tst(x)
y 32,16,8,8]) test_eq(y.shape, [
注意力机制需要三次矩阵乘法(此处用 1x1 卷积表示)。乘法在通道级别(我们张量中的第二个维度)进行,并且我们展平特征图(此处为 8x8)。如论文中所述,我们将这些乘法的结果记为 f
、g
和 h
。
= tst.query[0].weight.data,tst.key[0].weight.data,tst.value[0].weight.data
q,k,v 2, 16, 1], [2, 16, 1], [16, 16, 1]])
test_eq([q.shape, k.shape, v.shape], [[= map(lambda m: x.view(32, 16, 64).transpose(1,2) @ m.squeeze().t(), [q,k,v])
f,g,h 32,64,2], [32,64,2], [32,64,16]]) test_eq([f.shape, g.shape, h.shape], [[
注意力层的关键部分是计算特征图中每个位置(此处 8x8 = 64)的注意力权重。这些是总和为 1 的正数,告诉模型应该关注图片的哪个部分。我们将 f
与 g
的转置相乘(得到一个大小为 bs x 64 x 64 的结果),然后对第一个维度应用 softmax(得到总和为 1 的正数)。然后可以将结果与 h
的转置相乘,得到一个大小为 bs x 通道数 x 64 的输出,然后可以将其视为与原始输入相同大小的输出。
最终结果是 x + gamma * out
,如我们之前所见。
= F.softmax(torch.bmm(f, g.transpose(1,2)), dim=1)
beta 32, 64, 64])
test_eq(beta.shape, [= torch.bmm(h.transpose(1,2), beta)
out 32, 16, 64])
test_eq(out.shape, [+ out.view(32, 16, 8, 8), eps=1e-4) test_close(y, x
PooledSelfAttention2d
PooledSelfAttention2d (n_channels)
用于二维的池化自注意力层。
在 Big GAN 论文 中使用的自注意力层。
它使用与 SelfAttention
相同的注意力机制,但在计算矩阵 g
和 h
之前添加了一个步幅为 2 的最大池化层:注意力集中在一个 2x2 最大池化窗口上,而不是整个特征图。还在输出的末尾添加了一个最终的矩阵乘积,然后返回 gamma * out + x
。
SimpleSelfAttention
SimpleSelfAttention (n_in:int, ks=1, sym=False)
与 nn.Module
相同,但子类无需调用 super().__init__
像素洗牌
PixelShuffle 在 这篇文章 中提出,用于避免图像上采样时的棋盘状伪影。如果我们需要一个具有 ch_out
个滤波器的输出,我们使用一个具有 ch_out * (r**2)
个滤波器的卷积,其中 r
是上采样因子。然后我们像下图一样重新组织这些滤波器
icnr_init
icnr_init (x, scale=2, init=<function kaiming_normal_>)
x
的 ICNR 初始化,带有 scale
和 init
函数
ICNR 初始化在 这篇文章 中提出。它建议初始化将在 PixelShuffle 中使用的卷积,以便 r**2
个通道中的每个通道都获得相同的权重(这样在上图中,3x3 窗口中的 9 种颜色最初是相同的)。
这是在第一个维度上完成的,因为 PyTorch 以这种格式存储卷积层的权重:ch_out x ch_in x ks x ks
。
= torch.randn(16*4, 32, 1, 1)
tst = icnr_init(tst)
tst for i in range(0,16*4,4):
+1])
test_eq(tst[i],tst[i+2])
test_eq(tst[i],tst[i+3]) test_eq(tst[i],tst[i
PixelShuffle_ICNR
PixelShuffle_ICNR (ni, nf=None, scale=2, blur=False, norm_type=<NormType.Weight: 3>, act_cls=<class 'torch.nn.modules.activation.ReLU'>)
使用 nn.PixelShuffle
将 ni
滤波器上采样 scale
倍到 nf
(默认为 ni
)。
卷积层使用 icnr_init
初始化,并传递 act_cls
和 norm_type
(在我们的实验中,权重归一化的默认设置似乎最适合超分辨率问题)。
blur
选项来自 Super-Resolution using Convolutional Neural Networks without Any Checkerboard Artifacts,作者在该论文中添加了一点模糊来完全消除棋盘状伪影。
= PixelShuffle_ICNR(16)
psfl = torch.randn(64, 16, 8, 8)
x = psfl(x)
y 64, 16, 16, 16])
test_eq(y.shape, [#ICNR init makes every 2x2 window (stride 2) have the same elements
for i in range(0,16,2):
for j in range(0,16,2):
+1,j])
test_eq(y[:,:,i,j],y[:,:,i+1])
test_eq(y[:,:,i,j],y[:,:,i ,j+1,j+1]) test_eq(y[:,:,i,j],y[:,:,i
= PixelShuffle_ICNR(16, norm_type=None)
psfl = torch.randn(64, 16, 8, 8)
x = psfl(x)
y 64, 16, 16, 16])
test_eq(y.shape, [#ICNR init makes every 2x2 window (stride 2) have the same elements
for i in range(0,16,2):
for j in range(0,16,2):
+1,j])
test_eq(y[:,:,i,j],y[:,:,i+1])
test_eq(y[:,:,i,j],y[:,:,i ,j+1,j+1]) test_eq(y[:,:,i,j],y[:,:,i
= PixelShuffle_ICNR(16, norm_type=NormType.Spectral)
psfl = torch.randn(64, 16, 8, 8)
x = psfl(x)
y 64, 16, 16, 16])
test_eq(y.shape, [#ICNR init makes every 2x2 window (stride 2) have the same elements
for i in range(0,16,2):
for j in range(0,16,2):
+1,j])
test_eq(y[:,:,i,j],y[:,:,i+1])
test_eq(y[:,:,i,j],y[:,:,i ,j+1,j+1]) test_eq(y[:,:,i,j],y[:,:,i
Sequential 扩展
sequential
sequential (*args)
创建一个 nn.Sequential
,如果需要,使用 Lambda
包装项目
SequentialEx
SequentialEx (*layers)
类似于 nn.Sequential
,但具有 ModuleList 语义,并且可以访问模块输入
这对于以顺序方式编写需要记住输入(如 resnet 块)的层非常有用。
MergeLayer
MergeLayer (dense:bool=False)
通过将快捷连接与模块结果相加或(如果 dense=True
)拼接来合并它们。
= SequentialEx(ConvLayer(16, 16), ConvLayer(16,16))
res_block # just to test append - normally it would be in init params
res_block.append(MergeLayer()) = torch.randn(32, 16, 8, 8)
x = res_block(x)
y 32, 16, 8, 8])
test_eq(y.shape, [+ res_block[1](res_block[0](x))) test_eq(y, x
= TensorBase(torch.randn(32, 16, 8, 8))
x = res_block(x)
y None) test_is(y.orig,
拼接
等同于 keras.layers.Concatenate,它将在给定维度(默认为过滤器维度)上拼接 ModuleList 的输出
连接
Cat (layers, dim=1)
在给定维度上连接层输出
= [ConvLayer(2,4), ConvLayer(2,4), ConvLayer(2,4)]
layers = torch.rand(1,2,8,8)
x = Cat(layers)
cat 1,12,8,8])
test_eq(cat(x).shape, [for l in layers], dim=1)) test_eq(cat(x), torch.cat([l(x)
即用模型
SimpleCNN
SimpleCNN (filters, kernel_szs=None, strides=None, bn=True)
使用 filters
创建一个简单的 CNN。
模型是一个从 (filters[0],filters[1])
到 (filters[n-2],filters[n-1])
的卷积层序列(如果 n
是 filters
列表的长度),后跟一个 PoolFlatten
。kernel_szs
和 strides
默认为一个包含 3 的列表和一个包含 2 的列表。如果 bn=True
,卷积层序列为 conv-relu-batchnorm,否则为 conv-relu。
= SimpleCNN([8,16,32])
tst = list(tst.children())
mods len(mods), 3)
test_eq(0].in_channels, m[0].out_channels] for m in mods[:2]], [[8,16], [16,32]]) test_eq([[m[
测试核大小
= SimpleCNN([8,16,32], kernel_szs=[1,3])
tst = list(tst.children())
mods 0].kernel_size for m in mods[:2]], [(1,1), (3,3)]) test_eq([m[
测试步幅
= SimpleCNN([8,16,32], strides=[1,2])
tst = list(tst.children())
mods 0].stride for m in mods[:2]], [(1,1),(2,2)]) test_eq([m[
ProdLayer
ProdLayer ()
通过将快捷连接与模块结果相乘来合并它们。
SEModule
SEModule (ch, reduction, act_cls=<class 'torch.nn.modules.activation.ReLU'>)
残差块
ResBlock (expansion, ni, nf, stride=1, groups=1, reduction=None, nh1=None, nh2=None, dw=False, g2=1, sa=False, sym=False, norm_type=<NormType.Batch: 1>, act_cls=<class 'torch.nn.modules.activation.ReLU'>, ndim=2, ks=3, pool=<function AvgPool>, pool_first=True, padding=None, bias=None, bn_1st=True, transpose=False, init='auto', xtra=None, bias_std=0.01, dilation:Union[int,Tuple[int,int]]=1, padding_mode:str='zeros', device=None, dtype=None)
从 ni
到 nh
的 Resnet 块,带有 stride
这是一个 Resnet 块(根据 expansion
不同可以是普通块或 bottleneck 块,普通块为 1,传统 bottleneck 块为 4),它实现了 Bag of Tricks for Image Classification with Convolutional Neural Networks 中的改进。特别是,最后一个 batchnorm 层(如果选中该 norm_type
)使用零权重(或 gamma)初始化,以促进从网络开始到结束的信息流动。它还实现了可选的 Squeeze and Excitation 以及用于 ResNeXT 及类似模型的分组卷积(使用 dw=True
表示深度可分离卷积)。
kwargs
以及 norm_type
被传递给 ConvLayer
。
SEBlock
SEBlock (expansion, ni, nf, groups=1, reduction=16, stride=1, **kwargs)
SEResNeXtBlock
SEResNeXtBlock (expansion, ni, nf, groups=32, reduction=16, stride=1, base_width=4, **kwargs)
SeparableBlock
SeparableBlock (expansion, ni, nf, reduction=16, stride=1, base_width=4, **kwargs)
时间分布层
等同于 Keras TimeDistributed
层,能够在某个轴上计算 PyTorch Module
。
= 2, 5
bs, seq_len = torch.rand(bs,seq_len,3,2,2), torch.rand(bs,seq_len,3,2,2) x, y
= TimeDistributed(nn.Conv2d(3,4,1))
tconv 2,5,4,2,2))
test_eq(tconv(x).shape, (=True
tconv.low_mem2,5,4,2,2)) test_eq(tconv(x).shape, (
class Mod(Module):
def __init__(self):
self.conv = nn.Conv2d(3,4,1)
def forward(self, x, y):
return self.conv(x) + self.conv(y)
= TimeDistributed(Mod()) tmod
= tmod(x,y)
out 2,5,4,2,2))
test_eq(out.shape, (=True
tmod.low_mem= tmod(x,y)
out_low_mem 2,5,4,2,2))
test_eq(out_low_mem.shape, ( test_eq(out, out_low_mem)
class Mod2(Module):
def __init__(self):
self.conv = nn.Conv2d(3,4,1)
def forward(self, x, y):
return self.conv(x), self.conv(y)
= TimeDistributed(Mod2()) tmod2
= tmod2(x,y)
out len(out), 2)
test_eq(0].shape, (2,5,4,2,2))
test_eq(out[=True
tmod2.low_mem= tmod2(x,y)
out_low_mem 0].shape, (2,5,4,2,2))
test_eq(out_low_mem[ test_eq(out, out_low_mem)
TimeDistributed
TimeDistributed (module, low_mem=False, tdim=1)
在 tdim
轴上对每个步骤应用 module
。使用 low_mem
逐个计算以节省内存。
这个模块等同于 Keras TimeDistributed Layer。这个包装器允许将一个层应用于输入的每个时间切片。默认情况下,假设时间轴(tdim
)是第一个轴(批处理大小之后的那个轴)。一个典型的用法是使用图像编码器对图像序列进行编码。
TimeDistributed
的 forward
函数支持 *args
和 **kkwargs
,但只有 args
会被分割并独立传递给底层模块的每个时间步,而 kwargs
将按原样传递。当您有接受多个参数作为输入的模块时,这非常有用,这样您可以将所有需要分割的张量作为 args
,将其他不需要分割的参数作为 kwargs
。
这个模块对内存要求很高,因为它会尝试在批处理维度上同时传递多个时间步。如果遇到内存不足错误,请首先尝试将您的批处理大小除以时间步数。
from fastai.vision.all import *
= create_body(resnet18()) encoder
Resnet18 将编码一个具有 512 个通道的特征图。高度和宽度将除以 32。
= TimeDistributed(encoder) time_resnet
一个包含 2 个图像序列(长度为 5)的合成批次。(bs, seq_len, ch, w, h)
= torch.rand(2, 5, 3, 64, 64) image_sequence
time_resnet(image_sequence).shape
torch.Size([2, 5, 512, 2, 2])
通过这种方式,可以在特征空间上编码图像序列。还有一个 low_mem_forward
函数,它将逐个传递图像以减少 GPU 内存消耗。
time_resnet.low_mem_forward(image_sequence).shape
torch.Size([2, 5, 512, 2, 2])
Swish 和 Mish
swish
swish (x, inplace=False)
SwishJit
SwishJit ()
与 nn.Module
相同,但子类无需调用 super().__init__
MishJitAutoFn
MishJitAutoFn (*args, **kwargs)
*创建自定义 autograd.Function
的基类。
要创建自定义 autograd.Function
,请继承此类并实现 :meth:forward
和 :meth:backward
静态方法。然后,要在前向传播中使用您的自定义操作,请调用类方法 apply
。不要直接调用 :meth:forward
。
为确保正确性和最佳性能,请确保您在 ctx
上调用了正确的方法,并使用 :func:torch.autograd.gradcheck
验证您的反向传播函数。
有关如何使用此类的更多详细信息,请参阅 :ref:extending-autograd
。
示例:
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_AUTOGRAD)
>>> class Exp(Function):
>>> @staticmethod
>>> def forward(ctx, i):
>>> result = i.exp()
>>> ctx.save_for_backward(result)
>>> return result
>>>
>>> @staticmethod
>>> def backward(ctx, grad_output):
>>> result, = ctx.saved_tensors
>>> return grad_output * result
>>>
>>> # Use it by calling the apply method:
>>> # xdoctest: +SKIP
>>> output = Exp.apply(input)*
mish
mish (x, inplace=False)
MishJit
MishJit ()
与 nn.Module
相同,但子类无需调用 super().__init__
子模块辅助函数
很容易获取给定模型的所有参数列表。如果您想要所有子模块(如线性/卷积层)而不错过单独的参数,以下类将这些参数包装在伪模块中。
ParameterModule
ParameterModule (p)
在模块中注册一个单独的参数 p
。
children_and_parameters
children_and_parameters (m)
返回 m
的子模块及其未在模块中注册的直接参数。
class TstModule(Module):
def __init__(self): self.a,self.lin = nn.Parameter(torch.randn(1)),nn.Linear(5,10)
= TstModule()
tst = children_and_parameters(tst)
children len(children), 2)
test_eq(0], tst.lin)
test_eq(children[assert isinstance(children[1], ParameterModule)
1].val, tst.a) test_eq(children[
has_children
has_children (m)
class A(Module): pass
assert not has_children(A())
assert has_children(TstModule())
flatten_model
flatten_model (m)
返回 m
的所有子模块和参数列表。
= nn.Sequential(TstModule(), TstModule())
tst = flatten_model(tst)
children len(children), 4)
test_eq(assert isinstance(children[1], ParameterModule)
assert isinstance(children[3], ParameterModule)
NoneReduce
NoneReduce (loss_func)
用于以 none reduce 方式评估 loss_func
的上下文管理器。
= torch.randn(5),torch.randn(5)
x,y = nn.MSELoss()
loss_fn with NoneReduce(loss_fn) as loss_func:
= loss_func(x,y)
loss 5])
test_eq(loss.shape, ['mean')
test_eq(loss_fn.reduction,
= F.mse_loss
loss_fn with NoneReduce(loss_fn) as loss_func:
= loss_func(x,y)
loss 5])
test_eq(loss.shape, [ test_eq(loss_fn, F.mse_loss)
in_channels
in_channels (m)
返回 m
中第一个权重层的形状。
5,4,3), nn.Conv2d(4,3,3))), 5)
test_eq(in_channels(nn.Sequential(nn.Conv2d(4), nn.Conv2d(4,3,3))), 4)
test_eq(in_channels(nn.Sequential(nn.AvgPool2d(4), nn.Conv2d(4,3,3))), 4)
test_eq(in_channels(nn.Sequential(BatchNorm(4), nn.Conv2d(4,3,3))), 4)
test_eq(in_channels(nn.Sequential(InstanceNorm(4, affine=False), nn.Conv2d(4,3,3))), 4)
test_eq(in_channels(nn.Sequential(InstanceNorm(lambda : in_channels(nn.Sequential(nn.AvgPool2d(4)))) test_fail(