Commit fdeee889 authored by limm's avatar limm
Browse files

release v1.6.1 of mmcv

parent df465820
......@@ -27,25 +27,25 @@ layer = build_conv_layer(cfg, in_channels=3, out_channels=8, kernel_size=3)
1. 编写和注册自己的模块:
```python
from mmcv.cnn import UPSAMPLE_LAYERS
```python
from mmcv.cnn import UPSAMPLE_LAYERS
@UPSAMPLE_LAYERS.register_module()
class MyUpsample:
@UPSAMPLE_LAYERS.register_module()
class MyUpsample:
def __init__(self, scale_factor):
pass
def __init__(self, scale_factor):
pass
def forward(self, x):
pass
```
def forward(self, x):
pass
```
2. 在某处导入 `MyUpsample` (例如 `__init__.py` )然后使用它:
```python
cfg = dict(type='MyUpsample', scale_factor=2)
layer = build_upsample_layer(cfg)
```
```python
cfg = dict(type='MyUpsample', scale_factor=2)
layer = build_upsample_layer(cfg)
```
### 模块组件
......@@ -84,86 +84,86 @@ conv = ConvModule(
使用给定常量值初始化模型参数
```python
>>> import torch.nn as nn
>>> from mmcv.cnn import constant_init
>>> conv1 = nn.Conv2d(3, 3, 1)
>>> # constant_init(module, val, bias=0)
>>> constant_init(conv1, 1, 0)
>>> conv1.weight
```
```python
>>> import torch.nn as nn
>>> from mmcv.cnn import constant_init
>>> conv1 = nn.Conv2d(3, 3, 1)
>>> # constant_init(module, val, bias=0)
>>> constant_init(conv1, 1, 0)
>>> conv1.weight
```
- xavier_init
按照 [Understanding the difficulty of training deep feedforward neural networks - Glorot, X. & Bengio, Y. (2010)](http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf) 描述的方法初始化模型参数
按照 [Understanding the difficulty of training deep feedforward neural networks - Glorot, X. & Bengio, Y. (2010)](http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf) 描述的方法初始化模型参数
```python
>>> import torch.nn as nn
>>> from mmcv.cnn import xavier_init
>>> conv1 = nn.Conv2d(3, 3, 1)
>>> # xavier_init(module, gain=1, bias=0, distribution='normal')
>>> xavier_init(conv1, distribution='normal')
```
```python
>>> import torch.nn as nn
>>> from mmcv.cnn import xavier_init
>>> conv1 = nn.Conv2d(3, 3, 1)
>>> # xavier_init(module, gain=1, bias=0, distribution='normal')
>>> xavier_init(conv1, distribution='normal')
```
- normal_init
使用正态分布(高斯分布)初始化模型参数
```python
>>> import torch.nn as nn
>>> from mmcv.cnn import normal_init
>>> conv1 = nn.Conv2d(3, 3, 1)
>>> # normal_init(module, mean=0, std=1, bias=0)
>>> normal_init(conv1, std=0.01, bias=0)
```
```python
>>> import torch.nn as nn
>>> from mmcv.cnn import normal_init
>>> conv1 = nn.Conv2d(3, 3, 1)
>>> # normal_init(module, mean=0, std=1, bias=0)
>>> normal_init(conv1, std=0.01, bias=0)
```
- uniform_init
使用均匀分布初始化模型参数
```python
>>> import torch.nn as nn
>>> from mmcv.cnn import uniform_init
>>> conv1 = nn.Conv2d(3, 3, 1)
>>> # uniform_init(module, a=0, b=1, bias=0)
>>> uniform_init(conv1, a=0, b=1)
```
```python
>>> import torch.nn as nn
>>> from mmcv.cnn import uniform_init
>>> conv1 = nn.Conv2d(3, 3, 1)
>>> # uniform_init(module, a=0, b=1, bias=0)
>>> uniform_init(conv1, a=0, b=1)
```
- kaiming_init
按照 [Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification - He, K. et al. (2015)](https://www.cv-foundation.org/openaccess/content_iccv_2015/papers/He_Delving_Deep_into_ICCV_2015_paper.pdf) 描述的方法来初始化模型参数。
按照 [Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification - He, K. et al. (2015)](https://www.cv-foundation.org/openaccess/content_iccv_2015/papers/He_Delving_Deep_into_ICCV_2015_paper.pdf) 描述的方法来初始化模型参数。
```python
>>> import torch.nn as nn
>>> from mmcv.cnn import kaiming_init
>>> conv1 = nn.Conv2d(3, 3, 1)
>>> # kaiming_init(module, a=0, mode='fan_out', nonlinearity='relu', bias=0, distribution='normal')
>>> kaiming_init(conv1)
```
```python
>>> import torch.nn as nn
>>> from mmcv.cnn import kaiming_init
>>> conv1 = nn.Conv2d(3, 3, 1)
>>> # kaiming_init(module, a=0, mode='fan_out', nonlinearity='relu', bias=0, distribution='normal')
>>> kaiming_init(conv1)
```
- caffe2_xavier_init
caffe2中实现的 `xavier initialization`,对应于 PyTorch中的 `kaiming_uniform_`
```python
>>> import torch.nn as nn
>>> from mmcv.cnn import caffe2_xavier_init
>>> conv1 = nn.Conv2d(3, 3, 1)
>>> # caffe2_xavier_init(module, bias=0)
>>> caffe2_xavier_init(conv1)
```
```python
>>> import torch.nn as nn
>>> from mmcv.cnn import caffe2_xavier_init
>>> conv1 = nn.Conv2d(3, 3, 1)
>>> # caffe2_xavier_init(module, bias=0)
>>> caffe2_xavier_init(conv1)
```
- bias_init_with_prob
根据给定的概率初始化 `conv/fc`, 这在 [Focal Loss for Dense Object Detection](https://arxiv.org/pdf/1708.02002.pdf) 提出。
```python
>>> from mmcv.cnn import bias_init_with_prob
>>> # bias_init_with_prob is proposed in Focal Loss
>>> bias = bias_init_with_prob(0.01)
>>> bias
-4.59511985013459
```
```python
>>> from mmcv.cnn import bias_init_with_prob
>>> # bias_init_with_prob is proposed in Focal Loss
>>> bias = bias_init_with_prob(0.01)
>>> bias
-4.59511985013459
```
#### Initializers and configs
......@@ -183,9 +183,9 @@ conv = ConvModule(
1. 通过关键字 `layer` 来初始化模型
如果我们只定义了关键字 `layer` ,那么只初始化 `layer` 中包含的层。
如果我们只定义了关键字 `layer` ,那么只初始化 `layer` 中包含的层。
注意: 关键字 `layer` 支持的模块是带有 weights 和 bias 属性的 PyTorch 模块,所以不支持 `MultiheadAttention layer`
注意: 关键字 `layer` 支持的模块是带有 weights 和 bias 属性的 PyTorch 模块,所以不支持 `MultiheadAttention layer`
- 定义关键字 `layer` 列表并使用相同相同配置初始化模块
......@@ -247,243 +247,288 @@ conv = ConvModule(
- 当用属性名初始化某个特定部分时, 我们可以使用关键字 `override`, 关键字 `override` 对应的Value会替代init_cfg中相应的值
```python
import torch.nn as nn
from mmcv.cnn import initialize
class FooNet(nn.Module):
def __init__(self):
super().__init__()
self.feat = nn.Conv1d(3, 1, 3)
self.reg = nn.Conv2d(3, 3, 3)
self.cls = nn.Sequential(nn.Conv1d(3, 1, 3), nn.Linear(1,2))
# 如果我们想将模型的权重初始化为 1,将偏差初始化为 2
# 但希望 `cls` 中的权重为 3,偏差为 4,则我们可以使用关键字override
model = FooNet()
init_cfg = dict(type='Constant', layer=['Conv1d','Conv2d'], val=1, bias=2,
override=dict(type='Constant', name='reg', val=3, bias=4))
# 使用 dict(type='Constant', val=1, bias=2)来初始化 self.feat and self.cls
# 使用dict(type='Constant', val=3, bias=4)来初始化‘reg’模块。
initialize(model, init_cfg)
# model.reg.weight
# Parameter containing:
# tensor([[[[3., 3., 3.],
# [3., 3., 3.],
# [3., 3., 3.]],
# ...,
# [[3., 3., 3.],
# [3., 3., 3.],
# [3., 3., 3.]]]], requires_grad=True)
```
```python
import torch.nn as nn
from mmcv.cnn import initialize
class FooNet(nn.Module):
def __init__(self):
super().__init__()
self.feat = nn.Conv1d(3, 1, 3)
self.reg = nn.Conv2d(3, 3, 3)
self.cls = nn.Sequential(nn.Conv1d(3, 1, 3), nn.Linear(1,2))
# 如果我们想将模型的权重初始化为 1,将偏差初始化为 2
# 但希望 `reg` 中的权重为 3,偏差为 4,则我们可以使用关键字override
model = FooNet()
init_cfg = dict(type='Constant', layer=['Conv1d','Conv2d'], val=1, bias=2,
override=dict(type='Constant', name='reg', val=3, bias=4))
# 使用 dict(type='Constant', val=1, bias=2)来初始化 self.feat and self.cls
# 使用dict(type='Constant', val=3, bias=4)来初始化‘reg’模块。
initialize(model, init_cfg)
# model.reg.weight
# Parameter containing:
# tensor([[[[3., 3., 3.],
# [3., 3., 3.],
# [3., 3., 3.]],
# ...,
# [[3., 3., 3.],
# [3., 3., 3.],
# [3., 3., 3.]]]], requires_grad=True)
```
- 如果 init_cfg 中的关键字`layer`为None,则只初始化在关键字override中的子模块,并且省略override中的 type 和其他参数
```python
model = FooNet()
init_cfg = dict(type='Constant', val=1, bias=2, override=dict(name='reg'))
# self.feat 和 self.cls 使用pyTorch默认的初始化
# 将使用 dict(type='Constant', val=1, bias=2) 初始化名为 'reg' 的模块
initialize(model, init_cfg)
# model.reg.weight
# Parameter containing:
# tensor([[[[1., 1., 1.],
# [1., 1., 1.],
# [1., 1., 1.]],
# ...,
# [[1., 1., 1.],
# [1., 1., 1.],
# [1., 1., 1.]]]], requires_grad=True)
```
```python
model = FooNet()
init_cfg = dict(type='Constant', val=1, bias=2, override=dict(name='reg'))
# self.feat 和 self.cls 使用pyTorch默认的初始化
# 将使用 dict(type='Constant', val=1, bias=2) 初始化名为 'reg' 的模块
initialize(model, init_cfg)
# model.reg.weight
# Parameter containing:
# tensor([[[[1., 1., 1.],
# [1., 1., 1.],
# [1., 1., 1.]],
# ...,
# [[1., 1., 1.],
# [1., 1., 1.],
# [1., 1., 1.]]]], requires_grad=True)
```
- 如果我们没有定义关键字`layer``override` , 将不会初始化任何东西
- 关键字`override`的无效用法
```python
# 没有重写任何子模块
init_cfg = dict(type='Constant', layer=['Conv1d','Conv2d'],
val=1, bias=2,
override=dict(type='Constant', val=3, bias=4))
# 没有指定type,即便有其他参数,也是无效的。
init_cfg = dict(type='Constant', layer=['Conv1d','Conv2d'],
val=1, bias=2,
override=dict(name='reg', val=3, bias=4))
```
3. 用预训练模型初始化
```python
# 没有重写任何子模块
init_cfg = dict(type='Constant', layer=['Conv1d','Conv2d'],
val=1, bias=2,
override=dict(type='Constant', val=3, bias=4))
# 没有指定type,即便有其他参数,也是无效的。
init_cfg = dict(type='Constant', layer=['Conv1d','Conv2d'],
val=1, bias=2,
override=dict(name='reg', val=3, bias=4))
import torch.nn as nn
import torchvision.models as models
from mmcv.cnn import initialize
# 使用预训练模型来初始化
model = models.resnet50()
# model.conv1.weight
# Parameter containing:
# tensor([[[[-6.7435e-03, -2.3531e-02, -9.0143e-03, ..., -2.1245e-03,
# -1.8077e-03, 3.0338e-03],
# [-1.2603e-02, -2.7831e-02, 2.3187e-02, ..., -1.5793e-02,
# 1.1655e-02, 4.5889e-03],
# [-3.7916e-02, 1.2014e-02, 1.3815e-02, ..., -4.2651e-03,
# 1.7314e-02, -9.9998e-03],
# ...,
init_cfg = dict(type='Pretrained',
checkpoint='torchvision://resnet50')
initialize(model, init_cfg)
# model.conv1.weight
# Parameter containing:
# tensor([[[[ 1.3335e-02, 1.4664e-02, -1.5351e-02, ..., -4.0896e-02,
# -4.3034e-02, -7.0755e-02],
# [ 4.1205e-03, 5.8477e-03, 1.4948e-02, ..., 2.2060e-03,
# -2.0912e-02, -3.8517e-02],
# [ 2.2331e-02, 2.3595e-02, 1.6120e-02, ..., 1.0281e-01,
# 6.2641e-02, 5.1977e-02],
# ...,
# 使用关键字'prefix'用预训练模型的特定部分来初始化子模块权重
model = models.resnet50()
url = 'http://download.openmmlab.com/mmdetection/v2.0/retinanet/'\
'retinanet_r50_fpn_1x_coco/'\
'retinanet_r50_fpn_1x_coco_20200130-c2398f9e.pth'
init_cfg = dict(type='Pretrained',
checkpoint=url, prefix='backbone.')
initialize(model, init_cfg)
```
3. 用预训练模型初始化
4. 初始化继承自BaseModule、Sequential、ModuleList、ModuleDict的模型
```python
import torch.nn as nn
import torchvision.models as models
from mmcv.cnn import initialize
# 使用预训练模型来初始化
model = models.resnet50()
# model.conv1.weight
# Parameter containing:
# tensor([[[[-6.7435e-03, -2.3531e-02, -9.0143e-03, ..., -2.1245e-03,
# -1.8077e-03, 3.0338e-03],
# [-1.2603e-02, -2.7831e-02, 2.3187e-02, ..., -1.5793e-02,
# 1.1655e-02, 4.5889e-03],
# [-3.7916e-02, 1.2014e-02, 1.3815e-02, ..., -4.2651e-03,
# 1.7314e-02, -9.9998e-03],
# ...,
init_cfg = dict(type='Pretrained',
checkpoint='torchvision://resnet50')
initialize(model, init_cfg)
# model.conv1.weight
# Parameter containing:
# tensor([[[[ 1.3335e-02, 1.4664e-02, -1.5351e-02, ..., -4.0896e-02,
# -4.3034e-02, -7.0755e-02],
# [ 4.1205e-03, 5.8477e-03, 1.4948e-02, ..., 2.2060e-03,
# -2.0912e-02, -3.8517e-02],
# [ 2.2331e-02, 2.3595e-02, 1.6120e-02, ..., 1.0281e-01,
# 6.2641e-02, 5.1977e-02],
# ...,
# 使用关键字'prefix'用预训练模型的特定部分来初始化子模块权重
model = models.resnet50()
url = 'http://download.openmmlab.com/mmdetection/v2.0/retinanet/'\
'retinanet_r50_fpn_1x_coco/'\
'retinanet_r50_fpn_1x_coco_20200130-c2398f9e.pth'
init_cfg = dict(type='Pretrained',
checkpoint=url, prefix='backbone.')
initialize(model, init_cfg)
```
4. 初始化继承自BaseModule、Sequential、ModuleList的模型
`BaseModule` 继承自 `torch.nn.Module`, 它们之间唯一的不同是 `BaseModule` 实现了 `init_weight`
`Sequential` 继承自 `BaseModule` 和 `torch.nn.Sequential`
`ModuleList` 继承自 `BaseModule` 和 `torch.nn.ModuleList`
`````python
import torch.nn as nn
from mmcv.runner import BaseModule, Sequential, ModuleList
class FooConv1d(BaseModule):
def __init__(self, init_cfg=None):
super().__init__(init_cfg)
self.conv1d = nn.Conv1d(4, 1, 4)
def forward(self, x):
return self.conv1d(x)
class FooConv2d(BaseModule):
def __init__(self, init_cfg=None):
super().__init__(init_cfg)
self.conv2d = nn.Conv2d(3, 1, 3)
def forward(self, x):
return self.conv2d(x)
# BaseModule
init_cfg = dict(type='Constant', layer='Conv1d', val=0., bias=1.)
model = FooConv1d(init_cfg)
model.init_weights()
# model.conv1d.weight
# Parameter containing:
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]], requires_grad=True)
# Sequential
init_cfg1 = dict(type='Constant', layer='Conv1d', val=0., bias=1.)
init_cfg2 = dict(type='Constant', layer='Conv2d', val=2., bias=3.)
model1 = FooConv1d(init_cfg1)
model2 = FooConv2d(init_cfg2)
seq_model = Sequential(model1, model2)
seq_model.init_weights()
# seq_model[0].conv1d.weight
# Parameter containing:
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]], requires_grad=True)
# seq_model[1].conv2d.weight
# Parameter containing:
# tensor([[[[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]],
# ...,
# [[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]]]], requires_grad=True)
# inner init_cfg has higher priority
model1 = FooConv1d(init_cfg1)
model2 = FooConv2d(init_cfg2)
init_cfg = dict(type='Constant', layer=['Conv1d', 'Conv2d'], val=4., bias=5.)
seq_model = Sequential(model1, model2, init_cfg=init_cfg)
seq_model.init_weights()
# seq_model[0].conv1d.weight
# Parameter containing:
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]], requires_grad=True)
# seq_model[1].conv2d.weight
# Parameter containing:
# tensor([[[[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]],
# ...,
# [[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]]]], requires_grad=True)
# ModuleList
model1 = FooConv1d(init_cfg1)
model2 = FooConv2d(init_cfg2)
modellist = ModuleList([model1, model2])
modellist.init_weights()
# modellist[0].conv1d.weight
# Parameter containing:
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]], requires_grad=True)
# modellist[1].conv2d.weight
# Parameter containing:
# tensor([[[[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]],
# ...,
# [[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]]]], requires_grad=True)
# inner init_cfg has higher priority
model1 = FooConv1d(init_cfg1)
model2 = FooConv2d(init_cfg2)
init_cfg = dict(type='Constant', layer=['Conv1d', 'Conv2d'], val=4., bias=5.)
modellist = ModuleList([model1, model2], init_cfg=init_cfg)
modellist.init_weights()
# modellist[0].conv1d.weight
# Parameter containing:
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]], requires_grad=True)
# modellist[1].conv2d.weight
# Parameter containing:
# tensor([[[[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]],
# ...,
# [[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]]]], requires_grad=True)
`````
`BaseModule` 继承自 `torch.nn.Module`, 它们之间唯一的不同是 `BaseModule` 实现了 `init_weight`
`Sequential` 继承自 `BaseModule``torch.nn.Sequential`
`ModuleList` 继承自 `BaseModule``torch.nn.ModuleList`
`ModuleDict` 继承自 `BaseModule``torch.nn.ModuleDict`
```python
import torch.nn as nn
from mmcv.runner import BaseModule, Sequential, ModuleList, ModuleDict
class FooConv1d(BaseModule):
def __init__(self, init_cfg=None):
super().__init__(init_cfg)
self.conv1d = nn.Conv1d(4, 1, 4)
def forward(self, x):
return self.conv1d(x)
class FooConv2d(BaseModule):
def __init__(self, init_cfg=None):
super().__init__(init_cfg)
self.conv2d = nn.Conv2d(3, 1, 3)
def forward(self, x):
return self.conv2d(x)
# BaseModule
init_cfg = dict(type='Constant', layer='Conv1d', val=0., bias=1.)
model = FooConv1d(init_cfg)
model.init_weights()
# model.conv1d.weight
# Parameter containing:
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]], requires_grad=True)
# Sequential
init_cfg1 = dict(type='Constant', layer='Conv1d', val=0., bias=1.)
init_cfg2 = dict(type='Constant', layer='Conv2d', val=2., bias=3.)
model1 = FooConv1d(init_cfg1)
model2 = FooConv2d(init_cfg2)
seq_model = Sequential(model1, model2)
seq_model.init_weights()
# seq_model[0].conv1d.weight
# Parameter containing:
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]], requires_grad=True)
# seq_model[1].conv2d.weight
# Parameter containing:
# tensor([[[[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]],
# ...,
# [[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]]]], requires_grad=True)
# inner init_cfg has higher priority
model1 = FooConv1d(init_cfg1)
model2 = FooConv2d(init_cfg2)
init_cfg = dict(type='Constant', layer=['Conv1d', 'Conv2d'], val=4., bias=5.)
seq_model = Sequential(model1, model2, init_cfg=init_cfg)
seq_model.init_weights()
# seq_model[0].conv1d.weight
# Parameter containing:
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]], requires_grad=True)
# seq_model[1].conv2d.weight
# Parameter containing:
# tensor([[[[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]],
# ...,
# [[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]]]], requires_grad=True)
# ModuleList
model1 = FooConv1d(init_cfg1)
model2 = FooConv2d(init_cfg2)
modellist = ModuleList([model1, model2])
modellist.init_weights()
# modellist[0].conv1d.weight
# Parameter containing:
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]], requires_grad=True)
# modellist[1].conv2d.weight
# Parameter containing:
# tensor([[[[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]],
# ...,
# [[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]]]], requires_grad=True)
# inner init_cfg has higher priority
model1 = FooConv1d(init_cfg1)
model2 = FooConv2d(init_cfg2)
init_cfg = dict(type='Constant', layer=['Conv1d', 'Conv2d'], val=4., bias=5.)
modellist = ModuleList([model1, model2], init_cfg=init_cfg)
modellist.init_weights()
# modellist[0].conv1d.weight
# Parameter containing:
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]], requires_grad=True)
# modellist[1].conv2d.weight
# Parameter containing:
# tensor([[[[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]],
# ...,
# [[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]]]], requires_grad=True)
# ModuleDict
model1 = FooConv1d(init_cfg1)
model2 = FooConv2d(init_cfg2)
modeldict = ModuleDict(dict(model1=model1, model2=model2))
modeldict.init_weights()
# modeldict['model1'].conv1d.weight
# Parameter containing:
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]], requires_grad=True)
# modeldict['model2'].conv2d.weight
# Parameter containing:
# tensor([[[[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]],
# ...,
# [[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]]]], requires_grad=True)
# inner init_cfg has higher priority
model1 = FooConv1d(init_cfg1)
model2 = FooConv2d(init_cfg2)
init_cfg = dict(type='Constant', layer=['Conv1d', 'Conv2d'], val=4., bias=5.)
modeldict = ModuleDict(dict(model1=model1, model2=model2), init_cfg=init_cfg)
modeldict.init_weights()
# modeldict['model1'].conv1d.weight
# Parameter containing:
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]], requires_grad=True)
# modeldict['model2'].conv2d.weight
# Parameter containing:
# tensor([[[[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]],
# ...,
# [[2., 2., 2.],
# [2., 2., 2.],
# [2., 2., 2.]]]], requires_grad=True)
```
### Model Zoo
......
......@@ -40,6 +40,7 @@ d = 'string'
这里是一个带有预定义变量的配置文件的例子。
`config_a.py`
```python
a = 1
b = './work_dir/{{ fileBasenameNoExtension }}'
......@@ -65,6 +66,7 @@ c = '{{ fileExtname }}'
a = 1
b = dict(b1=[0, 1, 2], b2=None)
```
### 不含重复键值对从基类配置文件继承
`config_b.py`
......@@ -83,6 +85,7 @@ d = 'string'
... c=(1, 2),
... d='string')
```
`config_b.py`里的新字段与在`config_a.py`里的旧字段拼接
### 含重复键值对从基类配置文件继承
......
......@@ -252,9 +252,9 @@ flow = mmcv.flowread('compressed.jpg', quantize=True, concat_axis=1)
mmcv.flowshow(flow)
```
![progress](../../docs/_static/flow_visualization.png)
![progress](../../en/_static/flow_visualization.png)
3. 流变换
1. 流变换
```python
img1 = mmcv.imread('img1.jpg')
......@@ -264,12 +264,12 @@ warpped_img2 = mmcv.flow_warp(img1, flow)
img1 (左) and img2 (右)
![raw images](../../docs/_static/flow_raw_images.png)
![raw images](../../en/_static/flow_raw_images.png)
光流 (img2 -> img1)
![optical flow](../../docs/_static/flow_img2toimg1.png)
![optical flow](../../en/_static/flow_img2toimg1.png)
变换后的图像和真实图像的差异
![warpped image](../../docs/_static/flow_warp_diff.png)
![warpped image](../../en/_static/flow_warp_diff.png)
......@@ -107,6 +107,7 @@ c
d
e
```
#### 从硬盘读取
使用 `list_from_file` 读取 `a.txt`
......
## 算子
MMCV 提供了检测、分割等任务中常用的算子
| Device | CPU | CUDA | MLU | MPS |
| ---------------------------- | --- | ---- | --- | --- |
| ActiveRotatedFilter | √ | √ | | |
| AssignScoreWithK | | √ | | |
| BallQuery | | √ | | |
| BBoxOverlaps | | √ | √ | √ |
| BorderAlign | | √ | | |
| BoxIouRotated | √ | √ | | |
| CARAFE | | √ | | |
| ChamferDistance | | √ | | |
| CrissCrossAttention | | √ | | |
| ContourExpand | √ | | | |
| ConvexIoU | | √ | | |
| CornerPool | | √ | | |
| Correlation | | √ | | |
| Deformable Convolution v1/v2 | √ | √ | | |
| Deformable RoIPool | | √ | | |
| DiffIoURotated | | √ | | |
| DynamicScatter | | √ | | |
| FurthestPointSample | | √ | | |
| FurthestPointSampleWithDist | | √ | | |
| FusedBiasLeakyrelu | | √ | | |
| GatherPoints | | √ | | |
| GroupPoints | | √ | | |
| Iou3d | | √ | | |
| KNN | | √ | | |
| MaskedConv | | √ | | |
| MergeCells | | √ | | |
| MinAreaPolygon | | √ | | |
| ModulatedDeformConv2d | √ | √ | | |
| MultiScaleDeformableAttn | | √ | | |
| NMS | √ | √ | √ | |
| NMSRotated | √ | √ | | |
| PixelGroup | √ | | | |
| PointsInBoxes | √ | √ | | |
| PointsInPolygons | | √ | | |
| PSAMask | √ | √ | √ | |
| RotatedFeatureAlign | √ | √ | | |
| RoIPointPool3d | | √ | | |
| RoIPool | | √ | √ | |
| RoIAlignRotated | √ | √ | √ | |
| RiRoIAlignRotated | | √ | | |
| RoIAlign | √ | √ | √ | |
| RoIAwarePool3d | | √ | | |
| SAConv2d | | √ | | |
| SigmoidFocalLoss | | √ | √ | |
| SoftmaxFocalLoss | | √ | | |
| SoftNMS | | √ | | |
| Sparse Convolution | | √ | | |
| Synchronized BatchNorm | | √ | | |
| ThreeInterpolate | | √ | | |
| ThreeNN | | √ | | |
| TINShift | | √ | √ | |
| UpFirDn2d | | √ | | |
| Voxelization | √ | √ | | |
| PrRoIPool | | √ | | |
## 注册器
MMCV 使用 [注册器](https://github.com/open-mmlab/mmcv/blob/master/mmcv/utils/registry.py) 来管理具有相似功能的不同模块, 例如, 检测器中的主干网络、头部、和模型颈部。
在 OpenMMLab 家族中的绝大部分开源项目使用注册器去管理数据集和模型的模块,例如 [MMDetection](https://github.com/open-mmlab/mmdetection), [MMDetection3D](https://github.com/open-mmlab/mmdetection3d), [MMClassification](https://github.com/open-mmlab/mmclassification), [MMEditing](https://github.com/open-mmlab/mmediting) 等。
```{note}
在 v1.5.1 版本开始支持注册函数的功能。
```
### 什么是注册器
在MMCV中,注册器可以看作类到字符串的映射。
一个注册器中的类通常有相似的接口,但是可以实现不同的算法或支持不同的数据集。
借助注册器,用户可以通过使用相应的字符串查找并实例化该类,并根据他们的需要实例化对应模块。
在MMCV中,注册器可以看作类或函数到字符串的映射。
一个注册器中的类或函数通常有相似的接口,但是可以实现不同的算法或支持不同的数据集。
借助注册器,用户可以通过使用相应的字符串查找类或函数,并根据他们的需要实例化对应模块或调用函数获取结果。
一个典型的案例是,OpenMMLab 中的大部分开源项目的配置系统,这些系统通过配置文件来使用注册器创建钩子、执行器、模型和数据集。
可以在[这里](https://mmcv.readthedocs.io/en/latest/api.html?highlight=registry#mmcv.utils.Registry)找到注册器接口使用文档。
......@@ -15,7 +21,7 @@ MMCV 使用 [注册器](https://github.com/open-mmlab/mmcv/blob/master/mmcv/util
2. 创建注册器
3. 使用此注册器来管理模块
`Registry`(注册器)的参数 `build_func`(构建函数) 用来自定如何实例化类的实例,默认使用 [这里](https://mmcv.readthedocs.io/en/latest/api.html?highlight=registry#mmcv.utils.build_from_cfg)实现的`build_from_cfg`
`Registry`(注册器)的参数 `build_func`(构建函数) 用来自定如何实例化类的实例或如何调用函数获取结果,默认使用 [这里](https://mmcv.readthedocs.io/en/latest/api.html?highlight=registry#mmcv.utils.build_from_cfg) 实现的`build_from_cfg`
### 一个简单的例子
......@@ -29,9 +35,10 @@ from mmcv.utils import Registry
CONVERTERS = Registry('converter')
```
然后我们在包中可以实现不同的转换器(converter)。例如,在 `converters/converter1.py` 中实现 `Converter1`
然后我们在包中可以实现不同的转换器(converter),其可以为类或函数。例如,在 `converters/converter1.py` 中实现 `Converter1`,在 `converters/converter2.py` 中实现 `converter2`
```python
# converter1.py
from .builder import CONVERTERS
# 使用注册器管理模块
......@@ -41,19 +48,39 @@ class Converter1(object):
self.a = a
self.b = b
```
使用注册器管理模块的关键步骤是,将实现的模块注册到注册表 `CONVERTERS` 中。通过 `@CONVERTERS.register_module()` 装饰所实现的模块,字符串和类之间的映射就可以由 `CONVERTERS` 构建和维护,如下所示:
通过这种方式,就可以通过 `CONVERTERS` 建立字符串与类之间的映射,如下所示:
```python
# converter2.py
from .builder import CONVERTERS
from .converter1 import Converter1
# 使用注册器管理模块
@CONVERTERS.register_module()
def converter2(a, b)
return Converter1(a, b)
```
使用注册器管理模块的关键步骤是,将实现的模块注册到注册表 `CONVERTERS` 中。通过 `@CONVERTERS.register_module()` 装饰所实现的模块,字符串到类或函数之间的映射就可以由 `CONVERTERS` 构建和维护,如下所示:
通过这种方式,就可以通过 `CONVERTERS` 建立字符串与类或函数之间的映射,如下所示:
```python
'Converter1' -> <class 'Converter1'>
'converter2' -> <function 'converter2'>
```
```{note}
只有模块所在的文件被导入时,注册机制才会被触发,所以您需要在某处导入该文件。更多详情请查看 https://github.com/open-mmlab/mmdetection/issues/5974。
```
如果模块被成功注册了,你可以通过配置文件使用这个转换器(converter),如下所示:
```python
converter_cfg = dict(type='Converter1', a=a_value, b=b_value)
converter = CONVERTERS.build(converter_cfg)
converter1_cfg = dict(type='Converter1', a=a_value, b=b_value)
converter2_cfg = dict(type='converter2', a=a_value, b=b_value)
converter1 = CONVERTERS.build(converter1_cfg)
# returns the calling result
result = CONVERTERS.build(converter2_cfg)
```
### 自定义构建函数
......@@ -84,7 +111,7 @@ CONVERTERS = Registry('converter', build_func=build_converter)
该功能类似于默认的`build_from_cfg`。在大多数情况下,默认就足够了。
```
`build_model_from_cfg`也实现了在`nn.Sequentail`中构建PyTorch模块,你可以直接使用它们。
`build_model_from_cfg`也实现了在`nn.Sequential`中构建PyTorch模块,你可以直接使用它们。
### 注册器层结构
......
......@@ -8,7 +8,7 @@
### EpochBasedRunner
顾名思义,`EpochBasedRunner` 是指以 epoch 为周期的工作流,例如设置 workflow = [('train', 2), ('val', 1)] 表示循环迭代地训练 2 个 epoch,然后验证 1 个 epoch。MMDetection 目标检测框架默认采用的是 `EpochBasedRunner`
顾名思义,`EpochBasedRunner` 是指以 epoch 为周期的工作流,例如设置 workflow = \[('train', 2), ('val', 1)\] 表示循环迭代地训练 2 个 epoch,然后验证 1 个 epoch。MMDetection 目标检测框架默认采用的是 `EpochBasedRunner`
其抽象逻辑如下所示:
......@@ -25,6 +25,7 @@ while curr_epoch < max_epochs:
for _ in range(epochs):
epoch_runner(data_loaders[i], **kwargs)
```
目前支持训练和验证两个工作流,以训练函数为例,其抽象逻辑是:
```python
......@@ -40,7 +41,8 @@ def train(self, data_loader, **kwargs):
```
### IterBasedRunner
不同于 `EpochBasedRunner``IterBasedRunner` 是指以 iter 为周期的工作流,例如设置 workflow = [('train', 2), ('val', 1)] 表示循环迭代的训练 2 个 iter,然后验证 1 个 iter,MMSegmentation 语义分割框架默认采用的是 `EpochBasedRunner`
不同于 `EpochBasedRunner``IterBasedRunner` 是指以 iter 为周期的工作流,例如设置 workflow = \[('train', 2), ('val', 1)\] 表示循环迭代的训练 2 个 iter,然后验证 1 个 iter,MMSegmentation 语义分割框架默认采用的是 `IterBasedRunner`
其抽象逻辑如下所示:
......@@ -59,6 +61,7 @@ while curr_iter < max_iters:
for _ in range(iters):
iter_runner(iter_loaders[i], **kwargs)
```
目前支持训练和验证两个工作流,以验证函数为例,其抽象逻辑是:
```python
......@@ -75,6 +78,7 @@ def val(self, data_loader, **kwargs):
除了上述基础功能外,`EpochBasedRunner``IterBasedRunner` 还提供了 resume 、 save_checkpoint 和注册 hook 功能。
### 一个简单例子
以最常用的分类任务为例详细说明 `runner` 的使用方法。 开启任何一个训练任务,都需要包括如下步骤:
**(1) dataloader、model 和优化器等类初始化**
......@@ -148,8 +152,8 @@ runner.run(data_loaders, cfg.workflow)
关于 workflow 设置,以 `EpochBasedRunner` 为例,详情如下:
- 假设只想运行训练工作流,则可以设置 workflow = [('train', 1)],表示只进行迭代训练
- 假设想运行训练和验证工作流,则可以设置 workflow = [('train', 3), ('val', 1)],表示先训练 3 个 epoch ,然后切换到 val 工作流,运行 1 个 epoch,然后循环,直到训练 epoch 次数达到指定值
- 工作流设置还自由定制,例如你可以先验证再训练 workflow = [('val', 1), ('train', 1)]
- 假设只想运行训练工作流,则可以设置 workflow = \[('train', 1)\],表示只进行迭代训练
- 假设想运行训练和验证工作流,则可以设置 workflow = \[('train', 3), ('val', 1)\],表示先训练 3 个 epoch ,然后切换到 val 工作流,运行 1 个 epoch,然后循环,直到训练 epoch 次数达到指定值
- 工作流设置还自由定制,例如你可以先验证再训练 workflow = \[('val', 1), ('train', 1)\]
上述代码都已经封装到了各个代码库的 train.py 中,用户只需要设置相应的配置即可,上述流程会自动运行。
......@@ -17,7 +17,7 @@ mmcv.track_progress(func, tasks)
```
效果如下
![progress](../../docs/_static/progress.*)
![progress](../../en/_static/progress.*)
如果你想可视化多进程任务的进度,你可以使用 `track_parallel_progress`
......@@ -25,7 +25,7 @@ mmcv.track_progress(func, tasks)
mmcv.track_parallel_progress(func, tasks, 8) # 8 workers
```
![progress](../../docs/_static/parallel_progress.*)
![progress](../../_static/parallel_progress.*)
如果你想要迭代或枚举数据列表并可视化进度,你可以使用 `track_iter_progress`
......@@ -58,7 +58,6 @@ with mmcv.Timer():
你也可以使用 `since_start()``since_last_check()` 。前者返回计时器启动后的运行时长,后者返回最近一次查看计时器后的运行时长。
```python
timer = mmcv.Timer()
# code block 1 here
......
## 拉取请求
### 什么是拉取请求?
`拉取请求` (Pull Request), [GitHub 官方文档](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests)定义如下。
>拉取请求是一种通知机制。你修改了他人的代码,将你的修改通知原来作者,希望他合并你的修改。
### 基本的工作流:
1. 获取最新的代码库
2. 从主分支创建最新的分支进行开发
3. 提交修改
4. 推送你的修改并创建一个`拉取请求`
5. 讨论、审核代码
6. 将开发分支合并到主分支
### 具体步骤
1. 获取最新的代码库
+ 当你第一次提 PR 时
- 复刻 OpenMMLab 原代码库,点击 GitHub 页面右上角的 **Fork** 按钮即可
![avatar](../../docs/_static/community/1.png)
- 克隆复刻的代码库到本地
```bash
git clone git@github.com:XXX/mmcv.git
```
- 添加原代码库为上游代码库
```bash
git remote add upstream git@github.com:open-mmlab/mmcv
```
+ 从第二个 PR 起
- 检出本地代码库的主分支,然后从最新的原代码库的主分支拉取更新
```bash
git checkout master
git pull upstream master
```
2. 从主分支创建一个新的开发分支
```bash
git checkout -b branchname
```
注意:为了保证提交历史清晰可读,我们强烈推荐您先检出主分支 (master),再创建新的分支。
3. 提交你的修改
```bash
# coding
git add [files]
git commit -m 'messages'
```
4. 推送你的修改到复刻的代码库,并创建一个`拉取请求`
+ 推送当前分支到远端复刻的代码库
```bash
git push origin branchname
```
+ 创建一个`拉取请求`
![avatar](../../docs/_static/community/2.png)
+ 修改`拉取请求`信息模板,描述修改原因和修改内容。还可以在 PR 描述中,手动关联到相关的`议题` (issue),(更多细节,请参考[官方文档](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue))。
5. 讨论并评审你的代码
+ 创建`拉取请求`时,可以关联给相关人员进行评审
![avatar](../../docs/_static/community/3.png)
+ 根据评审人员的意见修改代码,并推送修改
6. `拉取请求`合并之后删除该分支
```bash
git branch -d branchname # delete local branch
git push origin --delete branchname # delete remote branch
```
### PR 规范
1. 使用 [pre-commit hook](https://pre-commit.com),尽量减少代码风格相关问题
2. 一个PR对应一个短期分支
3. 粒度要细,一个PR只做一件事情,避免超大的PR
>- Bad:实现Faster R-CNN
>- Acceptable:给 Faster R-CNN 添加一个 box head
>- Good:给 box head 增加一个参数来支持自定义的 conv 层数
4. 每次 Commit 时需要提供清晰且有意义 commit 信息
5. 提供清晰且有意义的`拉取请求`描述
>- 标题写明白任务名称,一般格式:[Prefix] Short description of the pull request (Suffix)
>- prefix: 新增功能 [Feature], 修 bug [Fix], 文档相关 [Docs], 开发中 [WIP] (暂时不会被review)
>- 描述里介绍`拉取请求`的主要修改内容,结果,以及对其他部分的影响, 参考`拉取请求`模板
>- 关联相关的`议题` (issue) 和其他`拉取请求`
## 常见问题
在这里我们列出了用户经常遇到的问题以及对应的解决方法。如果您遇到了其他常见的问题,并且知道可以帮到大家的解决办法,
欢迎随时丰富这个列表。
- MMCV 和 MMDetection 的兼容性问题;"ConvWS is already registered in conv layer"
请按照上述说明为您的 MMDetection 版本安装正确版本的 MMCV。
- "No module named 'mmcv.ops'"; "No module named 'mmcv._ext'"
1. 使用 `pip uninstall mmcv` 卸载您环境中的 mmcv
2. 按照上述说明安装 mmcv-full
- "invalid device function" 或者 "no kernel image is available for execution"
1. 检查 GPU 的 CUDA 计算能力
2. 运行 `python mmdet/utils/collect_env.py` 来检查 PyTorch、torchvision 和 MMCV 是否是针对正确的 GPU 架构构建的
您可能需要去设置 `TORCH_CUDA_ARCH_LIST` 来重新安装 MMCV
兼容性问题的可能会出现在使用旧版的 GPUs,如:colab 上的 Tesla K80 (3.7)
3. 检查运行环境是否和 mmcv/mmdet 编译时的环境相同。例如,您可能使用 CUDA 10.0 编译 mmcv,但在 CUDA 9.0 的环境中运行它
- "undefined symbol" 或者 "cannot open xxx.so"。
1. 如果符号和 CUDA/C++ 相关(例如:libcudart.so 或者 GLIBCXX),请检查 CUDA/GCC 运行时的版本是否和编译 mmcv 的一致
2. 如果符号和 PyTorch 相关(例如:符号包含 caffe、aten 和 TH),请检查 PyTorch 运行时的版本是否和编译 mmcv 的一致
3. 运行 `python mmdet/utils/collect_env.py` 以检查 PyTorch、torchvision 和 MMCV 构建和运行的环境是否相同
- "RuntimeError: CUDA error: invalid configuration argument"。
这个错误可能是由于您的 GPU 性能不佳造成的。尝试降低[THREADS_PER_BLOCK](https://github.com/open-mmlab/mmcv/blob/cac22f8cf5a904477e3b5461b1cc36856c2793da/mmcv/ops/csrc/common_cuda_helper.hpp#L10)
的值并重新编译 mmcv。
- "RuntimeError: nms is not compiled with GPU support"。
这个错误是由于您的 CUDA 环境没有正确安装。
您可以尝试重新安装您的 CUDA 环境,然后删除 mmcv/build 文件夹并重新编译 mmcv。
## CUDA 算子
MMCV 提供了检测、分割等任务中常用的 CUDA 算子
- AssignScoreWithK
- BallQuery
- BBoxOverlaps
- CARAFE
- CrissCrossAttention
- ContextBlock
- CornerPool
- Deformable Convolution v1/v2
- Deformable RoIPool
- DynamicScatter
- GatherPoints
- FurthestPointSample
- FurthestPointSampleWithDist
- GeneralizedAttention
- KNN
- MaskedConv
- NMS
- PSAMask
- RoIPointPool3d
- RoIPool
- RoIAlign
- RoIAwarePool3d
- SimpleRoIAlign
- SigmoidFocalLoss
- SoftmaxFocalLoss
- SoftNMS
- Synchronized BatchNorm
- Voxelization
- ThreeInterpolate
- ThreeNN
- Weight standardization
- Correlation
......@@ -14,7 +14,7 @@ from mmcv.utils import get_logger
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
super().__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
......
......@@ -13,3 +13,4 @@ from .visualization import *
# - runner
# - parallel
# - op
# - device
# Copyright (c) OpenMMLab. All rights reserved.
from typing import Union
import numpy as np
def quantize(arr, min_val, max_val, levels, dtype=np.int64):
def quantize(arr: np.ndarray,
min_val: Union[int, float],
max_val: Union[int, float],
levels: int,
dtype=np.int64) -> tuple:
"""Quantize an array of (-inf, inf) to [0, levels-1].
Args:
arr (ndarray): Input array.
min_val (scalar): Minimum value to be clipped.
max_val (scalar): Maximum value to be clipped.
min_val (int or float): Minimum value to be clipped.
max_val (int or float): Maximum value to be clipped.
levels (int): Quantization levels.
dtype (np.type): The type of the quantized array.
......@@ -29,13 +35,17 @@ def quantize(arr, min_val, max_val, levels, dtype=np.int64):
return quantized_arr
def dequantize(arr, min_val, max_val, levels, dtype=np.float64):
def dequantize(arr: np.ndarray,
min_val: Union[int, float],
max_val: Union[int, float],
levels: int,
dtype=np.float64) -> tuple:
"""Dequantize an array.
Args:
arr (ndarray): Input array.
min_val (scalar): Minimum value to be clipped.
max_val (scalar): Maximum value to be clipped.
min_val (int or float): Minimum value to be clipped.
max_val (int or float): Maximum value to be clipped.
levels (int): Quantization levels.
dtype (np.type): The type of the dequantized array.
......
# Copyright (c) OpenMMLab. All rights reserved.
import logging
from typing import Optional
import torch
import torch.nn as nn
......@@ -11,8 +13,8 @@ class AlexNet(nn.Module):
num_classes (int): number of classes for classification.
"""
def __init__(self, num_classes=-1):
super(AlexNet, self).__init__()
def __init__(self, num_classes: int = -1):
super().__init__()
self.num_classes = num_classes
self.features = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
......@@ -40,7 +42,7 @@ class AlexNet(nn.Module):
nn.Linear(4096, num_classes),
)
def init_weights(self, pretrained=None):
def init_weights(self, pretrained: Optional[str] = None) -> None:
if isinstance(pretrained, str):
logger = logging.getLogger()
from ..runner import load_checkpoint
......@@ -51,7 +53,7 @@ class AlexNet(nn.Module):
else:
raise TypeError('pretrained must be a str or None')
def forward(self, x):
def forward(self, x: torch.Tensor) -> torch.Tensor:
x = self.features(x)
if self.num_classes > 0:
......
# Copyright (c) OpenMMLab. All rights reserved.
from typing import Dict
import torch
import torch.nn as nn
import torch.nn.functional as F
......@@ -28,12 +30,12 @@ class Clamp(nn.Module):
Default to 1.
"""
def __init__(self, min=-1., max=1.):
super(Clamp, self).__init__()
def __init__(self, min: float = -1., max: float = 1.):
super().__init__()
self.min = min
self.max = max
def forward(self, x):
def forward(self, x) -> torch.Tensor:
"""Forward function.
Args:
......@@ -67,7 +69,7 @@ class GELU(nn.Module):
>>> output = m(input)
"""
def forward(self, input):
def forward(self, input: torch.Tensor) -> torch.Tensor:
return F.gelu(input)
......@@ -78,11 +80,12 @@ else:
ACTIVATION_LAYERS.register_module(module=nn.GELU)
def build_activation_layer(cfg):
def build_activation_layer(cfg: Dict) -> nn.Module:
"""Build activation layer.
Args:
cfg (dict): The activation layer config, which should contain:
- type (str): Layer type.
- layer args: Args needed to instantiate an activation layer.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment