nux1111 commited on
Commit
3fe88ef
·
verified ·
1 Parent(s): 43f65fd

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. src/custom_mesh_graphormer/modeling/data/mano_195_adjmat_indices.pt +3 -0
  2. src/custom_mesh_graphormer/modeling/data/mano_195_adjmat_size.pt +3 -0
  3. src/custom_timm/data/parsers/__pycache__/__init__.cpython-312.pyc +0 -0
  4. src/custom_timm/data/parsers/__pycache__/img_extensions.cpython-312.pyc +0 -0
  5. src/custom_timm/data/parsers/__pycache__/parser.cpython-312.pyc +0 -0
  6. src/custom_timm/data/parsers/__pycache__/parser_factory.cpython-312.pyc +0 -0
  7. src/custom_timm/data/parsers/__pycache__/parser_image_folder.cpython-312.pyc +0 -0
  8. src/custom_timm/data/parsers/__pycache__/parser_image_in_tar.cpython-312.pyc +0 -0
  9. src/custom_timm/models/__pycache__/beit.cpython-312.pyc +0 -0
  10. src/custom_timm/models/__pycache__/byoanet.cpython-312.pyc +0 -0
  11. src/custom_timm/models/__pycache__/byobnet.cpython-312.pyc +0 -0
  12. src/custom_timm/models/__pycache__/cait.cpython-312.pyc +0 -0
  13. src/custom_timm/models/__pycache__/coat.cpython-312.pyc +0 -0
  14. src/custom_timm/models/__pycache__/convit.cpython-312.pyc +0 -0
  15. src/custom_timm/models/__pycache__/convmixer.cpython-312.pyc +0 -0
  16. src/custom_timm/models/__pycache__/convnext.cpython-312.pyc +0 -0
  17. src/custom_timm/models/__pycache__/crossvit.cpython-312.pyc +0 -0
  18. src/custom_timm/models/__pycache__/cspnet.cpython-312.pyc +0 -0
  19. src/custom_timm/models/__pycache__/deit.cpython-312.pyc +0 -0
  20. src/custom_timm/models/__pycache__/densenet.cpython-312.pyc +0 -0
  21. src/custom_timm/models/layers/__init__.py +44 -0
  22. src/custom_timm/models/layers/activations.py +145 -0
  23. src/custom_timm/models/layers/activations_jit.py +90 -0
  24. src/custom_timm/models/layers/activations_me.py +218 -0
  25. src/custom_timm/models/layers/adaptive_avgmax_pool.py +118 -0
  26. src/custom_timm/models/layers/attention_pool2d.py +131 -0
  27. src/custom_timm/models/layers/blur_pool.py +42 -0
  28. src/custom_timm/models/layers/bottleneck_attn.py +157 -0
  29. src/custom_timm/models/layers/cbam.py +112 -0
  30. src/custom_timm/models/layers/classifier.py +56 -0
  31. src/custom_timm/models/layers/cond_conv2d.py +123 -0
  32. src/custom_timm/models/layers/config.py +115 -0
  33. src/custom_timm/models/layers/conv2d_same.py +42 -0
  34. src/custom_timm/models/layers/conv_bn_act.py +88 -0
  35. src/custom_timm/models/layers/create_act.py +154 -0
  36. src/custom_timm/models/layers/create_attn.py +89 -0
  37. src/custom_timm/models/layers/create_conv2d.py +36 -0
  38. src/custom_timm/models/layers/create_norm.py +56 -0
  39. src/custom_timm/models/layers/create_norm_act.py +91 -0
  40. src/custom_timm/models/layers/drop.py +169 -0
  41. src/custom_timm/models/layers/eca.py +145 -0
  42. src/custom_timm/models/layers/evo_norm.py +352 -0
  43. src/custom_timm/models/layers/fast_norm.py +78 -0
  44. src/custom_timm/models/layers/filter_response_norm.py +68 -0
  45. src/custom_timm/models/layers/gather_excite.py +90 -0
  46. src/custom_timm/models/layers/global_context.py +67 -0
  47. src/custom_timm/models/layers/halo_attn.py +233 -0
  48. src/custom_timm/models/layers/helpers.py +43 -0
  49. src/custom_timm/models/layers/inplace_abn.py +87 -0
  50. src/custom_timm/models/layers/lambda_layer.py +133 -0
src/custom_mesh_graphormer/modeling/data/mano_195_adjmat_indices.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f99d80a96bbced27df6b6dee4fbdc01ee326e7e2691a79ca596ad03f57db8a6a
3
+ size 21639
src/custom_mesh_graphormer/modeling/data/mano_195_adjmat_size.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cd137f9f2b1b8827251934784326a5b05f1415333101c13c849ed6b5eba6c3a4
3
+ size 173
src/custom_timm/data/parsers/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (350 Bytes). View file
 
src/custom_timm/data/parsers/__pycache__/img_extensions.cpython-312.pyc ADDED
Binary file (2.84 kB). View file
 
src/custom_timm/data/parsers/__pycache__/parser.cpython-312.pyc ADDED
Binary file (1.3 kB). View file
 
src/custom_timm/data/parsers/__pycache__/parser_factory.cpython-312.pyc ADDED
Binary file (1.36 kB). View file
 
src/custom_timm/data/parsers/__pycache__/parser_image_folder.cpython-312.pyc ADDED
Binary file (5.37 kB). View file
 
src/custom_timm/data/parsers/__pycache__/parser_image_in_tar.cpython-312.pyc ADDED
Binary file (13.7 kB). View file
 
src/custom_timm/models/__pycache__/beit.cpython-312.pyc ADDED
Binary file (27.1 kB). View file
 
src/custom_timm/models/__pycache__/byoanet.cpython-312.pyc ADDED
Binary file (14.3 kB). View file
 
src/custom_timm/models/__pycache__/byobnet.cpython-312.pyc ADDED
Binary file (66.9 kB). View file
 
src/custom_timm/models/__pycache__/cait.cpython-312.pyc ADDED
Binary file (22.2 kB). View file
 
src/custom_timm/models/__pycache__/coat.cpython-312.pyc ADDED
Binary file (35.2 kB). View file
 
src/custom_timm/models/__pycache__/convit.cpython-312.pyc ADDED
Binary file (22.9 kB). View file
 
src/custom_timm/models/__pycache__/convmixer.cpython-312.pyc ADDED
Binary file (7.31 kB). View file
 
src/custom_timm/models/__pycache__/convnext.cpython-312.pyc ADDED
Binary file (29.6 kB). View file
 
src/custom_timm/models/__pycache__/crossvit.cpython-312.pyc ADDED
Binary file (31.3 kB). View file
 
src/custom_timm/models/__pycache__/cspnet.cpython-312.pyc ADDED
Binary file (41.4 kB). View file
 
src/custom_timm/models/__pycache__/deit.cpython-312.pyc ADDED
Binary file (20.9 kB). View file
 
src/custom_timm/models/__pycache__/densenet.cpython-312.pyc ADDED
Binary file (19 kB). View file
 
src/custom_timm/models/layers/__init__.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .activations import *
2
+ from .adaptive_avgmax_pool import \
3
+ adaptive_avgmax_pool2d, select_adaptive_pool2d, AdaptiveAvgMaxPool2d, SelectAdaptivePool2d
4
+ from .blur_pool import BlurPool2d
5
+ from .classifier import ClassifierHead, create_classifier
6
+ from .cond_conv2d import CondConv2d, get_condconv_initializer
7
+ from .config import is_exportable, is_scriptable, is_no_jit, set_exportable, set_scriptable, set_no_jit,\
8
+ set_layer_config
9
+ from .conv2d_same import Conv2dSame, conv2d_same
10
+ from .conv_bn_act import ConvNormAct, ConvNormActAa, ConvBnAct
11
+ from .create_act import create_act_layer, get_act_layer, get_act_fn
12
+ from .create_attn import get_attn, create_attn
13
+ from .create_conv2d import create_conv2d
14
+ from .create_norm import get_norm_layer, create_norm_layer
15
+ from .create_norm_act import get_norm_act_layer, create_norm_act_layer, get_norm_act_layer
16
+ from .drop import DropBlock2d, DropPath, drop_block_2d, drop_path
17
+ from .eca import EcaModule, CecaModule, EfficientChannelAttn, CircularEfficientChannelAttn
18
+ from .evo_norm import EvoNorm2dB0, EvoNorm2dB1, EvoNorm2dB2,\
19
+ EvoNorm2dS0, EvoNorm2dS0a, EvoNorm2dS1, EvoNorm2dS1a, EvoNorm2dS2, EvoNorm2dS2a
20
+ from .fast_norm import is_fast_norm, set_fast_norm, fast_group_norm, fast_layer_norm
21
+ from .filter_response_norm import FilterResponseNormTlu2d, FilterResponseNormAct2d
22
+ from .gather_excite import GatherExcite
23
+ from .global_context import GlobalContext
24
+ from .helpers import to_ntuple, to_2tuple, to_3tuple, to_4tuple, make_divisible, extend_tuple
25
+ from .inplace_abn import InplaceAbn
26
+ from .linear import Linear
27
+ from .mixed_conv2d import MixedConv2d
28
+ from .mlp import Mlp, GluMlp, GatedMlp, ConvMlp
29
+ from .non_local_attn import NonLocalAttn, BatNonLocalAttn
30
+ from .norm import GroupNorm, GroupNorm1, LayerNorm, LayerNorm2d
31
+ from .norm_act import BatchNormAct2d, GroupNormAct, convert_sync_batchnorm
32
+ from .padding import get_padding, get_same_padding, pad_same
33
+ from .patch_embed import PatchEmbed
34
+ from .pool2d_same import AvgPool2dSame, create_pool2d
35
+ from .squeeze_excite import SEModule, SqueezeExcite, EffectiveSEModule, EffectiveSqueezeExcite
36
+ from .selective_kernel import SelectiveKernel
37
+ from .separable_conv import SeparableConv2d, SeparableConvNormAct
38
+ from .space_to_depth import SpaceToDepthModule
39
+ from .split_attn import SplitAttn
40
+ from .split_batchnorm import SplitBatchNorm2d, convert_splitbn_model
41
+ from .std_conv import StdConv2d, StdConv2dSame, ScaledStdConv2d, ScaledStdConv2dSame
42
+ from .test_time_pool import TestTimePoolHead, apply_test_time_pool
43
+ from .trace_utils import _assert, _float_to_int
44
+ from .weight_init import trunc_normal_, trunc_normal_tf_, variance_scaling_, lecun_normal_
src/custom_timm/models/layers/activations.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Activations
2
+
3
+ A collection of activations fn and modules with a common interface so that they can
4
+ easily be swapped. All have an `inplace` arg even if not used.
5
+
6
+ Hacked together by / Copyright 2020 Ross Wightman
7
+ """
8
+
9
+ import torch
10
+ from torch import nn as nn
11
+ from torch.nn import functional as F
12
+
13
+
14
+ def swish(x, inplace: bool = False):
15
+ """Swish - Described in: https://arxiv.org/abs/1710.05941
16
+ """
17
+ return x.mul_(x.sigmoid()) if inplace else x.mul(x.sigmoid())
18
+
19
+
20
+ class Swish(nn.Module):
21
+ def __init__(self, inplace: bool = False):
22
+ super(Swish, self).__init__()
23
+ self.inplace = inplace
24
+
25
+ def forward(self, x):
26
+ return swish(x, self.inplace)
27
+
28
+
29
+ def mish(x, inplace: bool = False):
30
+ """Mish: A Self Regularized Non-Monotonic Neural Activation Function - https://arxiv.org/abs/1908.08681
31
+ NOTE: I don't have a working inplace variant
32
+ """
33
+ return x.mul(F.softplus(x).tanh())
34
+
35
+
36
+ class Mish(nn.Module):
37
+ """Mish: A Self Regularized Non-Monotonic Neural Activation Function - https://arxiv.org/abs/1908.08681
38
+ """
39
+ def __init__(self, inplace: bool = False):
40
+ super(Mish, self).__init__()
41
+
42
+ def forward(self, x):
43
+ return mish(x)
44
+
45
+
46
+ def sigmoid(x, inplace: bool = False):
47
+ return x.sigmoid_() if inplace else x.sigmoid()
48
+
49
+
50
+ # PyTorch has this, but not with a consistent inplace argmument interface
51
+ class Sigmoid(nn.Module):
52
+ def __init__(self, inplace: bool = False):
53
+ super(Sigmoid, self).__init__()
54
+ self.inplace = inplace
55
+
56
+ def forward(self, x):
57
+ return x.sigmoid_() if self.inplace else x.sigmoid()
58
+
59
+
60
+ def tanh(x, inplace: bool = False):
61
+ return x.tanh_() if inplace else x.tanh()
62
+
63
+
64
+ # PyTorch has this, but not with a consistent inplace argmument interface
65
+ class Tanh(nn.Module):
66
+ def __init__(self, inplace: bool = False):
67
+ super(Tanh, self).__init__()
68
+ self.inplace = inplace
69
+
70
+ def forward(self, x):
71
+ return x.tanh_() if self.inplace else x.tanh()
72
+
73
+
74
+ def hard_swish(x, inplace: bool = False):
75
+ inner = F.relu6(x + 3.).div_(6.)
76
+ return x.mul_(inner) if inplace else x.mul(inner)
77
+
78
+
79
+ class HardSwish(nn.Module):
80
+ def __init__(self, inplace: bool = False):
81
+ super(HardSwish, self).__init__()
82
+ self.inplace = inplace
83
+
84
+ def forward(self, x):
85
+ return hard_swish(x, self.inplace)
86
+
87
+
88
+ def hard_sigmoid(x, inplace: bool = False):
89
+ if inplace:
90
+ return x.add_(3.).clamp_(0., 6.).div_(6.)
91
+ else:
92
+ return F.relu6(x + 3.) / 6.
93
+
94
+
95
+ class HardSigmoid(nn.Module):
96
+ def __init__(self, inplace: bool = False):
97
+ super(HardSigmoid, self).__init__()
98
+ self.inplace = inplace
99
+
100
+ def forward(self, x):
101
+ return hard_sigmoid(x, self.inplace)
102
+
103
+
104
+ def hard_mish(x, inplace: bool = False):
105
+ """ Hard Mish
106
+ Experimental, based on notes by Mish author Diganta Misra at
107
+ https://github.com/digantamisra98/H-Mish/blob/0da20d4bc58e696b6803f2523c58d3c8a82782d0/README.md
108
+ """
109
+ if inplace:
110
+ return x.mul_(0.5 * (x + 2).clamp(min=0, max=2))
111
+ else:
112
+ return 0.5 * x * (x + 2).clamp(min=0, max=2)
113
+
114
+
115
+ class HardMish(nn.Module):
116
+ def __init__(self, inplace: bool = False):
117
+ super(HardMish, self).__init__()
118
+ self.inplace = inplace
119
+
120
+ def forward(self, x):
121
+ return hard_mish(x, self.inplace)
122
+
123
+
124
+ class PReLU(nn.PReLU):
125
+ """Applies PReLU (w/ dummy inplace arg)
126
+ """
127
+ def __init__(self, num_parameters: int = 1, init: float = 0.25, inplace: bool = False) -> None:
128
+ super(PReLU, self).__init__(num_parameters=num_parameters, init=init)
129
+
130
+ def forward(self, input: torch.Tensor) -> torch.Tensor:
131
+ return F.prelu(input, self.weight)
132
+
133
+
134
+ def gelu(x: torch.Tensor, inplace: bool = False) -> torch.Tensor:
135
+ return F.gelu(x)
136
+
137
+
138
+ class GELU(nn.Module):
139
+ """Applies the Gaussian Error Linear Units function (w/ dummy inplace arg)
140
+ """
141
+ def __init__(self, inplace: bool = False):
142
+ super(GELU, self).__init__()
143
+
144
+ def forward(self, input: torch.Tensor) -> torch.Tensor:
145
+ return F.gelu(input)
src/custom_timm/models/layers/activations_jit.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Activations
2
+
3
+ A collection of jit-scripted activations fn and modules with a common interface so that they can
4
+ easily be swapped. All have an `inplace` arg even if not used.
5
+
6
+ All jit scripted activations are lacking in-place variations on purpose, scripted kernel fusion does not
7
+ currently work across in-place op boundaries, thus performance is equal to or less than the non-scripted
8
+ versions if they contain in-place ops.
9
+
10
+ Hacked together by / Copyright 2020 Ross Wightman
11
+ """
12
+
13
+ import torch
14
+ from torch import nn as nn
15
+ from torch.nn import functional as F
16
+
17
+
18
+ @torch.jit.script
19
+ def swish_jit(x, inplace: bool = False):
20
+ """Swish - Described in: https://arxiv.org/abs/1710.05941
21
+ """
22
+ return x.mul(x.sigmoid())
23
+
24
+
25
+ @torch.jit.script
26
+ def mish_jit(x, _inplace: bool = False):
27
+ """Mish: A Self Regularized Non-Monotonic Neural Activation Function - https://arxiv.org/abs/1908.08681
28
+ """
29
+ return x.mul(F.softplus(x).tanh())
30
+
31
+
32
+ class SwishJit(nn.Module):
33
+ def __init__(self, inplace: bool = False):
34
+ super(SwishJit, self).__init__()
35
+
36
+ def forward(self, x):
37
+ return swish_jit(x)
38
+
39
+
40
+ class MishJit(nn.Module):
41
+ def __init__(self, inplace: bool = False):
42
+ super(MishJit, self).__init__()
43
+
44
+ def forward(self, x):
45
+ return mish_jit(x)
46
+
47
+
48
+ @torch.jit.script
49
+ def hard_sigmoid_jit(x, inplace: bool = False):
50
+ # return F.relu6(x + 3.) / 6.
51
+ return (x + 3).clamp(min=0, max=6).div(6.) # clamp seems ever so slightly faster?
52
+
53
+
54
+ class HardSigmoidJit(nn.Module):
55
+ def __init__(self, inplace: bool = False):
56
+ super(HardSigmoidJit, self).__init__()
57
+
58
+ def forward(self, x):
59
+ return hard_sigmoid_jit(x)
60
+
61
+
62
+ @torch.jit.script
63
+ def hard_swish_jit(x, inplace: bool = False):
64
+ # return x * (F.relu6(x + 3.) / 6)
65
+ return x * (x + 3).clamp(min=0, max=6).div(6.) # clamp seems ever so slightly faster?
66
+
67
+
68
+ class HardSwishJit(nn.Module):
69
+ def __init__(self, inplace: bool = False):
70
+ super(HardSwishJit, self).__init__()
71
+
72
+ def forward(self, x):
73
+ return hard_swish_jit(x)
74
+
75
+
76
+ @torch.jit.script
77
+ def hard_mish_jit(x, inplace: bool = False):
78
+ """ Hard Mish
79
+ Experimental, based on notes by Mish author Diganta Misra at
80
+ https://github.com/digantamisra98/H-Mish/blob/0da20d4bc58e696b6803f2523c58d3c8a82782d0/README.md
81
+ """
82
+ return 0.5 * x * (x + 2).clamp(min=0, max=2)
83
+
84
+
85
+ class HardMishJit(nn.Module):
86
+ def __init__(self, inplace: bool = False):
87
+ super(HardMishJit, self).__init__()
88
+
89
+ def forward(self, x):
90
+ return hard_mish_jit(x)
src/custom_timm/models/layers/activations_me.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Activations (memory-efficient w/ custom autograd)
2
+
3
+ A collection of activations fn and modules with a common interface so that they can
4
+ easily be swapped. All have an `inplace` arg even if not used.
5
+
6
+ These activations are not compatible with jit scripting or ONNX export of the model, please use either
7
+ the JIT or basic versions of the activations.
8
+
9
+ Hacked together by / Copyright 2020 Ross Wightman
10
+ """
11
+
12
+ import torch
13
+ from torch import nn as nn
14
+ from torch.nn import functional as F
15
+
16
+
17
+ @torch.jit.script
18
+ def swish_jit_fwd(x):
19
+ return x.mul(torch.sigmoid(x))
20
+
21
+
22
+ @torch.jit.script
23
+ def swish_jit_bwd(x, grad_output):
24
+ x_sigmoid = torch.sigmoid(x)
25
+ return grad_output * (x_sigmoid * (1 + x * (1 - x_sigmoid)))
26
+
27
+
28
+ class SwishJitAutoFn(torch.autograd.Function):
29
+ """ torch.jit.script optimised Swish w/ memory-efficient checkpoint
30
+ Inspired by conversation btw Jeremy Howard & Adam Pazske
31
+ https://twitter.com/jeremyphoward/status/1188251041835315200
32
+ """
33
+ @staticmethod
34
+ def symbolic(g, x):
35
+ return g.op("Mul", x, g.op("Sigmoid", x))
36
+
37
+ @staticmethod
38
+ def forward(ctx, x):
39
+ ctx.save_for_backward(x)
40
+ return swish_jit_fwd(x)
41
+
42
+ @staticmethod
43
+ def backward(ctx, grad_output):
44
+ x = ctx.saved_tensors[0]
45
+ return swish_jit_bwd(x, grad_output)
46
+
47
+
48
+ def swish_me(x, inplace=False):
49
+ return SwishJitAutoFn.apply(x)
50
+
51
+
52
+ class SwishMe(nn.Module):
53
+ def __init__(self, inplace: bool = False):
54
+ super(SwishMe, self).__init__()
55
+
56
+ def forward(self, x):
57
+ return SwishJitAutoFn.apply(x)
58
+
59
+
60
+ @torch.jit.script
61
+ def mish_jit_fwd(x):
62
+ return x.mul(torch.tanh(F.softplus(x)))
63
+
64
+
65
+ @torch.jit.script
66
+ def mish_jit_bwd(x, grad_output):
67
+ x_sigmoid = torch.sigmoid(x)
68
+ x_tanh_sp = F.softplus(x).tanh()
69
+ return grad_output.mul(x_tanh_sp + x * x_sigmoid * (1 - x_tanh_sp * x_tanh_sp))
70
+
71
+
72
+ class MishJitAutoFn(torch.autograd.Function):
73
+ """ Mish: A Self Regularized Non-Monotonic Neural Activation Function - https://arxiv.org/abs/1908.08681
74
+ A memory efficient, jit scripted variant of Mish
75
+ """
76
+ @staticmethod
77
+ def forward(ctx, x):
78
+ ctx.save_for_backward(x)
79
+ return mish_jit_fwd(x)
80
+
81
+ @staticmethod
82
+ def backward(ctx, grad_output):
83
+ x = ctx.saved_tensors[0]
84
+ return mish_jit_bwd(x, grad_output)
85
+
86
+
87
+ def mish_me(x, inplace=False):
88
+ return MishJitAutoFn.apply(x)
89
+
90
+
91
+ class MishMe(nn.Module):
92
+ def __init__(self, inplace: bool = False):
93
+ super(MishMe, self).__init__()
94
+
95
+ def forward(self, x):
96
+ return MishJitAutoFn.apply(x)
97
+
98
+
99
+ @torch.jit.script
100
+ def hard_sigmoid_jit_fwd(x, inplace: bool = False):
101
+ return (x + 3).clamp(min=0, max=6).div(6.)
102
+
103
+
104
+ @torch.jit.script
105
+ def hard_sigmoid_jit_bwd(x, grad_output):
106
+ m = torch.ones_like(x) * ((x >= -3.) & (x <= 3.)) / 6.
107
+ return grad_output * m
108
+
109
+
110
+ class HardSigmoidJitAutoFn(torch.autograd.Function):
111
+ @staticmethod
112
+ def forward(ctx, x):
113
+ ctx.save_for_backward(x)
114
+ return hard_sigmoid_jit_fwd(x)
115
+
116
+ @staticmethod
117
+ def backward(ctx, grad_output):
118
+ x = ctx.saved_tensors[0]
119
+ return hard_sigmoid_jit_bwd(x, grad_output)
120
+
121
+
122
+ def hard_sigmoid_me(x, inplace: bool = False):
123
+ return HardSigmoidJitAutoFn.apply(x)
124
+
125
+
126
+ class HardSigmoidMe(nn.Module):
127
+ def __init__(self, inplace: bool = False):
128
+ super(HardSigmoidMe, self).__init__()
129
+
130
+ def forward(self, x):
131
+ return HardSigmoidJitAutoFn.apply(x)
132
+
133
+
134
+ @torch.jit.script
135
+ def hard_swish_jit_fwd(x):
136
+ return x * (x + 3).clamp(min=0, max=6).div(6.)
137
+
138
+
139
+ @torch.jit.script
140
+ def hard_swish_jit_bwd(x, grad_output):
141
+ m = torch.ones_like(x) * (x >= 3.)
142
+ m = torch.where((x >= -3.) & (x <= 3.), x / 3. + .5, m)
143
+ return grad_output * m
144
+
145
+
146
+ class HardSwishJitAutoFn(torch.autograd.Function):
147
+ """A memory efficient, jit-scripted HardSwish activation"""
148
+ @staticmethod
149
+ def forward(ctx, x):
150
+ ctx.save_for_backward(x)
151
+ return hard_swish_jit_fwd(x)
152
+
153
+ @staticmethod
154
+ def backward(ctx, grad_output):
155
+ x = ctx.saved_tensors[0]
156
+ return hard_swish_jit_bwd(x, grad_output)
157
+
158
+ @staticmethod
159
+ def symbolic(g, self):
160
+ input = g.op("Add", self, g.op('Constant', value_t=torch.tensor(3, dtype=torch.float)))
161
+ hardtanh_ = g.op("Clip", input, g.op('Constant', value_t=torch.tensor(0, dtype=torch.float)), g.op('Constant', value_t=torch.tensor(6, dtype=torch.float)))
162
+ hardtanh_ = g.op("Div", hardtanh_, g.op('Constant', value_t=torch.tensor(6, dtype=torch.float)))
163
+ return g.op("Mul", self, hardtanh_)
164
+
165
+
166
+ def hard_swish_me(x, inplace=False):
167
+ return HardSwishJitAutoFn.apply(x)
168
+
169
+
170
+ class HardSwishMe(nn.Module):
171
+ def __init__(self, inplace: bool = False):
172
+ super(HardSwishMe, self).__init__()
173
+
174
+ def forward(self, x):
175
+ return HardSwishJitAutoFn.apply(x)
176
+
177
+
178
+ @torch.jit.script
179
+ def hard_mish_jit_fwd(x):
180
+ return 0.5 * x * (x + 2).clamp(min=0, max=2)
181
+
182
+
183
+ @torch.jit.script
184
+ def hard_mish_jit_bwd(x, grad_output):
185
+ m = torch.ones_like(x) * (x >= -2.)
186
+ m = torch.where((x >= -2.) & (x <= 0.), x + 1., m)
187
+ return grad_output * m
188
+
189
+
190
+ class HardMishJitAutoFn(torch.autograd.Function):
191
+ """ A memory efficient, jit scripted variant of Hard Mish
192
+ Experimental, based on notes by Mish author Diganta Misra at
193
+ https://github.com/digantamisra98/H-Mish/blob/0da20d4bc58e696b6803f2523c58d3c8a82782d0/README.md
194
+ """
195
+ @staticmethod
196
+ def forward(ctx, x):
197
+ ctx.save_for_backward(x)
198
+ return hard_mish_jit_fwd(x)
199
+
200
+ @staticmethod
201
+ def backward(ctx, grad_output):
202
+ x = ctx.saved_tensors[0]
203
+ return hard_mish_jit_bwd(x, grad_output)
204
+
205
+
206
+ def hard_mish_me(x, inplace: bool = False):
207
+ return HardMishJitAutoFn.apply(x)
208
+
209
+
210
+ class HardMishMe(nn.Module):
211
+ def __init__(self, inplace: bool = False):
212
+ super(HardMishMe, self).__init__()
213
+
214
+ def forward(self, x):
215
+ return HardMishJitAutoFn.apply(x)
216
+
217
+
218
+
src/custom_timm/models/layers/adaptive_avgmax_pool.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ PyTorch selectable adaptive pooling
2
+ Adaptive pooling with the ability to select the type of pooling from:
3
+ * 'avg' - Average pooling
4
+ * 'max' - Max pooling
5
+ * 'avgmax' - Sum of average and max pooling re-scaled by 0.5
6
+ * 'avgmaxc' - Concatenation of average and max pooling along feature dim, doubles feature dim
7
+
8
+ Both a functional and a nn.Module version of the pooling is provided.
9
+
10
+ Hacked together by / Copyright 2020 Ross Wightman
11
+ """
12
+ import torch
13
+ import torch.nn as nn
14
+ import torch.nn.functional as F
15
+
16
+
17
+ def adaptive_pool_feat_mult(pool_type='avg'):
18
+ if pool_type == 'catavgmax':
19
+ return 2
20
+ else:
21
+ return 1
22
+
23
+
24
+ def adaptive_avgmax_pool2d(x, output_size=1):
25
+ x_avg = F.adaptive_avg_pool2d(x, output_size)
26
+ x_max = F.adaptive_max_pool2d(x, output_size)
27
+ return 0.5 * (x_avg + x_max)
28
+
29
+
30
+ def adaptive_catavgmax_pool2d(x, output_size=1):
31
+ x_avg = F.adaptive_avg_pool2d(x, output_size)
32
+ x_max = F.adaptive_max_pool2d(x, output_size)
33
+ return torch.cat((x_avg, x_max), 1)
34
+
35
+
36
+ def select_adaptive_pool2d(x, pool_type='avg', output_size=1):
37
+ """Selectable global pooling function with dynamic input kernel size
38
+ """
39
+ if pool_type == 'avg':
40
+ x = F.adaptive_avg_pool2d(x, output_size)
41
+ elif pool_type == 'avgmax':
42
+ x = adaptive_avgmax_pool2d(x, output_size)
43
+ elif pool_type == 'catavgmax':
44
+ x = adaptive_catavgmax_pool2d(x, output_size)
45
+ elif pool_type == 'max':
46
+ x = F.adaptive_max_pool2d(x, output_size)
47
+ else:
48
+ assert False, 'Invalid pool type: %s' % pool_type
49
+ return x
50
+
51
+
52
+ class FastAdaptiveAvgPool2d(nn.Module):
53
+ def __init__(self, flatten=False):
54
+ super(FastAdaptiveAvgPool2d, self).__init__()
55
+ self.flatten = flatten
56
+
57
+ def forward(self, x):
58
+ return x.mean((2, 3), keepdim=not self.flatten)
59
+
60
+
61
+ class AdaptiveAvgMaxPool2d(nn.Module):
62
+ def __init__(self, output_size=1):
63
+ super(AdaptiveAvgMaxPool2d, self).__init__()
64
+ self.output_size = output_size
65
+
66
+ def forward(self, x):
67
+ return adaptive_avgmax_pool2d(x, self.output_size)
68
+
69
+
70
+ class AdaptiveCatAvgMaxPool2d(nn.Module):
71
+ def __init__(self, output_size=1):
72
+ super(AdaptiveCatAvgMaxPool2d, self).__init__()
73
+ self.output_size = output_size
74
+
75
+ def forward(self, x):
76
+ return adaptive_catavgmax_pool2d(x, self.output_size)
77
+
78
+
79
+ class SelectAdaptivePool2d(nn.Module):
80
+ """Selectable global pooling layer with dynamic input kernel size
81
+ """
82
+ def __init__(self, output_size=1, pool_type='fast', flatten=False):
83
+ super(SelectAdaptivePool2d, self).__init__()
84
+ self.pool_type = pool_type or '' # convert other falsy values to empty string for consistent TS typing
85
+ self.flatten = nn.Flatten(1) if flatten else nn.Identity()
86
+ if pool_type == '':
87
+ self.pool = nn.Identity() # pass through
88
+ elif pool_type == 'fast':
89
+ assert output_size == 1
90
+ self.pool = FastAdaptiveAvgPool2d(flatten)
91
+ self.flatten = nn.Identity()
92
+ elif pool_type == 'avg':
93
+ self.pool = nn.AdaptiveAvgPool2d(output_size)
94
+ elif pool_type == 'avgmax':
95
+ self.pool = AdaptiveAvgMaxPool2d(output_size)
96
+ elif pool_type == 'catavgmax':
97
+ self.pool = AdaptiveCatAvgMaxPool2d(output_size)
98
+ elif pool_type == 'max':
99
+ self.pool = nn.AdaptiveMaxPool2d(output_size)
100
+ else:
101
+ assert False, 'Invalid pool type: %s' % pool_type
102
+
103
+ def is_identity(self):
104
+ return not self.pool_type
105
+
106
+ def forward(self, x):
107
+ x = self.pool(x)
108
+ x = self.flatten(x)
109
+ return x
110
+
111
+ def feat_mult(self):
112
+ return adaptive_pool_feat_mult(self.pool_type)
113
+
114
+ def __repr__(self):
115
+ return self.__class__.__name__ + ' (' \
116
+ + 'pool_type=' + self.pool_type \
117
+ + ', flatten=' + str(self.flatten) + ')'
118
+
src/custom_timm/models/layers/attention_pool2d.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Attention Pool 2D
2
+
3
+ Implementations of 2D spatial feature pooling using multi-head attention instead of average pool.
4
+
5
+ Based on idea in CLIP by OpenAI, licensed Apache 2.0
6
+ https://github.com/openai/CLIP/blob/3b473b0e682c091a9e53623eebc1ca1657385717/clip/model.py
7
+
8
+ Hacked together by / Copyright 2021 Ross Wightman
9
+ """
10
+ from typing import Union, Tuple
11
+
12
+ import torch
13
+ import torch.nn as nn
14
+
15
+ from .helpers import to_2tuple
16
+ from .pos_embed import apply_rot_embed, RotaryEmbedding
17
+ from .weight_init import trunc_normal_
18
+
19
+
20
+ class RotAttentionPool2d(nn.Module):
21
+ """ Attention based 2D feature pooling w/ rotary (relative) pos embedding.
22
+ This is a multi-head attention based replacement for (spatial) average pooling in NN architectures.
23
+
24
+ Adapted from the AttentionPool2d in CLIP w/ rotary embedding instead of learned embed.
25
+ https://github.com/openai/CLIP/blob/3b473b0e682c091a9e53623eebc1ca1657385717/clip/model.py
26
+
27
+ NOTE: While this impl does not require a fixed feature size, performance at differeing resolutions from
28
+ train varies widely and falls off dramatically. I'm not sure if there is a way around this... -RW
29
+ """
30
+ def __init__(
31
+ self,
32
+ in_features: int,
33
+ out_features: int = None,
34
+ embed_dim: int = None,
35
+ num_heads: int = 4,
36
+ qkv_bias: bool = True,
37
+ ):
38
+ super().__init__()
39
+ embed_dim = embed_dim or in_features
40
+ out_features = out_features or in_features
41
+ self.qkv = nn.Linear(in_features, embed_dim * 3, bias=qkv_bias)
42
+ self.proj = nn.Linear(embed_dim, out_features)
43
+ self.num_heads = num_heads
44
+ assert embed_dim % num_heads == 0
45
+ self.head_dim = embed_dim // num_heads
46
+ self.scale = self.head_dim ** -0.5
47
+ self.pos_embed = RotaryEmbedding(self.head_dim)
48
+
49
+ trunc_normal_(self.qkv.weight, std=in_features ** -0.5)
50
+ nn.init.zeros_(self.qkv.bias)
51
+
52
+ def forward(self, x):
53
+ B, _, H, W = x.shape
54
+ N = H * W
55
+ x = x.reshape(B, -1, N).permute(0, 2, 1)
56
+
57
+ x = torch.cat([x.mean(1, keepdim=True), x], dim=1)
58
+
59
+ x = self.qkv(x).reshape(B, N + 1, 3, self.num_heads, self.head_dim).permute(2, 0, 3, 1, 4)
60
+ q, k, v = x[0], x[1], x[2]
61
+
62
+ qc, q = q[:, :, :1], q[:, :, 1:]
63
+ sin_emb, cos_emb = self.pos_embed.get_embed((H, W))
64
+ q = apply_rot_embed(q, sin_emb, cos_emb)
65
+ q = torch.cat([qc, q], dim=2)
66
+
67
+ kc, k = k[:, :, :1], k[:, :, 1:]
68
+ k = apply_rot_embed(k, sin_emb, cos_emb)
69
+ k = torch.cat([kc, k], dim=2)
70
+
71
+ attn = (q @ k.transpose(-2, -1)) * self.scale
72
+ attn = attn.softmax(dim=-1)
73
+
74
+ x = (attn @ v).transpose(1, 2).reshape(B, N + 1, -1)
75
+ x = self.proj(x)
76
+ return x[:, 0]
77
+
78
+
79
+ class AttentionPool2d(nn.Module):
80
+ """ Attention based 2D feature pooling w/ learned (absolute) pos embedding.
81
+ This is a multi-head attention based replacement for (spatial) average pooling in NN architectures.
82
+
83
+ It was based on impl in CLIP by OpenAI
84
+ https://github.com/openai/CLIP/blob/3b473b0e682c091a9e53623eebc1ca1657385717/clip/model.py
85
+
86
+ NOTE: This requires feature size upon construction and well prevent adaptive sizing of the network.
87
+ """
88
+ def __init__(
89
+ self,
90
+ in_features: int,
91
+ feat_size: Union[int, Tuple[int, int]],
92
+ out_features: int = None,
93
+ embed_dim: int = None,
94
+ num_heads: int = 4,
95
+ qkv_bias: bool = True,
96
+ ):
97
+ super().__init__()
98
+
99
+ embed_dim = embed_dim or in_features
100
+ out_features = out_features or in_features
101
+ assert embed_dim % num_heads == 0
102
+ self.feat_size = to_2tuple(feat_size)
103
+ self.qkv = nn.Linear(in_features, embed_dim * 3, bias=qkv_bias)
104
+ self.proj = nn.Linear(embed_dim, out_features)
105
+ self.num_heads = num_heads
106
+ self.head_dim = embed_dim // num_heads
107
+ self.scale = self.head_dim ** -0.5
108
+
109
+ spatial_dim = self.feat_size[0] * self.feat_size[1]
110
+ self.pos_embed = nn.Parameter(torch.zeros(spatial_dim + 1, in_features))
111
+ trunc_normal_(self.pos_embed, std=in_features ** -0.5)
112
+ trunc_normal_(self.qkv.weight, std=in_features ** -0.5)
113
+ nn.init.zeros_(self.qkv.bias)
114
+
115
+ def forward(self, x):
116
+ B, _, H, W = x.shape
117
+ N = H * W
118
+ assert self.feat_size[0] == H
119
+ assert self.feat_size[1] == W
120
+ x = x.reshape(B, -1, N).permute(0, 2, 1)
121
+ x = torch.cat([x.mean(1, keepdim=True), x], dim=1)
122
+ x = x + self.pos_embed.unsqueeze(0).to(x.dtype)
123
+
124
+ x = self.qkv(x).reshape(B, N + 1, 3, self.num_heads, self.head_dim).permute(2, 0, 3, 1, 4)
125
+ q, k, v = x[0], x[1], x[2]
126
+ attn = (q @ k.transpose(-2, -1)) * self.scale
127
+ attn = attn.softmax(dim=-1)
128
+
129
+ x = (attn @ v).transpose(1, 2).reshape(B, N + 1, -1)
130
+ x = self.proj(x)
131
+ return x[:, 0]
src/custom_timm/models/layers/blur_pool.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ BlurPool layer inspired by
3
+ - Kornia's Max_BlurPool2d
4
+ - Making Convolutional Networks Shift-Invariant Again :cite:`zhang2019shiftinvar`
5
+
6
+ Hacked together by Chris Ha and Ross Wightman
7
+ """
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ import numpy as np
13
+ from .padding import get_padding
14
+
15
+
16
+ class BlurPool2d(nn.Module):
17
+ r"""Creates a module that computes blurs and downsample a given feature map.
18
+ See :cite:`zhang2019shiftinvar` for more details.
19
+ Corresponds to the Downsample class, which does blurring and subsampling
20
+
21
+ Args:
22
+ channels = Number of input channels
23
+ filt_size (int): binomial filter size for blurring. currently supports 3 (default) and 5.
24
+ stride (int): downsampling filter stride
25
+
26
+ Returns:
27
+ torch.Tensor: the transformed tensor.
28
+ """
29
+ def __init__(self, channels, filt_size=3, stride=2) -> None:
30
+ super(BlurPool2d, self).__init__()
31
+ assert filt_size > 1
32
+ self.channels = channels
33
+ self.filt_size = filt_size
34
+ self.stride = stride
35
+ self.padding = [get_padding(filt_size, stride, dilation=1)] * 4
36
+ coeffs = torch.tensor((np.poly1d((0.5, 0.5)) ** (self.filt_size - 1)).coeffs.astype(np.float32))
37
+ blur_filter = (coeffs[:, None] * coeffs[None, :])[None, None, :, :].repeat(self.channels, 1, 1, 1)
38
+ self.register_buffer('filt', blur_filter, persistent=False)
39
+
40
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
41
+ x = F.pad(x, self.padding, 'reflect')
42
+ return F.conv2d(x, self.filt, stride=self.stride, groups=self.channels)
src/custom_timm/models/layers/bottleneck_attn.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Bottleneck Self Attention (Bottleneck Transformers)
2
+
3
+ Paper: `Bottleneck Transformers for Visual Recognition` - https://arxiv.org/abs/2101.11605
4
+
5
+ @misc{2101.11605,
6
+ Author = {Aravind Srinivas and Tsung-Yi Lin and Niki Parmar and Jonathon Shlens and Pieter Abbeel and Ashish Vaswani},
7
+ Title = {Bottleneck Transformers for Visual Recognition},
8
+ Year = {2021},
9
+ }
10
+
11
+ Based on ref gist at: https://gist.github.com/aravindsrinivas/56359b79f0ce4449bcb04ab4b56a57a2
12
+
13
+ This impl is a WIP but given that it is based on the ref gist likely not too far off.
14
+
15
+ Hacked together by / Copyright 2021 Ross Wightman
16
+ """
17
+ from typing import List
18
+
19
+ import torch
20
+ import torch.nn as nn
21
+ import torch.nn.functional as F
22
+
23
+ from .helpers import to_2tuple, make_divisible
24
+ from .weight_init import trunc_normal_
25
+ from .trace_utils import _assert
26
+
27
+
28
+ def rel_logits_1d(q, rel_k, permute_mask: List[int]):
29
+ """ Compute relative logits along one dimension
30
+
31
+ As per: https://gist.github.com/aravindsrinivas/56359b79f0ce4449bcb04ab4b56a57a2
32
+ Originally from: `Attention Augmented Convolutional Networks` - https://arxiv.org/abs/1904.09925
33
+
34
+ Args:
35
+ q: (batch, heads, height, width, dim)
36
+ rel_k: (2 * width - 1, dim)
37
+ permute_mask: permute output dim according to this
38
+ """
39
+ B, H, W, dim = q.shape
40
+ x = (q @ rel_k.transpose(-1, -2))
41
+ x = x.reshape(-1, W, 2 * W -1)
42
+
43
+ # pad to shift from relative to absolute indexing
44
+ x_pad = F.pad(x, [0, 1]).flatten(1)
45
+ x_pad = F.pad(x_pad, [0, W - 1])
46
+
47
+ # reshape and slice out the padded elements
48
+ x_pad = x_pad.reshape(-1, W + 1, 2 * W - 1)
49
+ x = x_pad[:, :W, W - 1:]
50
+
51
+ # reshape and tile
52
+ x = x.reshape(B, H, 1, W, W).expand(-1, -1, H, -1, -1)
53
+ return x.permute(permute_mask)
54
+
55
+
56
+ class PosEmbedRel(nn.Module):
57
+ """ Relative Position Embedding
58
+ As per: https://gist.github.com/aravindsrinivas/56359b79f0ce4449bcb04ab4b56a57a2
59
+ Originally from: `Attention Augmented Convolutional Networks` - https://arxiv.org/abs/1904.09925
60
+ """
61
+ def __init__(self, feat_size, dim_head, scale):
62
+ super().__init__()
63
+ self.height, self.width = to_2tuple(feat_size)
64
+ self.dim_head = dim_head
65
+ self.height_rel = nn.Parameter(torch.randn(self.height * 2 - 1, dim_head) * scale)
66
+ self.width_rel = nn.Parameter(torch.randn(self.width * 2 - 1, dim_head) * scale)
67
+
68
+ def forward(self, q):
69
+ B, HW, _ = q.shape
70
+
71
+ # relative logits in width dimension.
72
+ q = q.reshape(B, self.height, self.width, -1)
73
+ rel_logits_w = rel_logits_1d(q, self.width_rel, permute_mask=(0, 1, 3, 2, 4))
74
+
75
+ # relative logits in height dimension.
76
+ q = q.transpose(1, 2)
77
+ rel_logits_h = rel_logits_1d(q, self.height_rel, permute_mask=(0, 3, 1, 4, 2))
78
+
79
+ rel_logits = rel_logits_h + rel_logits_w
80
+ rel_logits = rel_logits.reshape(B, HW, HW)
81
+ return rel_logits
82
+
83
+
84
+ class BottleneckAttn(nn.Module):
85
+ """ Bottleneck Attention
86
+ Paper: `Bottleneck Transformers for Visual Recognition` - https://arxiv.org/abs/2101.11605
87
+
88
+ The internal dimensions of the attention module are controlled by the interaction of several arguments.
89
+ * the output dimension of the module is specified by dim_out, which falls back to input dim if not set
90
+ * the value (v) dimension is set to dim_out // num_heads, the v projection determines the output dim
91
+ * the query and key (qk) dimensions are determined by
92
+ * num_heads * dim_head if dim_head is not None
93
+ * num_heads * (dim_out * attn_ratio // num_heads) if dim_head is None
94
+ * as seen above, attn_ratio determines the ratio of q and k relative to the output if dim_head not used
95
+
96
+ Args:
97
+ dim (int): input dimension to the module
98
+ dim_out (int): output dimension of the module, same as dim if not set
99
+ stride (int): output stride of the module, avg pool used if stride == 2 (default: 1).
100
+ num_heads (int): parallel attention heads (default: 4)
101
+ dim_head (int): dimension of query and key heads, calculated from dim_out * attn_ratio // num_heads if not set
102
+ qk_ratio (float): ratio of q and k dimensions to output dimension when dim_head not set. (default: 1.0)
103
+ qkv_bias (bool): add bias to q, k, and v projections
104
+ scale_pos_embed (bool): scale the position embedding as well as Q @ K
105
+ """
106
+ def __init__(
107
+ self, dim, dim_out=None, feat_size=None, stride=1, num_heads=4, dim_head=None,
108
+ qk_ratio=1.0, qkv_bias=False, scale_pos_embed=False):
109
+ super().__init__()
110
+ assert feat_size is not None, 'A concrete feature size matching expected input (H, W) is required'
111
+ dim_out = dim_out or dim
112
+ assert dim_out % num_heads == 0
113
+ self.num_heads = num_heads
114
+ self.dim_head_qk = dim_head or make_divisible(dim_out * qk_ratio, divisor=8) // num_heads
115
+ self.dim_head_v = dim_out // self.num_heads
116
+ self.dim_out_qk = num_heads * self.dim_head_qk
117
+ self.dim_out_v = num_heads * self.dim_head_v
118
+ self.scale = self.dim_head_qk ** -0.5
119
+ self.scale_pos_embed = scale_pos_embed
120
+
121
+ self.qkv = nn.Conv2d(dim, self.dim_out_qk * 2 + self.dim_out_v, 1, bias=qkv_bias)
122
+
123
+ # NOTE I'm only supporting relative pos embedding for now
124
+ self.pos_embed = PosEmbedRel(feat_size, dim_head=self.dim_head_qk, scale=self.scale)
125
+
126
+ self.pool = nn.AvgPool2d(2, 2) if stride == 2 else nn.Identity()
127
+
128
+ self.reset_parameters()
129
+
130
+ def reset_parameters(self):
131
+ trunc_normal_(self.qkv.weight, std=self.qkv.weight.shape[1] ** -0.5) # fan-in
132
+ trunc_normal_(self.pos_embed.height_rel, std=self.scale)
133
+ trunc_normal_(self.pos_embed.width_rel, std=self.scale)
134
+
135
+ def forward(self, x):
136
+ B, C, H, W = x.shape
137
+ _assert(H == self.pos_embed.height, '')
138
+ _assert(W == self.pos_embed.width, '')
139
+
140
+ x = self.qkv(x) # B, (2 * dim_head_qk + dim_head_v) * num_heads, H, W
141
+
142
+ # NOTE head vs channel split ordering in qkv projection was decided before I allowed qk to differ from v
143
+ # So, this is more verbose than if heads were before qkv splits, but throughput is not impacted.
144
+ q, k, v = torch.split(x, [self.dim_out_qk, self.dim_out_qk, self.dim_out_v], dim=1)
145
+ q = q.reshape(B * self.num_heads, self.dim_head_qk, -1).transpose(-1, -2)
146
+ k = k.reshape(B * self.num_heads, self.dim_head_qk, -1) # no transpose, for q @ k
147
+ v = v.reshape(B * self.num_heads, self.dim_head_v, -1).transpose(-1, -2)
148
+
149
+ if self.scale_pos_embed:
150
+ attn = (q @ k + self.pos_embed(q)) * self.scale # B * num_heads, H * W, H * W
151
+ else:
152
+ attn = (q @ k) * self.scale + self.pos_embed(q)
153
+ attn = attn.softmax(dim=-1)
154
+
155
+ out = (attn @ v).transpose(-1, -2).reshape(B, self.dim_out_v, H, W) # B, dim_out, H, W
156
+ out = self.pool(out)
157
+ return out
src/custom_timm/models/layers/cbam.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ CBAM (sort-of) Attention
2
+
3
+ Experimental impl of CBAM: Convolutional Block Attention Module: https://arxiv.org/abs/1807.06521
4
+
5
+ WARNING: Results with these attention layers have been mixed. They can significantly reduce performance on
6
+ some tasks, especially fine-grained it seems. I may end up removing this impl.
7
+
8
+ Hacked together by / Copyright 2020 Ross Wightman
9
+ """
10
+ import torch
11
+ from torch import nn as nn
12
+ import torch.nn.functional as F
13
+
14
+ from .conv_bn_act import ConvNormAct
15
+ from .create_act import create_act_layer, get_act_layer
16
+ from .helpers import make_divisible
17
+
18
+
19
+ class ChannelAttn(nn.Module):
20
+ """ Original CBAM channel attention module, currently avg + max pool variant only.
21
+ """
22
+ def __init__(
23
+ self, channels, rd_ratio=1./16, rd_channels=None, rd_divisor=1,
24
+ act_layer=nn.ReLU, gate_layer='sigmoid', mlp_bias=False):
25
+ super(ChannelAttn, self).__init__()
26
+ if not rd_channels:
27
+ rd_channels = make_divisible(channels * rd_ratio, rd_divisor, round_limit=0.)
28
+ self.fc1 = nn.Conv2d(channels, rd_channels, 1, bias=mlp_bias)
29
+ self.act = act_layer(inplace=True)
30
+ self.fc2 = nn.Conv2d(rd_channels, channels, 1, bias=mlp_bias)
31
+ self.gate = create_act_layer(gate_layer)
32
+
33
+ def forward(self, x):
34
+ x_avg = self.fc2(self.act(self.fc1(x.mean((2, 3), keepdim=True))))
35
+ x_max = self.fc2(self.act(self.fc1(x.amax((2, 3), keepdim=True))))
36
+ return x * self.gate(x_avg + x_max)
37
+
38
+
39
+ class LightChannelAttn(ChannelAttn):
40
+ """An experimental 'lightweight' that sums avg + max pool first
41
+ """
42
+ def __init__(
43
+ self, channels, rd_ratio=1./16, rd_channels=None, rd_divisor=1,
44
+ act_layer=nn.ReLU, gate_layer='sigmoid', mlp_bias=False):
45
+ super(LightChannelAttn, self).__init__(
46
+ channels, rd_ratio, rd_channels, rd_divisor, act_layer, gate_layer, mlp_bias)
47
+
48
+ def forward(self, x):
49
+ x_pool = 0.5 * x.mean((2, 3), keepdim=True) + 0.5 * x.amax((2, 3), keepdim=True)
50
+ x_attn = self.fc2(self.act(self.fc1(x_pool)))
51
+ return x * F.sigmoid(x_attn)
52
+
53
+
54
+ class SpatialAttn(nn.Module):
55
+ """ Original CBAM spatial attention module
56
+ """
57
+ def __init__(self, kernel_size=7, gate_layer='sigmoid'):
58
+ super(SpatialAttn, self).__init__()
59
+ self.conv = ConvNormAct(2, 1, kernel_size, apply_act=False)
60
+ self.gate = create_act_layer(gate_layer)
61
+
62
+ def forward(self, x):
63
+ x_attn = torch.cat([x.mean(dim=1, keepdim=True), x.amax(dim=1, keepdim=True)], dim=1)
64
+ x_attn = self.conv(x_attn)
65
+ return x * self.gate(x_attn)
66
+
67
+
68
+ class LightSpatialAttn(nn.Module):
69
+ """An experimental 'lightweight' variant that sums avg_pool and max_pool results.
70
+ """
71
+ def __init__(self, kernel_size=7, gate_layer='sigmoid'):
72
+ super(LightSpatialAttn, self).__init__()
73
+ self.conv = ConvNormAct(1, 1, kernel_size, apply_act=False)
74
+ self.gate = create_act_layer(gate_layer)
75
+
76
+ def forward(self, x):
77
+ x_attn = 0.5 * x.mean(dim=1, keepdim=True) + 0.5 * x.amax(dim=1, keepdim=True)
78
+ x_attn = self.conv(x_attn)
79
+ return x * self.gate(x_attn)
80
+
81
+
82
+ class CbamModule(nn.Module):
83
+ def __init__(
84
+ self, channels, rd_ratio=1./16, rd_channels=None, rd_divisor=1,
85
+ spatial_kernel_size=7, act_layer=nn.ReLU, gate_layer='sigmoid', mlp_bias=False):
86
+ super(CbamModule, self).__init__()
87
+ self.channel = ChannelAttn(
88
+ channels, rd_ratio=rd_ratio, rd_channels=rd_channels,
89
+ rd_divisor=rd_divisor, act_layer=act_layer, gate_layer=gate_layer, mlp_bias=mlp_bias)
90
+ self.spatial = SpatialAttn(spatial_kernel_size, gate_layer=gate_layer)
91
+
92
+ def forward(self, x):
93
+ x = self.channel(x)
94
+ x = self.spatial(x)
95
+ return x
96
+
97
+
98
+ class LightCbamModule(nn.Module):
99
+ def __init__(
100
+ self, channels, rd_ratio=1./16, rd_channels=None, rd_divisor=1,
101
+ spatial_kernel_size=7, act_layer=nn.ReLU, gate_layer='sigmoid', mlp_bias=False):
102
+ super(LightCbamModule, self).__init__()
103
+ self.channel = LightChannelAttn(
104
+ channels, rd_ratio=rd_ratio, rd_channels=rd_channels,
105
+ rd_divisor=rd_divisor, act_layer=act_layer, gate_layer=gate_layer, mlp_bias=mlp_bias)
106
+ self.spatial = LightSpatialAttn(spatial_kernel_size)
107
+
108
+ def forward(self, x):
109
+ x = self.channel(x)
110
+ x = self.spatial(x)
111
+ return x
112
+
src/custom_timm/models/layers/classifier.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Classifier head and layer factory
2
+
3
+ Hacked together by / Copyright 2020 Ross Wightman
4
+ """
5
+ from torch import nn as nn
6
+ from torch.nn import functional as F
7
+
8
+ from .adaptive_avgmax_pool import SelectAdaptivePool2d
9
+
10
+
11
+ def _create_pool(num_features, num_classes, pool_type='avg', use_conv=False):
12
+ flatten_in_pool = not use_conv # flatten when we use a Linear layer after pooling
13
+ if not pool_type:
14
+ assert num_classes == 0 or use_conv,\
15
+ 'Pooling can only be disabled if classifier is also removed or conv classifier is used'
16
+ flatten_in_pool = False # disable flattening if pooling is pass-through (no pooling)
17
+ global_pool = SelectAdaptivePool2d(pool_type=pool_type, flatten=flatten_in_pool)
18
+ num_pooled_features = num_features * global_pool.feat_mult()
19
+ return global_pool, num_pooled_features
20
+
21
+
22
+ def _create_fc(num_features, num_classes, use_conv=False):
23
+ if num_classes <= 0:
24
+ fc = nn.Identity() # pass-through (no classifier)
25
+ elif use_conv:
26
+ fc = nn.Conv2d(num_features, num_classes, 1, bias=True)
27
+ else:
28
+ fc = nn.Linear(num_features, num_classes, bias=True)
29
+ return fc
30
+
31
+
32
+ def create_classifier(num_features, num_classes, pool_type='avg', use_conv=False):
33
+ global_pool, num_pooled_features = _create_pool(num_features, num_classes, pool_type, use_conv=use_conv)
34
+ fc = _create_fc(num_pooled_features, num_classes, use_conv=use_conv)
35
+ return global_pool, fc
36
+
37
+
38
+ class ClassifierHead(nn.Module):
39
+ """Classifier head w/ configurable global pooling and dropout."""
40
+
41
+ def __init__(self, in_chs, num_classes, pool_type='avg', drop_rate=0., use_conv=False):
42
+ super(ClassifierHead, self).__init__()
43
+ self.drop_rate = drop_rate
44
+ self.global_pool, num_pooled_features = _create_pool(in_chs, num_classes, pool_type, use_conv=use_conv)
45
+ self.fc = _create_fc(num_pooled_features, num_classes, use_conv=use_conv)
46
+ self.flatten = nn.Flatten(1) if use_conv and pool_type else nn.Identity()
47
+
48
+ def forward(self, x, pre_logits: bool = False):
49
+ x = self.global_pool(x)
50
+ if self.drop_rate:
51
+ x = F.dropout(x, p=float(self.drop_rate), training=self.training)
52
+ if pre_logits:
53
+ return x.flatten(1)
54
+ else:
55
+ x = self.fc(x)
56
+ return self.flatten(x)
src/custom_timm/models/layers/cond_conv2d.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ PyTorch Conditionally Parameterized Convolution (CondConv)
2
+
3
+ Paper: CondConv: Conditionally Parameterized Convolutions for Efficient Inference
4
+ (https://arxiv.org/abs/1904.04971)
5
+
6
+ Hacked together by / Copyright 2020 Ross Wightman
7
+ """
8
+
9
+ import math
10
+ from functools import partial
11
+ import numpy as np
12
+ import torch
13
+ from torch import nn as nn
14
+ from torch.nn import functional as F
15
+
16
+ from .helpers import to_2tuple
17
+ from .conv2d_same import conv2d_same
18
+ from .padding import get_padding_value
19
+
20
+
21
+ def get_condconv_initializer(initializer, num_experts, expert_shape):
22
+ def condconv_initializer(weight):
23
+ """CondConv initializer function."""
24
+ num_params = np.prod(expert_shape)
25
+ if (len(weight.shape) != 2 or weight.shape[0] != num_experts or
26
+ weight.shape[1] != num_params):
27
+ raise (ValueError(
28
+ 'CondConv variables must have shape [num_experts, num_params]'))
29
+ for i in range(num_experts):
30
+ initializer(weight[i].view(expert_shape))
31
+ return condconv_initializer
32
+
33
+
34
+ class CondConv2d(nn.Module):
35
+ """ Conditionally Parameterized Convolution
36
+ Inspired by: https://github.com/tensorflow/tpu/blob/master/models/official/efficientnet/condconv/condconv_layers.py
37
+
38
+ Grouped convolution hackery for parallel execution of the per-sample kernel filters inspired by this discussion:
39
+ https://github.com/pytorch/pytorch/issues/17983
40
+ """
41
+ __constants__ = ['in_channels', 'out_channels', 'dynamic_padding']
42
+
43
+ def __init__(self, in_channels, out_channels, kernel_size=3,
44
+ stride=1, padding='', dilation=1, groups=1, bias=False, num_experts=4):
45
+ super(CondConv2d, self).__init__()
46
+
47
+ self.in_channels = in_channels
48
+ self.out_channels = out_channels
49
+ self.kernel_size = to_2tuple(kernel_size)
50
+ self.stride = to_2tuple(stride)
51
+ padding_val, is_padding_dynamic = get_padding_value(
52
+ padding, kernel_size, stride=stride, dilation=dilation)
53
+ self.dynamic_padding = is_padding_dynamic # if in forward to work with torchscript
54
+ self.padding = to_2tuple(padding_val)
55
+ self.dilation = to_2tuple(dilation)
56
+ self.groups = groups
57
+ self.num_experts = num_experts
58
+
59
+ self.weight_shape = (self.out_channels, self.in_channels // self.groups) + self.kernel_size
60
+ weight_num_param = 1
61
+ for wd in self.weight_shape:
62
+ weight_num_param *= wd
63
+ self.weight = torch.nn.Parameter(torch.Tensor(self.num_experts, weight_num_param))
64
+
65
+ if bias:
66
+ self.bias_shape = (self.out_channels,)
67
+ self.bias = torch.nn.Parameter(torch.Tensor(self.num_experts, self.out_channels))
68
+ else:
69
+ self.register_parameter('bias', None)
70
+
71
+ self.reset_parameters()
72
+
73
+ def reset_parameters(self):
74
+ init_weight = get_condconv_initializer(
75
+ partial(nn.init.kaiming_uniform_, a=math.sqrt(5)), self.num_experts, self.weight_shape)
76
+ init_weight(self.weight)
77
+ if self.bias is not None:
78
+ fan_in = np.prod(self.weight_shape[1:])
79
+ bound = 1 / math.sqrt(fan_in)
80
+ init_bias = get_condconv_initializer(
81
+ partial(nn.init.uniform_, a=-bound, b=bound), self.num_experts, self.bias_shape)
82
+ init_bias(self.bias)
83
+
84
+ def forward(self, x, routing_weights):
85
+ B, C, H, W = x.shape
86
+ weight = torch.matmul(routing_weights, self.weight)
87
+ new_weight_shape = (B * self.out_channels, self.in_channels // self.groups) + self.kernel_size
88
+ weight = weight.view(new_weight_shape)
89
+ bias = None
90
+ if self.bias is not None:
91
+ bias = torch.matmul(routing_weights, self.bias)
92
+ bias = bias.view(B * self.out_channels)
93
+ # move batch elements with channels so each batch element can be efficiently convolved with separate kernel
94
+ # reshape instead of view to work with channels_last input
95
+ x = x.reshape(1, B * C, H, W)
96
+ if self.dynamic_padding:
97
+ out = conv2d_same(
98
+ x, weight, bias, stride=self.stride, padding=self.padding,
99
+ dilation=self.dilation, groups=self.groups * B)
100
+ else:
101
+ out = F.conv2d(
102
+ x, weight, bias, stride=self.stride, padding=self.padding,
103
+ dilation=self.dilation, groups=self.groups * B)
104
+ out = out.permute([1, 0, 2, 3]).view(B, self.out_channels, out.shape[-2], out.shape[-1])
105
+
106
+ # Literal port (from TF definition)
107
+ # x = torch.split(x, 1, 0)
108
+ # weight = torch.split(weight, 1, 0)
109
+ # if self.bias is not None:
110
+ # bias = torch.matmul(routing_weights, self.bias)
111
+ # bias = torch.split(bias, 1, 0)
112
+ # else:
113
+ # bias = [None] * B
114
+ # out = []
115
+ # for xi, wi, bi in zip(x, weight, bias):
116
+ # wi = wi.view(*self.weight_shape)
117
+ # if bi is not None:
118
+ # bi = bi.view(*self.bias_shape)
119
+ # out.append(self.conv_fn(
120
+ # xi, wi, bi, stride=self.stride, padding=self.padding,
121
+ # dilation=self.dilation, groups=self.groups))
122
+ # out = torch.cat(out, 0)
123
+ return out
src/custom_timm/models/layers/config.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Model / Layer Config singleton state
2
+ """
3
+ from typing import Any, Optional
4
+
5
+ __all__ = [
6
+ 'is_exportable', 'is_scriptable', 'is_no_jit',
7
+ 'set_exportable', 'set_scriptable', 'set_no_jit', 'set_layer_config'
8
+ ]
9
+
10
+ # Set to True if prefer to have layers with no jit optimization (includes activations)
11
+ _NO_JIT = False
12
+
13
+ # Set to True if prefer to have activation layers with no jit optimization
14
+ # NOTE not currently used as no difference between no_jit and no_activation jit as only layers obeying
15
+ # the jit flags so far are activations. This will change as more layers are updated and/or added.
16
+ _NO_ACTIVATION_JIT = False
17
+
18
+ # Set to True if exporting a model with Same padding via ONNX
19
+ _EXPORTABLE = False
20
+
21
+ # Set to True if wanting to use torch.jit.script on a model
22
+ _SCRIPTABLE = False
23
+
24
+
25
+ def is_no_jit():
26
+ return _NO_JIT
27
+
28
+
29
+ class set_no_jit:
30
+ def __init__(self, mode: bool) -> None:
31
+ global _NO_JIT
32
+ self.prev = _NO_JIT
33
+ _NO_JIT = mode
34
+
35
+ def __enter__(self) -> None:
36
+ pass
37
+
38
+ def __exit__(self, *args: Any) -> bool:
39
+ global _NO_JIT
40
+ _NO_JIT = self.prev
41
+ return False
42
+
43
+
44
+ def is_exportable():
45
+ return _EXPORTABLE
46
+
47
+
48
+ class set_exportable:
49
+ def __init__(self, mode: bool) -> None:
50
+ global _EXPORTABLE
51
+ self.prev = _EXPORTABLE
52
+ _EXPORTABLE = mode
53
+
54
+ def __enter__(self) -> None:
55
+ pass
56
+
57
+ def __exit__(self, *args: Any) -> bool:
58
+ global _EXPORTABLE
59
+ _EXPORTABLE = self.prev
60
+ return False
61
+
62
+
63
+ def is_scriptable():
64
+ return _SCRIPTABLE
65
+
66
+
67
+ class set_scriptable:
68
+ def __init__(self, mode: bool) -> None:
69
+ global _SCRIPTABLE
70
+ self.prev = _SCRIPTABLE
71
+ _SCRIPTABLE = mode
72
+
73
+ def __enter__(self) -> None:
74
+ pass
75
+
76
+ def __exit__(self, *args: Any) -> bool:
77
+ global _SCRIPTABLE
78
+ _SCRIPTABLE = self.prev
79
+ return False
80
+
81
+
82
+ class set_layer_config:
83
+ """ Layer config context manager that allows setting all layer config flags at once.
84
+ If a flag arg is None, it will not change the current value.
85
+ """
86
+ def __init__(
87
+ self,
88
+ scriptable: Optional[bool] = None,
89
+ exportable: Optional[bool] = None,
90
+ no_jit: Optional[bool] = None,
91
+ no_activation_jit: Optional[bool] = None):
92
+ global _SCRIPTABLE
93
+ global _EXPORTABLE
94
+ global _NO_JIT
95
+ global _NO_ACTIVATION_JIT
96
+ self.prev = _SCRIPTABLE, _EXPORTABLE, _NO_JIT, _NO_ACTIVATION_JIT
97
+ if scriptable is not None:
98
+ _SCRIPTABLE = scriptable
99
+ if exportable is not None:
100
+ _EXPORTABLE = exportable
101
+ if no_jit is not None:
102
+ _NO_JIT = no_jit
103
+ if no_activation_jit is not None:
104
+ _NO_ACTIVATION_JIT = no_activation_jit
105
+
106
+ def __enter__(self) -> None:
107
+ pass
108
+
109
+ def __exit__(self, *args: Any) -> bool:
110
+ global _SCRIPTABLE
111
+ global _EXPORTABLE
112
+ global _NO_JIT
113
+ global _NO_ACTIVATION_JIT
114
+ _SCRIPTABLE, _EXPORTABLE, _NO_JIT, _NO_ACTIVATION_JIT = self.prev
115
+ return False
src/custom_timm/models/layers/conv2d_same.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Conv2d w/ Same Padding
2
+
3
+ Hacked together by / Copyright 2020 Ross Wightman
4
+ """
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from typing import Tuple, Optional
9
+
10
+ from .padding import pad_same, get_padding_value
11
+
12
+
13
+ def conv2d_same(
14
+ x, weight: torch.Tensor, bias: Optional[torch.Tensor] = None, stride: Tuple[int, int] = (1, 1),
15
+ padding: Tuple[int, int] = (0, 0), dilation: Tuple[int, int] = (1, 1), groups: int = 1):
16
+ x = pad_same(x, weight.shape[-2:], stride, dilation)
17
+ return F.conv2d(x, weight, bias, stride, (0, 0), dilation, groups)
18
+
19
+
20
+ class Conv2dSame(nn.Conv2d):
21
+ """ Tensorflow like 'SAME' convolution wrapper for 2D convolutions
22
+ """
23
+
24
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1,
25
+ padding=0, dilation=1, groups=1, bias=True):
26
+ super(Conv2dSame, self).__init__(
27
+ in_channels, out_channels, kernel_size, stride, 0, dilation, groups, bias)
28
+
29
+ def forward(self, x):
30
+ return conv2d_same(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)
31
+
32
+
33
+ def create_conv2d_pad(in_chs, out_chs, kernel_size, **kwargs):
34
+ padding = kwargs.pop('padding', '')
35
+ kwargs.setdefault('bias', False)
36
+ padding, is_dynamic = get_padding_value(padding, kernel_size, **kwargs)
37
+ if is_dynamic:
38
+ return Conv2dSame(in_chs, out_chs, kernel_size, **kwargs)
39
+ else:
40
+ return nn.Conv2d(in_chs, out_chs, kernel_size, padding=padding, **kwargs)
41
+
42
+
src/custom_timm/models/layers/conv_bn_act.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Conv2d + BN + Act
2
+
3
+ Hacked together by / Copyright 2020 Ross Wightman
4
+ """
5
+ import functools
6
+ from torch import nn as nn
7
+
8
+ from .create_conv2d import create_conv2d
9
+ from .create_norm_act import get_norm_act_layer
10
+
11
+
12
+ class ConvNormAct(nn.Module):
13
+ def __init__(
14
+ self, in_channels, out_channels, kernel_size=1, stride=1, padding='', dilation=1, groups=1,
15
+ bias=False, apply_act=True, norm_layer=nn.BatchNorm2d, act_layer=nn.ReLU, drop_layer=None):
16
+ super(ConvNormAct, self).__init__()
17
+ self.conv = create_conv2d(
18
+ in_channels, out_channels, kernel_size, stride=stride,
19
+ padding=padding, dilation=dilation, groups=groups, bias=bias)
20
+
21
+ # NOTE for backwards compatibility with models that use separate norm and act layer definitions
22
+ norm_act_layer = get_norm_act_layer(norm_layer, act_layer)
23
+ # NOTE for backwards (weight) compatibility, norm layer name remains `.bn`
24
+ norm_kwargs = dict(drop_layer=drop_layer) if drop_layer is not None else {}
25
+ self.bn = norm_act_layer(out_channels, apply_act=apply_act, **norm_kwargs)
26
+
27
+ @property
28
+ def in_channels(self):
29
+ return self.conv.in_channels
30
+
31
+ @property
32
+ def out_channels(self):
33
+ return self.conv.out_channels
34
+
35
+ def forward(self, x):
36
+ x = self.conv(x)
37
+ x = self.bn(x)
38
+ return x
39
+
40
+
41
+ ConvBnAct = ConvNormAct
42
+
43
+
44
+ def create_aa(aa_layer, channels, stride=2, enable=True):
45
+ if not aa_layer or not enable:
46
+ return nn.Identity()
47
+ if isinstance(aa_layer, functools.partial):
48
+ if issubclass(aa_layer.func, nn.AvgPool2d):
49
+ return aa_layer()
50
+ else:
51
+ return aa_layer(channels)
52
+ elif issubclass(aa_layer, nn.AvgPool2d):
53
+ return aa_layer(stride)
54
+ else:
55
+ return aa_layer(channels=channels, stride=stride)
56
+
57
+
58
+ class ConvNormActAa(nn.Module):
59
+ def __init__(
60
+ self, in_channels, out_channels, kernel_size=1, stride=1, padding='', dilation=1, groups=1,
61
+ bias=False, apply_act=True, norm_layer=nn.BatchNorm2d, act_layer=nn.ReLU, aa_layer=None, drop_layer=None):
62
+ super(ConvNormActAa, self).__init__()
63
+ use_aa = aa_layer is not None and stride == 2
64
+
65
+ self.conv = create_conv2d(
66
+ in_channels, out_channels, kernel_size, stride=1 if use_aa else stride,
67
+ padding=padding, dilation=dilation, groups=groups, bias=bias)
68
+
69
+ # NOTE for backwards compatibility with models that use separate norm and act layer definitions
70
+ norm_act_layer = get_norm_act_layer(norm_layer, act_layer)
71
+ # NOTE for backwards (weight) compatibility, norm layer name remains `.bn`
72
+ norm_kwargs = dict(drop_layer=drop_layer) if drop_layer is not None else {}
73
+ self.bn = norm_act_layer(out_channels, apply_act=apply_act, **norm_kwargs)
74
+ self.aa = create_aa(aa_layer, out_channels, stride=stride, enable=use_aa)
75
+
76
+ @property
77
+ def in_channels(self):
78
+ return self.conv.in_channels
79
+
80
+ @property
81
+ def out_channels(self):
82
+ return self.conv.out_channels
83
+
84
+ def forward(self, x):
85
+ x = self.conv(x)
86
+ x = self.bn(x)
87
+ x = self.aa(x)
88
+ return x
src/custom_timm/models/layers/create_act.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Activation Factory
2
+ Hacked together by / Copyright 2020 Ross Wightman
3
+ """
4
+ from typing import Union, Callable, Type
5
+
6
+ from .activations import *
7
+ from .activations_jit import *
8
+ from .activations_me import *
9
+ from .config import is_exportable, is_scriptable, is_no_jit
10
+
11
+ # PyTorch has an optimized, native 'silu' (aka 'swish') operator as of PyTorch 1.7.
12
+ # Also hardsigmoid, hardswish, and soon mish. This code will use native version if present.
13
+ # Eventually, the custom SiLU, Mish, Hard*, layers will be removed and only native variants will be used.
14
+ _has_silu = 'silu' in dir(torch.nn.functional)
15
+ _has_hardswish = 'hardswish' in dir(torch.nn.functional)
16
+ _has_hardsigmoid = 'hardsigmoid' in dir(torch.nn.functional)
17
+ _has_mish = 'mish' in dir(torch.nn.functional)
18
+
19
+
20
+ _ACT_FN_DEFAULT = dict(
21
+ silu=F.silu if _has_silu else swish,
22
+ swish=F.silu if _has_silu else swish,
23
+ mish=F.mish if _has_mish else mish,
24
+ relu=F.relu,
25
+ relu6=F.relu6,
26
+ leaky_relu=F.leaky_relu,
27
+ elu=F.elu,
28
+ celu=F.celu,
29
+ selu=F.selu,
30
+ gelu=gelu,
31
+ sigmoid=sigmoid,
32
+ tanh=tanh,
33
+ hard_sigmoid=F.hardsigmoid if _has_hardsigmoid else hard_sigmoid,
34
+ hard_swish=F.hardswish if _has_hardswish else hard_swish,
35
+ hard_mish=hard_mish,
36
+ )
37
+
38
+ _ACT_FN_JIT = dict(
39
+ silu=F.silu if _has_silu else swish_jit,
40
+ swish=F.silu if _has_silu else swish_jit,
41
+ mish=F.mish if _has_mish else mish_jit,
42
+ hard_sigmoid=F.hardsigmoid if _has_hardsigmoid else hard_sigmoid_jit,
43
+ hard_swish=F.hardswish if _has_hardswish else hard_swish_jit,
44
+ hard_mish=hard_mish_jit
45
+ )
46
+
47
+ _ACT_FN_ME = dict(
48
+ silu=F.silu if _has_silu else swish_me,
49
+ swish=F.silu if _has_silu else swish_me,
50
+ mish=F.mish if _has_mish else mish_me,
51
+ hard_sigmoid=F.hardsigmoid if _has_hardsigmoid else hard_sigmoid_me,
52
+ hard_swish=F.hardswish if _has_hardswish else hard_swish_me,
53
+ hard_mish=hard_mish_me,
54
+ )
55
+
56
+ _ACT_FNS = (_ACT_FN_ME, _ACT_FN_JIT, _ACT_FN_DEFAULT)
57
+ for a in _ACT_FNS:
58
+ a.setdefault('hardsigmoid', a.get('hard_sigmoid'))
59
+ a.setdefault('hardswish', a.get('hard_swish'))
60
+
61
+
62
+ _ACT_LAYER_DEFAULT = dict(
63
+ silu=nn.SiLU if _has_silu else Swish,
64
+ swish=nn.SiLU if _has_silu else Swish,
65
+ mish=nn.Mish if _has_mish else Mish,
66
+ relu=nn.ReLU,
67
+ relu6=nn.ReLU6,
68
+ leaky_relu=nn.LeakyReLU,
69
+ elu=nn.ELU,
70
+ prelu=PReLU,
71
+ celu=nn.CELU,
72
+ selu=nn.SELU,
73
+ gelu=GELU,
74
+ sigmoid=Sigmoid,
75
+ tanh=Tanh,
76
+ hard_sigmoid=nn.Hardsigmoid if _has_hardsigmoid else HardSigmoid,
77
+ hard_swish=nn.Hardswish if _has_hardswish else HardSwish,
78
+ hard_mish=HardMish,
79
+ )
80
+
81
+ _ACT_LAYER_JIT = dict(
82
+ silu=nn.SiLU if _has_silu else SwishJit,
83
+ swish=nn.SiLU if _has_silu else SwishJit,
84
+ mish=nn.Mish if _has_mish else MishJit,
85
+ hard_sigmoid=nn.Hardsigmoid if _has_hardsigmoid else HardSigmoidJit,
86
+ hard_swish=nn.Hardswish if _has_hardswish else HardSwishJit,
87
+ hard_mish=HardMishJit
88
+ )
89
+
90
+ _ACT_LAYER_ME = dict(
91
+ silu=nn.SiLU if _has_silu else SwishMe,
92
+ swish=nn.SiLU if _has_silu else SwishMe,
93
+ mish=nn.Mish if _has_mish else MishMe,
94
+ hard_sigmoid=nn.Hardsigmoid if _has_hardsigmoid else HardSigmoidMe,
95
+ hard_swish=nn.Hardswish if _has_hardswish else HardSwishMe,
96
+ hard_mish=HardMishMe,
97
+ )
98
+
99
+ _ACT_LAYERS = (_ACT_LAYER_ME, _ACT_LAYER_JIT, _ACT_LAYER_DEFAULT)
100
+ for a in _ACT_LAYERS:
101
+ a.setdefault('hardsigmoid', a.get('hard_sigmoid'))
102
+ a.setdefault('hardswish', a.get('hard_swish'))
103
+
104
+
105
+ def get_act_fn(name: Union[Callable, str] = 'relu'):
106
+ """ Activation Function Factory
107
+ Fetching activation fns by name with this function allows export or torch script friendly
108
+ functions to be returned dynamically based on current config.
109
+ """
110
+ if not name:
111
+ return None
112
+ if isinstance(name, Callable):
113
+ return name
114
+ if not (is_no_jit() or is_exportable() or is_scriptable()):
115
+ # If not exporting or scripting the model, first look for a memory-efficient version with
116
+ # custom autograd, then fallback
117
+ if name in _ACT_FN_ME:
118
+ return _ACT_FN_ME[name]
119
+ if not (is_no_jit() or is_exportable()):
120
+ if name in _ACT_FN_JIT:
121
+ return _ACT_FN_JIT[name]
122
+ return _ACT_FN_DEFAULT[name]
123
+
124
+
125
+ def get_act_layer(name: Union[Type[nn.Module], str] = 'relu'):
126
+ """ Activation Layer Factory
127
+ Fetching activation layers by name with this function allows export or torch script friendly
128
+ functions to be returned dynamically based on current config.
129
+ """
130
+ if not name:
131
+ return None
132
+ if not isinstance(name, str):
133
+ # callable, module, etc
134
+ return name
135
+ if not (is_no_jit() or is_exportable() or is_scriptable()):
136
+ if name in _ACT_LAYER_ME:
137
+ return _ACT_LAYER_ME[name]
138
+ if not (is_no_jit() or is_exportable()):
139
+ if name in _ACT_LAYER_JIT:
140
+ return _ACT_LAYER_JIT[name]
141
+ return _ACT_LAYER_DEFAULT[name]
142
+
143
+
144
+ def create_act_layer(name: Union[nn.Module, str], inplace=None, **kwargs):
145
+ act_layer = get_act_layer(name)
146
+ if act_layer is None:
147
+ return None
148
+ if inplace is None:
149
+ return act_layer(**kwargs)
150
+ try:
151
+ return act_layer(inplace=inplace, **kwargs)
152
+ except TypeError:
153
+ # recover if act layer doesn't have inplace arg
154
+ return act_layer(**kwargs)
src/custom_timm/models/layers/create_attn.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Attention Factory
2
+
3
+ Hacked together by / Copyright 2021 Ross Wightman
4
+ """
5
+ import torch
6
+ from functools import partial
7
+
8
+ from .bottleneck_attn import BottleneckAttn
9
+ from .cbam import CbamModule, LightCbamModule
10
+ from .eca import EcaModule, CecaModule
11
+ from .gather_excite import GatherExcite
12
+ from .global_context import GlobalContext
13
+ from .halo_attn import HaloAttn
14
+ from .lambda_layer import LambdaLayer
15
+ from .non_local_attn import NonLocalAttn, BatNonLocalAttn
16
+ from .selective_kernel import SelectiveKernel
17
+ from .split_attn import SplitAttn
18
+ from .squeeze_excite import SEModule, EffectiveSEModule
19
+
20
+
21
+ def get_attn(attn_type):
22
+ if isinstance(attn_type, torch.nn.Module):
23
+ return attn_type
24
+ module_cls = None
25
+ if attn_type:
26
+ if isinstance(attn_type, str):
27
+ attn_type = attn_type.lower()
28
+ # Lightweight attention modules (channel and/or coarse spatial).
29
+ # Typically added to existing network architecture blocks in addition to existing convolutions.
30
+ if attn_type == 'se':
31
+ module_cls = SEModule
32
+ elif attn_type == 'ese':
33
+ module_cls = EffectiveSEModule
34
+ elif attn_type == 'eca':
35
+ module_cls = EcaModule
36
+ elif attn_type == 'ecam':
37
+ module_cls = partial(EcaModule, use_mlp=True)
38
+ elif attn_type == 'ceca':
39
+ module_cls = CecaModule
40
+ elif attn_type == 'ge':
41
+ module_cls = GatherExcite
42
+ elif attn_type == 'gc':
43
+ module_cls = GlobalContext
44
+ elif attn_type == 'gca':
45
+ module_cls = partial(GlobalContext, fuse_add=True, fuse_scale=False)
46
+ elif attn_type == 'cbam':
47
+ module_cls = CbamModule
48
+ elif attn_type == 'lcbam':
49
+ module_cls = LightCbamModule
50
+
51
+ # Attention / attention-like modules w/ significant params
52
+ # Typically replace some of the existing workhorse convs in a network architecture.
53
+ # All of these accept a stride argument and can spatially downsample the input.
54
+ elif attn_type == 'sk':
55
+ module_cls = SelectiveKernel
56
+ elif attn_type == 'splat':
57
+ module_cls = SplitAttn
58
+
59
+ # Self-attention / attention-like modules w/ significant compute and/or params
60
+ # Typically replace some of the existing workhorse convs in a network architecture.
61
+ # All of these accept a stride argument and can spatially downsample the input.
62
+ elif attn_type == 'lambda':
63
+ return LambdaLayer
64
+ elif attn_type == 'bottleneck':
65
+ return BottleneckAttn
66
+ elif attn_type == 'halo':
67
+ return HaloAttn
68
+ elif attn_type == 'nl':
69
+ module_cls = NonLocalAttn
70
+ elif attn_type == 'bat':
71
+ module_cls = BatNonLocalAttn
72
+
73
+ # Woops!
74
+ else:
75
+ assert False, "Invalid attn module (%s)" % attn_type
76
+ elif isinstance(attn_type, bool):
77
+ if attn_type:
78
+ module_cls = SEModule
79
+ else:
80
+ module_cls = attn_type
81
+ return module_cls
82
+
83
+
84
+ def create_attn(attn_type, channels, **kwargs):
85
+ module_cls = get_attn(attn_type)
86
+ if module_cls is not None:
87
+ # NOTE: it's expected the first (positional) argument of all attention layers is the # input channels
88
+ return module_cls(channels, **kwargs)
89
+ return None
src/custom_timm/models/layers/create_conv2d.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Create Conv2d Factory Method
2
+
3
+ Hacked together by / Copyright 2020 Ross Wightman
4
+ """
5
+
6
+ from .mixed_conv2d import MixedConv2d
7
+ from .cond_conv2d import CondConv2d
8
+ from .conv2d_same import create_conv2d_pad
9
+
10
+
11
+ def create_conv2d(in_channels, out_channels, kernel_size, **kwargs):
12
+ """ Select a 2d convolution implementation based on arguments
13
+ Creates and returns one of torch.nn.Conv2d, Conv2dSame, MixedConv2d, or CondConv2d.
14
+
15
+ Used extensively by EfficientNet, MobileNetv3 and related networks.
16
+ """
17
+ if isinstance(kernel_size, list):
18
+ assert 'num_experts' not in kwargs # MixNet + CondConv combo not supported currently
19
+ if 'groups' in kwargs:
20
+ groups = kwargs.pop('groups')
21
+ if groups == in_channels:
22
+ kwargs['depthwise'] = True
23
+ else:
24
+ assert groups == 1
25
+ # We're going to use only lists for defining the MixedConv2d kernel groups,
26
+ # ints, tuples, other iterables will continue to pass to normal conv and specify h, w.
27
+ m = MixedConv2d(in_channels, out_channels, kernel_size, **kwargs)
28
+ else:
29
+ depthwise = kwargs.pop('depthwise', False)
30
+ # for DW out_channels must be multiple of in_channels as must have out_channels % groups == 0
31
+ groups = in_channels if depthwise else kwargs.pop('groups', 1)
32
+ if 'num_experts' in kwargs and kwargs['num_experts'] > 0:
33
+ m = CondConv2d(in_channels, out_channels, kernel_size, groups=groups, **kwargs)
34
+ else:
35
+ m = create_conv2d_pad(in_channels, out_channels, kernel_size, groups=groups, **kwargs)
36
+ return m
src/custom_timm/models/layers/create_norm.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Norm Layer Factory
2
+
3
+ Create norm modules by string (to mirror create_act and creat_norm-act fns)
4
+
5
+ Copyright 2022 Ross Wightman
6
+ """
7
+ import types
8
+ import functools
9
+
10
+ import torch.nn as nn
11
+
12
+ from .norm import GroupNorm, GroupNorm1, LayerNorm, LayerNorm2d
13
+
14
+ _NORM_MAP = dict(
15
+ batchnorm=nn.BatchNorm2d,
16
+ batchnorm2d=nn.BatchNorm2d,
17
+ batchnorm1d=nn.BatchNorm1d,
18
+ groupnorm=GroupNorm,
19
+ groupnorm1=GroupNorm1,
20
+ layernorm=LayerNorm,
21
+ layernorm2d=LayerNorm2d,
22
+ )
23
+ _NORM_TYPES = {m for n, m in _NORM_MAP.items()}
24
+
25
+
26
+ def create_norm_layer(layer_name, num_features, act_layer=None, apply_act=True, **kwargs):
27
+ layer = get_norm_layer(layer_name, act_layer=act_layer)
28
+ layer_instance = layer(num_features, apply_act=apply_act, **kwargs)
29
+ return layer_instance
30
+
31
+
32
+ def get_norm_layer(norm_layer):
33
+ assert isinstance(norm_layer, (type, str, types.FunctionType, functools.partial))
34
+ norm_kwargs = {}
35
+
36
+ # unbind partial fn, so args can be rebound later
37
+ if isinstance(norm_layer, functools.partial):
38
+ norm_kwargs.update(norm_layer.keywords)
39
+ norm_layer = norm_layer.func
40
+
41
+ if isinstance(norm_layer, str):
42
+ layer_name = norm_layer.replace('_', '')
43
+ norm_layer = _NORM_MAP.get(layer_name, None)
44
+ elif norm_layer in _NORM_TYPES:
45
+ norm_layer = norm_layer
46
+ elif isinstance(norm_layer, types.FunctionType):
47
+ # if function type, assume it is a lambda/fn that creates a norm layer
48
+ norm_layer = norm_layer
49
+ else:
50
+ type_name = norm_layer.__name__.lower().replace('_', '')
51
+ norm_layer = _NORM_MAP.get(type_name, None)
52
+ assert norm_layer is not None, f"No equivalent norm layer for {type_name}"
53
+
54
+ if norm_kwargs:
55
+ norm_layer = functools.partial(norm_layer, **norm_kwargs) # bind/rebind args
56
+ return norm_layer
src/custom_timm/models/layers/create_norm_act.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ NormAct (Normalizaiton + Activation Layer) Factory
2
+
3
+ Create norm + act combo modules that attempt to be backwards compatible with separate norm + act
4
+ isntances in models. Where these are used it will be possible to swap separate BN + act layers with
5
+ combined modules like IABN or EvoNorms.
6
+
7
+ Hacked together by / Copyright 2020 Ross Wightman
8
+ """
9
+ import types
10
+ import functools
11
+
12
+ from .evo_norm import *
13
+ from .filter_response_norm import FilterResponseNormAct2d, FilterResponseNormTlu2d
14
+ from .norm_act import BatchNormAct2d, GroupNormAct, LayerNormAct, LayerNormAct2d
15
+ from .inplace_abn import InplaceAbn
16
+
17
+ _NORM_ACT_MAP = dict(
18
+ batchnorm=BatchNormAct2d,
19
+ batchnorm2d=BatchNormAct2d,
20
+ groupnorm=GroupNormAct,
21
+ groupnorm1=functools.partial(GroupNormAct, num_groups=1),
22
+ layernorm=LayerNormAct,
23
+ layernorm2d=LayerNormAct2d,
24
+ evonormb0=EvoNorm2dB0,
25
+ evonormb1=EvoNorm2dB1,
26
+ evonormb2=EvoNorm2dB2,
27
+ evonorms0=EvoNorm2dS0,
28
+ evonorms0a=EvoNorm2dS0a,
29
+ evonorms1=EvoNorm2dS1,
30
+ evonorms1a=EvoNorm2dS1a,
31
+ evonorms2=EvoNorm2dS2,
32
+ evonorms2a=EvoNorm2dS2a,
33
+ frn=FilterResponseNormAct2d,
34
+ frntlu=FilterResponseNormTlu2d,
35
+ inplaceabn=InplaceAbn,
36
+ iabn=InplaceAbn,
37
+ )
38
+ _NORM_ACT_TYPES = {m for n, m in _NORM_ACT_MAP.items()}
39
+ # has act_layer arg to define act type
40
+ _NORM_ACT_REQUIRES_ARG = {
41
+ BatchNormAct2d, GroupNormAct, LayerNormAct, LayerNormAct2d, FilterResponseNormAct2d, InplaceAbn}
42
+
43
+
44
+ def create_norm_act_layer(layer_name, num_features, act_layer=None, apply_act=True, jit=False, **kwargs):
45
+ layer = get_norm_act_layer(layer_name, act_layer=act_layer)
46
+ layer_instance = layer(num_features, apply_act=apply_act, **kwargs)
47
+ if jit:
48
+ layer_instance = torch.jit.script(layer_instance)
49
+ return layer_instance
50
+
51
+
52
+ def get_norm_act_layer(norm_layer, act_layer=None):
53
+ assert isinstance(norm_layer, (type, str, types.FunctionType, functools.partial))
54
+ assert act_layer is None or isinstance(act_layer, (type, str, types.FunctionType, functools.partial))
55
+ norm_act_kwargs = {}
56
+
57
+ # unbind partial fn, so args can be rebound later
58
+ if isinstance(norm_layer, functools.partial):
59
+ norm_act_kwargs.update(norm_layer.keywords)
60
+ norm_layer = norm_layer.func
61
+
62
+ if isinstance(norm_layer, str):
63
+ layer_name = norm_layer.replace('_', '').lower().split('-')[0]
64
+ norm_act_layer = _NORM_ACT_MAP.get(layer_name, None)
65
+ elif norm_layer in _NORM_ACT_TYPES:
66
+ norm_act_layer = norm_layer
67
+ elif isinstance(norm_layer, types.FunctionType):
68
+ # if function type, must be a lambda/fn that creates a norm_act layer
69
+ norm_act_layer = norm_layer
70
+ else:
71
+ type_name = norm_layer.__name__.lower()
72
+ if type_name.startswith('batchnorm'):
73
+ norm_act_layer = BatchNormAct2d
74
+ elif type_name.startswith('groupnorm'):
75
+ norm_act_layer = GroupNormAct
76
+ elif type_name.startswith('groupnorm1'):
77
+ norm_act_layer = functools.partial(GroupNormAct, num_groups=1)
78
+ elif type_name.startswith('layernorm2d'):
79
+ norm_act_layer = LayerNormAct2d
80
+ elif type_name.startswith('layernorm'):
81
+ norm_act_layer = LayerNormAct
82
+ else:
83
+ assert False, f"No equivalent norm_act layer for {type_name}"
84
+
85
+ if norm_act_layer in _NORM_ACT_REQUIRES_ARG:
86
+ # pass `act_layer` through for backwards compat where `act_layer=None` implies no activation.
87
+ # In the future, may force use of `apply_act` with `act_layer` arg bound to relevant NormAct types
88
+ norm_act_kwargs.setdefault('act_layer', act_layer)
89
+ if norm_act_kwargs:
90
+ norm_act_layer = functools.partial(norm_act_layer, **norm_act_kwargs) # bind/rebind args
91
+ return norm_act_layer
src/custom_timm/models/layers/drop.py ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ DropBlock, DropPath
2
+
3
+ PyTorch implementations of DropBlock and DropPath (Stochastic Depth) regularization layers.
4
+
5
+ Papers:
6
+ DropBlock: A regularization method for convolutional networks (https://arxiv.org/abs/1810.12890)
7
+
8
+ Deep Networks with Stochastic Depth (https://arxiv.org/abs/1603.09382)
9
+
10
+ Code:
11
+ DropBlock impl inspired by two Tensorflow impl that I liked:
12
+ - https://github.com/tensorflow/tpu/blob/master/models/official/resnet/resnet_model.py#L74
13
+ - https://github.com/clovaai/assembled-cnn/blob/master/nets/blocks.py
14
+
15
+ Hacked together by / Copyright 2020 Ross Wightman
16
+ """
17
+ import torch
18
+ import torch.nn as nn
19
+ import torch.nn.functional as F
20
+
21
+
22
+ def drop_block_2d(
23
+ x, drop_prob: float = 0.1, block_size: int = 7, gamma_scale: float = 1.0,
24
+ with_noise: bool = False, inplace: bool = False, batchwise: bool = False):
25
+ """ DropBlock. See https://arxiv.org/pdf/1810.12890.pdf
26
+
27
+ DropBlock with an experimental gaussian noise option. This layer has been tested on a few training
28
+ runs with success, but needs further validation and possibly optimization for lower runtime impact.
29
+ """
30
+ B, C, H, W = x.shape
31
+ total_size = W * H
32
+ clipped_block_size = min(block_size, min(W, H))
33
+ # seed_drop_rate, the gamma parameter
34
+ gamma = gamma_scale * drop_prob * total_size / clipped_block_size ** 2 / (
35
+ (W - block_size + 1) * (H - block_size + 1))
36
+
37
+ # Forces the block to be inside the feature map.
38
+ w_i, h_i = torch.meshgrid(torch.arange(W).to(x.device), torch.arange(H).to(x.device))
39
+ valid_block = ((w_i >= clipped_block_size // 2) & (w_i < W - (clipped_block_size - 1) // 2)) & \
40
+ ((h_i >= clipped_block_size // 2) & (h_i < H - (clipped_block_size - 1) // 2))
41
+ valid_block = torch.reshape(valid_block, (1, 1, H, W)).to(dtype=x.dtype)
42
+
43
+ if batchwise:
44
+ # one mask for whole batch, quite a bit faster
45
+ uniform_noise = torch.rand((1, C, H, W), dtype=x.dtype, device=x.device)
46
+ else:
47
+ uniform_noise = torch.rand_like(x)
48
+ block_mask = ((2 - gamma - valid_block + uniform_noise) >= 1).to(dtype=x.dtype)
49
+ block_mask = -F.max_pool2d(
50
+ -block_mask,
51
+ kernel_size=clipped_block_size, # block_size,
52
+ stride=1,
53
+ padding=clipped_block_size // 2)
54
+
55
+ if with_noise:
56
+ normal_noise = torch.randn((1, C, H, W), dtype=x.dtype, device=x.device) if batchwise else torch.randn_like(x)
57
+ if inplace:
58
+ x.mul_(block_mask).add_(normal_noise * (1 - block_mask))
59
+ else:
60
+ x = x * block_mask + normal_noise * (1 - block_mask)
61
+ else:
62
+ normalize_scale = (block_mask.numel() / block_mask.to(dtype=torch.float32).sum().add(1e-7)).to(x.dtype)
63
+ if inplace:
64
+ x.mul_(block_mask * normalize_scale)
65
+ else:
66
+ x = x * block_mask * normalize_scale
67
+ return x
68
+
69
+
70
+ def drop_block_fast_2d(
71
+ x: torch.Tensor, drop_prob: float = 0.1, block_size: int = 7,
72
+ gamma_scale: float = 1.0, with_noise: bool = False, inplace: bool = False):
73
+ """ DropBlock. See https://arxiv.org/pdf/1810.12890.pdf
74
+
75
+ DropBlock with an experimental gaussian noise option. Simplied from above without concern for valid
76
+ block mask at edges.
77
+ """
78
+ B, C, H, W = x.shape
79
+ total_size = W * H
80
+ clipped_block_size = min(block_size, min(W, H))
81
+ gamma = gamma_scale * drop_prob * total_size / clipped_block_size ** 2 / (
82
+ (W - block_size + 1) * (H - block_size + 1))
83
+
84
+ block_mask = torch.empty_like(x).bernoulli_(gamma)
85
+ block_mask = F.max_pool2d(
86
+ block_mask.to(x.dtype), kernel_size=clipped_block_size, stride=1, padding=clipped_block_size // 2)
87
+
88
+ if with_noise:
89
+ normal_noise = torch.empty_like(x).normal_()
90
+ if inplace:
91
+ x.mul_(1. - block_mask).add_(normal_noise * block_mask)
92
+ else:
93
+ x = x * (1. - block_mask) + normal_noise * block_mask
94
+ else:
95
+ block_mask = 1 - block_mask
96
+ normalize_scale = (block_mask.numel() / block_mask.to(dtype=torch.float32).sum().add(1e-6)).to(dtype=x.dtype)
97
+ if inplace:
98
+ x.mul_(block_mask * normalize_scale)
99
+ else:
100
+ x = x * block_mask * normalize_scale
101
+ return x
102
+
103
+
104
+ class DropBlock2d(nn.Module):
105
+ """ DropBlock. See https://arxiv.org/pdf/1810.12890.pdf
106
+ """
107
+
108
+ def __init__(
109
+ self,
110
+ drop_prob: float = 0.1,
111
+ block_size: int = 7,
112
+ gamma_scale: float = 1.0,
113
+ with_noise: bool = False,
114
+ inplace: bool = False,
115
+ batchwise: bool = False,
116
+ fast: bool = True):
117
+ super(DropBlock2d, self).__init__()
118
+ self.drop_prob = drop_prob
119
+ self.gamma_scale = gamma_scale
120
+ self.block_size = block_size
121
+ self.with_noise = with_noise
122
+ self.inplace = inplace
123
+ self.batchwise = batchwise
124
+ self.fast = fast # FIXME finish comparisons of fast vs not
125
+
126
+ def forward(self, x):
127
+ if not self.training or not self.drop_prob:
128
+ return x
129
+ if self.fast:
130
+ return drop_block_fast_2d(
131
+ x, self.drop_prob, self.block_size, self.gamma_scale, self.with_noise, self.inplace)
132
+ else:
133
+ return drop_block_2d(
134
+ x, self.drop_prob, self.block_size, self.gamma_scale, self.with_noise, self.inplace, self.batchwise)
135
+
136
+
137
+ def drop_path(x, drop_prob: float = 0., training: bool = False, scale_by_keep: bool = True):
138
+ """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
139
+
140
+ This is the same as the DropConnect impl I created for EfficientNet, etc networks, however,
141
+ the original name is misleading as 'Drop Connect' is a different form of dropout in a separate paper...
142
+ See discussion: https://github.com/tensorflow/tpu/issues/494#issuecomment-532968956 ... I've opted for
143
+ changing the layer and argument names to 'drop path' rather than mix DropConnect as a layer name and use
144
+ 'survival rate' as the argument.
145
+
146
+ """
147
+ if drop_prob == 0. or not training:
148
+ return x
149
+ keep_prob = 1 - drop_prob
150
+ shape = (x.shape[0],) + (1,) * (x.ndim - 1) # work with diff dim tensors, not just 2D ConvNets
151
+ random_tensor = x.new_empty(shape).bernoulli_(keep_prob)
152
+ if keep_prob > 0.0 and scale_by_keep:
153
+ random_tensor.div_(keep_prob)
154
+ return x * random_tensor
155
+
156
+
157
+ class DropPath(nn.Module):
158
+ """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
159
+ """
160
+ def __init__(self, drop_prob: float = 0., scale_by_keep: bool = True):
161
+ super(DropPath, self).__init__()
162
+ self.drop_prob = drop_prob
163
+ self.scale_by_keep = scale_by_keep
164
+
165
+ def forward(self, x):
166
+ return drop_path(x, self.drop_prob, self.training, self.scale_by_keep)
167
+
168
+ def extra_repr(self):
169
+ return f'drop_prob={round(self.drop_prob,3):0.3f}'
src/custom_timm/models/layers/eca.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ECA module from ECAnet
3
+
4
+ paper: ECA-Net: Efficient Channel Attention for Deep Convolutional Neural Networks
5
+ https://arxiv.org/abs/1910.03151
6
+
7
+ Original ECA model borrowed from https://github.com/BangguWu/ECANet
8
+
9
+ Modified circular ECA implementation and adaption for use in timm package
10
+ by Chris Ha https://github.com/VRandme
11
+
12
+ Original License:
13
+
14
+ MIT License
15
+
16
+ Copyright (c) 2019 BangguWu, Qilong Wang
17
+
18
+ Permission is hereby granted, free of charge, to any person obtaining a copy
19
+ of this software and associated documentation files (the "Software"), to deal
20
+ in the Software without restriction, including without limitation the rights
21
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22
+ copies of the Software, and to permit persons to whom the Software is
23
+ furnished to do so, subject to the following conditions:
24
+
25
+ The above copyright notice and this permission notice shall be included in all
26
+ copies or substantial portions of the Software.
27
+
28
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34
+ SOFTWARE.
35
+ """
36
+ import math
37
+ from torch import nn
38
+ import torch.nn.functional as F
39
+
40
+
41
+ from .create_act import create_act_layer
42
+ from .helpers import make_divisible
43
+
44
+
45
+ class EcaModule(nn.Module):
46
+ """Constructs an ECA module.
47
+
48
+ Args:
49
+ channels: Number of channels of the input feature map for use in adaptive kernel sizes
50
+ for actual calculations according to channel.
51
+ gamma, beta: when channel is given parameters of mapping function
52
+ refer to original paper https://arxiv.org/pdf/1910.03151.pdf
53
+ (default=None. if channel size not given, use k_size given for kernel size.)
54
+ kernel_size: Adaptive selection of kernel size (default=3)
55
+ gamm: used in kernel_size calc, see above
56
+ beta: used in kernel_size calc, see above
57
+ act_layer: optional non-linearity after conv, enables conv bias, this is an experiment
58
+ gate_layer: gating non-linearity to use
59
+ """
60
+ def __init__(
61
+ self, channels=None, kernel_size=3, gamma=2, beta=1, act_layer=None, gate_layer='sigmoid',
62
+ rd_ratio=1/8, rd_channels=None, rd_divisor=8, use_mlp=False):
63
+ super(EcaModule, self).__init__()
64
+ if channels is not None:
65
+ t = int(abs(math.log(channels, 2) + beta) / gamma)
66
+ kernel_size = max(t if t % 2 else t + 1, 3)
67
+ assert kernel_size % 2 == 1
68
+ padding = (kernel_size - 1) // 2
69
+ if use_mlp:
70
+ # NOTE 'mlp' mode is a timm experiment, not in paper
71
+ assert channels is not None
72
+ if rd_channels is None:
73
+ rd_channels = make_divisible(channels * rd_ratio, divisor=rd_divisor)
74
+ act_layer = act_layer or nn.ReLU
75
+ self.conv = nn.Conv1d(1, rd_channels, kernel_size=1, padding=0, bias=True)
76
+ self.act = create_act_layer(act_layer)
77
+ self.conv2 = nn.Conv1d(rd_channels, 1, kernel_size=kernel_size, padding=padding, bias=True)
78
+ else:
79
+ self.conv = nn.Conv1d(1, 1, kernel_size=kernel_size, padding=padding, bias=False)
80
+ self.act = None
81
+ self.conv2 = None
82
+ self.gate = create_act_layer(gate_layer)
83
+
84
+ def forward(self, x):
85
+ y = x.mean((2, 3)).view(x.shape[0], 1, -1) # view for 1d conv
86
+ y = self.conv(y)
87
+ if self.conv2 is not None:
88
+ y = self.act(y)
89
+ y = self.conv2(y)
90
+ y = self.gate(y).view(x.shape[0], -1, 1, 1)
91
+ return x * y.expand_as(x)
92
+
93
+
94
+ EfficientChannelAttn = EcaModule # alias
95
+
96
+
97
+ class CecaModule(nn.Module):
98
+ """Constructs a circular ECA module.
99
+
100
+ ECA module where the conv uses circular padding rather than zero padding.
101
+ Unlike the spatial dimension, the channels do not have inherent ordering nor
102
+ locality. Although this module in essence, applies such an assumption, it is unnecessary
103
+ to limit the channels on either "edge" from being circularly adapted to each other.
104
+ This will fundamentally increase connectivity and possibly increase performance metrics
105
+ (accuracy, robustness), without significantly impacting resource metrics
106
+ (parameter size, throughput,latency, etc)
107
+
108
+ Args:
109
+ channels: Number of channels of the input feature map for use in adaptive kernel sizes
110
+ for actual calculations according to channel.
111
+ gamma, beta: when channel is given parameters of mapping function
112
+ refer to original paper https://arxiv.org/pdf/1910.03151.pdf
113
+ (default=None. if channel size not given, use k_size given for kernel size.)
114
+ kernel_size: Adaptive selection of kernel size (default=3)
115
+ gamm: used in kernel_size calc, see above
116
+ beta: used in kernel_size calc, see above
117
+ act_layer: optional non-linearity after conv, enables conv bias, this is an experiment
118
+ gate_layer: gating non-linearity to use
119
+ """
120
+
121
+ def __init__(self, channels=None, kernel_size=3, gamma=2, beta=1, act_layer=None, gate_layer='sigmoid'):
122
+ super(CecaModule, self).__init__()
123
+ if channels is not None:
124
+ t = int(abs(math.log(channels, 2) + beta) / gamma)
125
+ kernel_size = max(t if t % 2 else t + 1, 3)
126
+ has_act = act_layer is not None
127
+ assert kernel_size % 2 == 1
128
+
129
+ # PyTorch circular padding mode is buggy as of pytorch 1.4
130
+ # see https://github.com/pytorch/pytorch/pull/17240
131
+ # implement manual circular padding
132
+ self.padding = (kernel_size - 1) // 2
133
+ self.conv = nn.Conv1d(1, 1, kernel_size=kernel_size, padding=0, bias=has_act)
134
+ self.gate = create_act_layer(gate_layer)
135
+
136
+ def forward(self, x):
137
+ y = x.mean((2, 3)).view(x.shape[0], 1, -1)
138
+ # Manually implement circular padding, F.pad does not seemed to be bugged
139
+ y = F.pad(y, (self.padding, self.padding), mode='circular')
140
+ y = self.conv(y)
141
+ y = self.gate(y).view(x.shape[0], -1, 1, 1)
142
+ return x * y.expand_as(x)
143
+
144
+
145
+ CircularEfficientChannelAttn = CecaModule
src/custom_timm/models/layers/evo_norm.py ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ EvoNorm in PyTorch
2
+
3
+ Based on `Evolving Normalization-Activation Layers` - https://arxiv.org/abs/2004.02967
4
+ @inproceedings{NEURIPS2020,
5
+ author = {Liu, Hanxiao and Brock, Andy and Simonyan, Karen and Le, Quoc},
6
+ booktitle = {Advances in Neural Information Processing Systems},
7
+ editor = {H. Larochelle and M. Ranzato and R. Hadsell and M. F. Balcan and H. Lin},
8
+ pages = {13539--13550},
9
+ publisher = {Curran Associates, Inc.},
10
+ title = {Evolving Normalization-Activation Layers},
11
+ url = {https://proceedings.neurips.cc/paper/2020/file/9d4c03631b8b0c85ae08bf05eda37d0f-Paper.pdf},
12
+ volume = {33},
13
+ year = {2020}
14
+ }
15
+
16
+ An attempt at getting decent performing EvoNorms running in PyTorch.
17
+ While faster than other PyTorch impl, still quite a ways off the built-in BatchNorm
18
+ in terms of memory usage and throughput on GPUs.
19
+
20
+ I'm testing these modules on TPU w/ PyTorch XLA. Promising start but
21
+ currently working around some issues with builtin torch/tensor.var/std. Unlike
22
+ GPU, similar train speeds for EvoNormS variants and BatchNorm.
23
+
24
+ Hacked together by / Copyright 2020 Ross Wightman
25
+ """
26
+ from typing import Sequence, Union
27
+
28
+ import torch
29
+ import torch.nn as nn
30
+ import torch.nn.functional as F
31
+
32
+ from .create_act import create_act_layer
33
+ from .trace_utils import _assert
34
+
35
+
36
+ def instance_std(x, eps: float = 1e-5):
37
+ std = x.float().var(dim=(2, 3), unbiased=False, keepdim=True).add(eps).sqrt().to(x.dtype)
38
+ return std.expand(x.shape)
39
+
40
+
41
+ def instance_std_tpu(x, eps: float = 1e-5):
42
+ std = manual_var(x, dim=(2, 3)).add(eps).sqrt()
43
+ return std.expand(x.shape)
44
+ # instance_std = instance_std_tpu
45
+
46
+
47
+ def instance_rms(x, eps: float = 1e-5):
48
+ rms = x.float().square().mean(dim=(2, 3), keepdim=True).add(eps).sqrt().to(x.dtype)
49
+ return rms.expand(x.shape)
50
+
51
+
52
+ def manual_var(x, dim: Union[int, Sequence[int]], diff_sqm: bool = False):
53
+ xm = x.mean(dim=dim, keepdim=True)
54
+ if diff_sqm:
55
+ # difference of squared mean and mean squared, faster on TPU can be less stable
56
+ var = ((x * x).mean(dim=dim, keepdim=True) - (xm * xm)).clamp(0)
57
+ else:
58
+ var = ((x - xm) * (x - xm)).mean(dim=dim, keepdim=True)
59
+ return var
60
+
61
+
62
+ def group_std(x, groups: int = 32, eps: float = 1e-5, flatten: bool = False):
63
+ B, C, H, W = x.shape
64
+ x_dtype = x.dtype
65
+ _assert(C % groups == 0, '')
66
+ if flatten:
67
+ x = x.reshape(B, groups, -1) # FIXME simpler shape causing TPU / XLA issues
68
+ std = x.float().var(dim=2, unbiased=False, keepdim=True).add(eps).sqrt().to(x_dtype)
69
+ else:
70
+ x = x.reshape(B, groups, C // groups, H, W)
71
+ std = x.float().var(dim=(2, 3, 4), unbiased=False, keepdim=True).add(eps).sqrt().to(x_dtype)
72
+ return std.expand(x.shape).reshape(B, C, H, W)
73
+
74
+
75
+ def group_std_tpu(x, groups: int = 32, eps: float = 1e-5, diff_sqm: bool = False, flatten: bool = False):
76
+ # This is a workaround for some stability / odd behaviour of .var and .std
77
+ # running on PyTorch XLA w/ TPUs. These manual var impl are producing much better results
78
+ B, C, H, W = x.shape
79
+ _assert(C % groups == 0, '')
80
+ if flatten:
81
+ x = x.reshape(B, groups, -1) # FIXME simpler shape causing TPU / XLA issues
82
+ var = manual_var(x, dim=-1, diff_sqm=diff_sqm)
83
+ else:
84
+ x = x.reshape(B, groups, C // groups, H, W)
85
+ var = manual_var(x, dim=(2, 3, 4), diff_sqm=diff_sqm)
86
+ return var.add(eps).sqrt().expand(x.shape).reshape(B, C, H, W)
87
+ #group_std = group_std_tpu # FIXME TPU temporary
88
+
89
+
90
+ def group_rms(x, groups: int = 32, eps: float = 1e-5):
91
+ B, C, H, W = x.shape
92
+ _assert(C % groups == 0, '')
93
+ x_dtype = x.dtype
94
+ x = x.reshape(B, groups, C // groups, H, W)
95
+ rms = x.float().square().mean(dim=(2, 3, 4), keepdim=True).add(eps).sqrt_().to(x_dtype)
96
+ return rms.expand(x.shape).reshape(B, C, H, W)
97
+
98
+
99
+ class EvoNorm2dB0(nn.Module):
100
+ def __init__(self, num_features, apply_act=True, momentum=0.1, eps=1e-3, **_):
101
+ super().__init__()
102
+ self.apply_act = apply_act # apply activation (non-linearity)
103
+ self.momentum = momentum
104
+ self.eps = eps
105
+ self.weight = nn.Parameter(torch.ones(num_features))
106
+ self.bias = nn.Parameter(torch.zeros(num_features))
107
+ self.v = nn.Parameter(torch.ones(num_features)) if apply_act else None
108
+ self.register_buffer('running_var', torch.ones(num_features))
109
+ self.reset_parameters()
110
+
111
+ def reset_parameters(self):
112
+ nn.init.ones_(self.weight)
113
+ nn.init.zeros_(self.bias)
114
+ if self.v is not None:
115
+ nn.init.ones_(self.v)
116
+
117
+ def forward(self, x):
118
+ _assert(x.dim() == 4, 'expected 4D input')
119
+ x_dtype = x.dtype
120
+ v_shape = (1, -1, 1, 1)
121
+ if self.v is not None:
122
+ if self.training:
123
+ var = x.float().var(dim=(0, 2, 3), unbiased=False)
124
+ # var = manual_var(x, dim=(0, 2, 3)).squeeze()
125
+ n = x.numel() / x.shape[1]
126
+ self.running_var.copy_(
127
+ self.running_var * (1 - self.momentum) +
128
+ var.detach() * self.momentum * (n / (n - 1)))
129
+ else:
130
+ var = self.running_var
131
+ left = var.add(self.eps).sqrt_().to(x_dtype).view(v_shape).expand_as(x)
132
+ v = self.v.to(x_dtype).view(v_shape)
133
+ right = x * v + instance_std(x, self.eps)
134
+ x = x / left.max(right)
135
+ return x * self.weight.to(x_dtype).view(v_shape) + self.bias.to(x_dtype).view(v_shape)
136
+
137
+
138
+ class EvoNorm2dB1(nn.Module):
139
+ def __init__(self, num_features, apply_act=True, momentum=0.1, eps=1e-5, **_):
140
+ super().__init__()
141
+ self.apply_act = apply_act # apply activation (non-linearity)
142
+ self.momentum = momentum
143
+ self.eps = eps
144
+ self.weight = nn.Parameter(torch.ones(num_features))
145
+ self.bias = nn.Parameter(torch.zeros(num_features))
146
+ self.register_buffer('running_var', torch.ones(num_features))
147
+ self.reset_parameters()
148
+
149
+ def reset_parameters(self):
150
+ nn.init.ones_(self.weight)
151
+ nn.init.zeros_(self.bias)
152
+
153
+ def forward(self, x):
154
+ _assert(x.dim() == 4, 'expected 4D input')
155
+ x_dtype = x.dtype
156
+ v_shape = (1, -1, 1, 1)
157
+ if self.apply_act:
158
+ if self.training:
159
+ var = x.float().var(dim=(0, 2, 3), unbiased=False)
160
+ n = x.numel() / x.shape[1]
161
+ self.running_var.copy_(
162
+ self.running_var * (1 - self.momentum) +
163
+ var.detach().to(self.running_var.dtype) * self.momentum * (n / (n - 1)))
164
+ else:
165
+ var = self.running_var
166
+ var = var.to(x_dtype).view(v_shape)
167
+ left = var.add(self.eps).sqrt_()
168
+ right = (x + 1) * instance_rms(x, self.eps)
169
+ x = x / left.max(right)
170
+ return x * self.weight.view(v_shape).to(x_dtype) + self.bias.view(v_shape).to(x_dtype)
171
+
172
+
173
+ class EvoNorm2dB2(nn.Module):
174
+ def __init__(self, num_features, apply_act=True, momentum=0.1, eps=1e-5, **_):
175
+ super().__init__()
176
+ self.apply_act = apply_act # apply activation (non-linearity)
177
+ self.momentum = momentum
178
+ self.eps = eps
179
+ self.weight = nn.Parameter(torch.ones(num_features))
180
+ self.bias = nn.Parameter(torch.zeros(num_features))
181
+ self.register_buffer('running_var', torch.ones(num_features))
182
+ self.reset_parameters()
183
+
184
+ def reset_parameters(self):
185
+ nn.init.ones_(self.weight)
186
+ nn.init.zeros_(self.bias)
187
+
188
+ def forward(self, x):
189
+ _assert(x.dim() == 4, 'expected 4D input')
190
+ x_dtype = x.dtype
191
+ v_shape = (1, -1, 1, 1)
192
+ if self.apply_act:
193
+ if self.training:
194
+ var = x.float().var(dim=(0, 2, 3), unbiased=False)
195
+ n = x.numel() / x.shape[1]
196
+ self.running_var.copy_(
197
+ self.running_var * (1 - self.momentum) +
198
+ var.detach().to(self.running_var.dtype) * self.momentum * (n / (n - 1)))
199
+ else:
200
+ var = self.running_var
201
+ var = var.to(x_dtype).view(v_shape)
202
+ left = var.add(self.eps).sqrt_()
203
+ right = instance_rms(x, self.eps) - x
204
+ x = x / left.max(right)
205
+ return x * self.weight.view(v_shape).to(x_dtype) + self.bias.view(v_shape).to(x_dtype)
206
+
207
+
208
+ class EvoNorm2dS0(nn.Module):
209
+ def __init__(self, num_features, groups=32, group_size=None, apply_act=True, eps=1e-5, **_):
210
+ super().__init__()
211
+ self.apply_act = apply_act # apply activation (non-linearity)
212
+ if group_size:
213
+ assert num_features % group_size == 0
214
+ self.groups = num_features // group_size
215
+ else:
216
+ self.groups = groups
217
+ self.eps = eps
218
+ self.weight = nn.Parameter(torch.ones(num_features))
219
+ self.bias = nn.Parameter(torch.zeros(num_features))
220
+ self.v = nn.Parameter(torch.ones(num_features)) if apply_act else None
221
+ self.reset_parameters()
222
+
223
+ def reset_parameters(self):
224
+ nn.init.ones_(self.weight)
225
+ nn.init.zeros_(self.bias)
226
+ if self.v is not None:
227
+ nn.init.ones_(self.v)
228
+
229
+ def forward(self, x):
230
+ _assert(x.dim() == 4, 'expected 4D input')
231
+ x_dtype = x.dtype
232
+ v_shape = (1, -1, 1, 1)
233
+ if self.v is not None:
234
+ v = self.v.view(v_shape).to(x_dtype)
235
+ x = x * (x * v).sigmoid() / group_std(x, self.groups, self.eps)
236
+ return x * self.weight.view(v_shape).to(x_dtype) + self.bias.view(v_shape).to(x_dtype)
237
+
238
+
239
+ class EvoNorm2dS0a(EvoNorm2dS0):
240
+ def __init__(self, num_features, groups=32, group_size=None, apply_act=True, eps=1e-3, **_):
241
+ super().__init__(
242
+ num_features, groups=groups, group_size=group_size, apply_act=apply_act, eps=eps)
243
+
244
+ def forward(self, x):
245
+ _assert(x.dim() == 4, 'expected 4D input')
246
+ x_dtype = x.dtype
247
+ v_shape = (1, -1, 1, 1)
248
+ d = group_std(x, self.groups, self.eps)
249
+ if self.v is not None:
250
+ v = self.v.view(v_shape).to(x_dtype)
251
+ x = x * (x * v).sigmoid()
252
+ x = x / d
253
+ return x * self.weight.view(v_shape).to(x_dtype) + self.bias.view(v_shape).to(x_dtype)
254
+
255
+
256
+ class EvoNorm2dS1(nn.Module):
257
+ def __init__(
258
+ self, num_features, groups=32, group_size=None,
259
+ apply_act=True, act_layer=None, eps=1e-5, **_):
260
+ super().__init__()
261
+ act_layer = act_layer or nn.SiLU
262
+ self.apply_act = apply_act # apply activation (non-linearity)
263
+ if act_layer is not None and apply_act:
264
+ self.act = create_act_layer(act_layer)
265
+ else:
266
+ self.act = nn.Identity()
267
+ if group_size:
268
+ assert num_features % group_size == 0
269
+ self.groups = num_features // group_size
270
+ else:
271
+ self.groups = groups
272
+ self.eps = eps
273
+ self.pre_act_norm = False
274
+ self.weight = nn.Parameter(torch.ones(num_features))
275
+ self.bias = nn.Parameter(torch.zeros(num_features))
276
+ self.reset_parameters()
277
+
278
+ def reset_parameters(self):
279
+ nn.init.ones_(self.weight)
280
+ nn.init.zeros_(self.bias)
281
+
282
+ def forward(self, x):
283
+ _assert(x.dim() == 4, 'expected 4D input')
284
+ x_dtype = x.dtype
285
+ v_shape = (1, -1, 1, 1)
286
+ if self.apply_act:
287
+ x = self.act(x) / group_std(x, self.groups, self.eps)
288
+ return x * self.weight.view(v_shape).to(x_dtype) + self.bias.view(v_shape).to(x_dtype)
289
+
290
+
291
+ class EvoNorm2dS1a(EvoNorm2dS1):
292
+ def __init__(
293
+ self, num_features, groups=32, group_size=None,
294
+ apply_act=True, act_layer=None, eps=1e-3, **_):
295
+ super().__init__(
296
+ num_features, groups=groups, group_size=group_size, apply_act=apply_act, act_layer=act_layer, eps=eps)
297
+
298
+ def forward(self, x):
299
+ _assert(x.dim() == 4, 'expected 4D input')
300
+ x_dtype = x.dtype
301
+ v_shape = (1, -1, 1, 1)
302
+ x = self.act(x) / group_std(x, self.groups, self.eps)
303
+ return x * self.weight.view(v_shape).to(x_dtype) + self.bias.view(v_shape).to(x_dtype)
304
+
305
+
306
+ class EvoNorm2dS2(nn.Module):
307
+ def __init__(
308
+ self, num_features, groups=32, group_size=None,
309
+ apply_act=True, act_layer=None, eps=1e-5, **_):
310
+ super().__init__()
311
+ act_layer = act_layer or nn.SiLU
312
+ self.apply_act = apply_act # apply activation (non-linearity)
313
+ if act_layer is not None and apply_act:
314
+ self.act = create_act_layer(act_layer)
315
+ else:
316
+ self.act = nn.Identity()
317
+ if group_size:
318
+ assert num_features % group_size == 0
319
+ self.groups = num_features // group_size
320
+ else:
321
+ self.groups = groups
322
+ self.eps = eps
323
+ self.weight = nn.Parameter(torch.ones(num_features))
324
+ self.bias = nn.Parameter(torch.zeros(num_features))
325
+ self.reset_parameters()
326
+
327
+ def reset_parameters(self):
328
+ nn.init.ones_(self.weight)
329
+ nn.init.zeros_(self.bias)
330
+
331
+ def forward(self, x):
332
+ _assert(x.dim() == 4, 'expected 4D input')
333
+ x_dtype = x.dtype
334
+ v_shape = (1, -1, 1, 1)
335
+ if self.apply_act:
336
+ x = self.act(x) / group_rms(x, self.groups, self.eps)
337
+ return x * self.weight.view(v_shape).to(x_dtype) + self.bias.view(v_shape).to(x_dtype)
338
+
339
+
340
+ class EvoNorm2dS2a(EvoNorm2dS2):
341
+ def __init__(
342
+ self, num_features, groups=32, group_size=None,
343
+ apply_act=True, act_layer=None, eps=1e-3, **_):
344
+ super().__init__(
345
+ num_features, groups=groups, group_size=group_size, apply_act=apply_act, act_layer=act_layer, eps=eps)
346
+
347
+ def forward(self, x):
348
+ _assert(x.dim() == 4, 'expected 4D input')
349
+ x_dtype = x.dtype
350
+ v_shape = (1, -1, 1, 1)
351
+ x = self.act(x) / group_rms(x, self.groups, self.eps)
352
+ return x * self.weight.view(v_shape).to(x_dtype) + self.bias.view(v_shape).to(x_dtype)
src/custom_timm/models/layers/fast_norm.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ 'Fast' Normalization Functions
2
+
3
+ For GroupNorm and LayerNorm these functions bypass typical AMP upcast to float32.
4
+
5
+ Additionally, for LayerNorm, the APEX fused LN is used if available (which also does not upcast)
6
+
7
+ Hacked together by / Copyright 2022 Ross Wightman
8
+ """
9
+ from typing import List, Optional
10
+
11
+ import torch
12
+ from torch.nn import functional as F
13
+
14
+ try:
15
+ from apex.normalization.fused_layer_norm import fused_layer_norm_affine
16
+ has_apex = True
17
+ except ImportError:
18
+ has_apex = False
19
+
20
+
21
+ # fast (ie lower precision LN) can be disabled with this flag if issues crop up
22
+ _USE_FAST_NORM = False # defaulting to False for now
23
+
24
+
25
+ def is_fast_norm():
26
+ return _USE_FAST_NORM
27
+
28
+
29
+ def set_fast_norm(enable=True):
30
+ global _USE_FAST_NORM
31
+ _USE_FAST_NORM = enable
32
+
33
+
34
+ def fast_group_norm(
35
+ x: torch.Tensor,
36
+ num_groups: int,
37
+ weight: Optional[torch.Tensor] = None,
38
+ bias: Optional[torch.Tensor] = None,
39
+ eps: float = 1e-5
40
+ ) -> torch.Tensor:
41
+ if torch.jit.is_scripting():
42
+ # currently cannot use is_autocast_enabled within torchscript
43
+ return F.group_norm(x, num_groups, weight, bias, eps)
44
+
45
+ if torch.is_autocast_enabled():
46
+ # normally native AMP casts GN inputs to float32
47
+ # here we use the low precision autocast dtype
48
+ # FIXME what to do re CPU autocast?
49
+ dt = torch.get_autocast_gpu_dtype()
50
+ x, weight, bias = x.to(dt), weight.to(dt), bias.to(dt)
51
+
52
+ with torch.cuda.amp.autocast(enabled=False):
53
+ return F.group_norm(x, num_groups, weight, bias, eps)
54
+
55
+
56
+ def fast_layer_norm(
57
+ x: torch.Tensor,
58
+ normalized_shape: List[int],
59
+ weight: Optional[torch.Tensor] = None,
60
+ bias: Optional[torch.Tensor] = None,
61
+ eps: float = 1e-5
62
+ ) -> torch.Tensor:
63
+ if torch.jit.is_scripting():
64
+ # currently cannot use is_autocast_enabled within torchscript
65
+ return F.layer_norm(x, normalized_shape, weight, bias, eps)
66
+
67
+ if has_apex:
68
+ return fused_layer_norm_affine(x, weight, bias, normalized_shape, eps)
69
+
70
+ if torch.is_autocast_enabled():
71
+ # normally native AMP casts LN inputs to float32
72
+ # apex LN does not, this is behaving like Apex
73
+ dt = torch.get_autocast_gpu_dtype()
74
+ # FIXME what to do re CPU autocast?
75
+ x, weight, bias = x.to(dt), weight.to(dt), bias.to(dt)
76
+
77
+ with torch.cuda.amp.autocast(enabled=False):
78
+ return F.layer_norm(x, normalized_shape, weight, bias, eps)
src/custom_timm/models/layers/filter_response_norm.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Filter Response Norm in PyTorch
2
+
3
+ Based on `Filter Response Normalization Layer` - https://arxiv.org/abs/1911.09737
4
+
5
+ Hacked together by / Copyright 2021 Ross Wightman
6
+ """
7
+ import torch
8
+ import torch.nn as nn
9
+
10
+ from .create_act import create_act_layer
11
+ from .trace_utils import _assert
12
+
13
+
14
+ def inv_instance_rms(x, eps: float = 1e-5):
15
+ rms = x.square().float().mean(dim=(2, 3), keepdim=True).add(eps).rsqrt().to(x.dtype)
16
+ return rms.expand(x.shape)
17
+
18
+
19
+ class FilterResponseNormTlu2d(nn.Module):
20
+ def __init__(self, num_features, apply_act=True, eps=1e-5, rms=True, **_):
21
+ super(FilterResponseNormTlu2d, self).__init__()
22
+ self.apply_act = apply_act # apply activation (non-linearity)
23
+ self.rms = rms
24
+ self.eps = eps
25
+ self.weight = nn.Parameter(torch.ones(num_features))
26
+ self.bias = nn.Parameter(torch.zeros(num_features))
27
+ self.tau = nn.Parameter(torch.zeros(num_features)) if apply_act else None
28
+ self.reset_parameters()
29
+
30
+ def reset_parameters(self):
31
+ nn.init.ones_(self.weight)
32
+ nn.init.zeros_(self.bias)
33
+ if self.tau is not None:
34
+ nn.init.zeros_(self.tau)
35
+
36
+ def forward(self, x):
37
+ _assert(x.dim() == 4, 'expected 4D input')
38
+ x_dtype = x.dtype
39
+ v_shape = (1, -1, 1, 1)
40
+ x = x * inv_instance_rms(x, self.eps)
41
+ x = x * self.weight.view(v_shape).to(dtype=x_dtype) + self.bias.view(v_shape).to(dtype=x_dtype)
42
+ return torch.maximum(x, self.tau.reshape(v_shape).to(dtype=x_dtype)) if self.tau is not None else x
43
+
44
+
45
+ class FilterResponseNormAct2d(nn.Module):
46
+ def __init__(self, num_features, apply_act=True, act_layer=nn.ReLU, inplace=None, rms=True, eps=1e-5, **_):
47
+ super(FilterResponseNormAct2d, self).__init__()
48
+ if act_layer is not None and apply_act:
49
+ self.act = create_act_layer(act_layer, inplace=inplace)
50
+ else:
51
+ self.act = nn.Identity()
52
+ self.rms = rms
53
+ self.eps = eps
54
+ self.weight = nn.Parameter(torch.ones(num_features))
55
+ self.bias = nn.Parameter(torch.zeros(num_features))
56
+ self.reset_parameters()
57
+
58
+ def reset_parameters(self):
59
+ nn.init.ones_(self.weight)
60
+ nn.init.zeros_(self.bias)
61
+
62
+ def forward(self, x):
63
+ _assert(x.dim() == 4, 'expected 4D input')
64
+ x_dtype = x.dtype
65
+ v_shape = (1, -1, 1, 1)
66
+ x = x * inv_instance_rms(x, self.eps)
67
+ x = x * self.weight.view(v_shape).to(dtype=x_dtype) + self.bias.view(v_shape).to(dtype=x_dtype)
68
+ return self.act(x)
src/custom_timm/models/layers/gather_excite.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Gather-Excite Attention Block
2
+
3
+ Paper: `Gather-Excite: Exploiting Feature Context in CNNs` - https://arxiv.org/abs/1810.12348
4
+
5
+ Official code here, but it's only partial impl in Caffe: https://github.com/hujie-frank/GENet
6
+
7
+ I've tried to support all of the extent both w/ and w/o params. I don't believe I've seen another
8
+ impl that covers all of the cases.
9
+
10
+ NOTE: extent=0 + extra_params=False is equivalent to Squeeze-and-Excitation
11
+
12
+ Hacked together by / Copyright 2021 Ross Wightman
13
+ """
14
+ import math
15
+
16
+ from torch import nn as nn
17
+ import torch.nn.functional as F
18
+
19
+ from .create_act import create_act_layer, get_act_layer
20
+ from .create_conv2d import create_conv2d
21
+ from .helpers import make_divisible
22
+ from .mlp import ConvMlp
23
+
24
+
25
+ class GatherExcite(nn.Module):
26
+ """ Gather-Excite Attention Module
27
+ """
28
+ def __init__(
29
+ self, channels, feat_size=None, extra_params=False, extent=0, use_mlp=True,
30
+ rd_ratio=1./16, rd_channels=None, rd_divisor=1, add_maxpool=False,
31
+ act_layer=nn.ReLU, norm_layer=nn.BatchNorm2d, gate_layer='sigmoid'):
32
+ super(GatherExcite, self).__init__()
33
+ self.add_maxpool = add_maxpool
34
+ act_layer = get_act_layer(act_layer)
35
+ self.extent = extent
36
+ if extra_params:
37
+ self.gather = nn.Sequential()
38
+ if extent == 0:
39
+ assert feat_size is not None, 'spatial feature size must be specified for global extent w/ params'
40
+ self.gather.add_module(
41
+ 'conv1', create_conv2d(channels, channels, kernel_size=feat_size, stride=1, depthwise=True))
42
+ if norm_layer:
43
+ self.gather.add_module(f'norm1', nn.BatchNorm2d(channels))
44
+ else:
45
+ assert extent % 2 == 0
46
+ num_conv = int(math.log2(extent))
47
+ for i in range(num_conv):
48
+ self.gather.add_module(
49
+ f'conv{i + 1}',
50
+ create_conv2d(channels, channels, kernel_size=3, stride=2, depthwise=True))
51
+ if norm_layer:
52
+ self.gather.add_module(f'norm{i + 1}', nn.BatchNorm2d(channels))
53
+ if i != num_conv - 1:
54
+ self.gather.add_module(f'act{i + 1}', act_layer(inplace=True))
55
+ else:
56
+ self.gather = None
57
+ if self.extent == 0:
58
+ self.gk = 0
59
+ self.gs = 0
60
+ else:
61
+ assert extent % 2 == 0
62
+ self.gk = self.extent * 2 - 1
63
+ self.gs = self.extent
64
+
65
+ if not rd_channels:
66
+ rd_channels = make_divisible(channels * rd_ratio, rd_divisor, round_limit=0.)
67
+ self.mlp = ConvMlp(channels, rd_channels, act_layer=act_layer) if use_mlp else nn.Identity()
68
+ self.gate = create_act_layer(gate_layer)
69
+
70
+ def forward(self, x):
71
+ size = x.shape[-2:]
72
+ if self.gather is not None:
73
+ x_ge = self.gather(x)
74
+ else:
75
+ if self.extent == 0:
76
+ # global extent
77
+ x_ge = x.mean(dim=(2, 3), keepdims=True)
78
+ if self.add_maxpool:
79
+ # experimental codepath, may remove or change
80
+ x_ge = 0.5 * x_ge + 0.5 * x.amax((2, 3), keepdim=True)
81
+ else:
82
+ x_ge = F.avg_pool2d(
83
+ x, kernel_size=self.gk, stride=self.gs, padding=self.gk // 2, count_include_pad=False)
84
+ if self.add_maxpool:
85
+ # experimental codepath, may remove or change
86
+ x_ge = 0.5 * x_ge + 0.5 * F.max_pool2d(x, kernel_size=self.gk, stride=self.gs, padding=self.gk // 2)
87
+ x_ge = self.mlp(x_ge)
88
+ if x_ge.shape[-1] != 1 or x_ge.shape[-2] != 1:
89
+ x_ge = F.interpolate(x_ge, size=size)
90
+ return x * self.gate(x_ge)
src/custom_timm/models/layers/global_context.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Global Context Attention Block
2
+
3
+ Paper: `GCNet: Non-local Networks Meet Squeeze-Excitation Networks and Beyond`
4
+ - https://arxiv.org/abs/1904.11492
5
+
6
+ Official code consulted as reference: https://github.com/xvjiarui/GCNet
7
+
8
+ Hacked together by / Copyright 2021 Ross Wightman
9
+ """
10
+ from torch import nn as nn
11
+ import torch.nn.functional as F
12
+
13
+ from .create_act import create_act_layer, get_act_layer
14
+ from .helpers import make_divisible
15
+ from .mlp import ConvMlp
16
+ from .norm import LayerNorm2d
17
+
18
+
19
+ class GlobalContext(nn.Module):
20
+
21
+ def __init__(self, channels, use_attn=True, fuse_add=False, fuse_scale=True, init_last_zero=False,
22
+ rd_ratio=1./8, rd_channels=None, rd_divisor=1, act_layer=nn.ReLU, gate_layer='sigmoid'):
23
+ super(GlobalContext, self).__init__()
24
+ act_layer = get_act_layer(act_layer)
25
+
26
+ self.conv_attn = nn.Conv2d(channels, 1, kernel_size=1, bias=True) if use_attn else None
27
+
28
+ if rd_channels is None:
29
+ rd_channels = make_divisible(channels * rd_ratio, rd_divisor, round_limit=0.)
30
+ if fuse_add:
31
+ self.mlp_add = ConvMlp(channels, rd_channels, act_layer=act_layer, norm_layer=LayerNorm2d)
32
+ else:
33
+ self.mlp_add = None
34
+ if fuse_scale:
35
+ self.mlp_scale = ConvMlp(channels, rd_channels, act_layer=act_layer, norm_layer=LayerNorm2d)
36
+ else:
37
+ self.mlp_scale = None
38
+
39
+ self.gate = create_act_layer(gate_layer)
40
+ self.init_last_zero = init_last_zero
41
+ self.reset_parameters()
42
+
43
+ def reset_parameters(self):
44
+ if self.conv_attn is not None:
45
+ nn.init.kaiming_normal_(self.conv_attn.weight, mode='fan_in', nonlinearity='relu')
46
+ if self.mlp_add is not None:
47
+ nn.init.zeros_(self.mlp_add.fc2.weight)
48
+
49
+ def forward(self, x):
50
+ B, C, H, W = x.shape
51
+
52
+ if self.conv_attn is not None:
53
+ attn = self.conv_attn(x).reshape(B, 1, H * W) # (B, 1, H * W)
54
+ attn = F.softmax(attn, dim=-1).unsqueeze(3) # (B, 1, H * W, 1)
55
+ context = x.reshape(B, C, H * W).unsqueeze(1) @ attn
56
+ context = context.view(B, C, 1, 1)
57
+ else:
58
+ context = x.mean(dim=(2, 3), keepdim=True)
59
+
60
+ if self.mlp_scale is not None:
61
+ mlp_x = self.mlp_scale(context)
62
+ x = x * self.gate(mlp_x)
63
+ if self.mlp_add is not None:
64
+ mlp_x = self.mlp_add(context)
65
+ x = x + mlp_x
66
+
67
+ return x
src/custom_timm/models/layers/halo_attn.py ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Halo Self Attention
2
+
3
+ Paper: `Scaling Local Self-Attention for Parameter Efficient Visual Backbones`
4
+ - https://arxiv.org/abs/2103.12731
5
+
6
+ @misc{2103.12731,
7
+ Author = {Ashish Vaswani and Prajit Ramachandran and Aravind Srinivas and Niki Parmar and Blake Hechtman and
8
+ Jonathon Shlens},
9
+ Title = {Scaling Local Self-Attention for Parameter Efficient Visual Backbones},
10
+ Year = {2021},
11
+ }
12
+
13
+ Status:
14
+ This impl is a WIP, there is no official ref impl and some details in paper weren't clear to me.
15
+ The attention mechanism works but it's slow as implemented.
16
+
17
+ Hacked together by / Copyright 2021 Ross Wightman
18
+ """
19
+ from typing import List
20
+
21
+ import torch
22
+ from torch import nn
23
+ import torch.nn.functional as F
24
+
25
+ from .helpers import make_divisible
26
+ from .weight_init import trunc_normal_
27
+ from .trace_utils import _assert
28
+
29
+
30
+ def rel_logits_1d(q, rel_k, permute_mask: List[int]):
31
+ """ Compute relative logits along one dimension
32
+
33
+ As per: https://gist.github.com/aravindsrinivas/56359b79f0ce4449bcb04ab4b56a57a2
34
+ Originally from: `Attention Augmented Convolutional Networks` - https://arxiv.org/abs/1904.09925
35
+
36
+ Args:
37
+ q: (batch, height, width, dim)
38
+ rel_k: (2 * window - 1, dim)
39
+ permute_mask: permute output dim according to this
40
+ """
41
+ B, H, W, dim = q.shape
42
+ rel_size = rel_k.shape[0]
43
+ win_size = (rel_size + 1) // 2
44
+
45
+ x = (q @ rel_k.transpose(-1, -2))
46
+ x = x.reshape(-1, W, rel_size)
47
+
48
+ # pad to shift from relative to absolute indexing
49
+ x_pad = F.pad(x, [0, 1]).flatten(1)
50
+ x_pad = F.pad(x_pad, [0, rel_size - W])
51
+
52
+ # reshape and slice out the padded elements
53
+ x_pad = x_pad.reshape(-1, W + 1, rel_size)
54
+ x = x_pad[:, :W, win_size - 1:]
55
+
56
+ # reshape and tile
57
+ x = x.reshape(B, H, 1, W, win_size).expand(-1, -1, win_size, -1, -1)
58
+ return x.permute(permute_mask)
59
+
60
+
61
+ class PosEmbedRel(nn.Module):
62
+ """ Relative Position Embedding
63
+ As per: https://gist.github.com/aravindsrinivas/56359b79f0ce4449bcb04ab4b56a57a2
64
+ Originally from: `Attention Augmented Convolutional Networks` - https://arxiv.org/abs/1904.09925
65
+
66
+ """
67
+ def __init__(self, block_size, win_size, dim_head, scale):
68
+ """
69
+ Args:
70
+ block_size (int): block size
71
+ win_size (int): neighbourhood window size
72
+ dim_head (int): attention head dim
73
+ scale (float): scale factor (for init)
74
+ """
75
+ super().__init__()
76
+ self.block_size = block_size
77
+ self.dim_head = dim_head
78
+ self.height_rel = nn.Parameter(torch.randn(win_size * 2 - 1, dim_head) * scale)
79
+ self.width_rel = nn.Parameter(torch.randn(win_size * 2 - 1, dim_head) * scale)
80
+
81
+ def forward(self, q):
82
+ B, BB, HW, _ = q.shape
83
+
84
+ # relative logits in width dimension.
85
+ q = q.reshape(-1, self.block_size, self.block_size, self.dim_head)
86
+ rel_logits_w = rel_logits_1d(q, self.width_rel, permute_mask=(0, 1, 3, 2, 4))
87
+
88
+ # relative logits in height dimension.
89
+ q = q.transpose(1, 2)
90
+ rel_logits_h = rel_logits_1d(q, self.height_rel, permute_mask=(0, 3, 1, 4, 2))
91
+
92
+ rel_logits = rel_logits_h + rel_logits_w
93
+ rel_logits = rel_logits.reshape(B, BB, HW, -1)
94
+ return rel_logits
95
+
96
+
97
+ class HaloAttn(nn.Module):
98
+ """ Halo Attention
99
+
100
+ Paper: `Scaling Local Self-Attention for Parameter Efficient Visual Backbones`
101
+ - https://arxiv.org/abs/2103.12731
102
+
103
+ The internal dimensions of the attention module are controlled by the interaction of several arguments.
104
+ * the output dimension of the module is specified by dim_out, which falls back to input dim if not set
105
+ * the value (v) dimension is set to dim_out // num_heads, the v projection determines the output dim
106
+ * the query and key (qk) dimensions are determined by
107
+ * num_heads * dim_head if dim_head is not None
108
+ * num_heads * (dim_out * attn_ratio // num_heads) if dim_head is None
109
+ * as seen above, attn_ratio determines the ratio of q and k relative to the output if dim_head not used
110
+
111
+ Args:
112
+ dim (int): input dimension to the module
113
+ dim_out (int): output dimension of the module, same as dim if not set
114
+ feat_size (Tuple[int, int]): size of input feature_map (not used, for arg compat with bottle/lambda)
115
+ stride: output stride of the module, query downscaled if > 1 (default: 1).
116
+ num_heads: parallel attention heads (default: 8).
117
+ dim_head: dimension of query and key heads, calculated from dim_out * attn_ratio // num_heads if not set
118
+ block_size (int): size of blocks. (default: 8)
119
+ halo_size (int): size of halo overlap. (default: 3)
120
+ qk_ratio (float): ratio of q and k dimensions to output dimension when dim_head not set. (default: 1.0)
121
+ qkv_bias (bool) : add bias to q, k, and v projections
122
+ avg_down (bool): use average pool downsample instead of strided query blocks
123
+ scale_pos_embed (bool): scale the position embedding as well as Q @ K
124
+ """
125
+ def __init__(
126
+ self, dim, dim_out=None, feat_size=None, stride=1, num_heads=8, dim_head=None, block_size=8, halo_size=3,
127
+ qk_ratio=1.0, qkv_bias=False, avg_down=False, scale_pos_embed=False):
128
+ super().__init__()
129
+ dim_out = dim_out or dim
130
+ assert dim_out % num_heads == 0
131
+ assert stride in (1, 2)
132
+ self.num_heads = num_heads
133
+ self.dim_head_qk = dim_head or make_divisible(dim_out * qk_ratio, divisor=8) // num_heads
134
+ self.dim_head_v = dim_out // self.num_heads
135
+ self.dim_out_qk = num_heads * self.dim_head_qk
136
+ self.dim_out_v = num_heads * self.dim_head_v
137
+ self.scale = self.dim_head_qk ** -0.5
138
+ self.scale_pos_embed = scale_pos_embed
139
+ self.block_size = self.block_size_ds = block_size
140
+ self.halo_size = halo_size
141
+ self.win_size = block_size + halo_size * 2 # neighbourhood window size
142
+ self.block_stride = 1
143
+ use_avg_pool = False
144
+ if stride > 1:
145
+ use_avg_pool = avg_down or block_size % stride != 0
146
+ self.block_stride = 1 if use_avg_pool else stride
147
+ self.block_size_ds = self.block_size // self.block_stride
148
+
149
+ # FIXME not clear if this stride behaviour is what the paper intended
150
+ # Also, the paper mentions using a 3D conv for dealing with the blocking/gather, and leaving
151
+ # data in unfolded block form. I haven't wrapped my head around how that'd look.
152
+ self.q = nn.Conv2d(dim, self.dim_out_qk, 1, stride=self.block_stride, bias=qkv_bias)
153
+ self.kv = nn.Conv2d(dim, self.dim_out_qk + self.dim_out_v, 1, bias=qkv_bias)
154
+
155
+ self.pos_embed = PosEmbedRel(
156
+ block_size=self.block_size_ds, win_size=self.win_size, dim_head=self.dim_head_qk, scale=self.scale)
157
+
158
+ self.pool = nn.AvgPool2d(2, 2) if use_avg_pool else nn.Identity()
159
+
160
+ self.reset_parameters()
161
+
162
+ def reset_parameters(self):
163
+ std = self.q.weight.shape[1] ** -0.5 # fan-in
164
+ trunc_normal_(self.q.weight, std=std)
165
+ trunc_normal_(self.kv.weight, std=std)
166
+ trunc_normal_(self.pos_embed.height_rel, std=self.scale)
167
+ trunc_normal_(self.pos_embed.width_rel, std=self.scale)
168
+
169
+ def forward(self, x):
170
+ B, C, H, W = x.shape
171
+ _assert(H % self.block_size == 0, '')
172
+ _assert(W % self.block_size == 0, '')
173
+ num_h_blocks = H // self.block_size
174
+ num_w_blocks = W // self.block_size
175
+ num_blocks = num_h_blocks * num_w_blocks
176
+
177
+ q = self.q(x)
178
+ # unfold
179
+ q = q.reshape(
180
+ -1, self.dim_head_qk,
181
+ num_h_blocks, self.block_size_ds, num_w_blocks, self.block_size_ds).permute(0, 1, 3, 5, 2, 4)
182
+ # B, num_heads * dim_head * block_size ** 2, num_blocks
183
+ q = q.reshape(B * self.num_heads, self.dim_head_qk, -1, num_blocks).transpose(1, 3)
184
+ # B * num_heads, num_blocks, block_size ** 2, dim_head
185
+
186
+ kv = self.kv(x)
187
+ # Generate overlapping windows for kv. This approach is good for GPU and CPU. However, unfold() is not
188
+ # lowered for PyTorch XLA so it will be very slow. See code at bottom of file for XLA friendly approach.
189
+ # FIXME figure out how to switch impl between this and conv2d if XLA being used.
190
+ kv = F.pad(kv, [self.halo_size, self.halo_size, self.halo_size, self.halo_size])
191
+ kv = kv.unfold(2, self.win_size, self.block_size).unfold(3, self.win_size, self.block_size).reshape(
192
+ B * self.num_heads, self.dim_head_qk + self.dim_head_v, num_blocks, -1).permute(0, 2, 3, 1)
193
+ k, v = torch.split(kv, [self.dim_head_qk, self.dim_head_v], dim=-1)
194
+ # B * num_heads, num_blocks, win_size ** 2, dim_head_qk or dim_head_v
195
+
196
+ if self.scale_pos_embed:
197
+ attn = (q @ k.transpose(-1, -2) + self.pos_embed(q)) * self.scale
198
+ else:
199
+ attn = (q @ k.transpose(-1, -2)) * self.scale + self.pos_embed(q)
200
+ # B * num_heads, num_blocks, block_size ** 2, win_size ** 2
201
+ attn = attn.softmax(dim=-1)
202
+
203
+ out = (attn @ v).transpose(1, 3) # B * num_heads, dim_head_v, block_size ** 2, num_blocks
204
+ # fold
205
+ out = out.reshape(-1, self.block_size_ds, self.block_size_ds, num_h_blocks, num_w_blocks)
206
+ out = out.permute(0, 3, 1, 4, 2).contiguous().view(
207
+ B, self.dim_out_v, H // self.block_stride, W // self.block_stride)
208
+ # B, dim_out, H // block_stride, W // block_stride
209
+ out = self.pool(out)
210
+ return out
211
+
212
+
213
+ """ Three alternatives for overlapping windows.
214
+
215
+ `.unfold().unfold()` is same speed as stride tricks with similar clarity as F.unfold()
216
+
217
+ if is_xla:
218
+ # This code achieves haloing on PyTorch XLA with reasonable runtime trade-off, it is
219
+ # EXTREMELY slow for backward on a GPU though so I need a way of selecting based on environment.
220
+ WW = self.win_size ** 2
221
+ pw = torch.eye(WW, dtype=x.dtype, device=x.device).reshape(WW, 1, self.win_size, self.win_size)
222
+ kv = F.conv2d(kv.reshape(-1, 1, H, W), pw, stride=self.block_size, padding=self.halo_size)
223
+ elif self.stride_tricks:
224
+ kv = F.pad(kv, [self.halo_size, self.halo_size, self.halo_size, self.halo_size]).contiguous()
225
+ kv = kv.as_strided((
226
+ B, self.dim_out_qk + self.dim_out_v, self.win_size, self.win_size, num_h_blocks, num_w_blocks),
227
+ stride=(kv.stride(0), kv.stride(1), kv.shape[-1], 1, self.block_size * kv.shape[-1], self.block_size))
228
+ else:
229
+ kv = F.unfold(kv, kernel_size=self.win_size, stride=self.block_size, padding=self.halo_size)
230
+
231
+ kv = kv.reshape(
232
+ B * self.num_heads, self.dim_head_qk + self.dim_head_v, -1, num_blocks).transpose(1, 3)
233
+ """
src/custom_timm/models/layers/helpers.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Layer/Module Helpers
2
+
3
+ Hacked together by / Copyright 2020 Ross Wightman
4
+ """
5
+ from itertools import repeat
6
+ import collections.abc
7
+
8
+
9
+ # From PyTorch internals
10
+ def _ntuple(n):
11
+ def parse(x):
12
+ if isinstance(x, collections.abc.Iterable) and not isinstance(x, str):
13
+ return x
14
+ return tuple(repeat(x, n))
15
+ return parse
16
+
17
+
18
+ to_1tuple = _ntuple(1)
19
+ to_2tuple = _ntuple(2)
20
+ to_3tuple = _ntuple(3)
21
+ to_4tuple = _ntuple(4)
22
+ to_ntuple = _ntuple
23
+
24
+
25
+ def make_divisible(v, divisor=8, min_value=None, round_limit=.9):
26
+ min_value = min_value or divisor
27
+ new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
28
+ # Make sure that round down does not go down by more than 10%.
29
+ if new_v < round_limit * v:
30
+ new_v += divisor
31
+ return new_v
32
+
33
+
34
+ def extend_tuple(x, n):
35
+ # pdas a tuple to specified n by padding with last value
36
+ if not isinstance(x, (tuple, list)):
37
+ x = (x,)
38
+ else:
39
+ x = tuple(x)
40
+ pad_n = n - len(x)
41
+ if pad_n <= 0:
42
+ return x[:n]
43
+ return x + (x[-1],) * pad_n
src/custom_timm/models/layers/inplace_abn.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn as nn
3
+
4
+ try:
5
+ from inplace_abn.functions import inplace_abn, inplace_abn_sync
6
+ has_iabn = True
7
+ except ImportError:
8
+ has_iabn = False
9
+
10
+ def inplace_abn(x, weight, bias, running_mean, running_var,
11
+ training=True, momentum=0.1, eps=1e-05, activation="leaky_relu", activation_param=0.01):
12
+ raise ImportError(
13
+ "Please install InplaceABN:'pip install git+https://github.com/mapillary/inplace_abn.git@v1.0.12'")
14
+
15
+ def inplace_abn_sync(**kwargs):
16
+ inplace_abn(**kwargs)
17
+
18
+
19
+ class InplaceAbn(nn.Module):
20
+ """Activated Batch Normalization
21
+
22
+ This gathers a BatchNorm and an activation function in a single module
23
+
24
+ Parameters
25
+ ----------
26
+ num_features : int
27
+ Number of feature channels in the input and output.
28
+ eps : float
29
+ Small constant to prevent numerical issues.
30
+ momentum : float
31
+ Momentum factor applied to compute running statistics.
32
+ affine : bool
33
+ If `True` apply learned scale and shift transformation after normalization.
34
+ act_layer : str or nn.Module type
35
+ Name or type of the activation functions, one of: `leaky_relu`, `elu`
36
+ act_param : float
37
+ Negative slope for the `leaky_relu` activation.
38
+ """
39
+
40
+ def __init__(self, num_features, eps=1e-5, momentum=0.1, affine=True, apply_act=True,
41
+ act_layer="leaky_relu", act_param=0.01, drop_layer=None):
42
+ super(InplaceAbn, self).__init__()
43
+ self.num_features = num_features
44
+ self.affine = affine
45
+ self.eps = eps
46
+ self.momentum = momentum
47
+ if apply_act:
48
+ if isinstance(act_layer, str):
49
+ assert act_layer in ('leaky_relu', 'elu', 'identity', '')
50
+ self.act_name = act_layer if act_layer else 'identity'
51
+ else:
52
+ # convert act layer passed as type to string
53
+ if act_layer == nn.ELU:
54
+ self.act_name = 'elu'
55
+ elif act_layer == nn.LeakyReLU:
56
+ self.act_name = 'leaky_relu'
57
+ elif act_layer is None or act_layer == nn.Identity:
58
+ self.act_name = 'identity'
59
+ else:
60
+ assert False, f'Invalid act layer {act_layer.__name__} for IABN'
61
+ else:
62
+ self.act_name = 'identity'
63
+ self.act_param = act_param
64
+ if self.affine:
65
+ self.weight = nn.Parameter(torch.ones(num_features))
66
+ self.bias = nn.Parameter(torch.zeros(num_features))
67
+ else:
68
+ self.register_parameter('weight', None)
69
+ self.register_parameter('bias', None)
70
+ self.register_buffer('running_mean', torch.zeros(num_features))
71
+ self.register_buffer('running_var', torch.ones(num_features))
72
+ self.reset_parameters()
73
+
74
+ def reset_parameters(self):
75
+ nn.init.constant_(self.running_mean, 0)
76
+ nn.init.constant_(self.running_var, 1)
77
+ if self.affine:
78
+ nn.init.constant_(self.weight, 1)
79
+ nn.init.constant_(self.bias, 0)
80
+
81
+ def forward(self, x):
82
+ output = inplace_abn(
83
+ x, self.weight, self.bias, self.running_mean, self.running_var,
84
+ self.training, self.momentum, self.eps, self.act_name, self.act_param)
85
+ if isinstance(output, tuple):
86
+ output = output[0]
87
+ return output
src/custom_timm/models/layers/lambda_layer.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Lambda Layer
2
+
3
+ Paper: `LambdaNetworks: Modeling Long-Range Interactions Without Attention`
4
+ - https://arxiv.org/abs/2102.08602
5
+
6
+ @misc{2102.08602,
7
+ Author = {Irwan Bello},
8
+ Title = {LambdaNetworks: Modeling Long-Range Interactions Without Attention},
9
+ Year = {2021},
10
+ }
11
+
12
+ Status:
13
+ This impl is a WIP. Code snippets in the paper were used as reference but
14
+ good chance some details are missing/wrong.
15
+
16
+ I've only implemented local lambda conv based pos embeddings.
17
+
18
+ For a PyTorch impl that includes other embedding options checkout
19
+ https://github.com/lucidrains/lambda-networks
20
+
21
+ Hacked together by / Copyright 2021 Ross Wightman
22
+ """
23
+ import torch
24
+ from torch import nn
25
+ import torch.nn.functional as F
26
+
27
+ from .helpers import to_2tuple, make_divisible
28
+ from .weight_init import trunc_normal_
29
+
30
+
31
+ def rel_pos_indices(size):
32
+ size = to_2tuple(size)
33
+ pos = torch.stack(torch.meshgrid(torch.arange(size[0]), torch.arange(size[1]))).flatten(1)
34
+ rel_pos = pos[:, None, :] - pos[:, :, None]
35
+ rel_pos[0] += size[0] - 1
36
+ rel_pos[1] += size[1] - 1
37
+ return rel_pos # 2, H * W, H * W
38
+
39
+
40
+ class LambdaLayer(nn.Module):
41
+ """Lambda Layer
42
+
43
+ Paper: `LambdaNetworks: Modeling Long-Range Interactions Without Attention`
44
+ - https://arxiv.org/abs/2102.08602
45
+
46
+ NOTE: intra-depth parameter 'u' is fixed at 1. It did not appear worth the complexity to add.
47
+
48
+ The internal dimensions of the lambda module are controlled via the interaction of several arguments.
49
+ * the output dimension of the module is specified by dim_out, which falls back to input dim if not set
50
+ * the value (v) dimension is set to dim_out // num_heads, the v projection determines the output dim
51
+ * the query (q) and key (k) dimension are determined by
52
+ * dim_head = (dim_out * attn_ratio // num_heads) if dim_head is None
53
+ * q = num_heads * dim_head, k = dim_head
54
+ * as seen above, attn_ratio determines the ratio of q and k relative to the output if dim_head not set
55
+
56
+ Args:
57
+ dim (int): input dimension to the module
58
+ dim_out (int): output dimension of the module, same as dim if not set
59
+ feat_size (Tuple[int, int]): size of input feature_map for relative pos variant H, W
60
+ stride (int): output stride of the module, avg pool used if stride == 2
61
+ num_heads (int): parallel attention heads.
62
+ dim_head (int): dimension of query and key heads, calculated from dim_out * attn_ratio // num_heads if not set
63
+ r (int): local lambda convolution radius. Use lambda conv if set, else relative pos if not. (default: 9)
64
+ qk_ratio (float): ratio of q and k dimensions to output dimension when dim_head not set. (default: 1.0)
65
+ qkv_bias (bool): add bias to q, k, and v projections
66
+ """
67
+ def __init__(
68
+ self, dim, dim_out=None, feat_size=None, stride=1, num_heads=4, dim_head=16, r=9,
69
+ qk_ratio=1.0, qkv_bias=False):
70
+ super().__init__()
71
+ dim_out = dim_out or dim
72
+ assert dim_out % num_heads == 0, ' should be divided by num_heads'
73
+ self.dim_qk = dim_head or make_divisible(dim_out * qk_ratio, divisor=8) // num_heads
74
+ self.num_heads = num_heads
75
+ self.dim_v = dim_out // num_heads
76
+
77
+ self.qkv = nn.Conv2d(
78
+ dim,
79
+ num_heads * self.dim_qk + self.dim_qk + self.dim_v,
80
+ kernel_size=1, bias=qkv_bias)
81
+ self.norm_q = nn.BatchNorm2d(num_heads * self.dim_qk)
82
+ self.norm_v = nn.BatchNorm2d(self.dim_v)
83
+
84
+ if r is not None:
85
+ # local lambda convolution for pos
86
+ self.conv_lambda = nn.Conv3d(1, self.dim_qk, (r, r, 1), padding=(r // 2, r // 2, 0))
87
+ self.pos_emb = None
88
+ self.rel_pos_indices = None
89
+ else:
90
+ # relative pos embedding
91
+ assert feat_size is not None
92
+ feat_size = to_2tuple(feat_size)
93
+ rel_size = [2 * s - 1 for s in feat_size]
94
+ self.conv_lambda = None
95
+ self.pos_emb = nn.Parameter(torch.zeros(rel_size[0], rel_size[1], self.dim_qk))
96
+ self.register_buffer('rel_pos_indices', rel_pos_indices(feat_size), persistent=False)
97
+
98
+ self.pool = nn.AvgPool2d(2, 2) if stride == 2 else nn.Identity()
99
+
100
+ self.reset_parameters()
101
+
102
+ def reset_parameters(self):
103
+ trunc_normal_(self.qkv.weight, std=self.qkv.weight.shape[1] ** -0.5) # fan-in
104
+ if self.conv_lambda is not None:
105
+ trunc_normal_(self.conv_lambda.weight, std=self.dim_qk ** -0.5)
106
+ if self.pos_emb is not None:
107
+ trunc_normal_(self.pos_emb, std=.02)
108
+
109
+ def forward(self, x):
110
+ B, C, H, W = x.shape
111
+ M = H * W
112
+ qkv = self.qkv(x)
113
+ q, k, v = torch.split(qkv, [
114
+ self.num_heads * self.dim_qk, self.dim_qk, self.dim_v], dim=1)
115
+ q = self.norm_q(q).reshape(B, self.num_heads, self.dim_qk, M).transpose(-1, -2) # B, num_heads, M, K
116
+ v = self.norm_v(v).reshape(B, self.dim_v, M).transpose(-1, -2) # B, M, V
117
+ k = F.softmax(k.reshape(B, self.dim_qk, M), dim=-1) # B, K, M
118
+
119
+ content_lam = k @ v # B, K, V
120
+ content_out = q @ content_lam.unsqueeze(1) # B, num_heads, M, V
121
+
122
+ if self.pos_emb is None:
123
+ position_lam = self.conv_lambda(v.reshape(B, 1, H, W, self.dim_v)) # B, H, W, V, K
124
+ position_lam = position_lam.reshape(B, 1, self.dim_qk, H * W, self.dim_v).transpose(2, 3) # B, 1, M, K, V
125
+ else:
126
+ # FIXME relative pos embedding path not fully verified
127
+ pos_emb = self.pos_emb[self.rel_pos_indices[0], self.rel_pos_indices[1]].expand(B, -1, -1, -1)
128
+ position_lam = (pos_emb.transpose(-1, -2) @ v.unsqueeze(1)).unsqueeze(1) # B, 1, M, K, V
129
+ position_out = (q.unsqueeze(-2) @ position_lam).squeeze(-2) # B, num_heads, M, V
130
+
131
+ out = (content_out + position_out).transpose(-1, -2).reshape(B, C, H, W) # B, C (num_heads * V), H, W
132
+ out = self.pool(out)
133
+ return out