tuandunghcmut commited on
Commit
8b6974d
·
verified ·
1 Parent(s): 027dc4f

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. groundingLMM/mmcv/tests/data/config/a.b.py +5 -0
  2. groundingLMM/mmcv/tests/data/config/code.py +5 -0
  3. groundingLMM/mmcv/tests/data/config/i_child.py +4 -0
  4. groundingLMM/mmcv/tests/data/config/l2.yaml +1 -0
  5. groundingLMM/mmcv/tests/data/config/r.py +4 -0
  6. groundingLMM/mmcv/tests/data/config/s.py +2 -0
  7. groundingLMM/mmcv/tests/data/config/u.py +14 -0
  8. groundingLMM/mmcv/tests/data/config/v.py +12 -0
  9. groundingLMM/mmcv/tests/data/demo.lmdb/data.mdb +0 -0
  10. groundingLMM/mmcv/tests/data/demo.lmdb/lock.mdb +0 -0
  11. groundingLMM/mmcv/tests/data/for_scan/.file +0 -0
  12. groundingLMM/mmcv/tests/data/for_scan/1.json +0 -0
  13. groundingLMM/mmcv/tests/data/for_scan/1.txt +0 -0
  14. groundingLMM/mmcv/tests/data/for_scan/2.json +0 -0
  15. groundingLMM/mmcv/tests/data/for_scan/2.txt +0 -0
  16. groundingLMM/mmcv/tests/data/for_scan/3.TXT +0 -0
  17. groundingLMM/mmcv/tests/data/for_scan/a.bin +0 -0
  18. groundingLMM/mmcv/tests/test_cnn/test_build_layers.py +407 -0
  19. groundingLMM/mmcv/tests/test_cnn/test_context_block.py +59 -0
  20. groundingLMM/mmcv/tests/test_cnn/test_conv2d_adaptive_padding.py +28 -0
  21. groundingLMM/mmcv/tests/test_cnn/test_conv_module.py +251 -0
  22. groundingLMM/mmcv/tests/test_cnn/test_depthwise_seperable_conv_module.py +91 -0
  23. groundingLMM/mmcv/tests/test_cnn/test_flops_counter.py +152 -0
  24. groundingLMM/mmcv/tests/test_cnn/test_fuse_conv_bn.py +16 -0
  25. groundingLMM/mmcv/tests/test_cnn/test_generalized_attention.py +76 -0
  26. groundingLMM/mmcv/tests/test_cnn/test_hsigmoid.py +37 -0
  27. groundingLMM/mmcv/tests/test_cnn/test_hswish.py +21 -0
  28. groundingLMM/mmcv/tests/test_cnn/test_model_registry.py +64 -0
  29. groundingLMM/mmcv/tests/test_cnn/test_non_local.py +220 -0
  30. groundingLMM/mmcv/tests/test_cnn/test_revert_syncbn.py +59 -0
  31. groundingLMM/mmcv/tests/test_cnn/test_scale.py +22 -0
  32. groundingLMM/mmcv/tests/test_cnn/test_swish.py +16 -0
  33. groundingLMM/mmcv/tests/test_cnn/test_transformer.py +681 -0
  34. groundingLMM/mmcv/tests/test_cnn/test_weight_init.py +559 -0
  35. groundingLMM/mmcv/tests/test_cnn/test_wrappers.py +376 -0
  36. groundingLMM/mmcv/tests/test_image/test_colorspace.py +355 -0
  37. groundingLMM/mmcv/tests/test_image/test_geometric.py +610 -0
  38. groundingLMM/mmcv/tests/test_image/test_image_misc.py +73 -0
  39. groundingLMM/mmcv/tests/test_image/test_io.py +385 -0
  40. groundingLMM/mmcv/tests/test_image/test_photometric.py +380 -0
  41. groundingLMM/mmcv/tests/test_ops/test_correlation.py +46 -0
  42. groundingLMM/mmcv/tests/test_ops/test_gather_points.py +47 -0
  43. groundingLMM/mmcv/tests/test_ops/test_group_points.py +77 -0
  44. groundingLMM/mmcv/tests/test_ops/test_roi_align_rotated.py +136 -0
  45. groundingLMM/mmcv/tests/test_ops/test_roi_pool.py +83 -0
  46. groundingLMM/mmcv/tests/test_ops/test_roiaware_pool3d.py +135 -0
  47. groundingLMM/mmcv/tests/test_ops/test_roipoint_pool3d.py +36 -0
  48. groundingLMM/mmcv/tests/test_ops/test_rotated_feature_align.py +130 -0
  49. groundingLMM/mmcv/tests/test_ops/test_spconv.py +129 -0
  50. groundingLMM/mmcv/tests/test_ops/test_syncbn.py +295 -0
groundingLMM/mmcv/tests/data/config/a.b.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ item1 = [1, 2]
3
+ item2 = {'a': 0}
4
+ item3 = True
5
+ item4 = 'test'
groundingLMM/mmcv/tests/data/config/code.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ from mmcv import Config # isort:skip
3
+
4
+ cfg = Config.fromfile('./tests/data/config/a.py')
5
+ item5 = cfg.item1[0] + cfg.item2.a
groundingLMM/mmcv/tests/data/config/i_child.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ _base_ = './i_base.py'
3
+ item_cfg = {'b': 2}
4
+ item6 = {'cfg': item_cfg}
groundingLMM/mmcv/tests/data/config/l2.yaml ADDED
@@ -0,0 +1 @@
 
 
1
+ item2: {'a': 0}
groundingLMM/mmcv/tests/data/config/r.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import os
3
+
4
+ os.environ["TEST_VALUE"] = 'test'
groundingLMM/mmcv/tests/data/config/s.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ item = [{'a': 0}, {'b': 0, 'c': 0}]
groundingLMM/mmcv/tests/data/config/u.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ _base_ = ['./t.py']
3
+ base = '_base_.item8'
4
+ item11 = {{ _base_.item8 }}
5
+ item12 = {{ _base_.item9 }}
6
+ item13 = {{ _base_.item10 }}
7
+ item14 = {{ _base_.item1 }}
8
+ item15 = dict(
9
+ a = dict( b = {{ _base_.item2 }} ),
10
+ b = [{{ _base_.item3 }}],
11
+ c = [{{ _base_.item4 }}],
12
+ d = [[dict(e = {{ _base_.item5.a }})],{{ _base_.item6 }}],
13
+ e = {{ _base_.item1 }}
14
+ )
groundingLMM/mmcv/tests/data/config/v.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ _base_ = ['./u.py']
3
+ item21 = {{ _base_.item11 }}
4
+ item22 = item21
5
+ item23 = {{ _base_.item10 }}
6
+ item24 = item23
7
+ item25 = dict(
8
+ a = dict( b = item24 ),
9
+ b = [item24],
10
+ c = [[dict(e = item22)],{{ _base_.item6 }}],
11
+ e = item21
12
+ )
groundingLMM/mmcv/tests/data/demo.lmdb/data.mdb ADDED
Binary file (70.2 kB). View file
 
groundingLMM/mmcv/tests/data/demo.lmdb/lock.mdb ADDED
Binary file (8.19 kB). View file
 
groundingLMM/mmcv/tests/data/for_scan/.file ADDED
File without changes
groundingLMM/mmcv/tests/data/for_scan/1.json ADDED
File without changes
groundingLMM/mmcv/tests/data/for_scan/1.txt ADDED
File without changes
groundingLMM/mmcv/tests/data/for_scan/2.json ADDED
File without changes
groundingLMM/mmcv/tests/data/for_scan/2.txt ADDED
File without changes
groundingLMM/mmcv/tests/data/for_scan/3.TXT ADDED
File without changes
groundingLMM/mmcv/tests/data/for_scan/a.bin ADDED
File without changes
groundingLMM/mmcv/tests/test_cnn/test_build_layers.py ADDED
@@ -0,0 +1,407 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import numpy as np
3
+ import pytest
4
+ import torch
5
+ import torch.nn as nn
6
+
7
+ from mmcv.cnn.bricks import (ACTIVATION_LAYERS, CONV_LAYERS, NORM_LAYERS,
8
+ PADDING_LAYERS, PLUGIN_LAYERS,
9
+ build_activation_layer, build_conv_layer,
10
+ build_norm_layer, build_padding_layer,
11
+ build_plugin_layer, build_upsample_layer, is_norm)
12
+ from mmcv.cnn.bricks.norm import infer_abbr as infer_norm_abbr
13
+ from mmcv.cnn.bricks.plugin import infer_abbr as infer_plugin_abbr
14
+ from mmcv.cnn.bricks.upsample import PixelShufflePack
15
+ from mmcv.utils.parrots_wrapper import _BatchNorm
16
+
17
+
18
+ def test_build_conv_layer():
19
+ with pytest.raises(TypeError):
20
+ # cfg must be a dict
21
+ cfg = 'Conv2d'
22
+ build_conv_layer(cfg)
23
+
24
+ with pytest.raises(KeyError):
25
+ # `type` must be in cfg
26
+ cfg = dict(kernel_size=3)
27
+ build_conv_layer(cfg)
28
+
29
+ with pytest.raises(KeyError):
30
+ # unsupported conv type
31
+ cfg = dict(type='FancyConv')
32
+ build_conv_layer(cfg)
33
+
34
+ kwargs = dict(
35
+ in_channels=4, out_channels=8, kernel_size=3, groups=2, dilation=2)
36
+ cfg = None
37
+ layer = build_conv_layer(cfg, **kwargs)
38
+ assert isinstance(layer, nn.Conv2d)
39
+ assert layer.in_channels == kwargs['in_channels']
40
+ assert layer.out_channels == kwargs['out_channels']
41
+ assert layer.kernel_size == (kwargs['kernel_size'], kwargs['kernel_size'])
42
+ assert layer.groups == kwargs['groups']
43
+ assert layer.dilation == (kwargs['dilation'], kwargs['dilation'])
44
+
45
+ cfg = dict(type='Conv')
46
+ layer = build_conv_layer(cfg, **kwargs)
47
+ assert isinstance(layer, nn.Conv2d)
48
+ assert layer.in_channels == kwargs['in_channels']
49
+ assert layer.out_channels == kwargs['out_channels']
50
+ assert layer.kernel_size == (kwargs['kernel_size'], kwargs['kernel_size'])
51
+ assert layer.groups == kwargs['groups']
52
+ assert layer.dilation == (kwargs['dilation'], kwargs['dilation'])
53
+
54
+ cfg = dict(type='deconv')
55
+ layer = build_conv_layer(cfg, **kwargs)
56
+ assert isinstance(layer, nn.ConvTranspose2d)
57
+ assert layer.in_channels == kwargs['in_channels']
58
+ assert layer.out_channels == kwargs['out_channels']
59
+ assert layer.kernel_size == (kwargs['kernel_size'], kwargs['kernel_size'])
60
+ assert layer.groups == kwargs['groups']
61
+ assert layer.dilation == (kwargs['dilation'], kwargs['dilation'])
62
+
63
+ # sparse convs cannot support the case when groups>1
64
+ kwargs.pop('groups')
65
+
66
+ for type_name, module in CONV_LAYERS.module_dict.items():
67
+ cfg = dict(type=type_name)
68
+ # SparseInverseConv2d and SparseInverseConv3d do not have the argument
69
+ # 'dilation'
70
+ if type_name == 'SparseInverseConv2d' or type_name == \
71
+ 'SparseInverseConv3d':
72
+ kwargs.pop('dilation')
73
+ layer = build_conv_layer(cfg, **kwargs)
74
+ assert isinstance(layer, module)
75
+ assert layer.in_channels == kwargs['in_channels']
76
+ assert layer.out_channels == kwargs['out_channels']
77
+ kwargs['dilation'] = 2 # recover the key
78
+
79
+
80
+ def test_infer_norm_abbr():
81
+ with pytest.raises(TypeError):
82
+ # class_type must be a class
83
+ infer_norm_abbr(0)
84
+
85
+ class MyNorm:
86
+
87
+ _abbr_ = 'mn'
88
+
89
+ assert infer_norm_abbr(MyNorm) == 'mn'
90
+
91
+ class FancyBatchNorm:
92
+ pass
93
+
94
+ assert infer_norm_abbr(FancyBatchNorm) == 'bn'
95
+
96
+ class FancyInstanceNorm:
97
+ pass
98
+
99
+ assert infer_norm_abbr(FancyInstanceNorm) == 'in'
100
+
101
+ class FancyLayerNorm:
102
+ pass
103
+
104
+ assert infer_norm_abbr(FancyLayerNorm) == 'ln'
105
+
106
+ class FancyGroupNorm:
107
+ pass
108
+
109
+ assert infer_norm_abbr(FancyGroupNorm) == 'gn'
110
+
111
+ class FancyNorm:
112
+ pass
113
+
114
+ assert infer_norm_abbr(FancyNorm) == 'norm_layer'
115
+
116
+
117
+ def test_build_norm_layer():
118
+ with pytest.raises(TypeError):
119
+ # cfg must be a dict
120
+ cfg = 'BN'
121
+ build_norm_layer(cfg, 3)
122
+
123
+ with pytest.raises(KeyError):
124
+ # `type` must be in cfg
125
+ cfg = dict()
126
+ build_norm_layer(cfg, 3)
127
+
128
+ with pytest.raises(KeyError):
129
+ # unsupported norm type
130
+ cfg = dict(type='FancyNorm')
131
+ build_norm_layer(cfg, 3)
132
+
133
+ with pytest.raises(AssertionError):
134
+ # postfix must be int or str
135
+ cfg = dict(type='BN')
136
+ build_norm_layer(cfg, 3, postfix=[1, 2])
137
+
138
+ with pytest.raises(AssertionError):
139
+ # `num_groups` must be in cfg when using 'GN'
140
+ cfg = dict(type='GN')
141
+ build_norm_layer(cfg, 3)
142
+
143
+ # test each type of norm layer in norm_cfg
144
+ abbr_mapping = {
145
+ 'BN': 'bn',
146
+ 'BN1d': 'bn',
147
+ 'BN2d': 'bn',
148
+ 'BN3d': 'bn',
149
+ 'SyncBN': 'bn',
150
+ 'GN': 'gn',
151
+ 'LN': 'ln',
152
+ 'IN': 'in',
153
+ 'IN1d': 'in',
154
+ 'IN2d': 'in',
155
+ 'IN3d': 'in',
156
+ }
157
+ for type_name, module in NORM_LAYERS.module_dict.items():
158
+ if type_name == 'MMSyncBN': # skip MMSyncBN
159
+ continue
160
+ for postfix in ['_test', 1]:
161
+ cfg = dict(type=type_name)
162
+ if type_name == 'GN':
163
+ cfg['num_groups'] = 2
164
+ name, layer = build_norm_layer(cfg, 3, postfix=postfix)
165
+ assert name == abbr_mapping[type_name] + str(postfix)
166
+ assert isinstance(layer, module)
167
+ if type_name == 'GN':
168
+ assert layer.num_channels == 3
169
+ assert layer.num_groups == cfg['num_groups']
170
+ elif type_name != 'LN':
171
+ assert layer.num_features == 3
172
+
173
+
174
+ def test_build_activation_layer():
175
+ with pytest.raises(TypeError):
176
+ # cfg must be a dict
177
+ cfg = 'ReLU'
178
+ build_activation_layer(cfg)
179
+
180
+ with pytest.raises(KeyError):
181
+ # `type` must be in cfg
182
+ cfg = dict()
183
+ build_activation_layer(cfg)
184
+
185
+ with pytest.raises(KeyError):
186
+ # unsupported activation type
187
+ cfg = dict(type='FancyReLU')
188
+ build_activation_layer(cfg)
189
+
190
+ # test each type of activation layer in activation_cfg
191
+ for type_name, module in ACTIVATION_LAYERS.module_dict.items():
192
+ cfg['type'] = type_name
193
+ layer = build_activation_layer(cfg)
194
+ assert isinstance(layer, module)
195
+
196
+ # sanity check for Clamp
197
+ act = build_activation_layer(dict(type='Clamp'))
198
+ x = torch.randn(10) * 1000
199
+ y = act(x)
200
+ assert np.logical_and((y >= -1).numpy(), (y <= 1).numpy()).all()
201
+ act = build_activation_layer(dict(type='Clip', min=0))
202
+ y = act(x)
203
+ assert np.logical_and((y >= 0).numpy(), (y <= 1).numpy()).all()
204
+ act = build_activation_layer(dict(type='Clamp', max=0))
205
+ y = act(x)
206
+ assert np.logical_and((y >= -1).numpy(), (y <= 0).numpy()).all()
207
+
208
+
209
+ def test_build_padding_layer():
210
+ with pytest.raises(TypeError):
211
+ # cfg must be a dict
212
+ cfg = 'reflect'
213
+ build_padding_layer(cfg)
214
+
215
+ with pytest.raises(KeyError):
216
+ # `type` must be in cfg
217
+ cfg = dict()
218
+ build_padding_layer(cfg)
219
+
220
+ with pytest.raises(KeyError):
221
+ # unsupported activation type
222
+ cfg = dict(type='FancyPad')
223
+ build_padding_layer(cfg)
224
+
225
+ for type_name, module in PADDING_LAYERS.module_dict.items():
226
+ cfg['type'] = type_name
227
+ layer = build_padding_layer(cfg, 2)
228
+ assert isinstance(layer, module)
229
+
230
+ input_x = torch.randn(1, 2, 5, 5)
231
+ cfg = dict(type='reflect')
232
+ padding_layer = build_padding_layer(cfg, 2)
233
+ res = padding_layer(input_x)
234
+ assert res.shape == (1, 2, 9, 9)
235
+
236
+
237
+ def test_upsample_layer():
238
+ with pytest.raises(TypeError):
239
+ # cfg must be a dict
240
+ cfg = 'bilinear'
241
+ build_upsample_layer(cfg)
242
+
243
+ with pytest.raises(KeyError):
244
+ # `type` must be in cfg
245
+ cfg = dict()
246
+ build_upsample_layer(cfg)
247
+
248
+ with pytest.raises(KeyError):
249
+ # unsupported activation type
250
+ cfg = dict(type='FancyUpsample')
251
+ build_upsample_layer(cfg)
252
+
253
+ for type_name in ['nearest', 'bilinear']:
254
+ cfg['type'] = type_name
255
+ layer = build_upsample_layer(cfg)
256
+ assert isinstance(layer, nn.Upsample)
257
+ assert layer.mode == type_name
258
+
259
+ cfg = dict(
260
+ type='deconv', in_channels=3, out_channels=3, kernel_size=3, stride=2)
261
+ layer = build_upsample_layer(cfg)
262
+ assert isinstance(layer, nn.ConvTranspose2d)
263
+
264
+ cfg = dict(type='deconv')
265
+ kwargs = dict(in_channels=3, out_channels=3, kernel_size=3, stride=2)
266
+ layer = build_upsample_layer(cfg, **kwargs)
267
+ assert isinstance(layer, nn.ConvTranspose2d)
268
+ assert layer.in_channels == kwargs['in_channels']
269
+ assert layer.out_channels == kwargs['out_channels']
270
+ assert layer.kernel_size == (kwargs['kernel_size'], kwargs['kernel_size'])
271
+ assert layer.stride == (kwargs['stride'], kwargs['stride'])
272
+
273
+ layer = build_upsample_layer(cfg, 3, 3, 3, 2)
274
+ assert isinstance(layer, nn.ConvTranspose2d)
275
+ assert layer.in_channels == kwargs['in_channels']
276
+ assert layer.out_channels == kwargs['out_channels']
277
+ assert layer.kernel_size == (kwargs['kernel_size'], kwargs['kernel_size'])
278
+ assert layer.stride == (kwargs['stride'], kwargs['stride'])
279
+
280
+ cfg = dict(
281
+ type='pixel_shuffle',
282
+ in_channels=3,
283
+ out_channels=3,
284
+ scale_factor=2,
285
+ upsample_kernel=3)
286
+ layer = build_upsample_layer(cfg)
287
+
288
+ assert isinstance(layer, PixelShufflePack)
289
+ assert layer.scale_factor == 2
290
+ assert layer.upsample_kernel == 3
291
+
292
+
293
+ def test_pixel_shuffle_pack():
294
+ x_in = torch.rand(2, 3, 10, 10)
295
+ pixel_shuffle = PixelShufflePack(3, 3, scale_factor=2, upsample_kernel=3)
296
+ assert pixel_shuffle.upsample_conv.kernel_size == (3, 3)
297
+ x_out = pixel_shuffle(x_in)
298
+ assert x_out.shape == (2, 3, 20, 20)
299
+
300
+
301
+ def test_is_norm():
302
+ norm_set1 = [
303
+ nn.BatchNorm1d, nn.BatchNorm2d, nn.BatchNorm3d, nn.InstanceNorm1d,
304
+ nn.InstanceNorm2d, nn.InstanceNorm3d, nn.LayerNorm
305
+ ]
306
+ norm_set2 = [nn.GroupNorm]
307
+ for norm_type in norm_set1:
308
+ layer = norm_type(3)
309
+ assert is_norm(layer)
310
+ assert not is_norm(layer, exclude=(norm_type, ))
311
+ for norm_type in norm_set2:
312
+ layer = norm_type(3, 6)
313
+ assert is_norm(layer)
314
+ assert not is_norm(layer, exclude=(norm_type, ))
315
+
316
+ class MyNorm(nn.BatchNorm2d):
317
+ pass
318
+
319
+ layer = MyNorm(3)
320
+ assert is_norm(layer)
321
+ assert not is_norm(layer, exclude=_BatchNorm)
322
+ assert not is_norm(layer, exclude=(_BatchNorm, ))
323
+
324
+ layer = nn.Conv2d(3, 8, 1)
325
+ assert not is_norm(layer)
326
+
327
+ with pytest.raises(TypeError):
328
+ layer = nn.BatchNorm1d(3)
329
+ is_norm(layer, exclude='BN')
330
+
331
+ with pytest.raises(TypeError):
332
+ layer = nn.BatchNorm1d(3)
333
+ is_norm(layer, exclude=('BN', ))
334
+
335
+
336
+ def test_infer_plugin_abbr():
337
+ with pytest.raises(TypeError):
338
+ # class_type must be a class
339
+ infer_plugin_abbr(0)
340
+
341
+ class MyPlugin:
342
+
343
+ _abbr_ = 'mp'
344
+
345
+ assert infer_plugin_abbr(MyPlugin) == 'mp'
346
+
347
+ class FancyPlugin:
348
+ pass
349
+
350
+ assert infer_plugin_abbr(FancyPlugin) == 'fancy_plugin'
351
+
352
+
353
+ def test_build_plugin_layer():
354
+ with pytest.raises(TypeError):
355
+ # cfg must be a dict
356
+ cfg = 'Plugin'
357
+ build_plugin_layer(cfg)
358
+
359
+ with pytest.raises(KeyError):
360
+ # `type` must be in cfg
361
+ cfg = dict()
362
+ build_plugin_layer(cfg)
363
+
364
+ with pytest.raises(KeyError):
365
+ # unsupported plugin type
366
+ cfg = dict(type='FancyPlugin')
367
+ build_plugin_layer(cfg)
368
+
369
+ with pytest.raises(AssertionError):
370
+ # postfix must be int or str
371
+ cfg = dict(type='ConvModule')
372
+ build_plugin_layer(cfg, postfix=[1, 2])
373
+
374
+ # test ContextBlock
375
+ for postfix in ['', '_test', 1]:
376
+ cfg = dict(type='ContextBlock')
377
+ name, layer = build_plugin_layer(
378
+ cfg, postfix=postfix, in_channels=16, ratio=1. / 4)
379
+ assert name == 'context_block' + str(postfix)
380
+ assert isinstance(layer, PLUGIN_LAYERS.module_dict['ContextBlock'])
381
+
382
+ # test GeneralizedAttention
383
+ for postfix in ['', '_test', 1]:
384
+ cfg = dict(type='GeneralizedAttention')
385
+ name, layer = build_plugin_layer(cfg, postfix=postfix, in_channels=16)
386
+ assert name == 'gen_attention_block' + str(postfix)
387
+ assert isinstance(layer,
388
+ PLUGIN_LAYERS.module_dict['GeneralizedAttention'])
389
+
390
+ # test NonLocal2d
391
+ for postfix in ['', '_test', 1]:
392
+ cfg = dict(type='NonLocal2d')
393
+ name, layer = build_plugin_layer(cfg, postfix=postfix, in_channels=16)
394
+ assert name == 'nonlocal_block' + str(postfix)
395
+ assert isinstance(layer, PLUGIN_LAYERS.module_dict['NonLocal2d'])
396
+
397
+ # test ConvModule
398
+ for postfix in ['', '_test', 1]:
399
+ cfg = dict(type='ConvModule')
400
+ name, layer = build_plugin_layer(
401
+ cfg,
402
+ postfix=postfix,
403
+ in_channels=16,
404
+ out_channels=4,
405
+ kernel_size=3)
406
+ assert name == 'conv_block' + str(postfix)
407
+ assert isinstance(layer, PLUGIN_LAYERS.module_dict['ConvModule'])
groundingLMM/mmcv/tests/test_cnn/test_context_block.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import pytest
3
+ import torch
4
+
5
+ from mmcv.cnn.bricks import ContextBlock
6
+
7
+
8
+ def test_context_block():
9
+ with pytest.raises(AssertionError):
10
+ # pooling_type should be in ['att', 'avg']
11
+ ContextBlock(16, 1. / 4, pooling_type='unsupport_type')
12
+
13
+ with pytest.raises(AssertionError):
14
+ # fusion_types should be of type list or tuple
15
+ ContextBlock(16, 1. / 4, fusion_types='unsupport_type')
16
+
17
+ with pytest.raises(AssertionError):
18
+ # fusion_types should be in ['channel_add', 'channel_mul']
19
+ ContextBlock(16, 1. / 4, fusion_types=('unsupport_type', ))
20
+
21
+ # test pooling_type='att'
22
+ imgs = torch.randn(2, 16, 20, 20)
23
+ context_block = ContextBlock(16, 1. / 4, pooling_type='att')
24
+ out = context_block(imgs)
25
+ assert context_block.conv_mask.in_channels == 16
26
+ assert context_block.conv_mask.out_channels == 1
27
+ assert out.shape == imgs.shape
28
+
29
+ # test pooling_type='avg'
30
+ imgs = torch.randn(2, 16, 20, 20)
31
+ context_block = ContextBlock(16, 1. / 4, pooling_type='avg')
32
+ out = context_block(imgs)
33
+ assert hasattr(context_block, 'avg_pool')
34
+ assert out.shape == imgs.shape
35
+
36
+ # test fusion_types=('channel_add',)
37
+ imgs = torch.randn(2, 16, 20, 20)
38
+ context_block = ContextBlock(16, 1. / 4, fusion_types=('channel_add', ))
39
+ out = context_block(imgs)
40
+ assert context_block.channel_add_conv is not None
41
+ assert context_block.channel_mul_conv is None
42
+ assert out.shape == imgs.shape
43
+
44
+ # test fusion_types=('channel_mul',)
45
+ imgs = torch.randn(2, 16, 20, 20)
46
+ context_block = ContextBlock(16, 1. / 4, fusion_types=('channel_mul', ))
47
+ out = context_block(imgs)
48
+ assert context_block.channel_add_conv is None
49
+ assert context_block.channel_mul_conv is not None
50
+ assert out.shape == imgs.shape
51
+
52
+ # test fusion_types=('channel_add', 'channel_mul')
53
+ imgs = torch.randn(2, 16, 20, 20)
54
+ context_block = ContextBlock(
55
+ 16, 1. / 4, fusion_types=('channel_add', 'channel_mul'))
56
+ out = context_block(imgs)
57
+ assert context_block.channel_add_conv is not None
58
+ assert context_block.channel_mul_conv is not None
59
+ assert out.shape == imgs.shape
groundingLMM/mmcv/tests/test_cnn/test_conv2d_adaptive_padding.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import torch
3
+
4
+ from mmcv.cnn.bricks import Conv2dAdaptivePadding
5
+
6
+
7
+ def test_conv2d_samepadding():
8
+ # test Conv2dAdaptivePadding with stride=1
9
+ inputs = torch.rand((1, 3, 28, 28))
10
+ conv = Conv2dAdaptivePadding(3, 3, kernel_size=3, stride=1)
11
+ output = conv(inputs)
12
+ assert output.shape == inputs.shape
13
+
14
+ inputs = torch.rand((1, 3, 13, 13))
15
+ conv = Conv2dAdaptivePadding(3, 3, kernel_size=3, stride=1)
16
+ output = conv(inputs)
17
+ assert output.shape == inputs.shape
18
+
19
+ # test Conv2dAdaptivePadding with stride=2
20
+ inputs = torch.rand((1, 3, 28, 28))
21
+ conv = Conv2dAdaptivePadding(3, 3, kernel_size=3, stride=2)
22
+ output = conv(inputs)
23
+ assert output.shape == torch.Size([1, 3, 14, 14])
24
+
25
+ inputs = torch.rand((1, 3, 13, 13))
26
+ conv = Conv2dAdaptivePadding(3, 3, kernel_size=3, stride=2)
27
+ output = conv(inputs)
28
+ assert output.shape == torch.Size([1, 3, 7, 7])
groundingLMM/mmcv/tests/test_cnn/test_conv_module.py ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import warnings
3
+ from unittest.mock import patch
4
+
5
+ import pytest
6
+ import torch
7
+ import torch.nn as nn
8
+
9
+ from mmcv.cnn.bricks import CONV_LAYERS, ConvModule, HSigmoid, HSwish
10
+ from mmcv.utils import TORCH_VERSION, digit_version
11
+
12
+
13
+ @CONV_LAYERS.register_module()
14
+ class ExampleConv(nn.Module):
15
+
16
+ def __init__(self,
17
+ in_channels,
18
+ out_channels,
19
+ kernel_size,
20
+ stride=1,
21
+ padding=0,
22
+ dilation=1,
23
+ groups=1,
24
+ bias=True,
25
+ norm_cfg=None):
26
+ super(ExampleConv, self).__init__()
27
+ self.in_channels = in_channels
28
+ self.out_channels = out_channels
29
+ self.kernel_size = kernel_size
30
+ self.stride = stride
31
+ self.padding = padding
32
+ self.dilation = dilation
33
+ self.groups = groups
34
+ self.bias = bias
35
+ self.norm_cfg = norm_cfg
36
+ self.output_padding = (0, 0, 0)
37
+ self.transposed = False
38
+
39
+ self.conv0 = nn.Conv2d(in_channels, out_channels, kernel_size)
40
+ self.init_weights()
41
+
42
+ def forward(self, x):
43
+ x = self.conv0(x)
44
+ return x
45
+
46
+ def init_weights(self):
47
+ nn.init.constant_(self.conv0.weight, 0)
48
+
49
+
50
+ def test_conv_module():
51
+ with pytest.raises(AssertionError):
52
+ # conv_cfg must be a dict or None
53
+ conv_cfg = 'conv'
54
+ ConvModule(3, 8, 2, conv_cfg=conv_cfg)
55
+
56
+ with pytest.raises(AssertionError):
57
+ # norm_cfg must be a dict or None
58
+ norm_cfg = 'norm'
59
+ ConvModule(3, 8, 2, norm_cfg=norm_cfg)
60
+
61
+ with pytest.raises(KeyError):
62
+ # softmax is not supported
63
+ act_cfg = dict(type='softmax')
64
+ ConvModule(3, 8, 2, act_cfg=act_cfg)
65
+
66
+ # conv + norm + act
67
+ conv = ConvModule(3, 8, 2, norm_cfg=dict(type='BN'))
68
+ assert conv.with_activation
69
+ assert hasattr(conv, 'activate')
70
+ assert conv.with_norm
71
+ assert hasattr(conv, 'norm')
72
+ x = torch.rand(1, 3, 256, 256)
73
+ output = conv(x)
74
+ assert output.shape == (1, 8, 255, 255)
75
+
76
+ # conv + act
77
+ conv = ConvModule(3, 8, 2)
78
+ assert conv.with_activation
79
+ assert hasattr(conv, 'activate')
80
+ assert not conv.with_norm
81
+ assert conv.norm is None
82
+ x = torch.rand(1, 3, 256, 256)
83
+ output = conv(x)
84
+ assert output.shape == (1, 8, 255, 255)
85
+
86
+ # conv
87
+ conv = ConvModule(3, 8, 2, act_cfg=None)
88
+ assert not conv.with_norm
89
+ assert conv.norm is None
90
+ assert not conv.with_activation
91
+ assert not hasattr(conv, 'activate')
92
+ x = torch.rand(1, 3, 256, 256)
93
+ output = conv(x)
94
+ assert output.shape == (1, 8, 255, 255)
95
+
96
+ # conv with its own `init_weights` method
97
+ conv_module = ConvModule(
98
+ 3, 8, 2, conv_cfg=dict(type='ExampleConv'), act_cfg=None)
99
+ assert torch.equal(conv_module.conv.conv0.weight, torch.zeros(8, 3, 2, 2))
100
+
101
+ # with_spectral_norm=True
102
+ conv = ConvModule(3, 8, 3, padding=1, with_spectral_norm=True)
103
+ assert hasattr(conv.conv, 'weight_orig')
104
+ output = conv(x)
105
+ assert output.shape == (1, 8, 256, 256)
106
+
107
+ # padding_mode='reflect'
108
+ conv = ConvModule(3, 8, 3, padding=1, padding_mode='reflect')
109
+ assert isinstance(conv.padding_layer, nn.ReflectionPad2d)
110
+ output = conv(x)
111
+ assert output.shape == (1, 8, 256, 256)
112
+
113
+ # non-existing padding mode
114
+ with pytest.raises(KeyError):
115
+ conv = ConvModule(3, 8, 3, padding=1, padding_mode='non_exists')
116
+
117
+ # leaky relu
118
+ conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='LeakyReLU'))
119
+ assert isinstance(conv.activate, nn.LeakyReLU)
120
+ output = conv(x)
121
+ assert output.shape == (1, 8, 256, 256)
122
+
123
+ # tanh
124
+ conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='Tanh'))
125
+ assert isinstance(conv.activate, nn.Tanh)
126
+ output = conv(x)
127
+ assert output.shape == (1, 8, 256, 256)
128
+
129
+ # Sigmoid
130
+ conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='Sigmoid'))
131
+ assert isinstance(conv.activate, nn.Sigmoid)
132
+ output = conv(x)
133
+ assert output.shape == (1, 8, 256, 256)
134
+
135
+ # PReLU
136
+ conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='PReLU'))
137
+ assert isinstance(conv.activate, nn.PReLU)
138
+ output = conv(x)
139
+ assert output.shape == (1, 8, 256, 256)
140
+
141
+ # HSwish
142
+ conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='HSwish'))
143
+ if (TORCH_VERSION == 'parrots'
144
+ or digit_version(TORCH_VERSION) < digit_version('1.7')):
145
+ assert isinstance(conv.activate, HSwish)
146
+ else:
147
+ assert isinstance(conv.activate, nn.Hardswish)
148
+
149
+ output = conv(x)
150
+ assert output.shape == (1, 8, 256, 256)
151
+
152
+ # HSigmoid
153
+ conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='HSigmoid'))
154
+ assert isinstance(conv.activate, HSigmoid)
155
+ output = conv(x)
156
+ assert output.shape == (1, 8, 256, 256)
157
+
158
+
159
+ def test_bias():
160
+ # bias: auto, without norm
161
+ conv = ConvModule(3, 8, 2)
162
+ assert conv.conv.bias is not None
163
+
164
+ # bias: auto, with norm
165
+ conv = ConvModule(3, 8, 2, norm_cfg=dict(type='BN'))
166
+ assert conv.conv.bias is None
167
+
168
+ # bias: False, without norm
169
+ conv = ConvModule(3, 8, 2, bias=False)
170
+ assert conv.conv.bias is None
171
+
172
+ # bias: True, with batch norm
173
+ with pytest.warns(UserWarning) as record:
174
+ ConvModule(3, 8, 2, bias=True, norm_cfg=dict(type='BN'))
175
+ assert len(record) == 1
176
+ assert record[0].message.args[
177
+ 0] == 'Unnecessary conv bias before batch/instance norm'
178
+
179
+ # bias: True, with instance norm
180
+ with pytest.warns(UserWarning) as record:
181
+ ConvModule(3, 8, 2, bias=True, norm_cfg=dict(type='IN'))
182
+ assert len(record) == 1
183
+ assert record[0].message.args[
184
+ 0] == 'Unnecessary conv bias before batch/instance norm'
185
+
186
+ # bias: True, with other norm
187
+ with pytest.warns(UserWarning) as record:
188
+ norm_cfg = dict(type='GN', num_groups=1)
189
+ ConvModule(3, 8, 2, bias=True, norm_cfg=norm_cfg)
190
+ warnings.warn('No warnings')
191
+ assert len(record) == 1
192
+ assert record[0].message.args[0] == 'No warnings'
193
+
194
+
195
+ def conv_forward(self, x):
196
+ return x + '_conv'
197
+
198
+
199
+ def bn_forward(self, x):
200
+ return x + '_bn'
201
+
202
+
203
+ def relu_forward(self, x):
204
+ return x + '_relu'
205
+
206
+
207
+ @patch('torch.nn.ReLU.forward', relu_forward)
208
+ @patch('torch.nn.BatchNorm2d.forward', bn_forward)
209
+ @patch('torch.nn.Conv2d.forward', conv_forward)
210
+ def test_order():
211
+
212
+ with pytest.raises(AssertionError):
213
+ # order must be a tuple
214
+ order = ['conv', 'norm', 'act']
215
+ ConvModule(3, 8, 2, order=order)
216
+
217
+ with pytest.raises(AssertionError):
218
+ # length of order must be 3
219
+ order = ('conv', 'norm')
220
+ ConvModule(3, 8, 2, order=order)
221
+
222
+ with pytest.raises(AssertionError):
223
+ # order must be an order of 'conv', 'norm', 'act'
224
+ order = ('conv', 'norm', 'norm')
225
+ ConvModule(3, 8, 2, order=order)
226
+
227
+ with pytest.raises(AssertionError):
228
+ # order must be an order of 'conv', 'norm', 'act'
229
+ order = ('conv', 'norm', 'something')
230
+ ConvModule(3, 8, 2, order=order)
231
+
232
+ # ('conv', 'norm', 'act')
233
+ conv = ConvModule(3, 8, 2, norm_cfg=dict(type='BN'))
234
+ out = conv('input')
235
+ assert out == 'input_conv_bn_relu'
236
+
237
+ # ('norm', 'conv', 'act')
238
+ conv = ConvModule(
239
+ 3, 8, 2, norm_cfg=dict(type='BN'), order=('norm', 'conv', 'act'))
240
+ out = conv('input')
241
+ assert out == 'input_bn_conv_relu'
242
+
243
+ # ('conv', 'norm', 'act'), activate=False
244
+ conv = ConvModule(3, 8, 2, norm_cfg=dict(type='BN'))
245
+ out = conv('input', activate=False)
246
+ assert out == 'input_conv_bn'
247
+
248
+ # ('conv', 'norm', 'act'), activate=False
249
+ conv = ConvModule(3, 8, 2, norm_cfg=dict(type='BN'))
250
+ out = conv('input', norm=False)
251
+ assert out == 'input_conv_relu'
groundingLMM/mmcv/tests/test_cnn/test_depthwise_seperable_conv_module.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import pytest
3
+ import torch
4
+ import torch.nn as nn
5
+
6
+ from mmcv.cnn.bricks import DepthwiseSeparableConvModule
7
+
8
+
9
+ def test_depthwise_separable_conv():
10
+ with pytest.raises(AssertionError):
11
+ # conv_cfg must be a dict or None
12
+ DepthwiseSeparableConvModule(4, 8, 2, groups=2)
13
+
14
+ # test default config
15
+ conv = DepthwiseSeparableConvModule(3, 8, 2)
16
+ assert conv.depthwise_conv.conv.groups == 3
17
+ assert conv.pointwise_conv.conv.kernel_size == (1, 1)
18
+ assert not conv.depthwise_conv.with_norm
19
+ assert not conv.pointwise_conv.with_norm
20
+ assert conv.depthwise_conv.activate.__class__.__name__ == 'ReLU'
21
+ assert conv.pointwise_conv.activate.__class__.__name__ == 'ReLU'
22
+ x = torch.rand(1, 3, 256, 256)
23
+ output = conv(x)
24
+ assert output.shape == (1, 8, 255, 255)
25
+
26
+ # test dw_norm_cfg
27
+ conv = DepthwiseSeparableConvModule(3, 8, 2, dw_norm_cfg=dict(type='BN'))
28
+ assert conv.depthwise_conv.norm_name == 'bn'
29
+ assert not conv.pointwise_conv.with_norm
30
+ x = torch.rand(1, 3, 256, 256)
31
+ output = conv(x)
32
+ assert output.shape == (1, 8, 255, 255)
33
+
34
+ # test pw_norm_cfg
35
+ conv = DepthwiseSeparableConvModule(3, 8, 2, pw_norm_cfg=dict(type='BN'))
36
+ assert not conv.depthwise_conv.with_norm
37
+ assert conv.pointwise_conv.norm_name == 'bn'
38
+ x = torch.rand(1, 3, 256, 256)
39
+ output = conv(x)
40
+ assert output.shape == (1, 8, 255, 255)
41
+
42
+ # test norm_cfg
43
+ conv = DepthwiseSeparableConvModule(3, 8, 2, norm_cfg=dict(type='BN'))
44
+ assert conv.depthwise_conv.norm_name == 'bn'
45
+ assert conv.pointwise_conv.norm_name == 'bn'
46
+ x = torch.rand(1, 3, 256, 256)
47
+ output = conv(x)
48
+ assert output.shape == (1, 8, 255, 255)
49
+
50
+ # add test for ['norm', 'conv', 'act']
51
+ conv = DepthwiseSeparableConvModule(3, 8, 2, order=('norm', 'conv', 'act'))
52
+ x = torch.rand(1, 3, 256, 256)
53
+ output = conv(x)
54
+ assert output.shape == (1, 8, 255, 255)
55
+
56
+ conv = DepthwiseSeparableConvModule(
57
+ 3, 8, 3, padding=1, with_spectral_norm=True)
58
+ assert hasattr(conv.depthwise_conv.conv, 'weight_orig')
59
+ assert hasattr(conv.pointwise_conv.conv, 'weight_orig')
60
+ output = conv(x)
61
+ assert output.shape == (1, 8, 256, 256)
62
+
63
+ conv = DepthwiseSeparableConvModule(
64
+ 3, 8, 3, padding=1, padding_mode='reflect')
65
+ assert isinstance(conv.depthwise_conv.padding_layer, nn.ReflectionPad2d)
66
+ output = conv(x)
67
+ assert output.shape == (1, 8, 256, 256)
68
+
69
+ # test dw_act_cfg
70
+ conv = DepthwiseSeparableConvModule(
71
+ 3, 8, 3, padding=1, dw_act_cfg=dict(type='LeakyReLU'))
72
+ assert conv.depthwise_conv.activate.__class__.__name__ == 'LeakyReLU'
73
+ assert conv.pointwise_conv.activate.__class__.__name__ == 'ReLU'
74
+ output = conv(x)
75
+ assert output.shape == (1, 8, 256, 256)
76
+
77
+ # test pw_act_cfg
78
+ conv = DepthwiseSeparableConvModule(
79
+ 3, 8, 3, padding=1, pw_act_cfg=dict(type='LeakyReLU'))
80
+ assert conv.depthwise_conv.activate.__class__.__name__ == 'ReLU'
81
+ assert conv.pointwise_conv.activate.__class__.__name__ == 'LeakyReLU'
82
+ output = conv(x)
83
+ assert output.shape == (1, 8, 256, 256)
84
+
85
+ # test act_cfg
86
+ conv = DepthwiseSeparableConvModule(
87
+ 3, 8, 3, padding=1, act_cfg=dict(type='LeakyReLU'))
88
+ assert conv.depthwise_conv.activate.__class__.__name__ == 'LeakyReLU'
89
+ assert conv.pointwise_conv.activate.__class__.__name__ == 'LeakyReLU'
90
+ output = conv(x)
91
+ assert output.shape == (1, 8, 256, 256)
groundingLMM/mmcv/tests/test_cnn/test_flops_counter.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import pytest
3
+ import torch
4
+ import torch.nn as nn
5
+
6
+ from mmcv.cnn import get_model_complexity_info
7
+ from mmcv.cnn.utils.flops_counter import flops_to_string, params_to_string
8
+
9
+ try:
10
+ from StringIO import StringIO
11
+ except ImportError:
12
+ from io import StringIO
13
+
14
+ # yapf: disable
15
+ gt_results = [
16
+ {'model': nn.Conv1d(3, 8, 3), 'input': (3, 16), 'flops': 1120.0, 'params': 80.0}, # noqa: E501
17
+ {'model': nn.Conv2d(3, 8, 3), 'input': (3, 16, 16), 'flops': 43904.0, 'params': 224.0}, # noqa: E501
18
+ {'model': nn.Conv3d(3, 8, 3), 'input': (3, 3, 16, 16), 'flops': 128576.0, 'params': 656.0}, # noqa: E501
19
+ {'model': nn.ReLU(), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501
20
+ {'model': nn.PReLU(), 'input': (3, 16, 16), 'flops': 768.0, 'params': 1}, # noqa: E501
21
+ {'model': nn.ELU(), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501
22
+ {'model': nn.LeakyReLU(), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501
23
+ {'model': nn.ReLU6(), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501
24
+ {'model': nn.MaxPool1d(2), 'input': (3, 16), 'flops': 48.0, 'params': 0}, # noqa: E501
25
+ {'model': nn.MaxPool2d(2), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501
26
+ {'model': nn.MaxPool3d(2), 'input': (3, 3, 16, 16), 'flops': 2304.0, 'params': 0}, # noqa: E501
27
+ {'model': nn.AvgPool1d(2), 'input': (3, 16), 'flops': 48.0, 'params': 0}, # noqa: E501
28
+ {'model': nn.AvgPool2d(2), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501
29
+ {'model': nn.AvgPool3d(2), 'input': (3, 3, 16, 16), 'flops': 2304.0, 'params': 0}, # noqa: E501
30
+ {'model': nn.AdaptiveMaxPool1d(2), 'input': (3, 16), 'flops': 48.0, 'params': 0}, # noqa: E501
31
+ {'model': nn.AdaptiveMaxPool2d(2), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501
32
+ {'model': nn.AdaptiveMaxPool3d(2), 'input': (3, 3, 16, 16), 'flops': 2304.0, 'params': 0}, # noqa: E501
33
+ {'model': nn.AdaptiveAvgPool1d(2), 'input': (3, 16), 'flops': 48.0, 'params': 0}, # noqa: E501
34
+ {'model': nn.AdaptiveAvgPool2d(2), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501
35
+ {'model': nn.AdaptiveAvgPool3d(2), 'input': (3, 3, 16, 16), 'flops': 2304.0, 'params': 0}, # noqa: E501
36
+ {'model': nn.BatchNorm1d(3), 'input': (3, 16), 'flops': 96.0, 'params': 6.0}, # noqa: E501
37
+ {'model': nn.BatchNorm2d(3), 'input': (3, 16, 16), 'flops': 1536.0, 'params': 6.0}, # noqa: E501
38
+ {'model': nn.BatchNorm3d(3), 'input': (3, 3, 16, 16), 'flops': 4608.0, 'params': 6.0}, # noqa: E501
39
+ {'model': nn.GroupNorm(2, 6), 'input': (6, 16, 16), 'flops': 3072.0, 'params': 12.0}, # noqa: E501
40
+ {'model': nn.InstanceNorm1d(3, affine=True), 'input': (3, 16), 'flops': 96.0, 'params': 6.0}, # noqa: E501
41
+ {'model': nn.InstanceNorm2d(3, affine=True), 'input': (3, 16, 16), 'flops': 1536.0, 'params': 6.0}, # noqa: E501
42
+ {'model': nn.InstanceNorm3d(3, affine=True), 'input': (3, 3, 16, 16), 'flops': 4608.0, 'params': 6.0}, # noqa: E501
43
+ {'model': nn.LayerNorm((3, 16, 16)), 'input': (3, 16, 16), 'flops': 1536.0, 'params': 1536.0}, # noqa: E501
44
+ {'model': nn.LayerNorm((3, 16, 16), elementwise_affine=False), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501
45
+ {'model': nn.Linear(1024, 2), 'input': (1024, ), 'flops': 2048.0, 'params': 2050.0}, # noqa: E501
46
+ {'model': nn.ConvTranspose2d(3, 8, 3), 'input': (3, 16, 16), 'flops': 57888, 'params': 224.0}, # noqa: E501
47
+ {'model': nn.Upsample((32, 32)), 'input': (3, 16, 16), 'flops': 3072.0, 'params': 0} # noqa: E501
48
+ ]
49
+ # yapf: enable
50
+
51
+
52
+ class ExampleModel(nn.Module):
53
+
54
+ def __init__(self):
55
+ super().__init__()
56
+ self.conv2d = nn.Conv2d(3, 8, 3)
57
+
58
+ def forward(self, imgs):
59
+ x = torch.randn((1, *imgs))
60
+ return self.conv2d(x)
61
+
62
+
63
+ def input_constructor(x):
64
+ return dict(imgs=x)
65
+
66
+
67
+ def test_flops_counter():
68
+ with pytest.raises(AssertionError):
69
+ # input_res should be a tuple
70
+ model = nn.Conv2d(3, 8, 3)
71
+ input_res = [1, 3, 16, 16]
72
+ get_model_complexity_info(model, input_res)
73
+
74
+ with pytest.raises(AssertionError):
75
+ # len(input_res) >= 2
76
+ model = nn.Conv2d(3, 8, 3)
77
+ input_res = tuple()
78
+ get_model_complexity_info(model, input_res)
79
+
80
+ # test common layers
81
+ for item in gt_results:
82
+ model = item['model']
83
+ input = item['input']
84
+ flops, params = get_model_complexity_info(
85
+ model, input, as_strings=False, print_per_layer_stat=False)
86
+ assert flops == item['flops'] and params == item['params']
87
+
88
+ # test input constructor
89
+ model = ExampleModel()
90
+ x = (3, 16, 16)
91
+ flops, params = get_model_complexity_info(
92
+ model,
93
+ x,
94
+ as_strings=False,
95
+ print_per_layer_stat=False,
96
+ input_constructor=input_constructor)
97
+ assert flops == 43904.0 and params == 224.0
98
+
99
+ # test output string
100
+ model = nn.Conv3d(3, 8, 3)
101
+ x = (3, 3, 512, 512)
102
+ flops, params = get_model_complexity_info(
103
+ model, x, print_per_layer_stat=False)
104
+ assert flops == '0.17 GFLOPs' and params == str(656)
105
+
106
+ # test print per layer status
107
+ model = nn.Conv1d(3, 8, 3)
108
+ x = (3, 16)
109
+ out = StringIO()
110
+ get_model_complexity_info(model, x, ost=out)
111
+ assert out.getvalue() == \
112
+ 'Conv1d(0.0 M, 100.000% Params, 0.0 GFLOPs, 100.000% FLOPs, 3, 8, kernel_size=(3,), stride=(1,))\n' # noqa: E501
113
+
114
+ # test when model is not a common instance
115
+ model = nn.Sequential(nn.Conv2d(3, 8, 3), nn.Flatten(), nn.Linear(1568, 2))
116
+ x = (3, 16, 16)
117
+ flops, params = get_model_complexity_info(
118
+ model, x, as_strings=False, print_per_layer_stat=True)
119
+ assert flops == 47040.0 and params == 3362
120
+
121
+
122
+ def test_flops_to_string():
123
+ flops = 6.54321 * 10.**9
124
+ assert flops_to_string(flops) == '6.54 GFLOPs'
125
+ assert flops_to_string(flops, 'MFLOPs') == '6543.21 MFLOPs'
126
+ assert flops_to_string(flops, 'KFLOPs') == '6543210.0 KFLOPs'
127
+ assert flops_to_string(flops, 'FLOPs') == '6543210000.0 FLOPs'
128
+ assert flops_to_string(flops, precision=4) == '6.5432 GFLOPs'
129
+
130
+ flops = 6.54321 * 10.**9
131
+ assert flops_to_string(flops, None) == '6.54 GFLOPs'
132
+ flops = 3.21 * 10.**7
133
+ assert flops_to_string(flops, None) == '32.1 MFLOPs'
134
+ flops = 5.4 * 10.**3
135
+ assert flops_to_string(flops, None) == '5.4 KFLOPs'
136
+ flops = 987
137
+ assert flops_to_string(flops, None) == '987 FLOPs'
138
+
139
+
140
+ def test_params_to_string():
141
+ num_params = 3.21 * 10.**7
142
+ assert params_to_string(num_params) == '32.1 M'
143
+ num_params = 4.56 * 10.**5
144
+ assert params_to_string(num_params) == '456.0 k'
145
+ num_params = 7.89 * 10.**2
146
+ assert params_to_string(num_params) == '789.0'
147
+
148
+ num_params = 6.54321 * 10.**7
149
+ assert params_to_string(num_params, 'M') == '65.43 M'
150
+ assert params_to_string(num_params, 'K') == '65432.1 K'
151
+ assert params_to_string(num_params, '') == '65432100.0'
152
+ assert params_to_string(num_params, precision=4) == '65.4321 M'
groundingLMM/mmcv/tests/test_cnn/test_fuse_conv_bn.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import torch
3
+ import torch.nn as nn
4
+
5
+ from mmcv.cnn import ConvModule, fuse_conv_bn
6
+
7
+
8
+ def test_fuse_conv_bn():
9
+ inputs = torch.rand((1, 3, 5, 5))
10
+ modules = nn.ModuleList()
11
+ modules.append(nn.BatchNorm2d(3))
12
+ modules.append(ConvModule(3, 5, 3, norm_cfg=dict(type='BN')))
13
+ modules.append(ConvModule(5, 5, 3, norm_cfg=dict(type='BN')))
14
+ modules = nn.Sequential(*modules)
15
+ fused_modules = fuse_conv_bn(modules)
16
+ assert torch.equal(modules(inputs), fused_modules(inputs))
groundingLMM/mmcv/tests/test_cnn/test_generalized_attention.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import torch
3
+
4
+ from mmcv.cnn.bricks import GeneralizedAttention
5
+
6
+
7
+ def test_context_block():
8
+
9
+ # test attention_type='1000'
10
+ imgs = torch.randn(2, 16, 20, 20)
11
+ gen_attention_block = GeneralizedAttention(16, attention_type='1000')
12
+ assert gen_attention_block.query_conv.in_channels == 16
13
+ assert gen_attention_block.key_conv.in_channels == 16
14
+ assert gen_attention_block.key_conv.in_channels == 16
15
+ out = gen_attention_block(imgs)
16
+ assert out.shape == imgs.shape
17
+
18
+ # test attention_type='0100'
19
+ imgs = torch.randn(2, 16, 20, 20)
20
+ gen_attention_block = GeneralizedAttention(16, attention_type='0100')
21
+ assert gen_attention_block.query_conv.in_channels == 16
22
+ assert gen_attention_block.appr_geom_fc_x.in_features == 8
23
+ assert gen_attention_block.appr_geom_fc_y.in_features == 8
24
+ out = gen_attention_block(imgs)
25
+ assert out.shape == imgs.shape
26
+
27
+ # test attention_type='0010'
28
+ imgs = torch.randn(2, 16, 20, 20)
29
+ gen_attention_block = GeneralizedAttention(16, attention_type='0010')
30
+ assert gen_attention_block.key_conv.in_channels == 16
31
+ assert hasattr(gen_attention_block, 'appr_bias')
32
+ out = gen_attention_block(imgs)
33
+ assert out.shape == imgs.shape
34
+
35
+ # test attention_type='0001'
36
+ imgs = torch.randn(2, 16, 20, 20)
37
+ gen_attention_block = GeneralizedAttention(16, attention_type='0001')
38
+ assert gen_attention_block.appr_geom_fc_x.in_features == 8
39
+ assert gen_attention_block.appr_geom_fc_y.in_features == 8
40
+ assert hasattr(gen_attention_block, 'geom_bias')
41
+ out = gen_attention_block(imgs)
42
+ assert out.shape == imgs.shape
43
+
44
+ # test spatial_range >= 0
45
+ imgs = torch.randn(2, 256, 20, 20)
46
+ gen_attention_block = GeneralizedAttention(256, spatial_range=10)
47
+ assert hasattr(gen_attention_block, 'local_constraint_map')
48
+ out = gen_attention_block(imgs)
49
+ assert out.shape == imgs.shape
50
+
51
+ # test q_stride > 1
52
+ imgs = torch.randn(2, 16, 20, 20)
53
+ gen_attention_block = GeneralizedAttention(16, q_stride=2)
54
+ assert gen_attention_block.q_downsample is not None
55
+ out = gen_attention_block(imgs)
56
+ assert out.shape == imgs.shape
57
+
58
+ # test kv_stride > 1
59
+ imgs = torch.randn(2, 16, 20, 20)
60
+ gen_attention_block = GeneralizedAttention(16, kv_stride=2)
61
+ assert gen_attention_block.kv_downsample is not None
62
+ out = gen_attention_block(imgs)
63
+ assert out.shape == imgs.shape
64
+
65
+ # test fp16 with attention_type='1111'
66
+ if torch.cuda.is_available():
67
+ imgs = torch.randn(2, 16, 20, 20).cuda().to(torch.half)
68
+ gen_attention_block = GeneralizedAttention(
69
+ 16,
70
+ spatial_range=-1,
71
+ num_heads=8,
72
+ attention_type='1111',
73
+ kv_stride=2)
74
+ gen_attention_block.cuda().type(torch.half)
75
+ out = gen_attention_block(imgs)
76
+ assert out.shape == imgs.shape
groundingLMM/mmcv/tests/test_cnn/test_hsigmoid.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import pytest
3
+ import torch
4
+
5
+ from mmcv.cnn.bricks import HSigmoid
6
+
7
+
8
+ def test_hsigmoid():
9
+ # test assertion divisor can not be zero
10
+ with pytest.raises(AssertionError):
11
+ HSigmoid(divisor=0)
12
+
13
+ # test with default parameters
14
+ act = HSigmoid()
15
+ input_shape = torch.Size([1, 3, 64, 64])
16
+ input = torch.randn(input_shape)
17
+ output = act(input)
18
+ expected_output = torch.min(
19
+ torch.max((input + 3) / 6, torch.zeros(input_shape)),
20
+ torch.ones(input_shape))
21
+ # test output shape
22
+ assert output.shape == expected_output.shape
23
+ # test output value
24
+ assert torch.equal(output, expected_output)
25
+
26
+ # test with designated parameters
27
+ act = HSigmoid(1, 2, 0, 1)
28
+ input_shape = torch.Size([1, 3, 64, 64])
29
+ input = torch.randn(input_shape)
30
+ output = act(input)
31
+ expected_output = torch.min(
32
+ torch.max((input + 1) / 2, torch.zeros(input_shape)),
33
+ torch.ones(input_shape))
34
+ # test output shape
35
+ assert output.shape == expected_output.shape
36
+ # test output value
37
+ assert torch.equal(output, expected_output)
groundingLMM/mmcv/tests/test_cnn/test_hswish.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import torch
3
+ from torch.nn.functional import relu6
4
+
5
+ from mmcv.cnn.bricks import HSwish
6
+
7
+
8
+ def test_hswish():
9
+ # test inplace
10
+ act = HSwish(inplace=True)
11
+ assert act.act.inplace
12
+ act = HSwish()
13
+ assert not act.act.inplace
14
+
15
+ input = torch.randn(1, 3, 64, 64)
16
+ expected_output = input * relu6(input + 3) / 6
17
+ output = act(input)
18
+ # test output shape
19
+ assert output.shape == expected_output.shape
20
+ # test output value
21
+ assert torch.equal(output, expected_output)
groundingLMM/mmcv/tests/test_cnn/test_model_registry.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import torch.nn as nn
3
+
4
+ import mmcv
5
+ from mmcv.cnn import MODELS, build_model_from_cfg
6
+
7
+
8
+ def test_build_model_from_cfg():
9
+ BACKBONES = mmcv.Registry('backbone', build_func=build_model_from_cfg)
10
+
11
+ @BACKBONES.register_module()
12
+ class ResNet(nn.Module):
13
+
14
+ def __init__(self, depth, stages=4):
15
+ super().__init__()
16
+ self.depth = depth
17
+ self.stages = stages
18
+
19
+ def forward(self, x):
20
+ return x
21
+
22
+ @BACKBONES.register_module()
23
+ class ResNeXt(nn.Module):
24
+
25
+ def __init__(self, depth, stages=4):
26
+ super().__init__()
27
+ self.depth = depth
28
+ self.stages = stages
29
+
30
+ def forward(self, x):
31
+ return x
32
+
33
+ cfg = dict(type='ResNet', depth=50)
34
+ model = BACKBONES.build(cfg)
35
+ assert isinstance(model, ResNet)
36
+ assert model.depth == 50 and model.stages == 4
37
+
38
+ cfg = dict(type='ResNeXt', depth=50, stages=3)
39
+ model = BACKBONES.build(cfg)
40
+ assert isinstance(model, ResNeXt)
41
+ assert model.depth == 50 and model.stages == 3
42
+
43
+ cfg = [
44
+ dict(type='ResNet', depth=50),
45
+ dict(type='ResNeXt', depth=50, stages=3)
46
+ ]
47
+ model = BACKBONES.build(cfg)
48
+ assert isinstance(model, nn.Sequential)
49
+ assert isinstance(model[0], ResNet)
50
+ assert model[0].depth == 50 and model[0].stages == 4
51
+ assert isinstance(model[1], ResNeXt)
52
+ assert model[1].depth == 50 and model[1].stages == 3
53
+
54
+ # test inherit `build_func` from parent
55
+ NEW_MODELS = mmcv.Registry('models', parent=MODELS, scope='new')
56
+ assert NEW_MODELS.build_func is build_model_from_cfg
57
+
58
+ # test specify `build_func`
59
+ def pseudo_build(cfg):
60
+ return cfg
61
+
62
+ NEW_MODELS = mmcv.Registry(
63
+ 'models', parent=MODELS, build_func=pseudo_build)
64
+ assert NEW_MODELS.build_func is pseudo_build
groundingLMM/mmcv/tests/test_cnn/test_non_local.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import pytest
3
+ import torch
4
+ import torch.nn as nn
5
+
6
+ from mmcv.cnn import NonLocal1d, NonLocal2d, NonLocal3d
7
+ from mmcv.cnn.bricks.non_local import _NonLocalNd
8
+
9
+
10
+ def test_nonlocal():
11
+ with pytest.raises(ValueError):
12
+ # mode should be in ['embedded_gaussian', 'dot_product']
13
+ _NonLocalNd(3, mode='unsupport_mode')
14
+
15
+ # _NonLocalNd with zero initialization
16
+ _NonLocalNd(3)
17
+ _NonLocalNd(3, norm_cfg=dict(type='BN'))
18
+
19
+ # _NonLocalNd without zero initialization
20
+ _NonLocalNd(3, zeros_init=False)
21
+ _NonLocalNd(3, norm_cfg=dict(type='BN'), zeros_init=False)
22
+
23
+
24
+ def test_nonlocal3d():
25
+ # NonLocal3d with 'embedded_gaussian' mode
26
+ imgs = torch.randn(2, 3, 10, 20, 20)
27
+ nonlocal_3d = NonLocal3d(3)
28
+ if torch.__version__ == 'parrots':
29
+ if torch.cuda.is_available():
30
+ # NonLocal is only implemented on gpu in parrots
31
+ imgs = imgs.cuda()
32
+ nonlocal_3d.cuda()
33
+ out = nonlocal_3d(imgs)
34
+ assert out.shape == imgs.shape
35
+
36
+ # NonLocal3d with 'dot_product' mode
37
+ nonlocal_3d = NonLocal3d(3, mode='dot_product')
38
+ assert nonlocal_3d.mode == 'dot_product'
39
+ if torch.__version__ == 'parrots':
40
+ if torch.cuda.is_available():
41
+ nonlocal_3d.cuda()
42
+ out = nonlocal_3d(imgs)
43
+ assert out.shape == imgs.shape
44
+
45
+ # NonLocal3d with 'concatenation' mode
46
+ nonlocal_3d = NonLocal3d(3, mode='concatenation')
47
+ assert nonlocal_3d.mode == 'concatenation'
48
+ if torch.__version__ == 'parrots':
49
+ if torch.cuda.is_available():
50
+ nonlocal_3d.cuda()
51
+ out = nonlocal_3d(imgs)
52
+ assert out.shape == imgs.shape
53
+
54
+ # NonLocal3d with 'gaussian' mode
55
+ nonlocal_3d = NonLocal3d(3, mode='gaussian')
56
+ assert not hasattr(nonlocal_3d, 'phi')
57
+ assert nonlocal_3d.mode == 'gaussian'
58
+ if torch.__version__ == 'parrots':
59
+ if torch.cuda.is_available():
60
+ nonlocal_3d.cuda()
61
+ out = nonlocal_3d(imgs)
62
+ assert out.shape == imgs.shape
63
+
64
+ # NonLocal3d with 'gaussian' mode and sub_sample
65
+ nonlocal_3d = NonLocal3d(3, mode='gaussian', sub_sample=True)
66
+ assert isinstance(nonlocal_3d.g, nn.Sequential) and len(nonlocal_3d.g) == 2
67
+ assert isinstance(nonlocal_3d.g[1], nn.MaxPool3d)
68
+ assert nonlocal_3d.g[1].kernel_size == (1, 2, 2)
69
+ assert isinstance(nonlocal_3d.phi, nn.MaxPool3d)
70
+ if torch.__version__ == 'parrots':
71
+ if torch.cuda.is_available():
72
+ nonlocal_3d.cuda()
73
+ out = nonlocal_3d(imgs)
74
+ assert out.shape == imgs.shape
75
+
76
+ # NonLocal3d with 'dot_product' mode and sub_sample
77
+ nonlocal_3d = NonLocal3d(3, mode='dot_product', sub_sample=True)
78
+ for m in [nonlocal_3d.g, nonlocal_3d.phi]:
79
+ assert isinstance(m, nn.Sequential) and len(m) == 2
80
+ assert isinstance(m[1], nn.MaxPool3d)
81
+ assert m[1].kernel_size == (1, 2, 2)
82
+ if torch.__version__ == 'parrots':
83
+ if torch.cuda.is_available():
84
+ nonlocal_3d.cuda()
85
+ out = nonlocal_3d(imgs)
86
+ assert out.shape == imgs.shape
87
+
88
+
89
+ def test_nonlocal2d():
90
+ # NonLocal2d with 'embedded_gaussian' mode
91
+ imgs = torch.randn(2, 3, 20, 20)
92
+ nonlocal_2d = NonLocal2d(3)
93
+ if torch.__version__ == 'parrots':
94
+ if torch.cuda.is_available():
95
+ imgs = imgs.cuda()
96
+ nonlocal_2d.cuda()
97
+ out = nonlocal_2d(imgs)
98
+ assert out.shape == imgs.shape
99
+
100
+ # NonLocal2d with 'dot_product' mode
101
+ imgs = torch.randn(2, 3, 20, 20)
102
+ nonlocal_2d = NonLocal2d(3, mode='dot_product')
103
+ if torch.__version__ == 'parrots':
104
+ if torch.cuda.is_available():
105
+ imgs = imgs.cuda()
106
+ nonlocal_2d.cuda()
107
+ out = nonlocal_2d(imgs)
108
+ assert out.shape == imgs.shape
109
+
110
+ # NonLocal2d with 'concatenation' mode
111
+ imgs = torch.randn(2, 3, 20, 20)
112
+ nonlocal_2d = NonLocal2d(3, mode='concatenation')
113
+ if torch.__version__ == 'parrots':
114
+ if torch.cuda.is_available():
115
+ imgs = imgs.cuda()
116
+ nonlocal_2d.cuda()
117
+ out = nonlocal_2d(imgs)
118
+ assert out.shape == imgs.shape
119
+
120
+ # NonLocal2d with 'gaussian' mode
121
+ imgs = torch.randn(2, 3, 20, 20)
122
+ nonlocal_2d = NonLocal2d(3, mode='gaussian')
123
+ assert not hasattr(nonlocal_2d, 'phi')
124
+ if torch.__version__ == 'parrots':
125
+ if torch.cuda.is_available():
126
+ imgs = imgs.cuda()
127
+ nonlocal_2d.cuda()
128
+ out = nonlocal_2d(imgs)
129
+ assert out.shape == imgs.shape
130
+
131
+ # NonLocal2d with 'gaussian' mode and sub_sample
132
+ nonlocal_2d = NonLocal2d(3, mode='gaussian', sub_sample=True)
133
+ assert isinstance(nonlocal_2d.g, nn.Sequential) and len(nonlocal_2d.g) == 2
134
+ assert isinstance(nonlocal_2d.g[1], nn.MaxPool2d)
135
+ assert nonlocal_2d.g[1].kernel_size == (2, 2)
136
+ assert isinstance(nonlocal_2d.phi, nn.MaxPool2d)
137
+ if torch.__version__ == 'parrots':
138
+ if torch.cuda.is_available():
139
+ nonlocal_2d.cuda()
140
+ out = nonlocal_2d(imgs)
141
+ assert out.shape == imgs.shape
142
+
143
+ # NonLocal2d with 'dot_product' mode and sub_sample
144
+ nonlocal_2d = NonLocal2d(3, mode='dot_product', sub_sample=True)
145
+ for m in [nonlocal_2d.g, nonlocal_2d.phi]:
146
+ assert isinstance(m, nn.Sequential) and len(m) == 2
147
+ assert isinstance(m[1], nn.MaxPool2d)
148
+ assert m[1].kernel_size == (2, 2)
149
+ if torch.__version__ == 'parrots':
150
+ if torch.cuda.is_available():
151
+ nonlocal_2d.cuda()
152
+ out = nonlocal_2d(imgs)
153
+ assert out.shape == imgs.shape
154
+
155
+
156
+ def test_nonlocal1d():
157
+ # NonLocal1d with 'embedded_gaussian' mode
158
+ imgs = torch.randn(2, 3, 20)
159
+ nonlocal_1d = NonLocal1d(3)
160
+ if torch.__version__ == 'parrots':
161
+ if torch.cuda.is_available():
162
+ imgs = imgs.cuda()
163
+ nonlocal_1d.cuda()
164
+ out = nonlocal_1d(imgs)
165
+ assert out.shape == imgs.shape
166
+
167
+ # NonLocal1d with 'dot_product' mode
168
+ imgs = torch.randn(2, 3, 20)
169
+ nonlocal_1d = NonLocal1d(3, mode='dot_product')
170
+ if torch.__version__ == 'parrots':
171
+ if torch.cuda.is_available():
172
+ imgs = imgs.cuda()
173
+ nonlocal_1d.cuda()
174
+ out = nonlocal_1d(imgs)
175
+ assert out.shape == imgs.shape
176
+
177
+ # NonLocal1d with 'concatenation' mode
178
+ imgs = torch.randn(2, 3, 20)
179
+ nonlocal_1d = NonLocal1d(3, mode='concatenation')
180
+ if torch.__version__ == 'parrots':
181
+ if torch.cuda.is_available():
182
+ imgs = imgs.cuda()
183
+ nonlocal_1d.cuda()
184
+ out = nonlocal_1d(imgs)
185
+ assert out.shape == imgs.shape
186
+
187
+ # NonLocal1d with 'gaussian' mode
188
+ imgs = torch.randn(2, 3, 20)
189
+ nonlocal_1d = NonLocal1d(3, mode='gaussian')
190
+ assert not hasattr(nonlocal_1d, 'phi')
191
+ if torch.__version__ == 'parrots':
192
+ if torch.cuda.is_available():
193
+ imgs = imgs.cuda()
194
+ nonlocal_1d.cuda()
195
+ out = nonlocal_1d(imgs)
196
+ assert out.shape == imgs.shape
197
+
198
+ # NonLocal1d with 'gaussian' mode and sub_sample
199
+ nonlocal_1d = NonLocal1d(3, mode='gaussian', sub_sample=True)
200
+ assert isinstance(nonlocal_1d.g, nn.Sequential) and len(nonlocal_1d.g) == 2
201
+ assert isinstance(nonlocal_1d.g[1], nn.MaxPool1d)
202
+ assert nonlocal_1d.g[1].kernel_size == 2
203
+ assert isinstance(nonlocal_1d.phi, nn.MaxPool1d)
204
+ if torch.__version__ == 'parrots':
205
+ if torch.cuda.is_available():
206
+ nonlocal_1d.cuda()
207
+ out = nonlocal_1d(imgs)
208
+ assert out.shape == imgs.shape
209
+
210
+ # NonLocal1d with 'dot_product' mode and sub_sample
211
+ nonlocal_1d = NonLocal1d(3, mode='dot_product', sub_sample=True)
212
+ for m in [nonlocal_1d.g, nonlocal_1d.phi]:
213
+ assert isinstance(m, nn.Sequential) and len(m) == 2
214
+ assert isinstance(m[1], nn.MaxPool1d)
215
+ assert m[1].kernel_size == 2
216
+ if torch.__version__ == 'parrots':
217
+ if torch.cuda.is_available():
218
+ nonlocal_1d.cuda()
219
+ out = nonlocal_1d(imgs)
220
+ assert out.shape == imgs.shape
groundingLMM/mmcv/tests/test_cnn/test_revert_syncbn.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import os
3
+ import platform
4
+
5
+ import numpy as np
6
+ import pytest
7
+ import torch
8
+ import torch.distributed as dist
9
+
10
+ from mmcv.cnn.bricks import ConvModule
11
+ from mmcv.cnn.utils import revert_sync_batchnorm
12
+
13
+ if platform.system() == 'Windows':
14
+ import regex as re
15
+ else:
16
+ import re
17
+
18
+
19
+ def test_revert_syncbn():
20
+ conv = ConvModule(3, 8, 2, norm_cfg=dict(type='SyncBN'))
21
+ x = torch.randn(1, 3, 10, 10)
22
+ # Expect a ValueError prompting that SyncBN is not supported on CPU
23
+ with pytest.raises(ValueError):
24
+ y = conv(x)
25
+ conv = revert_sync_batchnorm(conv)
26
+ y = conv(x)
27
+ assert y.shape == (1, 8, 9, 9)
28
+
29
+
30
+ def test_revert_mmsyncbn():
31
+ if 'SLURM_NTASKS' not in os.environ or int(os.environ['SLURM_NTASKS']) < 2:
32
+ print('Must run on slurm with more than 1 process!\n'
33
+ 'srun -p test --gres=gpu:2 -n2')
34
+ return
35
+ rank = int(os.environ['SLURM_PROCID'])
36
+ world_size = int(os.environ['SLURM_NTASKS'])
37
+ local_rank = int(os.environ['SLURM_LOCALID'])
38
+ node_list = str(os.environ['SLURM_NODELIST'])
39
+
40
+ node_parts = re.findall('[0-9]+', node_list)
41
+ os.environ['MASTER_ADDR'] = (f'{node_parts[1]}.{node_parts[2]}' +
42
+ f'.{node_parts[3]}.{node_parts[4]}')
43
+ os.environ['MASTER_PORT'] = '12341'
44
+ os.environ['WORLD_SIZE'] = str(world_size)
45
+ os.environ['RANK'] = str(rank)
46
+
47
+ dist.init_process_group('nccl')
48
+ torch.cuda.set_device(local_rank)
49
+ x = torch.randn(1, 3, 10, 10).cuda()
50
+ dist.broadcast(x, src=0)
51
+ conv = ConvModule(3, 8, 2, norm_cfg=dict(type='MMSyncBN')).cuda()
52
+ conv.eval()
53
+ y_mmsyncbn = conv(x).detach().cpu().numpy()
54
+ conv = revert_sync_batchnorm(conv)
55
+ y_bn = conv(x).detach().cpu().numpy()
56
+ assert np.all(np.isclose(y_bn, y_mmsyncbn, 1e-3))
57
+ conv, x = conv.to('cpu'), x.to('cpu')
58
+ y_bn_cpu = conv(x).detach().numpy()
59
+ assert np.all(np.isclose(y_bn, y_bn_cpu, 1e-3))
groundingLMM/mmcv/tests/test_cnn/test_scale.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import torch
3
+
4
+ from mmcv.cnn.bricks import Scale
5
+
6
+
7
+ def test_scale():
8
+ # test default scale
9
+ scale = Scale()
10
+ assert scale.scale.data == 1.
11
+ assert scale.scale.dtype == torch.float
12
+ x = torch.rand(1, 3, 64, 64)
13
+ output = scale(x)
14
+ assert output.shape == (1, 3, 64, 64)
15
+
16
+ # test given scale
17
+ scale = Scale(10.)
18
+ assert scale.scale.data == 10.
19
+ assert scale.scale.dtype == torch.float
20
+ x = torch.rand(1, 3, 64, 64)
21
+ output = scale(x)
22
+ assert output.shape == (1, 3, 64, 64)
groundingLMM/mmcv/tests/test_cnn/test_swish.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import torch
3
+ import torch.nn.functional as F
4
+
5
+ from mmcv.cnn.bricks import Swish
6
+
7
+
8
+ def test_swish():
9
+ act = Swish()
10
+ input = torch.randn(1, 3, 64, 64)
11
+ expected_output = input * F.sigmoid(input)
12
+ output = act(input)
13
+ # test output shape
14
+ assert output.shape == expected_output.shape
15
+ # test output value
16
+ assert torch.equal(output, expected_output)
groundingLMM/mmcv/tests/test_cnn/test_transformer.py ADDED
@@ -0,0 +1,681 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import copy
3
+
4
+ import pytest
5
+ import torch
6
+
7
+ from mmcv.cnn.bricks.drop import DropPath
8
+ from mmcv.cnn.bricks.transformer import (FFN, AdaptivePadding,
9
+ BaseTransformerLayer,
10
+ MultiheadAttention, PatchEmbed,
11
+ PatchMerging,
12
+ TransformerLayerSequence)
13
+ from mmcv.runner import ModuleList
14
+
15
+
16
+ def test_adaptive_padding():
17
+
18
+ for padding in ('same', 'corner'):
19
+ kernel_size = 16
20
+ stride = 16
21
+ dilation = 1
22
+ input = torch.rand(1, 1, 15, 17)
23
+ adap_pad = AdaptivePadding(
24
+ kernel_size=kernel_size,
25
+ stride=stride,
26
+ dilation=dilation,
27
+ padding=padding)
28
+ out = adap_pad(input)
29
+ # padding to divisible by 16
30
+ assert (out.shape[2], out.shape[3]) == (16, 32)
31
+ input = torch.rand(1, 1, 16, 17)
32
+ out = adap_pad(input)
33
+ # padding to divisible by 16
34
+ assert (out.shape[2], out.shape[3]) == (16, 32)
35
+
36
+ kernel_size = (2, 2)
37
+ stride = (2, 2)
38
+ dilation = (1, 1)
39
+
40
+ adap_pad = AdaptivePadding(
41
+ kernel_size=kernel_size,
42
+ stride=stride,
43
+ dilation=dilation,
44
+ padding=padding)
45
+ input = torch.rand(1, 1, 11, 13)
46
+ out = adap_pad(input)
47
+ # padding to divisible by 2
48
+ assert (out.shape[2], out.shape[3]) == (12, 14)
49
+
50
+ kernel_size = (2, 2)
51
+ stride = (10, 10)
52
+ dilation = (1, 1)
53
+
54
+ adap_pad = AdaptivePadding(
55
+ kernel_size=kernel_size,
56
+ stride=stride,
57
+ dilation=dilation,
58
+ padding=padding)
59
+ input = torch.rand(1, 1, 10, 13)
60
+ out = adap_pad(input)
61
+ # no padding
62
+ assert (out.shape[2], out.shape[3]) == (10, 13)
63
+
64
+ kernel_size = (11, 11)
65
+ adap_pad = AdaptivePadding(
66
+ kernel_size=kernel_size,
67
+ stride=stride,
68
+ dilation=dilation,
69
+ padding=padding)
70
+ input = torch.rand(1, 1, 11, 13)
71
+ out = adap_pad(input)
72
+ # all padding
73
+ assert (out.shape[2], out.shape[3]) == (21, 21)
74
+
75
+ # test padding as kernel is (7,9)
76
+ input = torch.rand(1, 1, 11, 13)
77
+ stride = (3, 4)
78
+ kernel_size = (4, 5)
79
+ dilation = (2, 2)
80
+ # actually (7, 9)
81
+ adap_pad = AdaptivePadding(
82
+ kernel_size=kernel_size,
83
+ stride=stride,
84
+ dilation=dilation,
85
+ padding=padding)
86
+ dilation_out = adap_pad(input)
87
+ assert (dilation_out.shape[2], dilation_out.shape[3]) == (16, 21)
88
+ kernel_size = (7, 9)
89
+ dilation = (1, 1)
90
+ adap_pad = AdaptivePadding(
91
+ kernel_size=kernel_size,
92
+ stride=stride,
93
+ dilation=dilation,
94
+ padding=padding)
95
+ kernel79_out = adap_pad(input)
96
+ assert (kernel79_out.shape[2], kernel79_out.shape[3]) == (16, 21)
97
+ assert kernel79_out.shape == dilation_out.shape
98
+
99
+ # assert only support "same" "corner"
100
+ with pytest.raises(AssertionError):
101
+ AdaptivePadding(
102
+ kernel_size=kernel_size,
103
+ stride=stride,
104
+ dilation=dilation,
105
+ padding=1)
106
+
107
+
108
+ def test_patch_embed():
109
+ B = 2
110
+ H = 3
111
+ W = 4
112
+ C = 3
113
+ embed_dims = 10
114
+ kernel_size = 3
115
+ stride = 1
116
+ dummy_input = torch.rand(B, C, H, W)
117
+ patch_merge_1 = PatchEmbed(
118
+ in_channels=C,
119
+ embed_dims=embed_dims,
120
+ kernel_size=kernel_size,
121
+ stride=stride,
122
+ padding=0,
123
+ dilation=1,
124
+ norm_cfg=None)
125
+
126
+ x1, shape = patch_merge_1(dummy_input)
127
+ # test out shape
128
+ assert x1.shape == (2, 2, 10)
129
+ # test outsize is correct
130
+ assert shape == (1, 2)
131
+ # test L = out_h * out_w
132
+ assert shape[0] * shape[1] == x1.shape[1]
133
+
134
+ B = 2
135
+ H = 10
136
+ W = 10
137
+ C = 3
138
+ embed_dims = 10
139
+ kernel_size = 5
140
+ stride = 2
141
+ dummy_input = torch.rand(B, C, H, W)
142
+ # test dilation
143
+ patch_merge_2 = PatchEmbed(
144
+ in_channels=C,
145
+ embed_dims=embed_dims,
146
+ kernel_size=kernel_size,
147
+ stride=stride,
148
+ padding=0,
149
+ dilation=2,
150
+ norm_cfg=None,
151
+ )
152
+
153
+ x2, shape = patch_merge_2(dummy_input)
154
+ # test out shape
155
+ assert x2.shape == (2, 1, 10)
156
+ # test outsize is correct
157
+ assert shape == (1, 1)
158
+ # test L = out_h * out_w
159
+ assert shape[0] * shape[1] == x2.shape[1]
160
+
161
+ stride = 2
162
+ input_size = (10, 10)
163
+
164
+ dummy_input = torch.rand(B, C, H, W)
165
+ # test stride and norm
166
+ patch_merge_3 = PatchEmbed(
167
+ in_channels=C,
168
+ embed_dims=embed_dims,
169
+ kernel_size=kernel_size,
170
+ stride=stride,
171
+ padding=0,
172
+ dilation=2,
173
+ norm_cfg=dict(type='LN'),
174
+ input_size=input_size)
175
+
176
+ x3, shape = patch_merge_3(dummy_input)
177
+ # test out shape
178
+ assert x3.shape == (2, 1, 10)
179
+ # test outsize is correct
180
+ assert shape == (1, 1)
181
+ # test L = out_h * out_w
182
+ assert shape[0] * shape[1] == x3.shape[1]
183
+
184
+ # test the init_out_size with nn.Unfold
185
+ assert patch_merge_3.init_out_size[1] == (input_size[0] - 2 * 4 -
186
+ 1) // 2 + 1
187
+ assert patch_merge_3.init_out_size[0] == (input_size[0] - 2 * 4 -
188
+ 1) // 2 + 1
189
+ H = 11
190
+ W = 12
191
+ input_size = (H, W)
192
+ dummy_input = torch.rand(B, C, H, W)
193
+ # test stride and norm
194
+ patch_merge_3 = PatchEmbed(
195
+ in_channels=C,
196
+ embed_dims=embed_dims,
197
+ kernel_size=kernel_size,
198
+ stride=stride,
199
+ padding=0,
200
+ dilation=2,
201
+ norm_cfg=dict(type='LN'),
202
+ input_size=input_size)
203
+
204
+ _, shape = patch_merge_3(dummy_input)
205
+ # when input_size equal to real input
206
+ # the out_size should be equal to `init_out_size`
207
+ assert shape == patch_merge_3.init_out_size
208
+
209
+ input_size = (H, W)
210
+ dummy_input = torch.rand(B, C, H, W)
211
+ # test stride and norm
212
+ patch_merge_3 = PatchEmbed(
213
+ in_channels=C,
214
+ embed_dims=embed_dims,
215
+ kernel_size=kernel_size,
216
+ stride=stride,
217
+ padding=0,
218
+ dilation=2,
219
+ norm_cfg=dict(type='LN'),
220
+ input_size=input_size)
221
+
222
+ _, shape = patch_merge_3(dummy_input)
223
+ # when input_size equal to real input
224
+ # the out_size should be equal to `init_out_size`
225
+ assert shape == patch_merge_3.init_out_size
226
+
227
+ # test adap padding
228
+ for padding in ('same', 'corner'):
229
+ in_c = 2
230
+ embed_dims = 3
231
+ B = 2
232
+
233
+ # test stride is 1
234
+ input_size = (5, 5)
235
+ kernel_size = (5, 5)
236
+ stride = (1, 1)
237
+ dilation = 1
238
+ bias = False
239
+
240
+ x = torch.rand(B, in_c, *input_size)
241
+ patch_embed = PatchEmbed(
242
+ in_channels=in_c,
243
+ embed_dims=embed_dims,
244
+ kernel_size=kernel_size,
245
+ stride=stride,
246
+ padding=padding,
247
+ dilation=dilation,
248
+ bias=bias)
249
+
250
+ x_out, out_size = patch_embed(x)
251
+ assert x_out.size() == (B, 25, 3)
252
+ assert out_size == (5, 5)
253
+ assert x_out.size(1) == out_size[0] * out_size[1]
254
+
255
+ # test kernel_size == stride
256
+ input_size = (5, 5)
257
+ kernel_size = (5, 5)
258
+ stride = (5, 5)
259
+ dilation = 1
260
+ bias = False
261
+
262
+ x = torch.rand(B, in_c, *input_size)
263
+ patch_embed = PatchEmbed(
264
+ in_channels=in_c,
265
+ embed_dims=embed_dims,
266
+ kernel_size=kernel_size,
267
+ stride=stride,
268
+ padding=padding,
269
+ dilation=dilation,
270
+ bias=bias)
271
+
272
+ x_out, out_size = patch_embed(x)
273
+ assert x_out.size() == (B, 1, 3)
274
+ assert out_size == (1, 1)
275
+ assert x_out.size(1) == out_size[0] * out_size[1]
276
+
277
+ # test kernel_size == stride
278
+ input_size = (6, 5)
279
+ kernel_size = (5, 5)
280
+ stride = (5, 5)
281
+ dilation = 1
282
+ bias = False
283
+
284
+ x = torch.rand(B, in_c, *input_size)
285
+ patch_embed = PatchEmbed(
286
+ in_channels=in_c,
287
+ embed_dims=embed_dims,
288
+ kernel_size=kernel_size,
289
+ stride=stride,
290
+ padding=padding,
291
+ dilation=dilation,
292
+ bias=bias)
293
+
294
+ x_out, out_size = patch_embed(x)
295
+ assert x_out.size() == (B, 2, 3)
296
+ assert out_size == (2, 1)
297
+ assert x_out.size(1) == out_size[0] * out_size[1]
298
+
299
+ # test different kernel_size with different stride
300
+ input_size = (6, 5)
301
+ kernel_size = (6, 2)
302
+ stride = (6, 2)
303
+ dilation = 1
304
+ bias = False
305
+
306
+ x = torch.rand(B, in_c, *input_size)
307
+ patch_embed = PatchEmbed(
308
+ in_channels=in_c,
309
+ embed_dims=embed_dims,
310
+ kernel_size=kernel_size,
311
+ stride=stride,
312
+ padding=padding,
313
+ dilation=dilation,
314
+ bias=bias)
315
+
316
+ x_out, out_size = patch_embed(x)
317
+ assert x_out.size() == (B, 3, 3)
318
+ assert out_size == (1, 3)
319
+ assert x_out.size(1) == out_size[0] * out_size[1]
320
+
321
+
322
+ def test_patch_merging():
323
+
324
+ # Test the model with int padding
325
+ in_c = 3
326
+ out_c = 4
327
+ kernel_size = 3
328
+ stride = 3
329
+ padding = 1
330
+ dilation = 1
331
+ bias = False
332
+ # test the case `pad_to_stride` is False
333
+ patch_merge = PatchMerging(
334
+ in_channels=in_c,
335
+ out_channels=out_c,
336
+ kernel_size=kernel_size,
337
+ stride=stride,
338
+ padding=padding,
339
+ dilation=dilation,
340
+ bias=bias)
341
+ B, L, C = 1, 100, 3
342
+ input_size = (10, 10)
343
+ x = torch.rand(B, L, C)
344
+ x_out, out_size = patch_merge(x, input_size)
345
+ assert x_out.size() == (1, 16, 4)
346
+ assert out_size == (4, 4)
347
+ # assert out size is consistent with real output
348
+ assert x_out.size(1) == out_size[0] * out_size[1]
349
+ in_c = 4
350
+ out_c = 5
351
+ kernel_size = 6
352
+ stride = 3
353
+ padding = 2
354
+ dilation = 2
355
+ bias = False
356
+ patch_merge = PatchMerging(
357
+ in_channels=in_c,
358
+ out_channels=out_c,
359
+ kernel_size=kernel_size,
360
+ stride=stride,
361
+ padding=padding,
362
+ dilation=dilation,
363
+ bias=bias)
364
+ B, L, C = 1, 100, 4
365
+ input_size = (10, 10)
366
+ x = torch.rand(B, L, C)
367
+ x_out, out_size = patch_merge(x, input_size)
368
+ assert x_out.size() == (1, 4, 5)
369
+ assert out_size == (2, 2)
370
+ # assert out size is consistent with real output
371
+ assert x_out.size(1) == out_size[0] * out_size[1]
372
+
373
+ # Test with adaptive padding
374
+ for padding in ('same', 'corner'):
375
+ in_c = 2
376
+ out_c = 3
377
+ B = 2
378
+
379
+ # test stride is 1
380
+ input_size = (5, 5)
381
+ kernel_size = (5, 5)
382
+ stride = (1, 1)
383
+ dilation = 1
384
+ bias = False
385
+ L = input_size[0] * input_size[1]
386
+
387
+ x = torch.rand(B, L, in_c)
388
+ patch_merge = PatchMerging(
389
+ in_channels=in_c,
390
+ out_channels=out_c,
391
+ kernel_size=kernel_size,
392
+ stride=stride,
393
+ padding=padding,
394
+ dilation=dilation,
395
+ bias=bias)
396
+
397
+ x_out, out_size = patch_merge(x, input_size)
398
+ assert x_out.size() == (B, 25, 3)
399
+ assert out_size == (5, 5)
400
+ assert x_out.size(1) == out_size[0] * out_size[1]
401
+
402
+ # test kernel_size == stride
403
+ input_size = (5, 5)
404
+ kernel_size = (5, 5)
405
+ stride = (5, 5)
406
+ dilation = 1
407
+ bias = False
408
+ L = input_size[0] * input_size[1]
409
+
410
+ x = torch.rand(B, L, in_c)
411
+ patch_merge = PatchMerging(
412
+ in_channels=in_c,
413
+ out_channels=out_c,
414
+ kernel_size=kernel_size,
415
+ stride=stride,
416
+ padding=padding,
417
+ dilation=dilation,
418
+ bias=bias)
419
+
420
+ x_out, out_size = patch_merge(x, input_size)
421
+ assert x_out.size() == (B, 1, 3)
422
+ assert out_size == (1, 1)
423
+ assert x_out.size(1) == out_size[0] * out_size[1]
424
+
425
+ # test kernel_size == stride
426
+ input_size = (6, 5)
427
+ kernel_size = (5, 5)
428
+ stride = (5, 5)
429
+ dilation = 1
430
+ bias = False
431
+ L = input_size[0] * input_size[1]
432
+
433
+ x = torch.rand(B, L, in_c)
434
+ patch_merge = PatchMerging(
435
+ in_channels=in_c,
436
+ out_channels=out_c,
437
+ kernel_size=kernel_size,
438
+ stride=stride,
439
+ padding=padding,
440
+ dilation=dilation,
441
+ bias=bias)
442
+
443
+ x_out, out_size = patch_merge(x, input_size)
444
+ assert x_out.size() == (B, 2, 3)
445
+ assert out_size == (2, 1)
446
+ assert x_out.size(1) == out_size[0] * out_size[1]
447
+
448
+ # test different kernel_size with different stride
449
+ input_size = (6, 5)
450
+ kernel_size = (6, 2)
451
+ stride = (6, 2)
452
+ dilation = 1
453
+ bias = False
454
+ L = input_size[0] * input_size[1]
455
+
456
+ x = torch.rand(B, L, in_c)
457
+ patch_merge = PatchMerging(
458
+ in_channels=in_c,
459
+ out_channels=out_c,
460
+ kernel_size=kernel_size,
461
+ stride=stride,
462
+ padding=padding,
463
+ dilation=dilation,
464
+ bias=bias)
465
+
466
+ x_out, out_size = patch_merge(x, input_size)
467
+ assert x_out.size() == (B, 3, 3)
468
+ assert out_size == (1, 3)
469
+ assert x_out.size(1) == out_size[0] * out_size[1]
470
+
471
+
472
+ def test_multiheadattention():
473
+ MultiheadAttention(
474
+ embed_dims=5,
475
+ num_heads=5,
476
+ attn_drop=0,
477
+ proj_drop=0,
478
+ dropout_layer=dict(type='Dropout', drop_prob=0.),
479
+ batch_first=True)
480
+ batch_dim = 2
481
+ embed_dim = 5
482
+ num_query = 100
483
+ attn_batch_first = MultiheadAttention(
484
+ embed_dims=5,
485
+ num_heads=5,
486
+ attn_drop=0,
487
+ proj_drop=0,
488
+ dropout_layer=dict(type='DropPath', drop_prob=0.),
489
+ batch_first=True)
490
+
491
+ attn_query_first = MultiheadAttention(
492
+ embed_dims=5,
493
+ num_heads=5,
494
+ attn_drop=0,
495
+ proj_drop=0,
496
+ dropout_layer=dict(type='DropPath', drop_prob=0.),
497
+ batch_first=False)
498
+
499
+ param_dict = dict(attn_query_first.named_parameters())
500
+ for n, v in attn_batch_first.named_parameters():
501
+ param_dict[n].data = v.data
502
+
503
+ input_batch_first = torch.rand(batch_dim, num_query, embed_dim)
504
+ input_query_first = input_batch_first.transpose(0, 1)
505
+
506
+ assert torch.allclose(
507
+ attn_query_first(input_query_first).sum(),
508
+ attn_batch_first(input_batch_first).sum())
509
+
510
+ key_batch_first = torch.rand(batch_dim, num_query, embed_dim)
511
+ key_query_first = key_batch_first.transpose(0, 1)
512
+
513
+ assert torch.allclose(
514
+ attn_query_first(input_query_first, key_query_first).sum(),
515
+ attn_batch_first(input_batch_first, key_batch_first).sum())
516
+
517
+ identity = torch.ones_like(input_query_first)
518
+
519
+ # check deprecated arguments can be used normally
520
+
521
+ assert torch.allclose(
522
+ attn_query_first(
523
+ input_query_first, key_query_first, residual=identity).sum(),
524
+ attn_batch_first(input_batch_first, key_batch_first).sum() +
525
+ identity.sum() - input_batch_first.sum())
526
+
527
+ assert torch.allclose(
528
+ attn_query_first(
529
+ input_query_first, key_query_first, identity=identity).sum(),
530
+ attn_batch_first(input_batch_first, key_batch_first).sum() +
531
+ identity.sum() - input_batch_first.sum())
532
+
533
+ attn_query_first(
534
+ input_query_first, key_query_first, identity=identity).sum(),
535
+
536
+
537
+ def test_ffn():
538
+ with pytest.raises(AssertionError):
539
+ # num_fcs should be no less than 2
540
+ FFN(num_fcs=1)
541
+ FFN(dropout=0, add_residual=True)
542
+ ffn = FFN(dropout=0, add_identity=True)
543
+
544
+ input_tensor = torch.rand(2, 20, 256)
545
+ input_tensor_nbc = input_tensor.transpose(0, 1)
546
+ assert torch.allclose(ffn(input_tensor).sum(), ffn(input_tensor_nbc).sum())
547
+ residual = torch.rand_like(input_tensor)
548
+ torch.allclose(
549
+ ffn(input_tensor, residual=residual).sum(),
550
+ ffn(input_tensor).sum() + residual.sum() - input_tensor.sum())
551
+
552
+ torch.allclose(
553
+ ffn(input_tensor, identity=residual).sum(),
554
+ ffn(input_tensor).sum() + residual.sum() - input_tensor.sum())
555
+
556
+
557
+ @pytest.mark.skipif(not torch.cuda.is_available(), reason='Cuda not available')
558
+ def test_basetransformerlayer_cuda():
559
+ # To test if the BaseTransformerLayer's behaviour remains
560
+ # consistent after being deepcopied
561
+ operation_order = ('self_attn', 'ffn')
562
+ baselayer = BaseTransformerLayer(
563
+ operation_order=operation_order,
564
+ batch_first=True,
565
+ attn_cfgs=dict(
566
+ type='MultiheadAttention',
567
+ embed_dims=256,
568
+ num_heads=8,
569
+ ),
570
+ )
571
+ baselayers = ModuleList([copy.deepcopy(baselayer) for _ in range(2)])
572
+ baselayers.to('cuda')
573
+ x = torch.rand(2, 10, 256).cuda()
574
+ for m in baselayers:
575
+ x = m(x)
576
+ assert x.shape == torch.Size([2, 10, 256])
577
+
578
+
579
+ @pytest.mark.parametrize('embed_dims', [False, 256])
580
+ def test_basetransformerlayer(embed_dims):
581
+ attn_cfgs = dict(type='MultiheadAttention', embed_dims=256, num_heads=8),
582
+ if embed_dims:
583
+ ffn_cfgs = dict(
584
+ type='FFN',
585
+ embed_dims=embed_dims,
586
+ feedforward_channels=1024,
587
+ num_fcs=2,
588
+ ffn_drop=0.,
589
+ act_cfg=dict(type='ReLU', inplace=True),
590
+ )
591
+ else:
592
+ ffn_cfgs = dict(
593
+ type='FFN',
594
+ feedforward_channels=1024,
595
+ num_fcs=2,
596
+ ffn_drop=0.,
597
+ act_cfg=dict(type='ReLU', inplace=True),
598
+ )
599
+
600
+ feedforward_channels = 2048
601
+ ffn_dropout = 0.1
602
+ operation_order = ('self_attn', 'norm', 'ffn', 'norm')
603
+
604
+ # test deprecated_args
605
+ baselayer = BaseTransformerLayer(
606
+ attn_cfgs=attn_cfgs,
607
+ ffn_cfgs=ffn_cfgs,
608
+ feedforward_channels=feedforward_channels,
609
+ ffn_dropout=ffn_dropout,
610
+ operation_order=operation_order)
611
+ assert baselayer.batch_first is False
612
+ assert baselayer.ffns[0].feedforward_channels == feedforward_channels
613
+
614
+ attn_cfgs = dict(type='MultiheadAttention', num_heads=8, embed_dims=256),
615
+ feedforward_channels = 2048
616
+ ffn_dropout = 0.1
617
+ operation_order = ('self_attn', 'norm', 'ffn', 'norm')
618
+ baselayer = BaseTransformerLayer(
619
+ attn_cfgs=attn_cfgs,
620
+ feedforward_channels=feedforward_channels,
621
+ ffn_dropout=ffn_dropout,
622
+ operation_order=operation_order,
623
+ batch_first=True)
624
+ assert baselayer.attentions[0].batch_first
625
+ in_tensor = torch.rand(2, 10, 256)
626
+ baselayer(in_tensor)
627
+
628
+
629
+ def test_transformerlayersequence():
630
+ squeue = TransformerLayerSequence(
631
+ num_layers=6,
632
+ transformerlayers=dict(
633
+ type='BaseTransformerLayer',
634
+ attn_cfgs=[
635
+ dict(
636
+ type='MultiheadAttention',
637
+ embed_dims=256,
638
+ num_heads=8,
639
+ dropout=0.1),
640
+ dict(type='MultiheadAttention', embed_dims=256, num_heads=4)
641
+ ],
642
+ feedforward_channels=1024,
643
+ ffn_dropout=0.1,
644
+ operation_order=('self_attn', 'norm', 'cross_attn', 'norm', 'ffn',
645
+ 'norm')))
646
+ assert len(squeue.layers) == 6
647
+ assert squeue.pre_norm is False
648
+ with pytest.raises(AssertionError):
649
+ # if transformerlayers is a list, len(transformerlayers)
650
+ # should be equal to num_layers
651
+ TransformerLayerSequence(
652
+ num_layers=6,
653
+ transformerlayers=[
654
+ dict(
655
+ type='BaseTransformerLayer',
656
+ attn_cfgs=[
657
+ dict(
658
+ type='MultiheadAttention',
659
+ embed_dims=256,
660
+ num_heads=8,
661
+ dropout=0.1),
662
+ dict(type='MultiheadAttention', embed_dims=256)
663
+ ],
664
+ feedforward_channels=1024,
665
+ ffn_dropout=0.1,
666
+ operation_order=('self_attn', 'norm', 'cross_attn', 'norm',
667
+ 'ffn', 'norm'))
668
+ ])
669
+
670
+
671
+ def test_drop_path():
672
+ drop_path = DropPath(drop_prob=0)
673
+ test_in = torch.rand(2, 3, 4, 5)
674
+ assert test_in is drop_path(test_in)
675
+
676
+ drop_path = DropPath(drop_prob=0.1)
677
+ drop_path.training = False
678
+ test_in = torch.rand(2, 3, 4, 5)
679
+ assert test_in is drop_path(test_in)
680
+ drop_path.training = True
681
+ assert test_in is not drop_path(test_in)
groundingLMM/mmcv/tests/test_cnn/test_weight_init.py ADDED
@@ -0,0 +1,559 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import random
3
+ from tempfile import TemporaryDirectory
4
+
5
+ import numpy as np
6
+ import pytest
7
+ import torch
8
+ from scipy import stats
9
+ from torch import nn
10
+
11
+ from mmcv.cnn import (Caffe2XavierInit, ConstantInit, KaimingInit, NormalInit,
12
+ PretrainedInit, TruncNormalInit, UniformInit, XavierInit,
13
+ bias_init_with_prob, caffe2_xavier_init, constant_init,
14
+ initialize, kaiming_init, normal_init, trunc_normal_init,
15
+ uniform_init, xavier_init)
16
+
17
+
18
+ def test_constant_init():
19
+ conv_module = nn.Conv2d(3, 16, 3)
20
+ constant_init(conv_module, 0.1)
21
+ assert conv_module.weight.allclose(
22
+ torch.full_like(conv_module.weight, 0.1))
23
+ assert conv_module.bias.allclose(torch.zeros_like(conv_module.bias))
24
+ conv_module_no_bias = nn.Conv2d(3, 16, 3, bias=False)
25
+ constant_init(conv_module_no_bias, 0.1)
26
+ assert conv_module.weight.allclose(
27
+ torch.full_like(conv_module.weight, 0.1))
28
+
29
+
30
+ def test_xavier_init():
31
+ conv_module = nn.Conv2d(3, 16, 3)
32
+ xavier_init(conv_module, bias=0.1)
33
+ assert conv_module.bias.allclose(torch.full_like(conv_module.bias, 0.1))
34
+ xavier_init(conv_module, distribution='uniform')
35
+ # TODO: sanity check of weight distribution, e.g. mean, std
36
+ with pytest.raises(AssertionError):
37
+ xavier_init(conv_module, distribution='student-t')
38
+ conv_module_no_bias = nn.Conv2d(3, 16, 3, bias=False)
39
+ xavier_init(conv_module_no_bias)
40
+
41
+
42
+ def test_normal_init():
43
+ conv_module = nn.Conv2d(3, 16, 3)
44
+ normal_init(conv_module, bias=0.1)
45
+ # TODO: sanity check of weight distribution, e.g. mean, std
46
+ assert conv_module.bias.allclose(torch.full_like(conv_module.bias, 0.1))
47
+ conv_module_no_bias = nn.Conv2d(3, 16, 3, bias=False)
48
+ normal_init(conv_module_no_bias)
49
+ # TODO: sanity check distribution, e.g. mean, std
50
+
51
+
52
+ def test_trunc_normal_init():
53
+
54
+ def _random_float(a, b):
55
+ return (b - a) * random.random() + a
56
+
57
+ def _is_trunc_normal(tensor, mean, std, a, b):
58
+ # scipy's trunc norm is suited for data drawn from N(0, 1),
59
+ # so we need to transform our data to test it using scipy.
60
+ z_samples = (tensor.view(-1) - mean) / std
61
+ z_samples = z_samples.tolist()
62
+ a0 = (a - mean) / std
63
+ b0 = (b - mean) / std
64
+ p_value = stats.kstest(z_samples, 'truncnorm', args=(a0, b0))[1]
65
+ return p_value > 0.0001
66
+
67
+ conv_module = nn.Conv2d(3, 16, 3)
68
+ mean = _random_float(-3, 3)
69
+ std = _random_float(.01, 1)
70
+ a = _random_float(mean - 2 * std, mean)
71
+ b = _random_float(mean, mean + 2 * std)
72
+ trunc_normal_init(conv_module, mean, std, a, b, bias=0.1)
73
+ assert _is_trunc_normal(conv_module.weight, mean, std, a, b)
74
+ assert conv_module.bias.allclose(torch.full_like(conv_module.bias, 0.1))
75
+
76
+ conv_module_no_bias = nn.Conv2d(3, 16, 3, bias=False)
77
+ trunc_normal_init(conv_module_no_bias)
78
+ # TODO: sanity check distribution, e.g. mean, std
79
+
80
+
81
+ def test_uniform_init():
82
+ conv_module = nn.Conv2d(3, 16, 3)
83
+ uniform_init(conv_module, bias=0.1)
84
+ # TODO: sanity check of weight distribution, e.g. mean, std
85
+ assert conv_module.bias.allclose(torch.full_like(conv_module.bias, 0.1))
86
+ conv_module_no_bias = nn.Conv2d(3, 16, 3, bias=False)
87
+ uniform_init(conv_module_no_bias)
88
+
89
+
90
+ def test_kaiming_init():
91
+ conv_module = nn.Conv2d(3, 16, 3)
92
+ kaiming_init(conv_module, bias=0.1)
93
+ # TODO: sanity check of weight distribution, e.g. mean, std
94
+ assert conv_module.bias.allclose(torch.full_like(conv_module.bias, 0.1))
95
+ kaiming_init(conv_module, distribution='uniform')
96
+ with pytest.raises(AssertionError):
97
+ kaiming_init(conv_module, distribution='student-t')
98
+ conv_module_no_bias = nn.Conv2d(3, 16, 3, bias=False)
99
+ kaiming_init(conv_module_no_bias)
100
+
101
+
102
+ def test_caffe_xavier_init():
103
+ conv_module = nn.Conv2d(3, 16, 3)
104
+ caffe2_xavier_init(conv_module)
105
+
106
+
107
+ def test_bias_init_with_prob():
108
+ conv_module = nn.Conv2d(3, 16, 3)
109
+ prior_prob = 0.1
110
+ normal_init(conv_module, bias=bias_init_with_prob(0.1))
111
+ # TODO: sanity check of weight distribution, e.g. mean, std
112
+ bias = float(-np.log((1 - prior_prob) / prior_prob))
113
+ assert conv_module.bias.allclose(torch.full_like(conv_module.bias, bias))
114
+
115
+
116
+ def test_constaninit():
117
+ """test ConstantInit class."""
118
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Linear(1, 2))
119
+ func = ConstantInit(val=1, bias=2, layer='Conv2d')
120
+ func(model)
121
+ assert torch.equal(model[0].weight, torch.full(model[0].weight.shape, 1.))
122
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 2.))
123
+
124
+ assert not torch.equal(model[2].weight,
125
+ torch.full(model[2].weight.shape, 1.))
126
+ assert not torch.equal(model[2].bias, torch.full(model[2].bias.shape, 2.))
127
+
128
+ func = ConstantInit(val=3, bias_prob=0.01, layer='Linear')
129
+ func(model)
130
+ res = bias_init_with_prob(0.01)
131
+
132
+ assert torch.equal(model[0].weight, torch.full(model[0].weight.shape, 1.))
133
+ assert torch.equal(model[2].weight, torch.full(model[2].weight.shape, 3.))
134
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 2.))
135
+ assert torch.equal(model[2].bias, torch.full(model[2].bias.shape, res))
136
+
137
+ # test layer key with base class name
138
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Conv1d(1, 2, 1))
139
+ func = ConstantInit(val=4., bias=5., layer='_ConvNd')
140
+ func(model)
141
+ assert torch.all(model[0].weight == 4.)
142
+ assert torch.all(model[2].weight == 4.)
143
+ assert torch.all(model[0].bias == 5.)
144
+ assert torch.all(model[2].bias == 5.)
145
+
146
+ # test bias input type
147
+ with pytest.raises(TypeError):
148
+ func = ConstantInit(val=1, bias='1')
149
+ # test bias_prob type
150
+ with pytest.raises(TypeError):
151
+ func = ConstantInit(val=1, bias_prob='1')
152
+ # test layer input type
153
+ with pytest.raises(TypeError):
154
+ func = ConstantInit(val=1, layer=1)
155
+
156
+
157
+ def test_xavierinit():
158
+ """test XavierInit class."""
159
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Linear(1, 2))
160
+ func = XavierInit(bias=0.1, layer='Conv2d')
161
+ func(model)
162
+ assert model[0].bias.allclose(torch.full_like(model[2].bias, 0.1))
163
+ assert not model[2].bias.allclose(torch.full_like(model[0].bias, 0.1))
164
+
165
+ constant_func = ConstantInit(val=0, bias=0, layer=['Conv2d', 'Linear'])
166
+ func = XavierInit(gain=100, bias_prob=0.01, layer=['Conv2d', 'Linear'])
167
+ model.apply(constant_func)
168
+ assert torch.equal(model[0].weight, torch.full(model[0].weight.shape, 0.))
169
+ assert torch.equal(model[2].weight, torch.full(model[2].weight.shape, 0.))
170
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 0.))
171
+ assert torch.equal(model[2].bias, torch.full(model[2].bias.shape, 0.))
172
+
173
+ res = bias_init_with_prob(0.01)
174
+ func(model)
175
+ assert not torch.equal(model[0].weight,
176
+ torch.full(model[0].weight.shape, 0.))
177
+ assert not torch.equal(model[2].weight,
178
+ torch.full(model[2].weight.shape, 0.))
179
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, res))
180
+ assert torch.equal(model[2].bias, torch.full(model[2].bias.shape, res))
181
+
182
+ # test layer key with base class name
183
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Conv1d(1, 2, 1))
184
+ func = ConstantInit(val=4., bias=5., layer='_ConvNd')
185
+ func(model)
186
+ assert torch.all(model[0].weight == 4.)
187
+ assert torch.all(model[2].weight == 4.)
188
+ assert torch.all(model[0].bias == 5.)
189
+ assert torch.all(model[2].bias == 5.)
190
+
191
+ func = XavierInit(gain=100, bias_prob=0.01, layer='_ConvNd')
192
+ func(model)
193
+ assert not torch.all(model[0].weight == 4.)
194
+ assert not torch.all(model[2].weight == 4.)
195
+ assert torch.all(model[0].bias == res)
196
+ assert torch.all(model[2].bias == res)
197
+
198
+ # test bias input type
199
+ with pytest.raises(TypeError):
200
+ func = XavierInit(bias='0.1', layer='Conv2d')
201
+ # test layer inpur type
202
+ with pytest.raises(TypeError):
203
+ func = XavierInit(bias=0.1, layer=1)
204
+
205
+
206
+ def test_normalinit():
207
+ """test Normalinit class."""
208
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Linear(1, 2))
209
+
210
+ func = NormalInit(mean=100, std=1e-5, bias=200, layer=['Conv2d', 'Linear'])
211
+ func(model)
212
+ assert model[0].weight.allclose(torch.tensor(100.))
213
+ assert model[2].weight.allclose(torch.tensor(100.))
214
+ assert model[0].bias.allclose(torch.tensor(200.))
215
+ assert model[2].bias.allclose(torch.tensor(200.))
216
+
217
+ func = NormalInit(
218
+ mean=300, std=1e-5, bias_prob=0.01, layer=['Conv2d', 'Linear'])
219
+ res = bias_init_with_prob(0.01)
220
+ func(model)
221
+ assert model[0].weight.allclose(torch.tensor(300.))
222
+ assert model[2].weight.allclose(torch.tensor(300.))
223
+ assert model[0].bias.allclose(torch.tensor(res))
224
+ assert model[2].bias.allclose(torch.tensor(res))
225
+
226
+ # test layer key with base class name
227
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Conv1d(1, 2, 1))
228
+
229
+ func = NormalInit(mean=300, std=1e-5, bias_prob=0.01, layer='_ConvNd')
230
+ func(model)
231
+ assert model[0].weight.allclose(torch.tensor(300.))
232
+ assert model[2].weight.allclose(torch.tensor(300.))
233
+ assert torch.all(model[0].bias == res)
234
+ assert torch.all(model[2].bias == res)
235
+
236
+
237
+ def test_truncnormalinit():
238
+ """test TruncNormalInit class."""
239
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Linear(1, 2))
240
+
241
+ func = TruncNormalInit(
242
+ mean=100, std=1e-5, bias=200, a=0, b=200, layer=['Conv2d', 'Linear'])
243
+ func(model)
244
+ assert model[0].weight.allclose(torch.tensor(100.))
245
+ assert model[2].weight.allclose(torch.tensor(100.))
246
+ assert model[0].bias.allclose(torch.tensor(200.))
247
+ assert model[2].bias.allclose(torch.tensor(200.))
248
+
249
+ func = TruncNormalInit(
250
+ mean=300,
251
+ std=1e-5,
252
+ a=100,
253
+ b=400,
254
+ bias_prob=0.01,
255
+ layer=['Conv2d', 'Linear'])
256
+ res = bias_init_with_prob(0.01)
257
+ func(model)
258
+ assert model[0].weight.allclose(torch.tensor(300.))
259
+ assert model[2].weight.allclose(torch.tensor(300.))
260
+ assert model[0].bias.allclose(torch.tensor(res))
261
+ assert model[2].bias.allclose(torch.tensor(res))
262
+
263
+ # test layer key with base class name
264
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Conv1d(1, 2, 1))
265
+
266
+ func = TruncNormalInit(
267
+ mean=300, std=1e-5, a=100, b=400, bias_prob=0.01, layer='_ConvNd')
268
+ func(model)
269
+ assert model[0].weight.allclose(torch.tensor(300.))
270
+ assert model[2].weight.allclose(torch.tensor(300.))
271
+ assert torch.all(model[0].bias == res)
272
+ assert torch.all(model[2].bias == res)
273
+
274
+
275
+ def test_uniforminit():
276
+ """"test UniformInit class."""
277
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Linear(1, 2))
278
+ func = UniformInit(a=1, b=1, bias=2, layer=['Conv2d', 'Linear'])
279
+ func(model)
280
+ assert torch.equal(model[0].weight, torch.full(model[0].weight.shape, 1.))
281
+ assert torch.equal(model[2].weight, torch.full(model[2].weight.shape, 1.))
282
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 2.))
283
+ assert torch.equal(model[2].bias, torch.full(model[2].bias.shape, 2.))
284
+
285
+ func = UniformInit(a=100, b=100, layer=['Conv2d', 'Linear'], bias=10)
286
+ func(model)
287
+ assert torch.equal(model[0].weight, torch.full(model[0].weight.shape,
288
+ 100.))
289
+ assert torch.equal(model[2].weight, torch.full(model[2].weight.shape,
290
+ 100.))
291
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 10.))
292
+ assert torch.equal(model[2].bias, torch.full(model[2].bias.shape, 10.))
293
+
294
+ # test layer key with base class name
295
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Conv1d(1, 2, 1))
296
+
297
+ func = UniformInit(a=100, b=100, bias_prob=0.01, layer='_ConvNd')
298
+ res = bias_init_with_prob(0.01)
299
+ func(model)
300
+ assert torch.all(model[0].weight == 100.)
301
+ assert torch.all(model[2].weight == 100.)
302
+ assert torch.all(model[0].bias == res)
303
+ assert torch.all(model[2].bias == res)
304
+
305
+
306
+ def test_kaiminginit():
307
+ """test KaimingInit class."""
308
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Linear(1, 2))
309
+ func = KaimingInit(bias=0.1, layer='Conv2d')
310
+ func(model)
311
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 0.1))
312
+ assert not torch.equal(model[2].bias, torch.full(model[2].bias.shape, 0.1))
313
+
314
+ func = KaimingInit(a=100, bias=10, layer=['Conv2d', 'Linear'])
315
+ constant_func = ConstantInit(val=0, bias=0, layer=['Conv2d', 'Linear'])
316
+ model.apply(constant_func)
317
+ assert torch.equal(model[0].weight, torch.full(model[0].weight.shape, 0.))
318
+ assert torch.equal(model[2].weight, torch.full(model[2].weight.shape, 0.))
319
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 0.))
320
+ assert torch.equal(model[2].bias, torch.full(model[2].bias.shape, 0.))
321
+
322
+ func(model)
323
+ assert not torch.equal(model[0].weight,
324
+ torch.full(model[0].weight.shape, 0.))
325
+ assert not torch.equal(model[2].weight,
326
+ torch.full(model[2].weight.shape, 0.))
327
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 10.))
328
+ assert torch.equal(model[2].bias, torch.full(model[2].bias.shape, 10.))
329
+
330
+ # test layer key with base class name
331
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Conv1d(1, 2, 1))
332
+ func = KaimingInit(bias=0.1, layer='_ConvNd')
333
+ func(model)
334
+ assert torch.all(model[0].bias == 0.1)
335
+ assert torch.all(model[2].bias == 0.1)
336
+
337
+ func = KaimingInit(a=100, bias=10, layer='_ConvNd')
338
+ constant_func = ConstantInit(val=0, bias=0, layer='_ConvNd')
339
+ model.apply(constant_func)
340
+ assert torch.equal(model[0].weight, torch.full(model[0].weight.shape, 0.))
341
+ assert torch.equal(model[2].weight, torch.full(model[2].weight.shape, 0.))
342
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 0.))
343
+ assert torch.equal(model[2].bias, torch.full(model[2].bias.shape, 0.))
344
+
345
+ func(model)
346
+ assert not torch.equal(model[0].weight,
347
+ torch.full(model[0].weight.shape, 0.))
348
+ assert not torch.equal(model[2].weight,
349
+ torch.full(model[2].weight.shape, 0.))
350
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 10.))
351
+ assert torch.equal(model[2].bias, torch.full(model[2].bias.shape, 10.))
352
+
353
+
354
+ def test_caffe2xavierinit():
355
+ """test Caffe2XavierInit."""
356
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Linear(1, 2))
357
+ func = Caffe2XavierInit(bias=0.1, layer='Conv2d')
358
+ func(model)
359
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 0.1))
360
+ assert not torch.equal(model[2].bias, torch.full(model[2].bias.shape, 0.1))
361
+
362
+
363
+ class FooModule(nn.Module):
364
+
365
+ def __init__(self):
366
+ super().__init__()
367
+ self.linear = nn.Linear(1, 2)
368
+ self.conv2d = nn.Conv2d(3, 1, 3)
369
+ self.conv2d_2 = nn.Conv2d(3, 2, 3)
370
+
371
+
372
+ def test_pretrainedinit():
373
+ """test PretrainedInit class."""
374
+
375
+ modelA = FooModule()
376
+ constant_func = ConstantInit(val=1, bias=2, layer=['Conv2d', 'Linear'])
377
+ modelA.apply(constant_func)
378
+ modelB = FooModule()
379
+ funcB = PretrainedInit(checkpoint='modelA.pth')
380
+ modelC = nn.Linear(1, 2)
381
+ funcC = PretrainedInit(checkpoint='modelA.pth', prefix='linear.')
382
+ with TemporaryDirectory():
383
+ torch.save(modelA.state_dict(), 'modelA.pth')
384
+ funcB(modelB)
385
+ assert torch.equal(modelB.linear.weight,
386
+ torch.full(modelB.linear.weight.shape, 1.))
387
+ assert torch.equal(modelB.linear.bias,
388
+ torch.full(modelB.linear.bias.shape, 2.))
389
+ assert torch.equal(modelB.conv2d.weight,
390
+ torch.full(modelB.conv2d.weight.shape, 1.))
391
+ assert torch.equal(modelB.conv2d.bias,
392
+ torch.full(modelB.conv2d.bias.shape, 2.))
393
+ assert torch.equal(modelB.conv2d_2.weight,
394
+ torch.full(modelB.conv2d_2.weight.shape, 1.))
395
+ assert torch.equal(modelB.conv2d_2.bias,
396
+ torch.full(modelB.conv2d_2.bias.shape, 2.))
397
+
398
+ funcC(modelC)
399
+ assert torch.equal(modelC.weight, torch.full(modelC.weight.shape, 1.))
400
+ assert torch.equal(modelC.bias, torch.full(modelC.bias.shape, 2.))
401
+
402
+
403
+ def test_initialize():
404
+ model = nn.Sequential(nn.Conv2d(3, 1, 3), nn.ReLU(), nn.Linear(1, 2))
405
+ foonet = FooModule()
406
+
407
+ # test layer key
408
+ init_cfg = dict(type='Constant', layer=['Conv2d', 'Linear'], val=1, bias=2)
409
+ initialize(model, init_cfg)
410
+ assert torch.equal(model[0].weight, torch.full(model[0].weight.shape, 1.))
411
+ assert torch.equal(model[2].weight, torch.full(model[2].weight.shape, 1.))
412
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 2.))
413
+ assert torch.equal(model[2].bias, torch.full(model[2].bias.shape, 2.))
414
+ assert init_cfg == dict(
415
+ type='Constant', layer=['Conv2d', 'Linear'], val=1, bias=2)
416
+
417
+ # test init_cfg with list type
418
+ init_cfg = [
419
+ dict(type='Constant', layer='Conv2d', val=1, bias=2),
420
+ dict(type='Constant', layer='Linear', val=3, bias=4)
421
+ ]
422
+ initialize(model, init_cfg)
423
+ assert torch.equal(model[0].weight, torch.full(model[0].weight.shape, 1.))
424
+ assert torch.equal(model[2].weight, torch.full(model[2].weight.shape, 3.))
425
+ assert torch.equal(model[0].bias, torch.full(model[0].bias.shape, 2.))
426
+ assert torch.equal(model[2].bias, torch.full(model[2].bias.shape, 4.))
427
+ assert init_cfg == [
428
+ dict(type='Constant', layer='Conv2d', val=1, bias=2),
429
+ dict(type='Constant', layer='Linear', val=3, bias=4)
430
+ ]
431
+
432
+ # test layer key and override key
433
+ init_cfg = dict(
434
+ type='Constant',
435
+ val=1,
436
+ bias=2,
437
+ layer=['Conv2d', 'Linear'],
438
+ override=dict(type='Constant', name='conv2d_2', val=3, bias=4))
439
+ initialize(foonet, init_cfg)
440
+ assert torch.equal(foonet.linear.weight,
441
+ torch.full(foonet.linear.weight.shape, 1.))
442
+ assert torch.equal(foonet.linear.bias,
443
+ torch.full(foonet.linear.bias.shape, 2.))
444
+ assert torch.equal(foonet.conv2d.weight,
445
+ torch.full(foonet.conv2d.weight.shape, 1.))
446
+ assert torch.equal(foonet.conv2d.bias,
447
+ torch.full(foonet.conv2d.bias.shape, 2.))
448
+ assert torch.equal(foonet.conv2d_2.weight,
449
+ torch.full(foonet.conv2d_2.weight.shape, 3.))
450
+ assert torch.equal(foonet.conv2d_2.bias,
451
+ torch.full(foonet.conv2d_2.bias.shape, 4.))
452
+ assert init_cfg == dict(
453
+ type='Constant',
454
+ val=1,
455
+ bias=2,
456
+ layer=['Conv2d', 'Linear'],
457
+ override=dict(type='Constant', name='conv2d_2', val=3, bias=4))
458
+
459
+ # test override key
460
+ init_cfg = dict(
461
+ type='Constant', val=5, bias=6, override=dict(name='conv2d_2'))
462
+ initialize(foonet, init_cfg)
463
+ assert not torch.equal(foonet.linear.weight,
464
+ torch.full(foonet.linear.weight.shape, 5.))
465
+ assert not torch.equal(foonet.linear.bias,
466
+ torch.full(foonet.linear.bias.shape, 6.))
467
+ assert not torch.equal(foonet.conv2d.weight,
468
+ torch.full(foonet.conv2d.weight.shape, 5.))
469
+ assert not torch.equal(foonet.conv2d.bias,
470
+ torch.full(foonet.conv2d.bias.shape, 6.))
471
+ assert torch.equal(foonet.conv2d_2.weight,
472
+ torch.full(foonet.conv2d_2.weight.shape, 5.))
473
+ assert torch.equal(foonet.conv2d_2.bias,
474
+ torch.full(foonet.conv2d_2.bias.shape, 6.))
475
+ assert init_cfg == dict(
476
+ type='Constant', val=5, bias=6, override=dict(name='conv2d_2'))
477
+
478
+ init_cfg = dict(
479
+ type='Pretrained',
480
+ checkpoint='modelA.pth',
481
+ override=dict(type='Constant', name='conv2d_2', val=3, bias=4))
482
+ modelA = FooModule()
483
+ constant_func = ConstantInit(val=1, bias=2, layer=['Conv2d', 'Linear'])
484
+ modelA.apply(constant_func)
485
+ with TemporaryDirectory():
486
+ torch.save(modelA.state_dict(), 'modelA.pth')
487
+ initialize(foonet, init_cfg)
488
+ assert torch.equal(foonet.linear.weight,
489
+ torch.full(foonet.linear.weight.shape, 1.))
490
+ assert torch.equal(foonet.linear.bias,
491
+ torch.full(foonet.linear.bias.shape, 2.))
492
+ assert torch.equal(foonet.conv2d.weight,
493
+ torch.full(foonet.conv2d.weight.shape, 1.))
494
+ assert torch.equal(foonet.conv2d.bias,
495
+ torch.full(foonet.conv2d.bias.shape, 2.))
496
+ assert torch.equal(foonet.conv2d_2.weight,
497
+ torch.full(foonet.conv2d_2.weight.shape, 3.))
498
+ assert torch.equal(foonet.conv2d_2.bias,
499
+ torch.full(foonet.conv2d_2.bias.shape, 4.))
500
+ assert init_cfg == dict(
501
+ type='Pretrained',
502
+ checkpoint='modelA.pth',
503
+ override=dict(type='Constant', name='conv2d_2', val=3, bias=4))
504
+
505
+ # test init_cfg type
506
+ with pytest.raises(TypeError):
507
+ init_cfg = 'init_cfg'
508
+ initialize(foonet, init_cfg)
509
+
510
+ # test override value type
511
+ with pytest.raises(TypeError):
512
+ init_cfg = dict(
513
+ type='Constant',
514
+ val=1,
515
+ bias=2,
516
+ layer=['Conv2d', 'Linear'],
517
+ override='conv')
518
+ initialize(foonet, init_cfg)
519
+
520
+ # test override name
521
+ with pytest.raises(RuntimeError):
522
+ init_cfg = dict(
523
+ type='Constant',
524
+ val=1,
525
+ bias=2,
526
+ layer=['Conv2d', 'Linear'],
527
+ override=dict(type='Constant', name='conv2d_3', val=3, bias=4))
528
+ initialize(foonet, init_cfg)
529
+
530
+ # test list override name
531
+ with pytest.raises(RuntimeError):
532
+ init_cfg = dict(
533
+ type='Constant',
534
+ val=1,
535
+ bias=2,
536
+ layer=['Conv2d', 'Linear'],
537
+ override=[
538
+ dict(type='Constant', name='conv2d', val=3, bias=4),
539
+ dict(type='Constant', name='conv2d_3', val=5, bias=6)
540
+ ])
541
+ initialize(foonet, init_cfg)
542
+
543
+ # test override with args except type key
544
+ with pytest.raises(ValueError):
545
+ init_cfg = dict(
546
+ type='Constant',
547
+ val=1,
548
+ bias=2,
549
+ override=dict(name='conv2d_2', val=3, bias=4))
550
+ initialize(foonet, init_cfg)
551
+
552
+ # test override without name
553
+ with pytest.raises(ValueError):
554
+ init_cfg = dict(
555
+ type='Constant',
556
+ val=1,
557
+ bias=2,
558
+ override=dict(type='Constant', val=3, bias=4))
559
+ initialize(foonet, init_cfg)
groundingLMM/mmcv/tests/test_cnn/test_wrappers.py ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ from unittest.mock import patch
3
+
4
+ import pytest
5
+ import torch
6
+ import torch.nn as nn
7
+
8
+ from mmcv.cnn.bricks import (Conv2d, Conv3d, ConvTranspose2d, ConvTranspose3d,
9
+ Linear, MaxPool2d, MaxPool3d)
10
+
11
+ if torch.__version__ != 'parrots':
12
+ torch_version = '1.1'
13
+ else:
14
+ torch_version = 'parrots'
15
+
16
+
17
+ @patch('torch.__version__', torch_version)
18
+ @pytest.mark.parametrize(
19
+ 'in_w,in_h,in_channel,out_channel,kernel_size,stride,padding,dilation',
20
+ [(10, 10, 1, 1, 3, 1, 0, 1), (20, 20, 3, 3, 5, 2, 1, 2)])
21
+ def test_conv2d(in_w, in_h, in_channel, out_channel, kernel_size, stride,
22
+ padding, dilation):
23
+ """
24
+ CommandLine:
25
+ xdoctest -m tests/test_wrappers.py test_conv2d
26
+ """
27
+ # train mode
28
+ # wrapper op with 0-dim input
29
+ x_empty = torch.randn(0, in_channel, in_h, in_w)
30
+ torch.manual_seed(0)
31
+ wrapper = Conv2d(
32
+ in_channel,
33
+ out_channel,
34
+ kernel_size,
35
+ stride=stride,
36
+ padding=padding,
37
+ dilation=dilation)
38
+ wrapper_out = wrapper(x_empty)
39
+
40
+ # torch op with 3-dim input as shape reference
41
+ x_normal = torch.randn(3, in_channel, in_h, in_w).requires_grad_(True)
42
+ torch.manual_seed(0)
43
+ ref = nn.Conv2d(
44
+ in_channel,
45
+ out_channel,
46
+ kernel_size,
47
+ stride=stride,
48
+ padding=padding,
49
+ dilation=dilation)
50
+ ref_out = ref(x_normal)
51
+
52
+ assert wrapper_out.shape[0] == 0
53
+ assert wrapper_out.shape[1:] == ref_out.shape[1:]
54
+
55
+ wrapper_out.sum().backward()
56
+ assert wrapper.weight.grad is not None
57
+ assert wrapper.weight.grad.shape == wrapper.weight.shape
58
+
59
+ assert torch.equal(wrapper(x_normal), ref_out)
60
+
61
+ # eval mode
62
+ x_empty = torch.randn(0, in_channel, in_h, in_w)
63
+ wrapper = Conv2d(
64
+ in_channel,
65
+ out_channel,
66
+ kernel_size,
67
+ stride=stride,
68
+ padding=padding,
69
+ dilation=dilation)
70
+ wrapper.eval()
71
+ wrapper(x_empty)
72
+
73
+
74
+ @patch('torch.__version__', torch_version)
75
+ @pytest.mark.parametrize(
76
+ 'in_w,in_h,in_t,in_channel,out_channel,kernel_size,stride,padding,dilation', # noqa: E501
77
+ [(10, 10, 10, 1, 1, 3, 1, 0, 1), (20, 20, 20, 3, 3, 5, 2, 1, 2)])
78
+ def test_conv3d(in_w, in_h, in_t, in_channel, out_channel, kernel_size, stride,
79
+ padding, dilation):
80
+ """
81
+ CommandLine:
82
+ xdoctest -m tests/test_wrappers.py test_conv3d
83
+ """
84
+ # train mode
85
+ # wrapper op with 0-dim input
86
+ x_empty = torch.randn(0, in_channel, in_t, in_h, in_w)
87
+ torch.manual_seed(0)
88
+ wrapper = Conv3d(
89
+ in_channel,
90
+ out_channel,
91
+ kernel_size,
92
+ stride=stride,
93
+ padding=padding,
94
+ dilation=dilation)
95
+ wrapper_out = wrapper(x_empty)
96
+
97
+ # torch op with 3-dim input as shape reference
98
+ x_normal = torch.randn(3, in_channel, in_t, in_h,
99
+ in_w).requires_grad_(True)
100
+ torch.manual_seed(0)
101
+ ref = nn.Conv3d(
102
+ in_channel,
103
+ out_channel,
104
+ kernel_size,
105
+ stride=stride,
106
+ padding=padding,
107
+ dilation=dilation)
108
+ ref_out = ref(x_normal)
109
+
110
+ assert wrapper_out.shape[0] == 0
111
+ assert wrapper_out.shape[1:] == ref_out.shape[1:]
112
+
113
+ wrapper_out.sum().backward()
114
+ assert wrapper.weight.grad is not None
115
+ assert wrapper.weight.grad.shape == wrapper.weight.shape
116
+
117
+ assert torch.equal(wrapper(x_normal), ref_out)
118
+
119
+ # eval mode
120
+ x_empty = torch.randn(0, in_channel, in_t, in_h, in_w)
121
+ wrapper = Conv3d(
122
+ in_channel,
123
+ out_channel,
124
+ kernel_size,
125
+ stride=stride,
126
+ padding=padding,
127
+ dilation=dilation)
128
+ wrapper.eval()
129
+ wrapper(x_empty)
130
+
131
+
132
+ @patch('torch.__version__', torch_version)
133
+ @pytest.mark.parametrize(
134
+ 'in_w,in_h,in_channel,out_channel,kernel_size,stride,padding,dilation',
135
+ [(10, 10, 1, 1, 3, 1, 0, 1), (20, 20, 3, 3, 5, 2, 1, 2)])
136
+ def test_conv_transposed_2d(in_w, in_h, in_channel, out_channel, kernel_size,
137
+ stride, padding, dilation):
138
+ # wrapper op with 0-dim input
139
+ x_empty = torch.randn(0, in_channel, in_h, in_w, requires_grad=True)
140
+ # out padding must be smaller than either stride or dilation
141
+ op = min(stride, dilation) - 1
142
+ if torch.__version__ == 'parrots':
143
+ op = 0
144
+ torch.manual_seed(0)
145
+ wrapper = ConvTranspose2d(
146
+ in_channel,
147
+ out_channel,
148
+ kernel_size,
149
+ stride=stride,
150
+ padding=padding,
151
+ dilation=dilation,
152
+ output_padding=op)
153
+ wrapper_out = wrapper(x_empty)
154
+
155
+ # torch op with 3-dim input as shape reference
156
+ x_normal = torch.randn(3, in_channel, in_h, in_w)
157
+ torch.manual_seed(0)
158
+ ref = nn.ConvTranspose2d(
159
+ in_channel,
160
+ out_channel,
161
+ kernel_size,
162
+ stride=stride,
163
+ padding=padding,
164
+ dilation=dilation,
165
+ output_padding=op)
166
+ ref_out = ref(x_normal)
167
+
168
+ assert wrapper_out.shape[0] == 0
169
+ assert wrapper_out.shape[1:] == ref_out.shape[1:]
170
+
171
+ wrapper_out.sum().backward()
172
+ assert wrapper.weight.grad is not None
173
+ assert wrapper.weight.grad.shape == wrapper.weight.shape
174
+
175
+ assert torch.equal(wrapper(x_normal), ref_out)
176
+
177
+ # eval mode
178
+ x_empty = torch.randn(0, in_channel, in_h, in_w)
179
+ wrapper = ConvTranspose2d(
180
+ in_channel,
181
+ out_channel,
182
+ kernel_size,
183
+ stride=stride,
184
+ padding=padding,
185
+ dilation=dilation,
186
+ output_padding=op)
187
+ wrapper.eval()
188
+ wrapper(x_empty)
189
+
190
+
191
+ @patch('torch.__version__', torch_version)
192
+ @pytest.mark.parametrize(
193
+ 'in_w,in_h,in_t,in_channel,out_channel,kernel_size,stride,padding,dilation', # noqa: E501
194
+ [(10, 10, 10, 1, 1, 3, 1, 0, 1), (20, 20, 20, 3, 3, 5, 2, 1, 2)])
195
+ def test_conv_transposed_3d(in_w, in_h, in_t, in_channel, out_channel,
196
+ kernel_size, stride, padding, dilation):
197
+ # wrapper op with 0-dim input
198
+ x_empty = torch.randn(0, in_channel, in_t, in_h, in_w, requires_grad=True)
199
+ # out padding must be smaller than either stride or dilation
200
+ op = min(stride, dilation) - 1
201
+ torch.manual_seed(0)
202
+ wrapper = ConvTranspose3d(
203
+ in_channel,
204
+ out_channel,
205
+ kernel_size,
206
+ stride=stride,
207
+ padding=padding,
208
+ dilation=dilation,
209
+ output_padding=op)
210
+ wrapper_out = wrapper(x_empty)
211
+
212
+ # torch op with 3-dim input as shape reference
213
+ x_normal = torch.randn(3, in_channel, in_t, in_h, in_w)
214
+ torch.manual_seed(0)
215
+ ref = nn.ConvTranspose3d(
216
+ in_channel,
217
+ out_channel,
218
+ kernel_size,
219
+ stride=stride,
220
+ padding=padding,
221
+ dilation=dilation,
222
+ output_padding=op)
223
+ ref_out = ref(x_normal)
224
+
225
+ assert wrapper_out.shape[0] == 0
226
+ assert wrapper_out.shape[1:] == ref_out.shape[1:]
227
+
228
+ wrapper_out.sum().backward()
229
+ assert wrapper.weight.grad is not None
230
+ assert wrapper.weight.grad.shape == wrapper.weight.shape
231
+
232
+ assert torch.equal(wrapper(x_normal), ref_out)
233
+
234
+ # eval mode
235
+ x_empty = torch.randn(0, in_channel, in_t, in_h, in_w)
236
+ wrapper = ConvTranspose3d(
237
+ in_channel,
238
+ out_channel,
239
+ kernel_size,
240
+ stride=stride,
241
+ padding=padding,
242
+ dilation=dilation,
243
+ output_padding=op)
244
+ wrapper.eval()
245
+ wrapper(x_empty)
246
+
247
+
248
+ @patch('torch.__version__', torch_version)
249
+ @pytest.mark.parametrize(
250
+ 'in_w,in_h,in_channel,out_channel,kernel_size,stride,padding,dilation',
251
+ [(10, 10, 1, 1, 3, 1, 0, 1), (20, 20, 3, 3, 5, 2, 1, 2)])
252
+ def test_max_pool_2d(in_w, in_h, in_channel, out_channel, kernel_size, stride,
253
+ padding, dilation):
254
+ # wrapper op with 0-dim input
255
+ x_empty = torch.randn(0, in_channel, in_h, in_w, requires_grad=True)
256
+ wrapper = MaxPool2d(
257
+ kernel_size, stride=stride, padding=padding, dilation=dilation)
258
+ wrapper_out = wrapper(x_empty)
259
+
260
+ # torch op with 3-dim input as shape reference
261
+ x_normal = torch.randn(3, in_channel, in_h, in_w)
262
+ ref = nn.MaxPool2d(
263
+ kernel_size, stride=stride, padding=padding, dilation=dilation)
264
+ ref_out = ref(x_normal)
265
+
266
+ assert wrapper_out.shape[0] == 0
267
+ assert wrapper_out.shape[1:] == ref_out.shape[1:]
268
+
269
+ assert torch.equal(wrapper(x_normal), ref_out)
270
+
271
+
272
+ @patch('torch.__version__', torch_version)
273
+ @pytest.mark.parametrize(
274
+ 'in_w,in_h,in_t,in_channel,out_channel,kernel_size,stride,padding,dilation', # noqa: E501
275
+ [(10, 10, 10, 1, 1, 3, 1, 0, 1), (20, 20, 20, 3, 3, 5, 2, 1, 2)])
276
+ @pytest.mark.skipif(
277
+ torch.__version__ == 'parrots' and not torch.cuda.is_available(),
278
+ reason='parrots requires CUDA support')
279
+ def test_max_pool_3d(in_w, in_h, in_t, in_channel, out_channel, kernel_size,
280
+ stride, padding, dilation):
281
+ # wrapper op with 0-dim input
282
+ x_empty = torch.randn(0, in_channel, in_t, in_h, in_w, requires_grad=True)
283
+ wrapper = MaxPool3d(
284
+ kernel_size, stride=stride, padding=padding, dilation=dilation)
285
+ if torch.__version__ == 'parrots':
286
+ x_empty = x_empty.cuda()
287
+ wrapper_out = wrapper(x_empty)
288
+ # torch op with 3-dim input as shape reference
289
+ x_normal = torch.randn(3, in_channel, in_t, in_h, in_w)
290
+ ref = nn.MaxPool3d(
291
+ kernel_size, stride=stride, padding=padding, dilation=dilation)
292
+ if torch.__version__ == 'parrots':
293
+ x_normal = x_normal.cuda()
294
+ ref_out = ref(x_normal)
295
+
296
+ assert wrapper_out.shape[0] == 0
297
+ assert wrapper_out.shape[1:] == ref_out.shape[1:]
298
+
299
+ assert torch.equal(wrapper(x_normal), ref_out)
300
+
301
+
302
+ @patch('torch.__version__', torch_version)
303
+ @pytest.mark.parametrize('in_w,in_h,in_feature,out_feature', [(10, 10, 1, 1),
304
+ (20, 20, 3, 3)])
305
+ def test_linear(in_w, in_h, in_feature, out_feature):
306
+ # wrapper op with 0-dim input
307
+ x_empty = torch.randn(0, in_feature, requires_grad=True)
308
+ torch.manual_seed(0)
309
+ wrapper = Linear(in_feature, out_feature)
310
+ wrapper_out = wrapper(x_empty)
311
+
312
+ # torch op with 3-dim input as shape reference
313
+ x_normal = torch.randn(3, in_feature)
314
+ torch.manual_seed(0)
315
+ ref = nn.Linear(in_feature, out_feature)
316
+ ref_out = ref(x_normal)
317
+
318
+ assert wrapper_out.shape[0] == 0
319
+ assert wrapper_out.shape[1:] == ref_out.shape[1:]
320
+
321
+ wrapper_out.sum().backward()
322
+ assert wrapper.weight.grad is not None
323
+ assert wrapper.weight.grad.shape == wrapper.weight.shape
324
+
325
+ assert torch.equal(wrapper(x_normal), ref_out)
326
+
327
+ # eval mode
328
+ x_empty = torch.randn(0, in_feature)
329
+ wrapper = Linear(in_feature, out_feature)
330
+ wrapper.eval()
331
+ wrapper(x_empty)
332
+
333
+
334
+ @patch('mmcv.cnn.bricks.wrappers.TORCH_VERSION', (1, 10))
335
+ def test_nn_op_forward_called():
336
+
337
+ for m in ['Conv2d', 'ConvTranspose2d', 'MaxPool2d']:
338
+ with patch(f'torch.nn.{m}.forward') as nn_module_forward:
339
+ # randn input
340
+ x_empty = torch.randn(0, 3, 10, 10)
341
+ wrapper = eval(m)(3, 2, 1)
342
+ wrapper(x_empty)
343
+ nn_module_forward.assert_called_with(x_empty)
344
+
345
+ # non-randn input
346
+ x_normal = torch.randn(1, 3, 10, 10)
347
+ wrapper = eval(m)(3, 2, 1)
348
+ wrapper(x_normal)
349
+ nn_module_forward.assert_called_with(x_normal)
350
+
351
+ for m in ['Conv3d', 'ConvTranspose3d', 'MaxPool3d']:
352
+ with patch(f'torch.nn.{m}.forward') as nn_module_forward:
353
+ # randn input
354
+ x_empty = torch.randn(0, 3, 10, 10, 10)
355
+ wrapper = eval(m)(3, 2, 1)
356
+ wrapper(x_empty)
357
+ nn_module_forward.assert_called_with(x_empty)
358
+
359
+ # non-randn input
360
+ x_normal = torch.randn(1, 3, 10, 10, 10)
361
+ wrapper = eval(m)(3, 2, 1)
362
+ wrapper(x_normal)
363
+ nn_module_forward.assert_called_with(x_normal)
364
+
365
+ with patch('torch.nn.Linear.forward') as nn_module_forward:
366
+ # randn input
367
+ x_empty = torch.randn(0, 3)
368
+ wrapper = Linear(3, 3)
369
+ wrapper(x_empty)
370
+ nn_module_forward.assert_called_with(x_empty)
371
+
372
+ # non-randn input
373
+ x_normal = torch.randn(1, 3)
374
+ wrapper = Linear(3, 3)
375
+ wrapper(x_normal)
376
+ nn_module_forward.assert_called_with(x_normal)
groundingLMM/mmcv/tests/test_image/test_colorspace.py ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import cv2
3
+ import numpy as np
4
+ import pytest
5
+ from numpy.testing import assert_array_almost_equal, assert_array_equal
6
+
7
+ import mmcv
8
+ from mmcv.image.colorspace import (_convert_input_type_range,
9
+ _convert_output_type_range)
10
+
11
+
12
+ def test_bgr2gray():
13
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
14
+ out_img = mmcv.bgr2gray(in_img)
15
+ computed_gray = (
16
+ in_img[:, :, 0] * 0.114 + in_img[:, :, 1] * 0.587 +
17
+ in_img[:, :, 2] * 0.299)
18
+ assert_array_almost_equal(out_img, computed_gray, decimal=4)
19
+ out_img_3d = mmcv.bgr2gray(in_img, True)
20
+ assert out_img_3d.shape == (10, 10, 1)
21
+ assert_array_almost_equal(out_img_3d[..., 0], out_img, decimal=4)
22
+
23
+
24
+ def test_rgb2gray():
25
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
26
+ out_img = mmcv.rgb2gray(in_img)
27
+ computed_gray = (
28
+ in_img[:, :, 0] * 0.299 + in_img[:, :, 1] * 0.587 +
29
+ in_img[:, :, 2] * 0.114)
30
+ assert_array_almost_equal(out_img, computed_gray, decimal=4)
31
+ out_img_3d = mmcv.rgb2gray(in_img, True)
32
+ assert out_img_3d.shape == (10, 10, 1)
33
+ assert_array_almost_equal(out_img_3d[..., 0], out_img, decimal=4)
34
+
35
+
36
+ def test_gray2bgr():
37
+ in_img = np.random.rand(10, 10).astype(np.float32)
38
+ out_img = mmcv.gray2bgr(in_img)
39
+ assert out_img.shape == (10, 10, 3)
40
+ for i in range(3):
41
+ assert_array_almost_equal(out_img[..., i], in_img, decimal=4)
42
+
43
+
44
+ def test_gray2rgb():
45
+ in_img = np.random.rand(10, 10).astype(np.float32)
46
+ out_img = mmcv.gray2rgb(in_img)
47
+ assert out_img.shape == (10, 10, 3)
48
+ for i in range(3):
49
+ assert_array_almost_equal(out_img[..., i], in_img, decimal=4)
50
+
51
+
52
+ def test_bgr2rgb():
53
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
54
+ out_img = mmcv.bgr2rgb(in_img)
55
+ assert out_img.shape == in_img.shape
56
+ assert_array_equal(out_img[..., 0], in_img[..., 2])
57
+ assert_array_equal(out_img[..., 1], in_img[..., 1])
58
+ assert_array_equal(out_img[..., 2], in_img[..., 0])
59
+
60
+
61
+ def test_rgb2bgr():
62
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
63
+ out_img = mmcv.rgb2bgr(in_img)
64
+ assert out_img.shape == in_img.shape
65
+ assert_array_equal(out_img[..., 0], in_img[..., 2])
66
+ assert_array_equal(out_img[..., 1], in_img[..., 1])
67
+ assert_array_equal(out_img[..., 2], in_img[..., 0])
68
+
69
+
70
+ def test_bgr2hsv():
71
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
72
+ out_img = mmcv.bgr2hsv(in_img)
73
+ argmax = in_img.argmax(axis=2)
74
+ computed_hsv = np.empty_like(in_img)
75
+ for i in range(in_img.shape[0]):
76
+ for j in range(in_img.shape[1]):
77
+ b, g, r = in_img[i, j]
78
+ v = max(r, g, b)
79
+ s = (v - min(r, g, b)) / v if v != 0 else 0
80
+ if argmax[i, j] == 0:
81
+ h = 240 + 60 * (r - g) / (v - min(r, g, b))
82
+ elif argmax[i, j] == 1:
83
+ h = 120 + 60 * (b - r) / (v - min(r, g, b))
84
+ else:
85
+ h = 60 * (g - b) / (v - min(r, g, b))
86
+ if h < 0:
87
+ h += 360
88
+ computed_hsv[i, j, :] = [h, s, v]
89
+ assert_array_almost_equal(out_img, computed_hsv, decimal=2)
90
+
91
+
92
+ def test_convert_input_type_range():
93
+ with pytest.raises(TypeError):
94
+ # The img type should be np.float32 or np.uint8
95
+ in_img = np.random.rand(10, 10, 3).astype(np.uint64)
96
+ _convert_input_type_range(in_img)
97
+ # np.float32
98
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
99
+ out_img = _convert_input_type_range(in_img)
100
+ assert out_img.dtype == np.float32
101
+ assert np.absolute(out_img).mean() < 1
102
+ # np.uint8
103
+ in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8)
104
+ out_img = _convert_input_type_range(in_img)
105
+ assert out_img.dtype == np.float32
106
+ assert np.absolute(out_img).mean() < 1
107
+
108
+
109
+ def test_convert_output_type_range():
110
+ with pytest.raises(TypeError):
111
+ # The dst_type should be np.float32 or np.uint8
112
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
113
+ _convert_output_type_range(in_img, np.uint64)
114
+ # np.float32
115
+ in_img = (np.random.rand(10, 10, 3) * 255).astype(np.float32)
116
+ out_img = _convert_output_type_range(in_img, np.float32)
117
+ assert out_img.dtype == np.float32
118
+ assert np.absolute(out_img).mean() < 1
119
+ # np.uint8
120
+ in_img = (np.random.rand(10, 10, 3) * 255).astype(np.float32)
121
+ out_img = _convert_output_type_range(in_img, np.uint8)
122
+ assert out_img.dtype == np.uint8
123
+ assert np.absolute(out_img).mean() > 1
124
+
125
+
126
+ def assert_image_almost_equal(x, y, atol=1):
127
+ assert x.dtype == np.uint8
128
+ assert y.dtype == np.uint8
129
+ assert np.all(np.abs(x.astype(np.int32) - y.astype(np.int32)) <= atol)
130
+
131
+
132
+ def test_rgb2ycbcr():
133
+ with pytest.raises(TypeError):
134
+ # The img type should be np.float32 or np.uint8
135
+ in_img = np.random.rand(10, 10, 3).astype(np.uint64)
136
+ mmcv.rgb2ycbcr(in_img)
137
+
138
+ # float32
139
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
140
+ out_img = mmcv.rgb2ycbcr(in_img)
141
+ computed_ycbcr = np.empty_like(in_img)
142
+ for i in range(in_img.shape[0]):
143
+ for j in range(in_img.shape[1]):
144
+ r, g, b = in_img[i, j]
145
+ y = 16 + r * 65.481 + g * 128.553 + b * 24.966
146
+ cb = 128 - r * 37.797 - g * 74.203 + b * 112.0
147
+ cr = 128 + r * 112.0 - g * 93.786 - b * 18.214
148
+ computed_ycbcr[i, j, :] = [y, cb, cr]
149
+ computed_ycbcr /= 255.
150
+ assert_array_almost_equal(out_img, computed_ycbcr, decimal=2)
151
+ # y_only=True
152
+ out_img = mmcv.rgb2ycbcr(in_img, y_only=True)
153
+ computed_y = np.empty_like(out_img, dtype=out_img.dtype)
154
+ for i in range(in_img.shape[0]):
155
+ for j in range(in_img.shape[1]):
156
+ r, g, b = in_img[i, j]
157
+ y = 16 + r * 65.481 + g * 128.553 + b * 24.966
158
+ computed_y[i, j] = y
159
+ computed_y /= 255.
160
+ assert_array_almost_equal(out_img, computed_y, decimal=2)
161
+
162
+ # uint8
163
+ in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8)
164
+ out_img = mmcv.rgb2ycbcr(in_img)
165
+ computed_ycbcr = np.empty_like(in_img)
166
+ in_img = in_img / 255.
167
+ for i in range(in_img.shape[0]):
168
+ for j in range(in_img.shape[1]):
169
+ r, g, b = in_img[i, j]
170
+ y = 16 + r * 65.481 + g * 128.553 + b * 24.966
171
+ cb = 128 - r * 37.797 - g * 74.203 + b * 112.0
172
+ cr = 128 + r * 112.0 - g * 93.786 - b * 18.214
173
+ y, cb, cr = y.round(), cb.round(), cr.round()
174
+ computed_ycbcr[i, j, :] = [y, cb, cr]
175
+ assert_image_almost_equal(out_img, computed_ycbcr)
176
+ # y_only=True
177
+ in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8)
178
+ out_img = mmcv.rgb2ycbcr(in_img, y_only=True)
179
+ computed_y = np.empty_like(out_img, dtype=out_img.dtype)
180
+ in_img = in_img / 255.
181
+ for i in range(in_img.shape[0]):
182
+ for j in range(in_img.shape[1]):
183
+ r, g, b = in_img[i, j]
184
+ y = 16 + r * 65.481 + g * 128.553 + b * 24.966
185
+ y = y.round()
186
+ computed_y[i, j] = y
187
+ assert_image_almost_equal(out_img, computed_y)
188
+
189
+
190
+ def test_bgr2ycbcr():
191
+ # float32
192
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
193
+ out_img = mmcv.bgr2ycbcr(in_img)
194
+ computed_ycbcr = np.empty_like(in_img)
195
+ for i in range(in_img.shape[0]):
196
+ for j in range(in_img.shape[1]):
197
+ b, g, r = in_img[i, j]
198
+ y = 16 + r * 65.481 + g * 128.553 + b * 24.966
199
+ cb = 128 - r * 37.797 - g * 74.203 + b * 112.0
200
+ cr = 128 + r * 112.0 - g * 93.786 - b * 18.214
201
+ computed_ycbcr[i, j, :] = [y, cb, cr]
202
+ computed_ycbcr /= 255.
203
+ assert_array_almost_equal(out_img, computed_ycbcr, decimal=2)
204
+ # y_only=True
205
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
206
+ out_img = mmcv.bgr2ycbcr(in_img, y_only=True)
207
+ computed_y = np.empty_like(out_img, dtype=out_img.dtype)
208
+ for i in range(in_img.shape[0]):
209
+ for j in range(in_img.shape[1]):
210
+ b, g, r = in_img[i, j]
211
+ y = 16 + r * 65.481 + g * 128.553 + b * 24.966
212
+ computed_y[i, j] = y
213
+ computed_y /= 255.
214
+ assert_array_almost_equal(out_img, computed_y, decimal=2)
215
+
216
+ # uint8
217
+ in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8)
218
+ out_img = mmcv.bgr2ycbcr(in_img)
219
+ computed_ycbcr = np.empty_like(in_img)
220
+ in_img = in_img / 255.
221
+ for i in range(in_img.shape[0]):
222
+ for j in range(in_img.shape[1]):
223
+ b, g, r = in_img[i, j]
224
+ y = 16 + r * 65.481 + g * 128.553 + b * 24.966
225
+ cb = 128 - r * 37.797 - g * 74.203 + b * 112.0
226
+ cr = 128 + r * 112.0 - g * 93.786 - b * 18.214
227
+ y, cb, cr = y.round(), cb.round(), cr.round()
228
+ computed_ycbcr[i, j, :] = [y, cb, cr]
229
+ assert_image_almost_equal(out_img, computed_ycbcr)
230
+ # y_only = True
231
+ in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8)
232
+ out_img = mmcv.bgr2ycbcr(in_img, y_only=True)
233
+ computed_y = np.empty_like(out_img, dtype=out_img.dtype)
234
+ in_img = in_img / 255.
235
+ for i in range(in_img.shape[0]):
236
+ for j in range(in_img.shape[1]):
237
+ b, g, r = in_img[i, j]
238
+ y = 16 + r * 65.481 + g * 128.553 + b * 24.966
239
+ y = y.round()
240
+ computed_y[i, j] = y
241
+ assert_image_almost_equal(out_img, computed_y)
242
+
243
+
244
+ def test_ycbcr2rgb():
245
+ with pytest.raises(TypeError):
246
+ # The img type should be np.float32 or np.uint8
247
+ in_img = np.random.rand(10, 10, 3).astype(np.uint64)
248
+ mmcv.ycbcr2rgb(in_img)
249
+
250
+ # float32
251
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
252
+ out_img = mmcv.ycbcr2rgb(in_img)
253
+ computed_rgb = np.empty_like(in_img)
254
+ in_img *= 255.
255
+ for i in range(in_img.shape[0]):
256
+ for j in range(in_img.shape[1]):
257
+ y, cb, cr = in_img[i, j]
258
+ r = -222.921 + y * 0.00456621 * 255 + cr * 0.00625893 * 255
259
+ g = 135.576 + y * 0.00456621 * 255 - cb * 0.00153632 * 255 - \
260
+ cr * 0.00318811 * 255
261
+ b = -276.836 + y * 0.00456621 * 255. + cb * 0.00791071 * 255
262
+ computed_rgb[i, j, :] = [r, g, b]
263
+ computed_rgb /= 255.
264
+ assert_array_almost_equal(out_img, computed_rgb, decimal=2)
265
+
266
+ # uint8
267
+ in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8)
268
+ out_img = mmcv.ycbcr2rgb(in_img)
269
+ computed_rgb = np.empty_like(in_img)
270
+ for i in range(in_img.shape[0]):
271
+ for j in range(in_img.shape[1]):
272
+ y, cb, cr = in_img[i, j]
273
+ r = -222.921 + y * 0.00456621 * 255 + cr * 0.00625893 * 255
274
+ g = 135.576 + y * 0.00456621 * 255 - cb * 0.00153632 * 255 - \
275
+ cr * 0.00318811 * 255
276
+ b = -276.836 + y * 0.00456621 * 255. + cb * 0.00791071 * 255
277
+ r, g, b = r.round(), g.round(), b.round()
278
+ computed_rgb[i, j, :] = [r, g, b]
279
+ assert_image_almost_equal(out_img, computed_rgb)
280
+
281
+
282
+ def test_ycbcr2bgr():
283
+ # float32
284
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
285
+ out_img = mmcv.ycbcr2bgr(in_img)
286
+ computed_bgr = np.empty_like(in_img)
287
+ in_img *= 255.
288
+ for i in range(in_img.shape[0]):
289
+ for j in range(in_img.shape[1]):
290
+ y, cb, cr = in_img[i, j]
291
+ r = -222.921 + y * 0.00456621 * 255 + cr * 0.00625893 * 255
292
+ g = 135.576 + y * 0.00456621 * 255 - cb * 0.00153632 * 255 - \
293
+ cr * 0.00318811 * 255
294
+ b = -276.836 + y * 0.00456621 * 255. + cb * 0.00791071 * 255
295
+ computed_bgr[i, j, :] = [b, g, r]
296
+ computed_bgr /= 255.
297
+ assert_array_almost_equal(out_img, computed_bgr, decimal=2)
298
+
299
+ # uint8
300
+ in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8)
301
+ out_img = mmcv.ycbcr2bgr(in_img)
302
+ computed_bgr = np.empty_like(in_img)
303
+ for i in range(in_img.shape[0]):
304
+ for j in range(in_img.shape[1]):
305
+ y, cb, cr = in_img[i, j]
306
+ r = -222.921 + y * 0.00456621 * 255 + cr * 0.00625893 * 255
307
+ g = 135.576 + y * 0.00456621 * 255 - cb * 0.00153632 * 255 - \
308
+ cr * 0.00318811 * 255
309
+ b = -276.836 + y * 0.00456621 * 255. + cb * 0.00791071 * 255
310
+ r, g, b = r.round(), g.round(), b.round()
311
+ computed_bgr[i, j, :] = [b, g, r]
312
+ assert_image_almost_equal(out_img, computed_bgr)
313
+
314
+
315
+ def test_bgr2hls():
316
+ in_img = np.random.rand(10, 10, 3).astype(np.float32)
317
+ out_img = mmcv.bgr2hls(in_img)
318
+ argmax = in_img.argmax(axis=2)
319
+ computed_hls = np.empty_like(in_img)
320
+ for i in range(in_img.shape[0]):
321
+ for j in range(in_img.shape[1]):
322
+ b, g, r = in_img[i, j]
323
+ maxc = max(r, g, b)
324
+ minc = min(r, g, b)
325
+ _l = (minc + maxc) / 2.0
326
+ if minc == maxc:
327
+ h = 0.0
328
+ s = 0.0
329
+ if _l <= 0.5:
330
+ s = (maxc - minc) / (maxc + minc)
331
+ else:
332
+ s = (maxc - minc) / (2.0 - maxc - minc)
333
+ if argmax[i, j] == 2:
334
+ h = 60 * (g - b) / (maxc - minc)
335
+ elif argmax[i, j] == 1:
336
+ h = 60 * (2.0 + (b - r) / (maxc - minc))
337
+ else:
338
+ h = 60 * (4.0 + (r - g) / (maxc - minc))
339
+ if h < 0:
340
+ h += 360
341
+ computed_hls[i, j, :] = [h, _l, s]
342
+ assert_array_almost_equal(out_img, computed_hls, decimal=2)
343
+
344
+
345
+ @pytest.mark.parametrize('src,dst,ref', [('bgr', 'gray', cv2.COLOR_BGR2GRAY),
346
+ ('rgb', 'gray', cv2.COLOR_RGB2GRAY),
347
+ ('bgr', 'rgb', cv2.COLOR_BGR2RGB),
348
+ ('rgb', 'bgr', cv2.COLOR_RGB2BGR),
349
+ ('bgr', 'hsv', cv2.COLOR_BGR2HSV),
350
+ ('hsv', 'bgr', cv2.COLOR_HSV2BGR),
351
+ ('bgr', 'hls', cv2.COLOR_BGR2HLS),
352
+ ('hls', 'bgr', cv2.COLOR_HLS2BGR)])
353
+ def test_imconvert(src, dst, ref):
354
+ img = np.random.rand(10, 10, 3).astype(np.float32)
355
+ assert_array_equal(mmcv.imconvert(img, src, dst), cv2.cvtColor(img, ref))
groundingLMM/mmcv/tests/test_image/test_geometric.py ADDED
@@ -0,0 +1,610 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import os.path as osp
3
+
4
+ import cv2
5
+ import numpy as np
6
+ import pytest
7
+ from numpy.testing import assert_array_equal
8
+
9
+ import mmcv
10
+
11
+
12
+ class TestGeometric:
13
+
14
+ @classmethod
15
+ def setup_class(cls):
16
+ cls.data_dir = osp.join(osp.dirname(__file__), '../data')
17
+ # the test img resolution is 400x300
18
+ cls.img_path = osp.join(cls.data_dir, 'color.jpg')
19
+ cls.img = cv2.imread(cls.img_path)
20
+
21
+ def test_imresize(self):
22
+ resized_img = mmcv.imresize(self.img, (1000, 600))
23
+ assert resized_img.shape == (600, 1000, 3)
24
+ resized_img, w_scale, h_scale = mmcv.imresize(self.img, (1000, 600),
25
+ True)
26
+ assert (resized_img.shape == (600, 1000, 3) and w_scale == 2.5
27
+ and h_scale == 2.0)
28
+ resized_img_dst = np.empty((600, 1000, 3), dtype=self.img.dtype)
29
+ resized_img = mmcv.imresize(self.img, (1000, 600), out=resized_img_dst)
30
+ assert id(resized_img_dst) == id(resized_img)
31
+ assert_array_equal(resized_img_dst,
32
+ mmcv.imresize(self.img, (1000, 600)))
33
+ for mode in ['nearest', 'bilinear', 'bicubic', 'area', 'lanczos']:
34
+ resized_img = mmcv.imresize(
35
+ self.img, (1000, 600), interpolation=mode)
36
+ assert resized_img.shape == (600, 1000, 3)
37
+
38
+ # test pillow resize
39
+ for mode in [
40
+ 'nearest', 'bilinear', 'bicubic', 'box', 'lanczos', 'hamming'
41
+ ]:
42
+ resized_img = mmcv.imresize(
43
+ self.img, (1000, 600), interpolation=mode, backend='pillow')
44
+ assert resized_img.shape == (600, 1000, 3)
45
+
46
+ # resize backend must be 'cv2' or 'pillow'
47
+ with pytest.raises(ValueError):
48
+ mmcv.imresize(self.img, (1000, 600), backend='not support')
49
+
50
+ def test_imresize_to_multiple(self):
51
+ # test size and keep_ratio = False
52
+ resized_img = mmcv.imresize_to_multiple(
53
+ self.img, divisor=16, size=(511, 513), keep_ratio=False)
54
+ assert resized_img.shape == (528, 512, 3)
55
+ resized_img = mmcv.imresize_to_multiple(
56
+ self.img, divisor=(16, 32), size=(511, 513), keep_ratio=False)
57
+ assert resized_img.shape == (544, 512, 3)
58
+
59
+ # test size, keep_ratio = True, and return_scale
60
+ resized_img, w_scale, h_scale = mmcv.imresize_to_multiple(
61
+ self.img,
62
+ divisor=16,
63
+ size=(1000, 600),
64
+ keep_ratio=True,
65
+ return_scale=True)
66
+ assert resized_img.shape == (
67
+ 608, 800, 3) and h_scale == 608 / 300 and w_scale == 800 / 400
68
+ resized_img, w_scale, h_scale = mmcv.imresize_to_multiple(
69
+ self.img,
70
+ divisor=(18, 16),
71
+ size=(1000, 600),
72
+ keep_ratio=True,
73
+ return_scale=True)
74
+ assert resized_img.shape == (
75
+ 608, 810, 3) and h_scale == 608 / 300 and w_scale == 810 / 400
76
+
77
+ # test scale_factor and return_scale
78
+ resized_img, w_scale, h_scale = mmcv.imresize_to_multiple(
79
+ self.img, divisor=16, scale_factor=2, return_scale=True)
80
+ assert resized_img.shape == (
81
+ 608, 800, 3) and h_scale == 608 / 300 and w_scale == 800 / 400
82
+ resized_img, w_scale, h_scale = mmcv.imresize_to_multiple(
83
+ self.img, divisor=16, scale_factor=(2, 3), return_scale=True)
84
+ assert resized_img.shape == (
85
+ 912, 800, 3) and h_scale == 912 / 300 and w_scale == 800 / 400
86
+ resized_img, w_scale, h_scale = mmcv.imresize_to_multiple(
87
+ self.img, divisor=(18, 16), scale_factor=(2, 3), return_scale=True)
88
+ assert resized_img.shape == (
89
+ 912, 810, 3) and h_scale == 912 / 300 and w_scale == 810 / 400
90
+
91
+ # one of size and scale_factor should be given
92
+ with pytest.raises(ValueError):
93
+ mmcv.imresize_to_multiple(
94
+ self.img, divisor=16, size=(1000, 600), scale_factor=2)
95
+ with pytest.raises(ValueError):
96
+ mmcv.imresize_to_multiple(
97
+ self.img, divisor=16, size=None, scale_factor=None)
98
+
99
+ def test_imresize_like(self):
100
+ a = np.zeros((100, 200, 3))
101
+ resized_img = mmcv.imresize_like(self.img, a)
102
+ assert resized_img.shape == (100, 200, 3)
103
+
104
+ def test_rescale_size(self):
105
+ new_size, scale_factor = mmcv.rescale_size((400, 300), 1.5, True)
106
+ assert new_size == (600, 450) and scale_factor == 1.5
107
+ new_size, scale_factor = mmcv.rescale_size((400, 300), 0.934, True)
108
+ assert new_size == (374, 280) and scale_factor == 0.934
109
+
110
+ new_size = mmcv.rescale_size((400, 300), 1.5)
111
+ assert new_size == (600, 450)
112
+ new_size = mmcv.rescale_size((400, 300), 0.934)
113
+ assert new_size == (374, 280)
114
+
115
+ new_size, scale_factor = mmcv.rescale_size((400, 300), (1000, 600),
116
+ True)
117
+ assert new_size == (800, 600) and scale_factor == 2.0
118
+ new_size, scale_factor = mmcv.rescale_size((400, 300), (180, 200),
119
+ True)
120
+ assert new_size == (200, 150) and scale_factor == 0.5
121
+
122
+ new_size = mmcv.rescale_size((400, 300), (1000, 600))
123
+ assert new_size == (800, 600)
124
+ new_size = mmcv.rescale_size((400, 300), (180, 200))
125
+ assert new_size == (200, 150)
126
+
127
+ with pytest.raises(ValueError):
128
+ mmcv.rescale_size((400, 300), -0.5)
129
+ with pytest.raises(TypeError):
130
+ mmcv.rescale_size()((400, 300), [100, 100])
131
+
132
+ def test_imrescale(self):
133
+ # rescale by a certain factor
134
+ resized_img = mmcv.imrescale(self.img, 1.5)
135
+ assert resized_img.shape == (450, 600, 3)
136
+ resized_img = mmcv.imrescale(self.img, 0.934)
137
+ assert resized_img.shape == (280, 374, 3)
138
+
139
+ # rescale by a certain max_size
140
+ # resize (400, 300) to (max_1000, max_600)
141
+ resized_img = mmcv.imrescale(self.img, (1000, 600))
142
+ assert resized_img.shape == (600, 800, 3)
143
+ resized_img, scale = mmcv.imrescale(
144
+ self.img, (1000, 600), return_scale=True)
145
+ assert resized_img.shape == (600, 800, 3) and scale == 2.0
146
+ # resize (400, 300) to (max_200, max_180)
147
+ resized_img = mmcv.imrescale(self.img, (180, 200))
148
+ assert resized_img.shape == (150, 200, 3)
149
+ resized_img, scale = mmcv.imrescale(
150
+ self.img, (180, 200), return_scale=True)
151
+ assert resized_img.shape == (150, 200, 3) and scale == 0.5
152
+
153
+ # test exceptions
154
+ with pytest.raises(ValueError):
155
+ mmcv.imrescale(self.img, -0.5)
156
+ with pytest.raises(TypeError):
157
+ mmcv.imrescale(self.img, [100, 100])
158
+
159
+ def test_imflip(self):
160
+ # direction must be "horizontal" or "vertical" or "diagonal"
161
+ with pytest.raises(AssertionError):
162
+ mmcv.imflip(np.random.rand(80, 60, 3), direction='random')
163
+
164
+ # test horizontal flip (color image)
165
+ img = np.random.rand(80, 60, 3)
166
+ h, w, c = img.shape
167
+ flipped_img = mmcv.imflip(img)
168
+ assert flipped_img.shape == img.shape
169
+ for i in range(h):
170
+ for j in range(w):
171
+ for k in range(c):
172
+ assert flipped_img[i, j, k] == img[i, w - 1 - j, k]
173
+
174
+ # test vertical flip (color image)
175
+ flipped_img = mmcv.imflip(img, direction='vertical')
176
+ assert flipped_img.shape == img.shape
177
+ for i in range(h):
178
+ for j in range(w):
179
+ for k in range(c):
180
+ assert flipped_img[i, j, k] == img[h - 1 - i, j, k]
181
+
182
+ # test diagonal flip (color image)
183
+ flipped_img = mmcv.imflip(img, direction='diagonal')
184
+ assert flipped_img.shape == img.shape
185
+ for i in range(h):
186
+ for j in range(w):
187
+ for k in range(c):
188
+ assert flipped_img[i, j, k] == img[h - 1 - i, w - 1 - j, k]
189
+
190
+ # test horizontal flip (grayscale image)
191
+ img = np.random.rand(80, 60)
192
+ h, w = img.shape
193
+ flipped_img = mmcv.imflip(img)
194
+ assert flipped_img.shape == img.shape
195
+ for i in range(h):
196
+ for j in range(w):
197
+ assert flipped_img[i, j] == img[i, w - 1 - j]
198
+
199
+ # test vertical flip (grayscale image)
200
+ flipped_img = mmcv.imflip(img, direction='vertical')
201
+ assert flipped_img.shape == img.shape
202
+ for i in range(h):
203
+ for j in range(w):
204
+ assert flipped_img[i, j] == img[h - 1 - i, j]
205
+
206
+ # test diagonal flip (grayscale image)
207
+ flipped_img = mmcv.imflip(img, direction='diagonal')
208
+ assert flipped_img.shape == img.shape
209
+ for i in range(h):
210
+ for j in range(w):
211
+ assert flipped_img[i, j] == img[h - 1 - i, w - 1 - j]
212
+
213
+ def test_imflip_(self):
214
+ # direction must be "horizontal" or "vertical" or "diagonal"
215
+ with pytest.raises(AssertionError):
216
+ mmcv.imflip_(np.random.rand(80, 60, 3), direction='random')
217
+
218
+ # test horizontal flip (color image)
219
+ img = np.random.rand(80, 60, 3)
220
+ h, w, c = img.shape
221
+ img_for_flip = img.copy()
222
+ flipped_img = mmcv.imflip_(img_for_flip)
223
+ assert flipped_img.shape == img.shape
224
+ assert flipped_img.shape == img_for_flip.shape
225
+ assert id(flipped_img) == id(img_for_flip)
226
+ for i in range(h):
227
+ for j in range(w):
228
+ for k in range(c):
229
+ assert flipped_img[i, j, k] == img[i, w - 1 - j, k]
230
+ assert flipped_img[i, j, k] == img_for_flip[i, j, k]
231
+
232
+ # test vertical flip (color image)
233
+ img_for_flip = img.copy()
234
+ flipped_img = mmcv.imflip_(img_for_flip, direction='vertical')
235
+ assert flipped_img.shape == img.shape
236
+ assert flipped_img.shape == img_for_flip.shape
237
+ assert id(flipped_img) == id(img_for_flip)
238
+ for i in range(h):
239
+ for j in range(w):
240
+ for k in range(c):
241
+ assert flipped_img[i, j, k] == img[h - 1 - i, j, k]
242
+ assert flipped_img[i, j, k] == img_for_flip[i, j, k]
243
+
244
+ # test diagonal flip (color image)
245
+ img_for_flip = img.copy()
246
+ flipped_img = mmcv.imflip_(img_for_flip, direction='diagonal')
247
+ assert flipped_img.shape == img.shape
248
+ assert flipped_img.shape == img_for_flip.shape
249
+ assert id(flipped_img) == id(img_for_flip)
250
+ for i in range(h):
251
+ for j in range(w):
252
+ for k in range(c):
253
+ assert flipped_img[i, j, k] == img[h - 1 - i, w - 1 - j, k]
254
+ assert flipped_img[i, j, k] == img_for_flip[i, j, k]
255
+
256
+ # test horizontal flip (grayscale image)
257
+ img = np.random.rand(80, 60)
258
+ h, w = img.shape
259
+ img_for_flip = img.copy()
260
+ flipped_img = mmcv.imflip_(img_for_flip)
261
+ assert flipped_img.shape == img.shape
262
+ assert flipped_img.shape == img_for_flip.shape
263
+ assert id(flipped_img) == id(img_for_flip)
264
+ for i in range(h):
265
+ for j in range(w):
266
+ assert flipped_img[i, j] == img[i, w - 1 - j]
267
+ assert flipped_img[i, j] == img_for_flip[i, j]
268
+
269
+ # test vertical flip (grayscale image)
270
+ img_for_flip = img.copy()
271
+ flipped_img = mmcv.imflip_(img_for_flip, direction='vertical')
272
+ assert flipped_img.shape == img.shape
273
+ assert flipped_img.shape == img_for_flip.shape
274
+ assert id(flipped_img) == id(img_for_flip)
275
+ for i in range(h):
276
+ for j in range(w):
277
+ assert flipped_img[i, j] == img[h - 1 - i, j]
278
+ assert flipped_img[i, j] == img_for_flip[i, j]
279
+
280
+ # test diagonal flip (grayscale image)
281
+ img_for_flip = img.copy()
282
+ flipped_img = mmcv.imflip_(img_for_flip, direction='diagonal')
283
+ assert flipped_img.shape == img.shape
284
+ assert flipped_img.shape == img_for_flip.shape
285
+ assert id(flipped_img) == id(img_for_flip)
286
+ for i in range(h):
287
+ for j in range(w):
288
+ assert flipped_img[i, j] == img[h - 1 - i, w - 1 - j]
289
+ assert flipped_img[i, j] == img_for_flip[i, j]
290
+
291
+ def test_imcrop(self):
292
+ # yapf: disable
293
+ bboxes = np.array([[100, 100, 199, 199], # center
294
+ [0, 0, 150, 100], # left-top corner
295
+ [250, 200, 399, 299], # right-bottom corner
296
+ [0, 100, 399, 199], # wide
297
+ [150, 0, 299, 299]]) # tall
298
+ # yapf: enable
299
+
300
+ # crop one bbox
301
+ patch = mmcv.imcrop(self.img, bboxes[0, :])
302
+ patches = mmcv.imcrop(self.img, bboxes[[0], :])
303
+ assert patch.shape == (100, 100, 3)
304
+ patch_path = osp.join(self.data_dir, 'patches')
305
+ ref_patch = np.load(patch_path + '/0.npy')
306
+ assert_array_equal(patch, ref_patch)
307
+ assert isinstance(patches, list) and len(patches) == 1
308
+ assert_array_equal(patches[0], ref_patch)
309
+
310
+ # crop with no scaling and padding
311
+ patches = mmcv.imcrop(self.img, bboxes)
312
+ assert len(patches) == bboxes.shape[0]
313
+ for i in range(len(patches)):
314
+ ref_patch = np.load(patch_path + f'/{i}.npy')
315
+ assert_array_equal(patches[i], ref_patch)
316
+
317
+ # crop with scaling and no padding
318
+ patches = mmcv.imcrop(self.img, bboxes, 1.2)
319
+ for i in range(len(patches)):
320
+ ref_patch = np.load(patch_path + f'/scale_{i}.npy')
321
+ assert_array_equal(patches[i], ref_patch)
322
+
323
+ # crop with scaling and padding
324
+ patches = mmcv.imcrop(self.img, bboxes, 1.2, pad_fill=[255, 255, 0])
325
+ for i in range(len(patches)):
326
+ ref_patch = np.load(patch_path + f'/pad_{i}.npy')
327
+ assert_array_equal(patches[i], ref_patch)
328
+ patches = mmcv.imcrop(self.img, bboxes, 1.2, pad_fill=0)
329
+ for i in range(len(patches)):
330
+ ref_patch = np.load(patch_path + f'/pad0_{i}.npy')
331
+ assert_array_equal(patches[i], ref_patch)
332
+
333
+ def test_impad(self):
334
+ # grayscale image
335
+ img = np.random.rand(10, 10).astype(np.float32)
336
+ padded_img = mmcv.impad(img, padding=(0, 0, 2, 5), pad_val=0)
337
+ assert_array_equal(img, padded_img[:10, :10])
338
+ assert_array_equal(
339
+ np.zeros((5, 12), dtype='float32'), padded_img[10:, :])
340
+ assert_array_equal(
341
+ np.zeros((15, 2), dtype='float32'), padded_img[:, 10:])
342
+
343
+ # RGB image
344
+ img = np.random.rand(10, 10, 3).astype(np.float32)
345
+ padded_img = mmcv.impad(img, padding=(0, 0, 2, 5), pad_val=0)
346
+ assert_array_equal(img, padded_img[:10, :10, :])
347
+ assert_array_equal(
348
+ np.zeros((5, 12, 3), dtype='float32'), padded_img[10:, :, :])
349
+ assert_array_equal(
350
+ np.zeros((15, 2, 3), dtype='float32'), padded_img[:, 10:, :])
351
+
352
+ # RGB image with different values for three channels.
353
+ img = np.random.randint(256, size=(10, 10, 3)).astype('uint8')
354
+ padded_img = mmcv.impad(
355
+ img, padding=(0, 0, 2, 5), pad_val=(100, 110, 120))
356
+ assert_array_equal(img, padded_img[:10, :10, :])
357
+ assert_array_equal(
358
+ np.array([100, 110, 120], dtype='uint8') * np.ones(
359
+ (5, 12, 3), dtype='uint8'), padded_img[10:, :, :])
360
+ assert_array_equal(
361
+ np.array([100, 110, 120], dtype='uint8') * np.ones(
362
+ (15, 2, 3), dtype='uint8'), padded_img[:, 10:, :])
363
+
364
+ # Pad the grayscale image to shape (15, 12)
365
+ img = np.random.rand(10, 10).astype(np.float32)
366
+ padded_img = mmcv.impad(img, shape=(15, 12))
367
+ assert_array_equal(img, padded_img[:10, :10])
368
+ assert_array_equal(
369
+ np.zeros((5, 12), dtype='float32'), padded_img[10:, :])
370
+ assert_array_equal(
371
+ np.zeros((15, 2), dtype='float32'), padded_img[:, 10:])
372
+
373
+ # Pad the RGB image to shape (15, 12)
374
+ img = np.random.rand(10, 10, 3).astype(np.float32)
375
+ padded_img = mmcv.impad(img, shape=(15, 12))
376
+ assert_array_equal(img, padded_img[:10, :10, :])
377
+ assert_array_equal(
378
+ np.zeros((5, 12, 3), dtype='float32'), padded_img[10:, :, :])
379
+ assert_array_equal(
380
+ np.zeros((15, 2, 3), dtype='float32'), padded_img[:, 10:, :])
381
+
382
+ # Pad the RGB image to shape (15, 12) with different values for
383
+ # three channels.
384
+ img = np.random.randint(256, size=(10, 10, 3)).astype('uint8')
385
+ padded_img = mmcv.impad(img, shape=(15, 12), pad_val=(100, 110, 120))
386
+ assert_array_equal(img, padded_img[:10, :10, :])
387
+ assert_array_equal(
388
+ np.array([100, 110, 120], dtype='uint8') * np.ones(
389
+ (5, 12, 3), dtype='uint8'), padded_img[10:, :, :])
390
+ assert_array_equal(
391
+ np.array([100, 110, 120], dtype='uint8') * np.ones(
392
+ (15, 2, 3), dtype='uint8'), padded_img[:, 10:, :])
393
+
394
+ # RGB image with padding=[5, 2]
395
+ img = np.random.rand(10, 10, 3).astype(np.float32)
396
+ padded_img = mmcv.impad(img, padding=(5, 2), pad_val=0)
397
+
398
+ assert padded_img.shape == (14, 20, 3)
399
+ assert_array_equal(img, padded_img[2:12, 5:15, :])
400
+ assert_array_equal(
401
+ np.zeros((2, 5, 3), dtype='float32'), padded_img[:2, :5, :])
402
+ assert_array_equal(
403
+ np.zeros((2, 5, 3), dtype='float32'), padded_img[12:, :5, :])
404
+ assert_array_equal(
405
+ np.zeros((2, 5, 3), dtype='float32'), padded_img[:2, 15:, :])
406
+ assert_array_equal(
407
+ np.zeros((2, 5, 3), dtype='float32'), padded_img[12:, 15:, :])
408
+
409
+ # RGB image with type(pad_val) = tuple
410
+ pad_val = (0, 1, 2)
411
+ img = np.random.rand(10, 10, 3).astype(np.float32)
412
+ padded_img = mmcv.impad(img, padding=(0, 0, 5, 2), pad_val=pad_val)
413
+
414
+ assert padded_img.shape == (12, 15, 3)
415
+ assert_array_equal(img, padded_img[:10, :10, :])
416
+ assert_array_equal(pad_val[0] * np.ones((2, 15, 1), dtype='float32'),
417
+ padded_img[10:, :, 0:1])
418
+ assert_array_equal(pad_val[1] * np.ones((2, 15, 1), dtype='float32'),
419
+ padded_img[10:, :, 1:2])
420
+ assert_array_equal(pad_val[2] * np.ones((2, 15, 1), dtype='float32'),
421
+ padded_img[10:, :, 2:3])
422
+
423
+ assert_array_equal(pad_val[0] * np.ones((12, 5, 1), dtype='float32'),
424
+ padded_img[:, 10:, 0:1])
425
+ assert_array_equal(pad_val[1] * np.ones((12, 5, 1), dtype='float32'),
426
+ padded_img[:, 10:, 1:2])
427
+ assert_array_equal(pad_val[2] * np.ones((12, 5, 1), dtype='float32'),
428
+ padded_img[:, 10:, 2:3])
429
+
430
+ # test different padding mode with channel number = 3
431
+ for mode in ['constant', 'edge', 'reflect', 'symmetric']:
432
+ img = np.random.rand(10, 10, 3).astype(np.float32)
433
+ padded_img = mmcv.impad(
434
+ img, padding=(0, 0, 5, 2), pad_val=pad_val, padding_mode=mode)
435
+ assert padded_img.shape == (12, 15, 3)
436
+
437
+ # test different padding mode with channel number = 1
438
+ for mode in ['constant', 'edge', 'reflect', 'symmetric']:
439
+ img = np.random.rand(10, 10).astype(np.float32)
440
+ padded_img = mmcv.impad(
441
+ img, padding=(0, 0, 5, 2), pad_val=0, padding_mode=mode)
442
+ assert padded_img.shape == (12, 15)
443
+
444
+ # Padding must be a int or a 2, or 4 element tuple.
445
+ with pytest.raises(ValueError):
446
+ mmcv.impad(img, padding=(1, 1, 1))
447
+
448
+ # pad_val must be a int or a tuple
449
+ with pytest.raises(TypeError):
450
+ mmcv.impad(img, padding=(1, 1, 1, 1), pad_val='wrong')
451
+
452
+ # When pad_val is a tuple,
453
+ # len(pad_val) should be equal to img.shape[-1]
454
+ img = np.random.rand(10, 10, 3).astype(np.float32)
455
+ with pytest.raises(AssertionError):
456
+ mmcv.impad(img, padding=3, pad_val=(100, 200))
457
+
458
+ with pytest.raises(AssertionError):
459
+ mmcv.impad(img, padding=2, pad_val=0, padding_mode='unknown')
460
+
461
+ with pytest.raises(AssertionError):
462
+ mmcv.impad(img, shape=(12, 15), padding=(0, 0, 5, 2))
463
+
464
+ def test_impad_to_multiple(self):
465
+ img = np.random.rand(11, 14, 3).astype(np.float32)
466
+ padded_img = mmcv.impad_to_multiple(img, 4)
467
+ assert padded_img.shape == (12, 16, 3)
468
+ img = np.random.rand(20, 12).astype(np.float32)
469
+ padded_img = mmcv.impad_to_multiple(img, 5)
470
+ assert padded_img.shape == (20, 15)
471
+ img = np.random.rand(20, 12).astype(np.float32)
472
+ padded_img = mmcv.impad_to_multiple(img, 2)
473
+ assert padded_img.shape == (20, 12)
474
+
475
+ def test_cutout(self):
476
+ img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8)
477
+
478
+ # shape must be int or tuple
479
+ with pytest.raises(AssertionError):
480
+ mmcv.cutout(img, 2.5)
481
+ # pad_val must be int or float or tuple with the same length
482
+ # of img channels
483
+ with pytest.raises(AssertionError):
484
+ mmcv.cutout(img, 1, (1, 2, 3))
485
+ with pytest.raises(TypeError):
486
+ mmcv.cutout(img, 1, None)
487
+
488
+ # test cutout the whole img
489
+ assert_array_equal(mmcv.cutout(img, 6), np.zeros_like(img))
490
+ # test not cutout
491
+ assert_array_equal(mmcv.cutout(img, 0), img)
492
+ # test cutout when shape is int
493
+ np.random.seed(0)
494
+ img_cutout = np.array([[1, 2, 3], [4, 0, 6], [7, 8,
495
+ 9]]).astype(np.uint8)
496
+ assert_array_equal(mmcv.cutout(img, 1), img_cutout)
497
+ img_cutout = np.array([[1, 2, 3], [4, 10, 6], [7, 8,
498
+ 9]]).astype(np.uint8)
499
+ assert_array_equal(mmcv.cutout(img, 1, pad_val=10), img_cutout)
500
+ # test cutout when shape is tuple
501
+ np.random.seed(0)
502
+ img_cutout = np.array([[1, 2, 3], [0, 0, 6], [7, 8,
503
+ 9]]).astype(np.uint8)
504
+ assert_array_equal(mmcv.cutout(img, (1, 2)), img_cutout)
505
+ img_cutout = np.array([[1, 2, 3], [10, 10, 6], [7, 8,
506
+ 9]]).astype(np.uint8)
507
+ assert_array_equal(mmcv.cutout(img, (1, 2), pad_val=10), img_cutout)
508
+
509
+ def test_imrotate(self):
510
+ img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8)
511
+ assert_array_equal(mmcv.imrotate(img, 0), img)
512
+ img_r = np.array([[7, 4, 1], [8, 5, 2], [9, 6, 3]])
513
+ assert_array_equal(mmcv.imrotate(img, 90), img_r)
514
+ img_r = np.array([[3, 6, 9], [2, 5, 8], [1, 4, 7]])
515
+ assert_array_equal(mmcv.imrotate(img, -90), img_r)
516
+
517
+ img = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]).astype(np.uint8)
518
+ img_r = np.array([[0, 6, 2, 0], [0, 7, 3, 0]])
519
+ assert_array_equal(mmcv.imrotate(img, 90), img_r)
520
+ img_r = np.array([[1, 0, 0, 0], [2, 0, 0, 0]])
521
+ assert_array_equal(mmcv.imrotate(img, 90, center=(0, 0)), img_r)
522
+ img_r = np.array([[255, 6, 2, 255], [255, 7, 3, 255]])
523
+ assert_array_equal(mmcv.imrotate(img, 90, border_value=255), img_r)
524
+ img_r = np.array([[5, 1], [6, 2], [7, 3], [8, 4]])
525
+ assert_array_equal(mmcv.imrotate(img, 90, auto_bound=True), img_r)
526
+
527
+ with pytest.raises(ValueError):
528
+ mmcv.imrotate(img, 90, center=(0, 0), auto_bound=True)
529
+
530
+ def test_imshear(self):
531
+ img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8)
532
+ assert_array_equal(mmcv.imshear(img, 0), img)
533
+ # magnitude=1, horizontal
534
+ img_sheared = np.array([[1, 2, 3], [0, 4, 5], [0, 0, 7]],
535
+ dtype=np.uint8)
536
+ assert_array_equal(mmcv.imshear(img, 1), img_sheared)
537
+ # magnitude=-1, vertical
538
+ img_sheared = np.array([[1, 5, 9], [4, 8, 0], [7, 0, 0]],
539
+ dtype=np.uint8)
540
+ assert_array_equal(mmcv.imshear(img, -1, 'vertical'), img_sheared)
541
+ # magnitude=1, vertical, borderValue=100
542
+ borderValue = 100
543
+ img_sheared = np.array(
544
+ [[1, borderValue, borderValue], [4, 2, borderValue], [7, 5, 3]],
545
+ dtype=np.uint8)
546
+ assert_array_equal(
547
+ mmcv.imshear(img, 1, 'vertical', borderValue), img_sheared)
548
+ # magnitude=1, vertical, borderValue=100, img shape (h,w,3)
549
+ img = np.stack([img, img, img], axis=-1)
550
+ img_sheared = np.stack([img_sheared, img_sheared, img_sheared],
551
+ axis=-1)
552
+ assert_array_equal(
553
+ mmcv.imshear(img, 1, 'vertical', borderValue), img_sheared)
554
+ # test tuple format of borderValue
555
+ assert_array_equal(
556
+ mmcv.imshear(img, 1, 'vertical',
557
+ (borderValue, borderValue, borderValue)), img_sheared)
558
+
559
+ # test invalid length of borderValue
560
+ with pytest.raises(AssertionError):
561
+ mmcv.imshear(img, 0.5, 'horizontal', (borderValue, ))
562
+
563
+ # test invalid type of borderValue
564
+ with pytest.raises(ValueError):
565
+ mmcv.imshear(img, 0.5, 'horizontal', [borderValue])
566
+
567
+ # test invalid value of direction
568
+ with pytest.raises(AssertionError):
569
+ mmcv.imshear(img, 0.5, 'diagonal')
570
+
571
+ def test_imtranslate(self):
572
+ img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.uint8)
573
+ assert_array_equal(mmcv.imtranslate(img, 0), img)
574
+ # offset=1, horizontal
575
+ img_translated = np.array([[128, 1, 2], [128, 4, 5], [128, 7, 8]],
576
+ dtype=np.uint8)
577
+ assert_array_equal(
578
+ mmcv.imtranslate(img, 1, border_value=128), img_translated)
579
+ # offset=-1, vertical
580
+ img_translated = np.array([[4, 5, 6], [7, 8, 9], [0, 0, 0]],
581
+ dtype=np.uint8)
582
+ assert_array_equal(
583
+ mmcv.imtranslate(img, -1, 'vertical'), img_translated)
584
+ # offset=-2, horizontal
585
+ img = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=np.uint8)
586
+ img = np.stack([img, img, img], axis=-1)
587
+ img_translated = [[3, 4, 128, 128], [7, 8, 128, 128]]
588
+ img_translated = np.stack(
589
+ [img_translated, img_translated, img_translated], axis=-1)
590
+ assert_array_equal(
591
+ mmcv.imtranslate(img, -2, border_value=128), img_translated)
592
+ # offset=2, vertical
593
+ border_value = (110, 120, 130)
594
+ img_translated = np.stack([
595
+ np.ones((2, 4)) * border_value[0],
596
+ np.ones((2, 4)) * border_value[1],
597
+ np.ones((2, 4)) * border_value[2]
598
+ ],
599
+ axis=-1).astype(np.uint8)
600
+ assert_array_equal(
601
+ mmcv.imtranslate(img, 2, 'vertical', border_value), img_translated)
602
+ # test invalid number elements in border_value
603
+ with pytest.raises(AssertionError):
604
+ mmcv.imtranslate(img, 1, border_value=(1, ))
605
+ # test invalid type of border_value
606
+ with pytest.raises(ValueError):
607
+ mmcv.imtranslate(img, 1, border_value=[1, 2, 3])
608
+ # test invalid value of direction
609
+ with pytest.raises(AssertionError):
610
+ mmcv.imtranslate(img, 1, 'diagonal')
groundingLMM/mmcv/tests/test_image/test_image_misc.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import numpy as np
3
+ import pytest
4
+ from numpy.testing import assert_array_equal
5
+
6
+ import mmcv
7
+
8
+ try:
9
+ import torch
10
+ except ImportError:
11
+ torch = None
12
+
13
+
14
+ @pytest.mark.skipif(torch is None, reason='requires torch library')
15
+ def test_tensor2imgs():
16
+
17
+ # test tensor obj
18
+ with pytest.raises(AssertionError):
19
+ tensor = np.random.rand(2, 3, 3)
20
+ mmcv.tensor2imgs(tensor)
21
+
22
+ # test tensor ndim
23
+ with pytest.raises(AssertionError):
24
+ tensor = torch.randn(2, 3, 3)
25
+ mmcv.tensor2imgs(tensor)
26
+
27
+ # test tensor dim-1
28
+ with pytest.raises(AssertionError):
29
+ tensor = torch.randn(2, 4, 3, 3)
30
+ mmcv.tensor2imgs(tensor)
31
+
32
+ # test mean length
33
+ with pytest.raises(AssertionError):
34
+ tensor = torch.randn(2, 3, 5, 5)
35
+ mmcv.tensor2imgs(tensor, mean=(1, ))
36
+ tensor = torch.randn(2, 1, 5, 5)
37
+ mmcv.tensor2imgs(tensor, mean=(0, 0, 0))
38
+
39
+ # test std length
40
+ with pytest.raises(AssertionError):
41
+ tensor = torch.randn(2, 3, 5, 5)
42
+ mmcv.tensor2imgs(tensor, std=(1, ))
43
+ tensor = torch.randn(2, 1, 5, 5)
44
+ mmcv.tensor2imgs(tensor, std=(1, 1, 1))
45
+
46
+ # test to_rgb
47
+ with pytest.raises(AssertionError):
48
+ tensor = torch.randn(2, 1, 5, 5)
49
+ mmcv.tensor2imgs(tensor, mean=(0, ), std=(1, ), to_rgb=True)
50
+
51
+ # test rgb=True
52
+ tensor = torch.randn(2, 3, 5, 5)
53
+ gts = [
54
+ t.cpu().numpy().transpose(1, 2, 0).astype(np.uint8)
55
+ for t in tensor.flip(1)
56
+ ]
57
+ outputs = mmcv.tensor2imgs(tensor, to_rgb=True)
58
+ for gt, output in zip(gts, outputs):
59
+ assert_array_equal(gt, output)
60
+
61
+ # test rgb=False
62
+ tensor = torch.randn(2, 3, 5, 5)
63
+ gts = [t.cpu().numpy().transpose(1, 2, 0).astype(np.uint8) for t in tensor]
64
+ outputs = mmcv.tensor2imgs(tensor, to_rgb=False)
65
+ for gt, output in zip(gts, outputs):
66
+ assert_array_equal(gt, output)
67
+
68
+ # test tensor channel 1 and rgb=False
69
+ tensor = torch.randn(2, 1, 5, 5)
70
+ gts = [t.squeeze(0).cpu().numpy().astype(np.uint8) for t in tensor]
71
+ outputs = mmcv.tensor2imgs(tensor, to_rgb=False)
72
+ for gt, output in zip(gts, outputs):
73
+ assert_array_equal(gt, output)
groundingLMM/mmcv/tests/test_image/test_io.py ADDED
@@ -0,0 +1,385 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import os
3
+ import os.path as osp
4
+ import sys
5
+ import tempfile
6
+ from pathlib import Path
7
+ from unittest.mock import MagicMock, patch
8
+
9
+ import cv2
10
+ import numpy as np
11
+ import pytest
12
+ from numpy.testing import assert_allclose, assert_array_equal
13
+
14
+ import mmcv
15
+ from mmcv.fileio.file_client import HTTPBackend, PetrelBackend
16
+
17
+
18
+ class TestIO:
19
+
20
+ @classmethod
21
+ def setup_class(cls):
22
+ cls.data_dir = osp.join(osp.dirname(__file__), '../data')
23
+ # the test img resolution is 400x300
24
+ cls.img_path = osp.join(cls.data_dir, 'color.jpg')
25
+ cls.img_path_obj = Path(cls.img_path)
26
+ cls.gray_img_path = osp.join(cls.data_dir, 'grayscale.jpg')
27
+ cls.gray_img_path_obj = Path(cls.gray_img_path)
28
+ cls.gray_img_dim3_path = osp.join(cls.data_dir, 'grayscale_dim3.jpg')
29
+ cls.gray_alpha_img_path = osp.join(cls.data_dir, 'gray_alpha.png')
30
+ cls.palette_img_path = osp.join(cls.data_dir, 'palette.gif')
31
+ cls.exif_img_path = osp.join(cls.data_dir, 'color_exif.jpg')
32
+ cls.img = cv2.imread(cls.img_path)
33
+ cls.tiff_path = osp.join(cls.data_dir, 'uint16-5channel.tif')
34
+ # petrel s3 path
35
+ cls.s3_path = 's3://path/of/your/file.jpg'
36
+ # http path
37
+ cls.http_path = 'http://path/of/your/file.jpg'
38
+ # add mock package
39
+ sys.modules['petrel_client'] = MagicMock()
40
+ sys.modules['petrel_client.client'] = MagicMock()
41
+
42
+ @classmethod
43
+ def teardown_class(cls):
44
+ # clean instances avoid to influence other unittest
45
+ mmcv.FileClient._instances = {}
46
+
47
+ def assert_img_equal(self, img, ref_img, ratio_thr=0.999):
48
+ assert img.shape == ref_img.shape
49
+ assert img.dtype == ref_img.dtype
50
+ area = ref_img.shape[0] * ref_img.shape[1]
51
+ diff = np.abs(img.astype('int32') - ref_img.astype('int32'))
52
+ assert np.sum(diff <= 1) / float(area) > ratio_thr
53
+
54
+ def test_imread(self):
55
+ # backend cv2
56
+ mmcv.use_backend('cv2')
57
+
58
+ # HardDiskBackend
59
+ img_cv2_color_bgr = mmcv.imread(self.img_path)
60
+ assert img_cv2_color_bgr.shape == (300, 400, 3)
61
+ img_cv2_color_rgb = mmcv.imread(self.img_path, channel_order='rgb')
62
+ assert img_cv2_color_rgb.shape == (300, 400, 3)
63
+ assert_array_equal(img_cv2_color_rgb[:, :, ::-1], img_cv2_color_bgr)
64
+ img_cv2_grayscale1 = mmcv.imread(self.img_path, 'grayscale')
65
+ assert img_cv2_grayscale1.shape == (300, 400)
66
+ img_cv2_grayscale2 = mmcv.imread(self.gray_img_path)
67
+ assert img_cv2_grayscale2.shape == (300, 400, 3)
68
+ img_cv2_unchanged = mmcv.imread(self.gray_img_path, 'unchanged')
69
+ assert img_cv2_unchanged.shape == (300, 400)
70
+ img_cv2_unchanged = mmcv.imread(img_cv2_unchanged)
71
+ assert_array_equal(img_cv2_unchanged, mmcv.imread(img_cv2_unchanged))
72
+
73
+ img_cv2_color_bgr = mmcv.imread(self.img_path_obj)
74
+ assert img_cv2_color_bgr.shape == (300, 400, 3)
75
+ img_cv2_color_rgb = mmcv.imread(self.img_path_obj, channel_order='rgb')
76
+ assert img_cv2_color_rgb.shape == (300, 400, 3)
77
+ assert_array_equal(img_cv2_color_rgb[:, :, ::-1], img_cv2_color_bgr)
78
+ img_cv2_grayscale1 = mmcv.imread(self.img_path_obj, 'grayscale')
79
+ assert img_cv2_grayscale1.shape == (300, 400)
80
+ img_cv2_grayscale2 = mmcv.imread(self.gray_img_path_obj)
81
+ assert img_cv2_grayscale2.shape == (300, 400, 3)
82
+ img_cv2_unchanged = mmcv.imread(self.gray_img_path_obj, 'unchanged')
83
+ assert img_cv2_unchanged.shape == (300, 400)
84
+ with pytest.raises(TypeError):
85
+ mmcv.imread(1)
86
+
87
+ # PetrelBackend
88
+ img_cv2_color_bgr = mmcv.imread(self.img_path)
89
+ with patch.object(
90
+ PetrelBackend, 'get',
91
+ return_value=img_cv2_color_bgr) as mock_method:
92
+ img_cv2_color_bgr_petrel = mmcv.imread(self.s3_path, backend='cv2')
93
+ img_cv2_color_bgr_petrel_with_args = mmcv.imread(
94
+ self.s3_path,
95
+ backend='cv2',
96
+ file_client_args={'backend': 'petrel'})
97
+ mock_method.assert_called()
98
+ assert_array_equal(img_cv2_color_bgr_petrel,
99
+ img_cv2_color_bgr_petrel_with_args)
100
+
101
+ # HTTPBackend
102
+ img_cv2_color_bgr = mmcv.imread(self.img_path)
103
+ with patch.object(
104
+ HTTPBackend, 'get',
105
+ return_value=img_cv2_color_bgr) as mock_method:
106
+ img_cv2_color_bgr_http = mmcv.imread(self.http_path, backend='cv2')
107
+ img_cv2_color_bgr_http_with_args = mmcv.imread(
108
+ self.http_path,
109
+ backend='cv2',
110
+ file_client_args={'backend': 'http'})
111
+ mock_method.assert_called()
112
+ assert_array_equal(img_cv2_color_bgr_http,
113
+ img_cv2_color_bgr_http_with_args)
114
+
115
+ with pytest.raises(FileNotFoundError):
116
+ mmcv.imread('/not/exists/' + self.img_path)
117
+
118
+ # test arg backend pillow
119
+ img_pil_gray_alpha = mmcv.imread(
120
+ self.gray_alpha_img_path, 'grayscale', backend='pillow')
121
+ assert img_pil_gray_alpha.shape == (400, 500)
122
+ mean = img_pil_gray_alpha[300:, 400:].mean()
123
+ assert_allclose(img_pil_gray_alpha[300:, 400:] - mean, 0)
124
+ img_pil_gray_alpha = mmcv.imread(
125
+ self.gray_alpha_img_path, backend='pillow')
126
+ mean = img_pil_gray_alpha[300:, 400:].mean(axis=(0, 1))
127
+ assert_allclose(img_pil_gray_alpha[300:, 400:] - mean, 0)
128
+ assert img_pil_gray_alpha.shape == (400, 500, 3)
129
+ img_pil_gray_alpha = mmcv.imread(
130
+ self.gray_alpha_img_path, 'unchanged', backend='pillow')
131
+ assert img_pil_gray_alpha.shape == (400, 500, 2)
132
+ img_pil_palette = mmcv.imread(
133
+ self.palette_img_path, 'grayscale', backend='pillow')
134
+ assert img_pil_palette.shape == (300, 400)
135
+ img_pil_palette = mmcv.imread(self.palette_img_path, backend='pillow')
136
+ assert img_pil_palette.shape == (300, 400, 3)
137
+ img_pil_palette = mmcv.imread(
138
+ self.palette_img_path, 'unchanged', backend='pillow')
139
+ assert img_pil_palette.shape == (300, 400)
140
+
141
+ # backend pillow
142
+ mmcv.use_backend('pillow')
143
+ img_pil_grayscale1 = mmcv.imread(self.img_path, 'grayscale')
144
+ assert img_pil_grayscale1.shape == (300, 400)
145
+ img_pil_gray_alpha = mmcv.imread(self.gray_alpha_img_path, 'grayscale')
146
+ assert img_pil_gray_alpha.shape == (400, 500)
147
+ mean = img_pil_gray_alpha[300:, 400:].mean()
148
+ assert_allclose(img_pil_gray_alpha[300:, 400:] - mean, 0)
149
+ img_pil_gray_alpha = mmcv.imread(self.gray_alpha_img_path)
150
+ mean = img_pil_gray_alpha[300:, 400:].mean(axis=(0, 1))
151
+ assert_allclose(img_pil_gray_alpha[300:, 400:] - mean, 0)
152
+ assert img_pil_gray_alpha.shape == (400, 500, 3)
153
+ img_pil_gray_alpha = mmcv.imread(self.gray_alpha_img_path, 'unchanged')
154
+ assert img_pil_gray_alpha.shape == (400, 500, 2)
155
+ img_pil_palette = mmcv.imread(self.palette_img_path, 'grayscale')
156
+ assert img_pil_palette.shape == (300, 400)
157
+ img_pil_palette = mmcv.imread(self.palette_img_path)
158
+ assert img_pil_palette.shape == (300, 400, 3)
159
+ img_pil_palette = mmcv.imread(self.palette_img_path, 'unchanged')
160
+ assert img_pil_palette.shape == (300, 400)
161
+ img_pil_grayscale2 = mmcv.imread(self.gray_img_path)
162
+ assert img_pil_grayscale2.shape == (300, 400, 3)
163
+ img_pil_unchanged = mmcv.imread(self.gray_img_path, 'unchanged')
164
+ assert img_pil_unchanged.shape == (300, 400)
165
+ img_pil_unchanged = mmcv.imread(img_pil_unchanged)
166
+ assert_array_equal(img_pil_unchanged, mmcv.imread(img_pil_unchanged))
167
+
168
+ img_pil_color_bgr = mmcv.imread(self.img_path_obj)
169
+ assert img_pil_color_bgr.shape == (300, 400, 3)
170
+ img_pil_color_rgb = mmcv.imread(self.img_path_obj, channel_order='rgb')
171
+ assert img_pil_color_rgb.shape == (300, 400, 3)
172
+ assert (img_pil_color_rgb == img_cv2_color_rgb).sum() / float(
173
+ img_cv2_color_rgb.size) > 0.5
174
+ assert_array_equal(img_pil_color_rgb[:, :, ::-1], img_pil_color_bgr)
175
+ img_pil_grayscale1 = mmcv.imread(self.img_path_obj, 'grayscale')
176
+ assert img_pil_grayscale1.shape == (300, 400)
177
+ img_pil_grayscale2 = mmcv.imread(self.gray_img_path_obj)
178
+ assert img_pil_grayscale2.shape == (300, 400, 3)
179
+ img_pil_unchanged = mmcv.imread(self.gray_img_path_obj, 'unchanged')
180
+ assert img_pil_unchanged.shape == (300, 400)
181
+ with pytest.raises(TypeError):
182
+ mmcv.imread(1)
183
+
184
+ # backend turbojpeg
185
+ mmcv.use_backend('turbojpeg')
186
+
187
+ img_turbojpeg_color_bgr = mmcv.imread(self.img_path)
188
+ assert img_turbojpeg_color_bgr.shape == (300, 400, 3)
189
+ assert_array_equal(img_turbojpeg_color_bgr, img_cv2_color_bgr)
190
+
191
+ img_turbojpeg_color_rgb = mmcv.imread(
192
+ self.img_path, channel_order='rgb')
193
+ assert img_turbojpeg_color_rgb.shape == (300, 400, 3)
194
+ assert_array_equal(img_turbojpeg_color_rgb, img_cv2_color_rgb)
195
+
196
+ with pytest.raises(ValueError):
197
+ mmcv.imread(self.img_path, channel_order='unsupport_order')
198
+
199
+ img_turbojpeg_grayscale1 = mmcv.imread(self.img_path, flag='grayscale')
200
+ assert img_turbojpeg_grayscale1.shape == (300, 400)
201
+ assert_array_equal(img_turbojpeg_grayscale1, img_cv2_grayscale1)
202
+
203
+ img_turbojpeg_grayscale2 = mmcv.imread(self.gray_img_path)
204
+ assert img_turbojpeg_grayscale2.shape == (300, 400, 3)
205
+ assert_array_equal(img_turbojpeg_grayscale2, img_cv2_grayscale2)
206
+
207
+ img_turbojpeg_grayscale2 = mmcv.imread(img_turbojpeg_grayscale2)
208
+ assert_array_equal(img_turbojpeg_grayscale2,
209
+ mmcv.imread(img_turbojpeg_grayscale2))
210
+
211
+ with pytest.raises(ValueError):
212
+ mmcv.imread(self.gray_img_path, 'unchanged')
213
+
214
+ with pytest.raises(TypeError):
215
+ mmcv.imread(1)
216
+
217
+ with pytest.raises(AssertionError):
218
+ mmcv.use_backend('unsupport_backend')
219
+
220
+ with pytest.raises(ValueError):
221
+ mmcv.imread(self.img_path, 'unsupported_backend')
222
+
223
+ # backend tifffile, multi channel tiff file(> 4 channels).
224
+ mmcv.use_backend('tifffile')
225
+ img_tifffile = mmcv.imread(self.tiff_path)
226
+ assert img_tifffile.shape == (200, 150, 5)
227
+
228
+ mmcv.use_backend('cv2')
229
+
230
+ # consistent exif behaviour
231
+ img_cv2_exif = mmcv.imread(self.exif_img_path)
232
+ img_pil_exif = mmcv.imread(self.exif_img_path, backend='pillow')
233
+ assert img_cv2_exif.shape == (400, 300, 3)
234
+ assert img_pil_exif.shape == (400, 300, 3)
235
+ img_cv2_exif_unchanged = mmcv.imread(
236
+ self.exif_img_path, flag='unchanged')
237
+ img_pil_exif_unchanged = mmcv.imread(
238
+ self.exif_img_path, backend='pillow', flag='unchanged')
239
+ assert img_cv2_exif_unchanged.shape == (300, 400, 3)
240
+ assert img_pil_exif_unchanged.shape == (300, 400, 3)
241
+ img_cv2_color_ignore_exif = mmcv.imread(
242
+ self.exif_img_path, flag='color_ignore_orientation')
243
+ img_pil_color_ignore_exif = mmcv.imread(
244
+ self.exif_img_path,
245
+ backend='pillow',
246
+ flag='color_ignore_orientation')
247
+ assert img_cv2_color_ignore_exif.shape == (300, 400, 3)
248
+ assert img_pil_color_ignore_exif.shape == (300, 400, 3)
249
+ img_cv2_grayscale_ignore_exif = mmcv.imread(
250
+ self.exif_img_path, flag='grayscale_ignore_orientation')
251
+ img_pil_grayscale_ignore_exif = mmcv.imread(
252
+ self.exif_img_path,
253
+ backend='pillow',
254
+ flag='grayscale_ignore_orientation')
255
+ assert img_cv2_grayscale_ignore_exif.shape == (300, 400)
256
+ assert img_pil_grayscale_ignore_exif.shape == (300, 400)
257
+
258
+ def test_imfrombytes(self):
259
+ # backend cv2, channel order: bgr
260
+ mmcv.use_backend('cv2')
261
+ with open(self.img_path, 'rb') as f:
262
+ img_bytes = f.read()
263
+ img_cv2 = mmcv.imfrombytes(img_bytes)
264
+ assert img_cv2.shape == (300, 400, 3)
265
+
266
+ # backend cv2, channel order: rgb
267
+ mmcv.use_backend('cv2')
268
+ with open(self.img_path, 'rb') as f:
269
+ img_bytes = f.read()
270
+ img_rgb_cv2 = mmcv.imfrombytes(img_bytes, channel_order='rgb')
271
+ assert img_rgb_cv2.shape == (300, 400, 3)
272
+ assert_array_equal(img_rgb_cv2, img_cv2[:, :, ::-1])
273
+
274
+ # backend cv2, grayscale, decode as 3 channels
275
+ with open(self.gray_img_path, 'rb') as f:
276
+ img_bytes = f.read()
277
+ gray_img_rgb_cv2 = mmcv.imfrombytes(img_bytes)
278
+ assert gray_img_rgb_cv2.shape == (300, 400, 3)
279
+
280
+ # backend cv2, grayscale
281
+ with open(self.gray_img_path, 'rb') as f:
282
+ img_bytes = f.read()
283
+ gray_img_cv2 = mmcv.imfrombytes(img_bytes, flag='grayscale')
284
+ assert gray_img_cv2.shape == (300, 400)
285
+
286
+ # backend cv2, grayscale dim3
287
+ with open(self.gray_img_dim3_path, 'rb') as f:
288
+ img_bytes = f.read()
289
+ gray_img_dim3_cv2 = mmcv.imfrombytes(img_bytes, flag='grayscale')
290
+ assert gray_img_dim3_cv2.shape == (300, 400)
291
+
292
+ # arg backend pillow, channel order: bgr
293
+ with open(self.img_path, 'rb') as f:
294
+ img_bytes = f.read()
295
+ img_pillow = mmcv.imfrombytes(img_bytes, backend='pillow')
296
+ assert img_pillow.shape == (300, 400, 3)
297
+ # Pillow and opencv decoding may not be the same
298
+ assert (img_cv2 == img_pillow).sum() / float(img_cv2.size) > 0.5
299
+
300
+ # backend pillow, channel order: bgr
301
+ mmcv.use_backend('pillow')
302
+ with open(self.img_path, 'rb') as f:
303
+ img_bytes = f.read()
304
+ img_pillow = mmcv.imfrombytes(img_bytes)
305
+ assert img_pillow.shape == (300, 400, 3)
306
+ # Pillow and opencv decoding may not be the same
307
+ assert (img_cv2 == img_pillow).sum() / float(img_cv2.size) > 0.5
308
+
309
+ # backend turbojpeg, channel order: bgr
310
+ mmcv.use_backend('turbojpeg')
311
+ with open(self.img_path, 'rb') as f:
312
+ img_bytes = f.read()
313
+ img_turbojpeg = mmcv.imfrombytes(img_bytes)
314
+ assert img_turbojpeg.shape == (300, 400, 3)
315
+ assert_array_equal(img_cv2, img_turbojpeg)
316
+
317
+ # backend turbojpeg, channel order: rgb
318
+ with open(self.img_path, 'rb') as f:
319
+ img_bytes = f.read()
320
+ img_rgb_turbojpeg = mmcv.imfrombytes(img_bytes, channel_order='rgb')
321
+ assert img_rgb_turbojpeg.shape == (300, 400, 3)
322
+ assert_array_equal(img_rgb_turbojpeg, img_cv2[:, :, ::-1])
323
+
324
+ # backend turbojpeg, grayscale, decode as 3 channels
325
+ with open(self.gray_img_path, 'rb') as f:
326
+ img_bytes = f.read()
327
+ gray_img_turbojpeg = mmcv.imfrombytes(img_bytes)
328
+ assert gray_img_turbojpeg.shape == (300, 400, 3)
329
+ assert_array_equal(gray_img_rgb_cv2, gray_img_turbojpeg)
330
+
331
+ # backend turbojpeg, grayscale
332
+ with open(self.gray_img_path, 'rb') as f:
333
+ img_bytes = f.read()
334
+ gray_img_turbojpeg = mmcv.imfrombytes(img_bytes, flag='grayscale')
335
+ assert gray_img_turbojpeg.shape == (300, 400)
336
+ assert_array_equal(gray_img_cv2, gray_img_turbojpeg)
337
+
338
+ # backend turbojpeg, grayscale dim3
339
+ with open(self.gray_img_dim3_path, 'rb') as f:
340
+ img_bytes = f.read()
341
+ gray_img_dim3_turbojpeg = mmcv.imfrombytes(img_bytes, flag='grayscale')
342
+ assert gray_img_dim3_turbojpeg.shape == (300, 400)
343
+ assert_array_equal(gray_img_dim3_cv2, gray_img_dim3_turbojpeg)
344
+
345
+ mmcv.use_backend('cv2')
346
+
347
+ with pytest.raises(ValueError):
348
+ with open(self.img_path, 'rb') as f:
349
+ img_bytes = f.read()
350
+ mmcv.imfrombytes(img_bytes, backend='unsupported_backend')
351
+
352
+ def test_imwrite(self):
353
+ img = mmcv.imread(self.img_path)
354
+ out_file = osp.join(tempfile.gettempdir(), 'mmcv_test.jpg')
355
+ mmcv.imwrite(img, out_file)
356
+ rewrite_img = mmcv.imread(out_file)
357
+ os.remove(out_file)
358
+ self.assert_img_equal(img, rewrite_img)
359
+
360
+ # test petrel client
361
+ with patch.object(
362
+ PetrelBackend, 'put', return_value=None) as mock_method:
363
+ ret = mmcv.imwrite(img, self.s3_path)
364
+ ret_with_args = mmcv.imwrite(
365
+ img, self.s3_path, file_client_args={'backend': 'petrel'})
366
+ assert ret
367
+ assert ret_with_args
368
+ mock_method.assert_called()
369
+
370
+ with pytest.raises(cv2.error):
371
+ mmcv.imwrite(img, 'error_file.jppg')
372
+
373
+ @patch('mmcv.image.io.TurboJPEG', None)
374
+ def test_no_turbojpeg(self):
375
+ with pytest.raises(ImportError):
376
+ mmcv.use_backend('turbojpeg')
377
+
378
+ mmcv.use_backend('cv2')
379
+
380
+ @patch('mmcv.image.io.Image', None)
381
+ def test_no_pillow(self):
382
+ with pytest.raises(ImportError):
383
+ mmcv.use_backend('pillow')
384
+
385
+ mmcv.use_backend('cv2')
groundingLMM/mmcv/tests/test_image/test_photometric.py ADDED
@@ -0,0 +1,380 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import os.path as osp
3
+
4
+ import cv2
5
+ import numpy as np
6
+ import pytest
7
+ from numpy.testing import assert_array_equal
8
+
9
+ import mmcv
10
+
11
+
12
+ class TestPhotometric:
13
+
14
+ @classmethod
15
+ def setup_class(cls):
16
+ # the test img resolution is 400x300
17
+ cls.img_path = osp.join(osp.dirname(__file__), '../data/color.jpg')
18
+ cls.img = cv2.imread(cls.img_path)
19
+ cls.mean = np.array([123.675, 116.28, 103.53], dtype=np.float32)
20
+ cls.std = np.array([58.395, 57.12, 57.375], dtype=np.float32)
21
+
22
+ def test_imnormalize(self):
23
+ rgb_img = self.img[:, :, ::-1]
24
+ baseline = (rgb_img - self.mean) / self.std
25
+ img = mmcv.imnormalize(self.img, self.mean, self.std)
26
+ assert np.allclose(img, baseline)
27
+ assert id(img) != id(self.img)
28
+ img = mmcv.imnormalize(rgb_img, self.mean, self.std, to_rgb=False)
29
+ assert np.allclose(img, baseline)
30
+ assert id(img) != id(rgb_img)
31
+
32
+ def test_imnormalize_(self):
33
+ img_for_normalize = np.float32(self.img)
34
+ rgb_img_for_normalize = np.float32(self.img[:, :, ::-1])
35
+ baseline = (rgb_img_for_normalize - self.mean) / self.std
36
+ img = mmcv.imnormalize_(img_for_normalize, self.mean, self.std)
37
+ assert np.allclose(img_for_normalize, baseline)
38
+ assert id(img) == id(img_for_normalize)
39
+ img = mmcv.imnormalize_(
40
+ rgb_img_for_normalize, self.mean, self.std, to_rgb=False)
41
+ assert np.allclose(img, baseline)
42
+ assert id(img) == id(rgb_img_for_normalize)
43
+
44
+ def test_imdenormalize(self):
45
+ norm_img = (self.img[:, :, ::-1] - self.mean) / self.std
46
+ rgb_baseline = (norm_img * self.std + self.mean)
47
+ bgr_baseline = rgb_baseline[:, :, ::-1]
48
+ img = mmcv.imdenormalize(norm_img, self.mean, self.std)
49
+ assert np.allclose(img, bgr_baseline)
50
+ img = mmcv.imdenormalize(norm_img, self.mean, self.std, to_bgr=False)
51
+ assert np.allclose(img, rgb_baseline)
52
+
53
+ def test_iminvert(self):
54
+ img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
55
+ dtype=np.uint8)
56
+ img_r = np.array([[255, 127, 0], [254, 128, 1], [253, 126, 2]],
57
+ dtype=np.uint8)
58
+ assert_array_equal(mmcv.iminvert(img), img_r)
59
+
60
+ def test_solarize(self):
61
+ img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
62
+ dtype=np.uint8)
63
+ img_r = np.array([[0, 127, 0], [1, 127, 1], [2, 126, 2]],
64
+ dtype=np.uint8)
65
+ assert_array_equal(mmcv.solarize(img), img_r)
66
+ img_r = np.array([[0, 127, 0], [1, 128, 1], [2, 126, 2]],
67
+ dtype=np.uint8)
68
+ assert_array_equal(mmcv.solarize(img, 100), img_r)
69
+
70
+ def test_posterize(self):
71
+ img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
72
+ dtype=np.uint8)
73
+ img_r = np.array([[0, 128, 128], [0, 0, 128], [0, 128, 128]],
74
+ dtype=np.uint8)
75
+ assert_array_equal(mmcv.posterize(img, 1), img_r)
76
+ img_r = np.array([[0, 128, 224], [0, 96, 224], [0, 128, 224]],
77
+ dtype=np.uint8)
78
+ assert_array_equal(mmcv.posterize(img, 3), img_r)
79
+
80
+ def test_adjust_color(self):
81
+ img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
82
+ dtype=np.uint8)
83
+ img = np.stack([img, img, img], axis=-1)
84
+ assert_array_equal(mmcv.adjust_color(img), img)
85
+ img_gray = mmcv.bgr2gray(img)
86
+ img_r = np.stack([img_gray, img_gray, img_gray], axis=-1)
87
+ assert_array_equal(mmcv.adjust_color(img, 0), img_r)
88
+ assert_array_equal(mmcv.adjust_color(img, 0, 1), img_r)
89
+ assert_array_equal(
90
+ mmcv.adjust_color(img, 0.5, 0.5),
91
+ np.round(np.clip((img * 0.5 + img_r * 0.5), 0,
92
+ 255)).astype(img.dtype))
93
+ assert_array_equal(
94
+ mmcv.adjust_color(img, 1, 1.5),
95
+ np.round(np.clip(img * 1 + img_r * 1.5, 0, 255)).astype(img.dtype))
96
+ assert_array_equal(
97
+ mmcv.adjust_color(img, 0.8, -0.6, gamma=2),
98
+ np.round(np.clip(img * 0.8 - 0.6 * img_r + 2, 0,
99
+ 255)).astype(img.dtype))
100
+ assert_array_equal(
101
+ mmcv.adjust_color(img, 0.8, -0.6, gamma=-0.6),
102
+ np.round(np.clip(img * 0.8 - 0.6 * img_r - 0.6, 0,
103
+ 255)).astype(img.dtype))
104
+
105
+ # test float type of image
106
+ img = img.astype(np.float32)
107
+ assert_array_equal(
108
+ np.round(mmcv.adjust_color(img, 0.8, -0.6, gamma=-0.6)),
109
+ np.round(np.clip(img * 0.8 - 0.6 * img_r - 0.6, 0, 255)))
110
+
111
+ def test_imequalize(self, nb_rand_test=100):
112
+
113
+ def _imequalize(img):
114
+ # equalize the image using PIL.ImageOps.equalize
115
+ from PIL import Image, ImageOps
116
+ img = Image.fromarray(img)
117
+ equalized_img = np.asarray(ImageOps.equalize(img))
118
+ return equalized_img
119
+
120
+ img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
121
+ dtype=np.uint8)
122
+ img = np.stack([img, img, img], axis=-1)
123
+ equalized_img = mmcv.imequalize(img)
124
+ assert_array_equal(equalized_img, _imequalize(img))
125
+
126
+ # test equalize with case step=0
127
+ img = np.array([[0, 0, 0], [120, 120, 120], [255, 255, 255]],
128
+ dtype=np.uint8)
129
+ img = np.stack([img, img, img], axis=-1)
130
+ assert_array_equal(mmcv.imequalize(img), img)
131
+
132
+ # test equalize with randomly sampled image.
133
+ for _ in range(nb_rand_test):
134
+ img = np.clip(np.random.normal(0, 1, (256, 256, 3)) * 260, 0,
135
+ 255).astype(np.uint8)
136
+ equalized_img = mmcv.imequalize(img)
137
+ assert_array_equal(equalized_img, _imequalize(img))
138
+
139
+ def test_adjust_brightness(self, nb_rand_test=100):
140
+
141
+ def _adjust_brightness(img, factor):
142
+ # adjust the brightness of image using
143
+ # PIL.ImageEnhance.Brightness
144
+ from PIL import Image
145
+ from PIL.ImageEnhance import Brightness
146
+ img = Image.fromarray(img)
147
+ brightened_img = Brightness(img).enhance(factor)
148
+ return np.asarray(brightened_img)
149
+
150
+ img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
151
+ dtype=np.uint8)
152
+ img = np.stack([img, img, img], axis=-1)
153
+ # test case with factor 1.0
154
+ assert_array_equal(mmcv.adjust_brightness(img, 1.), img)
155
+ # test case with factor 0.0
156
+ assert_array_equal(mmcv.adjust_brightness(img, 0.), np.zeros_like(img))
157
+ # test adjust_brightness with randomly sampled images and factors.
158
+ for _ in range(nb_rand_test):
159
+ img = np.clip(
160
+ np.random.uniform(0, 1, (1000, 1200, 3)) * 260, 0,
161
+ 255).astype(np.uint8)
162
+ factor = np.random.uniform() + np.random.choice([0, 1])
163
+ np.testing.assert_allclose(
164
+ mmcv.adjust_brightness(img, factor).astype(np.int32),
165
+ _adjust_brightness(img, factor).astype(np.int32),
166
+ rtol=0,
167
+ atol=1)
168
+
169
+ def test_adjust_contrast(self, nb_rand_test=100):
170
+
171
+ def _adjust_contrast(img, factor):
172
+ from PIL import Image
173
+ from PIL.ImageEnhance import Contrast
174
+
175
+ # Image.fromarray defaultly supports RGB, not BGR.
176
+ # convert from BGR to RGB
177
+ img = Image.fromarray(img[..., ::-1], mode='RGB')
178
+ contrasted_img = Contrast(img).enhance(factor)
179
+ # convert from RGB to BGR
180
+ return np.asarray(contrasted_img)[..., ::-1]
181
+
182
+ img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
183
+ dtype=np.uint8)
184
+ img = np.stack([img, img, img], axis=-1)
185
+ # test case with factor 1.0
186
+ assert_array_equal(mmcv.adjust_contrast(img, 1.), img)
187
+ # test case with factor 0.0
188
+ assert_array_equal(
189
+ mmcv.adjust_contrast(img, 0.), _adjust_contrast(img, 0.))
190
+ # test adjust_contrast with randomly sampled images and factors.
191
+ for _ in range(nb_rand_test):
192
+ img = np.clip(
193
+ np.random.uniform(0, 1, (1200, 1000, 3)) * 260, 0,
194
+ 255).astype(np.uint8)
195
+ factor = np.random.uniform() + np.random.choice([0, 1])
196
+ # Note the gap (less_equal 1) between PIL.ImageEnhance.Contrast
197
+ # and mmcv.adjust_contrast comes from the gap that converts from
198
+ # a color image to gray image using mmcv or PIL.
199
+ np.testing.assert_allclose(
200
+ mmcv.adjust_contrast(img, factor).astype(np.int32),
201
+ _adjust_contrast(img, factor).astype(np.int32),
202
+ rtol=0,
203
+ atol=1)
204
+
205
+ def test_auto_contrast(self, nb_rand_test=100):
206
+
207
+ def _auto_contrast(img, cutoff=0):
208
+ from PIL import Image
209
+ from PIL.ImageOps import autocontrast
210
+
211
+ # Image.fromarray defaultly supports RGB, not BGR.
212
+ # convert from BGR to RGB
213
+ img = Image.fromarray(img[..., ::-1], mode='RGB')
214
+ contrasted_img = autocontrast(img, cutoff)
215
+ # convert from RGB to BGR
216
+ return np.asarray(contrasted_img)[..., ::-1]
217
+
218
+ img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
219
+ dtype=np.uint8)
220
+ img = np.stack([img, img, img], axis=-1)
221
+
222
+ # test case without cut-off
223
+ assert_array_equal(mmcv.auto_contrast(img), _auto_contrast(img))
224
+ # test case with cut-off as int
225
+ assert_array_equal(
226
+ mmcv.auto_contrast(img, 10), _auto_contrast(img, 10))
227
+ # test case with cut-off as float
228
+ assert_array_equal(
229
+ mmcv.auto_contrast(img, 12.5), _auto_contrast(img, 12.5))
230
+ # test case with cut-off as tuple
231
+ assert_array_equal(
232
+ mmcv.auto_contrast(img, (10, 10)), _auto_contrast(img, 10))
233
+ # test case with cut-off with sum over 100
234
+ assert_array_equal(
235
+ mmcv.auto_contrast(img, 60), _auto_contrast(img, 60))
236
+
237
+ # test auto_contrast with randomly sampled images and factors.
238
+ for _ in range(nb_rand_test):
239
+ img = np.clip(
240
+ np.random.uniform(0, 1, (1200, 1000, 3)) * 260, 0,
241
+ 255).astype(np.uint8)
242
+ # cut-offs are not set as tuple since in `build.yml`, pillow 6.2.2
243
+ # is installed, which does not support setting low cut-off and high
244
+ # cut-off differently.
245
+ # With pillow above 8.0.0, cutoff can be set as tuple
246
+ cutoff = np.random.rand() * 100
247
+ assert_array_equal(
248
+ mmcv.auto_contrast(img, cutoff), _auto_contrast(img, cutoff))
249
+
250
+ def test_adjust_sharpness(self, nb_rand_test=100):
251
+
252
+ def _adjust_sharpness(img, factor):
253
+ # adjust the sharpness of image using
254
+ # PIL.ImageEnhance.Sharpness
255
+ from PIL import Image
256
+ from PIL.ImageEnhance import Sharpness
257
+ img = Image.fromarray(img)
258
+ sharpened_img = Sharpness(img).enhance(factor)
259
+ return np.asarray(sharpened_img)
260
+
261
+ img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
262
+ dtype=np.uint8)
263
+ img = np.stack([img, img, img], axis=-1)
264
+
265
+ # test case with invalid type of kernel
266
+ with pytest.raises(AssertionError):
267
+ mmcv.adjust_sharpness(img, 1., kernel=1.)
268
+ # test case with invalid shape of kernel
269
+ kernel = np.ones((3, 3, 3))
270
+ with pytest.raises(AssertionError):
271
+ mmcv.adjust_sharpness(img, 1., kernel=kernel)
272
+ # test case with all-zero kernel, factor 0.0
273
+ kernel = np.zeros((3, 3))
274
+ assert_array_equal(
275
+ mmcv.adjust_sharpness(img, 0., kernel=kernel), np.zeros_like(img))
276
+
277
+ # test case with factor 1.0
278
+ assert_array_equal(mmcv.adjust_sharpness(img, 1.), img)
279
+ # test adjust_sharpness with randomly sampled images and factors.
280
+ for _ in range(nb_rand_test):
281
+ img = np.clip(
282
+ np.random.uniform(0, 1, (1000, 1200, 3)) * 260, 0,
283
+ 255).astype(np.uint8)
284
+ factor = np.random.uniform()
285
+ # Note the gap between PIL.ImageEnhance.Sharpness and
286
+ # mmcv.adjust_sharpness mainly comes from the difference ways of
287
+ # handling img edges when applying filters
288
+ np.testing.assert_allclose(
289
+ mmcv.adjust_sharpness(img, factor).astype(np.int32)[1:-1,
290
+ 1:-1],
291
+ _adjust_sharpness(img, factor).astype(np.int32)[1:-1, 1:-1],
292
+ rtol=0,
293
+ atol=1)
294
+
295
+ def test_adjust_lighting(self):
296
+ img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8)
297
+ img = np.stack([img, img, img], axis=-1)
298
+
299
+ # eigval and eigvec must be np.ndarray
300
+ with pytest.raises(AssertionError):
301
+ mmcv.adjust_lighting(img, 1, np.ones((3, 1)))
302
+ with pytest.raises(AssertionError):
303
+ mmcv.adjust_lighting(img, np.array([1]), (1, 1, 1))
304
+ # we must have the same number of eigval and eigvec
305
+ with pytest.raises(AssertionError):
306
+ mmcv.adjust_lighting(img, np.array([1]), np.eye(2))
307
+ with pytest.raises(AssertionError):
308
+ mmcv.adjust_lighting(img, np.array([1]), np.array([1]))
309
+
310
+ img_adjusted = mmcv.adjust_lighting(
311
+ img,
312
+ np.random.normal(0, 1, 2),
313
+ np.random.normal(0, 1, (3, 2)),
314
+ alphastd=0.)
315
+ assert_array_equal(img_adjusted, img)
316
+
317
+ def test_lut_transform(self):
318
+ lut_table = np.array(list(range(256)))
319
+
320
+ # test assertion image values should between 0 and 255.
321
+ with pytest.raises(AssertionError):
322
+ mmcv.lut_transform(np.array([256]), lut_table)
323
+ with pytest.raises(AssertionError):
324
+ mmcv.lut_transform(np.array([-1]), lut_table)
325
+
326
+ # test assertion lut_table should be ndarray with shape (256, )
327
+ with pytest.raises(AssertionError):
328
+ mmcv.lut_transform(np.array([0]), list(range(256)))
329
+ with pytest.raises(AssertionError):
330
+ mmcv.lut_transform(np.array([1]), np.array(list(range(257))))
331
+
332
+ img = mmcv.lut_transform(self.img, lut_table)
333
+ baseline = cv2.LUT(self.img, lut_table)
334
+ assert np.allclose(img, baseline)
335
+
336
+ input_img = np.array(
337
+ [[[0, 128, 255], [255, 128, 0]], [[0, 128, 255], [255, 128, 0]]],
338
+ dtype=float)
339
+ img = mmcv.lut_transform(input_img, lut_table)
340
+ baseline = cv2.LUT(np.array(input_img, dtype=np.uint8), lut_table)
341
+ assert np.allclose(img, baseline)
342
+
343
+ input_img = np.random.randint(0, 256, size=(7, 8, 9, 10, 11))
344
+ img = mmcv.lut_transform(input_img, lut_table)
345
+ baseline = cv2.LUT(np.array(input_img, dtype=np.uint8), lut_table)
346
+ assert np.allclose(img, baseline)
347
+
348
+ def test_clahe(self):
349
+
350
+ def _clahe(img, clip_limit=40.0, tile_grid_size=(8, 8)):
351
+ clahe = cv2.createCLAHE(clip_limit, tile_grid_size)
352
+ return clahe.apply(np.array(img, dtype=np.uint8))
353
+
354
+ # test assertion image should have the right shape
355
+ with pytest.raises(AssertionError):
356
+ mmcv.clahe(self.img)
357
+
358
+ # test assertion tile_grid_size should be a tuple with 2 integers
359
+ with pytest.raises(AssertionError):
360
+ mmcv.clahe(self.img[:, :, 0], tile_grid_size=(8.0, 8.0))
361
+ with pytest.raises(AssertionError):
362
+ mmcv.clahe(self.img[:, :, 0], tile_grid_size=(8, 8, 8))
363
+ with pytest.raises(AssertionError):
364
+ mmcv.clahe(self.img[:, :, 0], tile_grid_size=[8, 8])
365
+
366
+ # test with different channels
367
+ for i in range(self.img.shape[-1]):
368
+ img = mmcv.clahe(self.img[:, :, i])
369
+ img_std = _clahe(self.img[:, :, i])
370
+ assert np.allclose(img, img_std)
371
+ assert id(img) != id(self.img[:, :, i])
372
+ assert id(img_std) != id(self.img[:, :, i])
373
+
374
+ # test case with clip_limit=1.2
375
+ for i in range(self.img.shape[-1]):
376
+ img = mmcv.clahe(self.img[:, :, i], 1.2)
377
+ img_std = _clahe(self.img[:, :, i], 1.2)
378
+ assert np.allclose(img, img_std)
379
+ assert id(img) != id(self.img[:, :, i])
380
+ assert id(img_std) != id(self.img[:, :, i])
groundingLMM/mmcv/tests/test_ops/test_correlation.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import pytest
3
+ import torch
4
+
5
+ from mmcv.ops import Correlation
6
+
7
+ _input1 = [[[[1., 2., 3.], [0., 1., 2.], [3., 5., 2.]]]]
8
+ _input2 = [[[[1., 2., 3.], [3., 1., 2.], [8., 5., 2.]]]]
9
+
10
+ gt_out_shape = (1, 1, 1, 3, 3)
11
+ _gt_out = [[[[[1., 4., 9.], [0., 1., 4.], [24., 25., 4.]]]]]
12
+ gt_input1_grad = [[[[1., 2., 3.], [3., 1., 2.], [8., 5., 2.]]]]
13
+
14
+
15
+ def assert_equal_tensor(tensor_a, tensor_b):
16
+
17
+ assert tensor_a.eq(tensor_b).all()
18
+
19
+
20
+ class TestCorrelation:
21
+
22
+ def _test_correlation(self, dtype=torch.float):
23
+
24
+ layer = Correlation(max_displacement=0)
25
+
26
+ input1 = torch.tensor(_input1, dtype=dtype).cuda()
27
+ input2 = torch.tensor(_input2, dtype=dtype).cuda()
28
+ input1.requires_grad = True
29
+ input2.requires_grad = True
30
+ out = layer(input1, input2)
31
+ out.backward(torch.ones_like(out))
32
+
33
+ # `eq_cpu` is not implemented for 'Half' in torch1.5.0,
34
+ # so we need to make a comparison for cuda tensor
35
+ # rather than cpu tensor
36
+ gt_out = torch.tensor(_gt_out, dtype=dtype).cuda()
37
+ assert_equal_tensor(out, gt_out)
38
+ assert_equal_tensor(input1.grad.detach(), input2)
39
+ assert_equal_tensor(input2.grad.detach(), input1)
40
+
41
+ @pytest.mark.skipif(
42
+ not torch.cuda.is_available(), reason='requires CUDA support')
43
+ def test_correlation(self):
44
+ self._test_correlation(torch.float)
45
+ self._test_correlation(torch.double)
46
+ self._test_correlation(torch.half)
groundingLMM/mmcv/tests/test_ops/test_gather_points.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import pytest
3
+ import torch
4
+
5
+ from mmcv.ops import gather_points
6
+
7
+
8
+ @pytest.mark.skipif(
9
+ not torch.cuda.is_available(), reason='requires CUDA support')
10
+ def test_gather_points():
11
+ features = torch.tensor([[[
12
+ -1.6095, -0.1029, -0.8876, -1.2447, -2.4031, 0.3708, -1.1586, -1.4967,
13
+ -0.4800, 0.2252
14
+ ],
15
+ [
16
+ 1.9138, 3.4979, 1.6854, 1.5631, 3.6776,
17
+ 3.1154, 2.1705, 2.5221, 2.0411, 3.1446
18
+ ],
19
+ [
20
+ -1.4173, 0.3073, -1.4339, -1.4340, -1.2770,
21
+ -0.2867, -1.4162, -1.4044, -1.4245, -1.4074
22
+ ]],
23
+ [[
24
+ 0.2160, 0.0842, 0.3661, -0.2749, -0.4909,
25
+ -0.6066, -0.8773, -0.0745, -0.9496, 0.1434
26
+ ],
27
+ [
28
+ 1.3644, 1.8087, 1.6855, 1.9563, 1.2746,
29
+ 1.9662, 0.9566, 1.8778, 1.1437, 1.3639
30
+ ],
31
+ [
32
+ -0.7172, 0.1692, 0.2241, 0.0721, -0.7540,
33
+ 0.0462, -0.6227, 0.3223, -0.6944, -0.5294
34
+ ]]]).cuda()
35
+
36
+ idx = torch.tensor([[0, 1, 4, 0, 0, 0], [0, 5, 6, 0, 0, 0]]).int().cuda()
37
+
38
+ output = gather_points(features, idx)
39
+ expected_output = torch.tensor(
40
+ [[[-1.6095, -0.1029, -2.4031, -1.6095, -1.6095, -1.6095],
41
+ [1.9138, 3.4979, 3.6776, 1.9138, 1.9138, 1.9138],
42
+ [-1.4173, 0.3073, -1.2770, -1.4173, -1.4173, -1.4173]],
43
+ [[0.2160, -0.6066, -0.8773, 0.2160, 0.2160, 0.2160],
44
+ [1.3644, 1.9662, 0.9566, 1.3644, 1.3644, 1.3644],
45
+ [-0.7172, 0.0462, -0.6227, -0.7172, -0.7172, -0.7172]]]).cuda()
46
+
47
+ assert torch.allclose(output, expected_output)
groundingLMM/mmcv/tests/test_ops/test_group_points.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import pytest
3
+ import torch
4
+
5
+ from mmcv.ops import grouping_operation
6
+
7
+
8
+ @pytest.mark.skipif(
9
+ not torch.cuda.is_available(), reason='requires CUDA support')
10
+ def test_grouping_points():
11
+ idx = torch.tensor([[[0, 0, 0], [3, 3, 3], [8, 8, 8], [0, 0, 0], [0, 0, 0],
12
+ [0, 0, 0]],
13
+ [[0, 0, 0], [6, 6, 6], [9, 9, 9], [0, 0, 0], [0, 0, 0],
14
+ [0, 0, 0]]]).int().cuda()
15
+ festures = torch.tensor([[[
16
+ 0.5798, -0.7981, -0.9280, -1.3311, 1.3687, 0.9277, -0.4164, -1.8274,
17
+ 0.9268, 0.8414
18
+ ],
19
+ [
20
+ 5.4247, 1.5113, 2.3944, 1.4740, 5.0300,
21
+ 5.1030, 1.9360, 2.1939, 2.1581, 3.4666
22
+ ],
23
+ [
24
+ -1.6266, -1.0281, -1.0393, -1.6931, -1.3982,
25
+ -0.5732, -1.0830, -1.7561, -1.6786, -1.6967
26
+ ]],
27
+ [[
28
+ -0.0380, -0.1880, -1.5724, 0.6905, -0.3190,
29
+ 0.7798, -0.3693, -0.9457, -0.2942, -1.8527
30
+ ],
31
+ [
32
+ 1.1773, 1.5009, 2.6399, 5.9242, 1.0962,
33
+ 2.7346, 6.0865, 1.5555, 4.3303, 2.8229
34
+ ],
35
+ [
36
+ -0.6646, -0.6870, -0.1125, -0.2224, -0.3445,
37
+ -1.4049, 0.4990, -0.7037, -0.9924, 0.0386
38
+ ]]]).cuda()
39
+
40
+ output = grouping_operation(festures, idx)
41
+ expected_output = torch.tensor([[[[0.5798, 0.5798, 0.5798],
42
+ [-1.3311, -1.3311, -1.3311],
43
+ [0.9268, 0.9268, 0.9268],
44
+ [0.5798, 0.5798, 0.5798],
45
+ [0.5798, 0.5798, 0.5798],
46
+ [0.5798, 0.5798, 0.5798]],
47
+ [[5.4247, 5.4247, 5.4247],
48
+ [1.4740, 1.4740, 1.4740],
49
+ [2.1581, 2.1581, 2.1581],
50
+ [5.4247, 5.4247, 5.4247],
51
+ [5.4247, 5.4247, 5.4247],
52
+ [5.4247, 5.4247, 5.4247]],
53
+ [[-1.6266, -1.6266, -1.6266],
54
+ [-1.6931, -1.6931, -1.6931],
55
+ [-1.6786, -1.6786, -1.6786],
56
+ [-1.6266, -1.6266, -1.6266],
57
+ [-1.6266, -1.6266, -1.6266],
58
+ [-1.6266, -1.6266, -1.6266]]],
59
+ [[[-0.0380, -0.0380, -0.0380],
60
+ [-0.3693, -0.3693, -0.3693],
61
+ [-1.8527, -1.8527, -1.8527],
62
+ [-0.0380, -0.0380, -0.0380],
63
+ [-0.0380, -0.0380, -0.0380],
64
+ [-0.0380, -0.0380, -0.0380]],
65
+ [[1.1773, 1.1773, 1.1773],
66
+ [6.0865, 6.0865, 6.0865],
67
+ [2.8229, 2.8229, 2.8229],
68
+ [1.1773, 1.1773, 1.1773],
69
+ [1.1773, 1.1773, 1.1773],
70
+ [1.1773, 1.1773, 1.1773]],
71
+ [[-0.6646, -0.6646, -0.6646],
72
+ [0.4990, 0.4990, 0.4990],
73
+ [0.0386, 0.0386, 0.0386],
74
+ [-0.6646, -0.6646, -0.6646],
75
+ [-0.6646, -0.6646, -0.6646],
76
+ [-0.6646, -0.6646, -0.6646]]]]).cuda()
77
+ assert torch.allclose(output, expected_output)
groundingLMM/mmcv/tests/test_ops/test_roi_align_rotated.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import numpy as np
3
+ import pytest
4
+ import torch
5
+
6
+ _USING_PARROTS = True
7
+ try:
8
+ from parrots.autograd import gradcheck
9
+ except ImportError:
10
+ from torch.autograd import gradcheck
11
+ _USING_PARROTS = False
12
+
13
+ # yapf:disable
14
+ inputs = [([[[[1., 2.], [3., 4.]]]],
15
+ [[0., 0.5, 0.5, 1., 1., 0]]),
16
+ ([[[[1., 2.], [3., 4.]]]],
17
+ [[0., 0.5, 0.5, 1., 1., np.pi / 2]]),
18
+ ([[[[1., 2.], [3., 4.]],
19
+ [[4., 3.], [2., 1.]]]],
20
+ [[0., 0.5, 0.5, 1., 1., 0]]),
21
+ ([[[[1., 2., 5., 6.], [3., 4., 7., 8.],
22
+ [9., 10., 13., 14.], [11., 12., 15., 16.]]]],
23
+ [[0., 1.5, 1.5, 3., 3., 0]]),
24
+ ([[[[1., 2., 5., 6.], [3., 4., 7., 8.],
25
+ [9., 10., 13., 14.], [11., 12., 15., 16.]]]],
26
+ [[0., 1.5, 1.5, 3., 3., np.pi / 2]])]
27
+ outputs = [([[[[1.0, 1.25], [1.5, 1.75]]]],
28
+ [[[[3.0625, 0.4375], [0.4375, 0.0625]]]]),
29
+ ([[[[1.5, 1], [1.75, 1.25]]]],
30
+ [[[[3.0625, 0.4375], [0.4375, 0.0625]]]]),
31
+ ([[[[1.0, 1.25], [1.5, 1.75]],
32
+ [[4.0, 3.75], [3.5, 3.25]]]],
33
+ [[[[3.0625, 0.4375], [0.4375, 0.0625]],
34
+ [[3.0625, 0.4375], [0.4375, 0.0625]]]]),
35
+ ([[[[1.9375, 4.75], [7.5625, 10.375]]]],
36
+ [[[[0.47265625, 0.42968750, 0.42968750, 0.04296875],
37
+ [0.42968750, 0.39062500, 0.39062500, 0.03906250],
38
+ [0.42968750, 0.39062500, 0.39062500, 0.03906250],
39
+ [0.04296875, 0.03906250, 0.03906250, 0.00390625]]]]),
40
+ ([[[[7.5625, 1.9375], [10.375, 4.75]]]],
41
+ [[[[0.47265625, 0.42968750, 0.42968750, 0.04296875],
42
+ [0.42968750, 0.39062500, 0.39062500, 0.03906250],
43
+ [0.42968750, 0.39062500, 0.39062500, 0.03906250],
44
+ [0.04296875, 0.03906250, 0.03906250, 0.00390625]]]])]
45
+ # yapf:enable
46
+
47
+ pool_h = 2
48
+ pool_w = 2
49
+ spatial_scale = 1.0
50
+ sampling_ratio = 2
51
+
52
+
53
+ def _test_roialign_rotated_gradcheck(device, dtype):
54
+ if not torch.cuda.is_available() and device == 'cuda':
55
+ pytest.skip('unittest does not support GPU yet.')
56
+ try:
57
+ from mmcv.ops import RoIAlignRotated
58
+ except ModuleNotFoundError:
59
+ pytest.skip('RoIAlignRotated op is not successfully compiled')
60
+ if dtype is torch.half:
61
+ pytest.skip('grad check does not support fp16')
62
+ for case in inputs:
63
+ np_input = np.array(case[0])
64
+ np_rois = np.array(case[1])
65
+
66
+ x = torch.tensor(
67
+ np_input, dtype=dtype, device=device, requires_grad=True)
68
+ rois = torch.tensor(np_rois, dtype=dtype, device=device)
69
+
70
+ froipool = RoIAlignRotated((pool_h, pool_w), spatial_scale,
71
+ sampling_ratio)
72
+
73
+ if torch.__version__ == 'parrots':
74
+ gradcheck(
75
+ froipool, (x, rois), no_grads=[rois], delta=1e-5, pt_atol=1e-5)
76
+ else:
77
+ gradcheck(froipool, (x, rois), eps=1e-5, atol=1e-5)
78
+
79
+
80
+ def _test_roialign_rotated_allclose(device, dtype):
81
+ if not torch.cuda.is_available() and device == 'cuda':
82
+ pytest.skip('unittest does not support GPU yet.')
83
+ try:
84
+ from mmcv.ops import RoIAlignRotated, roi_align_rotated
85
+ except ModuleNotFoundError:
86
+ pytest.skip('test requires compilation')
87
+ pool_h = 2
88
+ pool_w = 2
89
+ spatial_scale = 1.0
90
+ sampling_ratio = 2
91
+
92
+ for case, output in zip(inputs, outputs):
93
+ np_input = np.array(case[0])
94
+ np_rois = np.array(case[1])
95
+ np_output = np.array(output[0])
96
+ np_grad = np.array(output[1])
97
+
98
+ x = torch.tensor(
99
+ np_input, dtype=dtype, device=device, requires_grad=True)
100
+ rois = torch.tensor(np_rois, dtype=dtype, device=device)
101
+
102
+ output = roi_align_rotated(x, rois, (pool_h, pool_w), spatial_scale,
103
+ sampling_ratio, True)
104
+ output.backward(torch.ones_like(output))
105
+ assert np.allclose(
106
+ output.data.type(torch.float).cpu().numpy(), np_output, atol=1e-3)
107
+ assert np.allclose(
108
+ x.grad.data.type(torch.float).cpu().numpy(), np_grad, atol=1e-3)
109
+
110
+ # Test deprecated parameters
111
+ roi_align_rotated_module_deprecated = RoIAlignRotated(
112
+ out_size=(pool_h, pool_w),
113
+ spatial_scale=spatial_scale,
114
+ sample_num=sampling_ratio)
115
+
116
+ output_1 = roi_align_rotated_module_deprecated(x, rois)
117
+
118
+ roi_align_rotated_module_new = RoIAlignRotated(
119
+ output_size=(pool_h, pool_w),
120
+ spatial_scale=spatial_scale,
121
+ sampling_ratio=sampling_ratio)
122
+
123
+ output_2 = roi_align_rotated_module_new(x, rois)
124
+
125
+ assert np.allclose(
126
+ output_1.data.type(torch.float).cpu().numpy(),
127
+ output_2.data.type(torch.float).cpu().numpy())
128
+
129
+
130
+ @pytest.mark.parametrize('device', ['cuda', 'cpu'])
131
+ @pytest.mark.parametrize('dtype', [torch.float, torch.double, torch.half])
132
+ def test_roialign_rotated(device, dtype):
133
+ # check double only
134
+ if (dtype is torch.double):
135
+ _test_roialign_rotated_gradcheck(device=device, dtype=dtype)
136
+ _test_roialign_rotated_allclose(device=device, dtype=dtype)
groundingLMM/mmcv/tests/test_ops/test_roi_pool.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import os
3
+
4
+ import numpy as np
5
+ import torch
6
+
7
+ _USING_PARROTS = True
8
+ try:
9
+ from parrots.autograd import gradcheck
10
+ except ImportError:
11
+ from torch.autograd import gradcheck
12
+
13
+ _USING_PARROTS = False
14
+
15
+ cur_dir = os.path.dirname(os.path.abspath(__file__))
16
+
17
+ inputs = [([[[[1., 2.], [3., 4.]]]], [[0., 0., 0., 1., 1.]]),
18
+ ([[[[1., 2.], [3., 4.]], [[4., 3.], [2.,
19
+ 1.]]]], [[0., 0., 0., 1., 1.]]),
20
+ ([[[[1., 2., 5., 6.], [3., 4., 7., 8.], [9., 10., 13., 14.],
21
+ [11., 12., 15., 16.]]]], [[0., 0., 0., 3., 3.]])]
22
+ outputs = [([[[[1., 2.], [3., 4.]]]], [[[[1., 1.], [1., 1.]]]]),
23
+ ([[[[1., 2.], [3., 4.]], [[4., 3.], [2., 1.]]]], [[[[1., 1.],
24
+ [1., 1.]],
25
+ [[1., 1.],
26
+ [1., 1.]]]]),
27
+ ([[[[4., 8.], [12., 16.]]]], [[[[0., 0., 0., 0.], [0., 1., 0., 1.],
28
+ [0., 0., 0., 0.], [0., 1., 0.,
29
+ 1.]]]])]
30
+
31
+
32
+ class TestRoiPool(object):
33
+
34
+ def test_roipool_gradcheck(self):
35
+ if not torch.cuda.is_available():
36
+ return
37
+ from mmcv.ops import RoIPool
38
+ pool_h = 2
39
+ pool_w = 2
40
+ spatial_scale = 1.0
41
+
42
+ for case in inputs:
43
+ np_input = np.array(case[0])
44
+ np_rois = np.array(case[1])
45
+
46
+ x = torch.tensor(np_input, device='cuda', requires_grad=True)
47
+ rois = torch.tensor(np_rois, device='cuda')
48
+
49
+ froipool = RoIPool((pool_h, pool_w), spatial_scale)
50
+
51
+ if _USING_PARROTS:
52
+ pass
53
+ # gradcheck(froipool, (x, rois), no_grads=[rois])
54
+ else:
55
+ gradcheck(froipool, (x, rois), eps=1e-2, atol=1e-2)
56
+
57
+ def _test_roipool_allclose(self, dtype=torch.float):
58
+ if not torch.cuda.is_available():
59
+ return
60
+ from mmcv.ops import roi_pool
61
+ pool_h = 2
62
+ pool_w = 2
63
+ spatial_scale = 1.0
64
+
65
+ for case, output in zip(inputs, outputs):
66
+ np_input = np.array(case[0])
67
+ np_rois = np.array(case[1])
68
+ np_output = np.array(output[0])
69
+ np_grad = np.array(output[1])
70
+
71
+ x = torch.tensor(
72
+ np_input, dtype=dtype, device='cuda', requires_grad=True)
73
+ rois = torch.tensor(np_rois, dtype=dtype, device='cuda')
74
+
75
+ output = roi_pool(x, rois, (pool_h, pool_w), spatial_scale)
76
+ output.backward(torch.ones_like(output))
77
+ assert np.allclose(output.data.cpu().numpy(), np_output, 1e-3)
78
+ assert np.allclose(x.grad.data.cpu().numpy(), np_grad, 1e-3)
79
+
80
+ def test_roipool_allclose(self):
81
+ self._test_roipool_allclose(torch.double)
82
+ self._test_roipool_allclose(torch.float)
83
+ self._test_roipool_allclose(torch.half)
groundingLMM/mmcv/tests/test_ops/test_roiaware_pool3d.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import numpy as np
3
+ import pytest
4
+ import torch
5
+
6
+ from mmcv.ops import (RoIAwarePool3d, points_in_boxes_all, points_in_boxes_cpu,
7
+ points_in_boxes_part)
8
+
9
+
10
+ @pytest.mark.skipif(
11
+ not torch.cuda.is_available(), reason='requires CUDA support')
12
+ def test_RoIAwarePool3d():
13
+ roiaware_pool3d_max = RoIAwarePool3d(
14
+ out_size=4, max_pts_per_voxel=128, mode='max')
15
+ roiaware_pool3d_avg = RoIAwarePool3d(
16
+ out_size=4, max_pts_per_voxel=128, mode='avg')
17
+ rois = torch.tensor(
18
+ [[1.0, 2.0, 3.0, 5.0, 4.0, 6.0, -0.3 - np.pi / 2],
19
+ [-10.0, 23.0, 16.0, 20.0, 10.0, 20.0, -0.5 - np.pi / 2]],
20
+ dtype=torch.float32).cuda(
21
+ ) # boxes (m, 7) with bottom center in lidar coordinate
22
+ pts = torch.tensor(
23
+ [[1, 2, 3.3], [1.2, 2.5, 3.0], [0.8, 2.1, 3.5], [1.6, 2.6, 3.6],
24
+ [0.8, 1.2, 3.9], [-9.2, 21.0, 18.2], [3.8, 7.9, 6.3],
25
+ [4.7, 3.5, -12.2], [3.8, 7.6, -2], [-10.6, -12.9, -20], [-16, -18, 9],
26
+ [-21.3, -52, -5], [0, 0, 0], [6, 7, 8], [-2, -3, -4]],
27
+ dtype=torch.float32).cuda() # points (n, 3) in lidar coordinate
28
+ pts_feature = pts.clone()
29
+
30
+ pooled_features_max = roiaware_pool3d_max(
31
+ rois=rois, pts=pts, pts_feature=pts_feature)
32
+ assert pooled_features_max.shape == torch.Size([2, 4, 4, 4, 3])
33
+ assert torch.allclose(pooled_features_max.sum(),
34
+ torch.tensor(51.100).cuda(), 1e-3)
35
+
36
+ pooled_features_avg = roiaware_pool3d_avg(
37
+ rois=rois, pts=pts, pts_feature=pts_feature)
38
+ assert pooled_features_avg.shape == torch.Size([2, 4, 4, 4, 3])
39
+ assert torch.allclose(pooled_features_avg.sum(),
40
+ torch.tensor(49.750).cuda(), 1e-3)
41
+
42
+
43
+ @pytest.mark.skipif(
44
+ not torch.cuda.is_available(), reason='requires CUDA support')
45
+ def test_points_in_boxes_part():
46
+ boxes = torch.tensor(
47
+ [[[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.3]],
48
+ [[-10.0, 23.0, 16.0, 10, 20, 20, 0.5]]],
49
+ dtype=torch.float32).cuda(
50
+ ) # boxes (b, t, 7) with bottom center in lidar coordinate
51
+ pts = torch.tensor(
52
+ [[[1, 2, 3.3], [1.2, 2.5, 3.0], [0.8, 2.1, 3.5], [1.6, 2.6, 3.6],
53
+ [0.8, 1.2, 3.9], [-9.2, 21.0, 18.2], [3.8, 7.9, 6.3],
54
+ [4.7, 3.5, -12.2]],
55
+ [[3.8, 7.6, -2], [-10.6, -12.9, -20], [-16, -18, 9], [-21.3, -52, -5],
56
+ [0, 0, 0], [6, 7, 8], [-2, -3, -4], [6, 4, 9]]],
57
+ dtype=torch.float32).cuda() # points (b, m, 3) in lidar coordinate
58
+
59
+ point_indices = points_in_boxes_part(points=pts, boxes=boxes)
60
+ expected_point_indices = torch.tensor(
61
+ [[0, 0, 0, 0, 0, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1]],
62
+ dtype=torch.int32).cuda()
63
+ assert point_indices.shape == torch.Size([2, 8])
64
+ assert (point_indices == expected_point_indices).all()
65
+
66
+ boxes = torch.tensor([[[0.0, 0.0, 0.0, 1.0, 20.0, 1.0, 0.523598]]],
67
+ dtype=torch.float32).cuda() # 30 degrees
68
+ pts = torch.tensor(
69
+ [[[4, 6.928, 0], [6.928, 4, 0], [4, -6.928, 0], [6.928, -4, 0],
70
+ [-4, 6.928, 0], [-6.928, 4, 0], [-4, -6.928, 0], [-6.928, -4, 0]]],
71
+ dtype=torch.float32).cuda()
72
+ point_indices = points_in_boxes_part(points=pts, boxes=boxes)
73
+ expected_point_indices = torch.tensor([[-1, -1, 0, -1, 0, -1, -1, -1]],
74
+ dtype=torch.int32).cuda()
75
+ assert (point_indices == expected_point_indices).all()
76
+
77
+
78
+ def test_points_in_boxes_cpu():
79
+ boxes = torch.tensor(
80
+ [[[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.3],
81
+ [-10.0, 23.0, 16.0, 10, 20, 20, 0.5]]],
82
+ dtype=torch.float32
83
+ ) # boxes (m, 7) with bottom center in lidar coordinate
84
+ pts = torch.tensor(
85
+ [[[1, 2, 3.3], [1.2, 2.5, 3.0], [0.8, 2.1, 3.5], [1.6, 2.6, 3.6],
86
+ [0.8, 1.2, 3.9], [-9.2, 21.0, 18.2], [3.8, 7.9, 6.3],
87
+ [4.7, 3.5, -12.2], [3.8, 7.6, -2], [-10.6, -12.9, -20], [
88
+ -16, -18, 9
89
+ ], [-21.3, -52, -5], [0, 0, 0], [6, 7, 8], [-2, -3, -4]]],
90
+ dtype=torch.float32) # points (n, 3) in lidar coordinate
91
+
92
+ point_indices = points_in_boxes_cpu(points=pts, boxes=boxes)
93
+ expected_point_indices = torch.tensor(
94
+ [[[1, 0], [1, 0], [1, 0], [1, 0], [1, 0], [0, 1], [0, 0], [0, 0],
95
+ [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]],
96
+ dtype=torch.int32)
97
+ assert point_indices.shape == torch.Size([1, 15, 2])
98
+ assert (point_indices == expected_point_indices).all()
99
+
100
+ boxes = torch.tensor([[[0.0, 0.0, 0.0, 1.0, 20.0, 1.0, 0.523598]]],
101
+ dtype=torch.float32) # 30 degrees
102
+ pts = torch.tensor(
103
+ [[[4, 6.928, 0], [6.928, 4, 0], [4, -6.928, 0], [6.928, -4, 0],
104
+ [-4, 6.928, 0], [-6.928, 4, 0], [-4, -6.928, 0], [-6.928, -4, 0]]],
105
+ dtype=torch.float32)
106
+ point_indices = points_in_boxes_cpu(points=pts, boxes=boxes)
107
+ expected_point_indices = torch.tensor(
108
+ [[[0], [0], [1], [0], [1], [0], [0], [0]]], dtype=torch.int32)
109
+ assert (point_indices == expected_point_indices).all()
110
+
111
+
112
+ @pytest.mark.skipif(
113
+ not torch.cuda.is_available(), reason='requires CUDA support')
114
+ def test_points_in_boxes_all():
115
+
116
+ boxes = torch.tensor(
117
+ [[[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.3],
118
+ [-10.0, 23.0, 16.0, 10, 20, 20, 0.5]]],
119
+ dtype=torch.float32).cuda(
120
+ ) # boxes (m, 7) with bottom center in lidar coordinate
121
+ pts = torch.tensor(
122
+ [[[1, 2, 3.3], [1.2, 2.5, 3.0], [0.8, 2.1, 3.5], [1.6, 2.6, 3.6],
123
+ [0.8, 1.2, 3.9], [-9.2, 21.0, 18.2], [3.8, 7.9, 6.3],
124
+ [4.7, 3.5, -12.2], [3.8, 7.6, -2], [-10.6, -12.9, -20], [
125
+ -16, -18, 9
126
+ ], [-21.3, -52, -5], [0, 0, 0], [6, 7, 8], [-2, -3, -4]]],
127
+ dtype=torch.float32).cuda() # points (n, 3) in lidar coordinate
128
+
129
+ point_indices = points_in_boxes_all(points=pts, boxes=boxes)
130
+ expected_point_indices = torch.tensor(
131
+ [[[1, 0], [1, 0], [1, 0], [1, 0], [1, 0], [0, 1], [0, 0], [0, 0],
132
+ [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]],
133
+ dtype=torch.int32).cuda()
134
+ assert point_indices.shape == torch.Size([1, 15, 2])
135
+ assert (point_indices == expected_point_indices).all()
groundingLMM/mmcv/tests/test_ops/test_roipoint_pool3d.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import pytest
3
+ import torch
4
+
5
+ from mmcv.ops import RoIPointPool3d
6
+
7
+
8
+ @pytest.mark.skipif(
9
+ not torch.cuda.is_available(), reason='requires CUDA support')
10
+ def test_gather_points():
11
+ feats = torch.tensor(
12
+ [[1, 2, 3.3], [1.2, 2.5, 3.0], [0.8, 2.1, 3.5], [1.6, 2.6, 3.6],
13
+ [0.8, 1.2, 3.9], [-9.2, 21.0, 18.2], [3.8, 7.9, 6.3],
14
+ [4.7, 3.5, -12.2], [3.8, 7.6, -2], [-10.6, -12.9, -20], [-16, -18, 9],
15
+ [-21.3, -52, -5], [0, 0, 0], [6, 7, 8], [-2, -3, -4]],
16
+ dtype=torch.float32).unsqueeze(0).cuda()
17
+ points = feats.clone()
18
+ rois = torch.tensor([[[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.3],
19
+ [-10.0, 23.0, 16.0, 10, 20, 20, 0.5]]],
20
+ dtype=torch.float32).cuda()
21
+
22
+ roipoint_pool3d = RoIPointPool3d(num_sampled_points=4)
23
+ roi_feat, empty_flag = roipoint_pool3d(feats, points, rois)
24
+ expected_roi_feat = torch.tensor([[[[1, 2, 3.3, 1, 2, 3.3],
25
+ [1.2, 2.5, 3, 1.2, 2.5, 3],
26
+ [0.8, 2.1, 3.5, 0.8, 2.1, 3.5],
27
+ [1.6, 2.6, 3.6, 1.6, 2.6, 3.6]],
28
+ [[-9.2, 21, 18.2, -9.2, 21, 18.2],
29
+ [-9.2, 21, 18.2, -9.2, 21, 18.2],
30
+ [-9.2, 21, 18.2, -9.2, 21, 18.2],
31
+ [-9.2, 21, 18.2, -9.2, 21,
32
+ 18.2]]]]).cuda()
33
+ expected_empty_flag = torch.tensor([[0, 0]]).int().cuda()
34
+
35
+ assert torch.allclose(roi_feat, expected_roi_feat)
36
+ assert torch.allclose(empty_flag, expected_empty_flag)
groundingLMM/mmcv/tests/test_ops/test_rotated_feature_align.py ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import pytest
3
+ import torch
4
+
5
+ from mmcv.ops import rotated_feature_align
6
+
7
+
8
+ @pytest.mark.skipif(
9
+ not torch.cuda.is_available(), reason='requires CUDA support')
10
+ def test_rotated_feature_align():
11
+ feature = torch.tensor([[[[1.2924, -0.2172, -0.5222, 0.1172],
12
+ [0.9144, 1.2248, 1.3115, -0.9690],
13
+ [-0.8949, -1.1797, -0.9093, -0.3961],
14
+ [-0.4586, 0.5062, -0.7947, -0.7397]],
15
+ [[-1.0943, -0.7495, 1.3461, -1.1652],
16
+ [0.2034, 0.6763, -1.2357, 0.5231],
17
+ [-1.0062, 1.2592, 1.4225, -0.3951],
18
+ [-0.1242, -1.6240, 0.1932, 2.7181]],
19
+ [[-1.6271, -1.0276, 0.0578, -0.2997],
20
+ [-0.9684, -1.6946, -1.3188, -1.1938],
21
+ [-1.6744, -0.8917, -0.6556,
22
+ 1.0073], [-0.1205, 0.3671, -0.3731, -0.5347]]],
23
+ [[[0.7035, 0.2089, -0.1774, 3.4670],
24
+ [-0.8505, -0.9278, 1.4714, 0.1644],
25
+ [0.0898, 0.3531, -0.4007, 0.1927],
26
+ [1.2569, -0.2636, -0.5223, 0.0616]],
27
+ [[0.1760, -0.7639, -0.4600, -1.3260],
28
+ [-0.9921, -0.2970, -0.8955, 1.0508],
29
+ [1.3515, -0.1641, 1.9679, 1.1986],
30
+ [-0.3616, 0.6287, 0.4933, 0.3360]],
31
+ [[-0.5860, 0.2124, -0.8700, 2.4200],
32
+ [-0.0551, -1.5103, -1.6779, 0.8399],
33
+ [0.8431, 1.2414, -1.1243, -0.3887],
34
+ [-2.1254, 0.6047, -0.3515, 0.7254]]]],
35
+ device='cuda',
36
+ requires_grad=True)
37
+
38
+ bbox = torch.tensor(
39
+ [[[[1.3080e+01, 1.2688e+01, 1.1214e+01, 9.3944e+01, -9.1905e-01],
40
+ [3.8104e+01, 1.0134e+01, 1.4659e+02, 9.0306e+01, -9.8211e-01],
41
+ [-5.3213e+01, 4.9508e+01, 5.1513e+01, 3.2055e+01, -3.1954e-01],
42
+ [2.6974e+01, 2.5248e+01, 5.4495e+01, 3.1083e+00, -6.2127e-01]],
43
+ [[-1.5604e+01, -5.1908e+01, 2.3998e+02, 1.5008e+01, -1.2546e+00],
44
+ [3.1354e+01, -7.3635e+00, 6.7879e+01, 3.5081e+01, -3.3851e-01],
45
+ [-5.3292e+00, 9.1946e+00, 1.2834e+01, 1.0485e+01, -1.3039e+00],
46
+ [-2.3925e+01, 3.6623e+01, 3.9875e+01, 7.2009e+01, -6.5934e-01]],
47
+ [[7.2114e+01, -2.3781e+01, 2.9106e+01, 8.4501e+01, -1.1340e+00],
48
+ [2.6258e+01, -7.7034e+00, 1.7629e+02, 1.0615e+02, -1.2156e+00],
49
+ [3.8057e+01, 4.6016e+01, 1.2965e+01, 6.9384e+00, -1.0855e+00],
50
+ [2.4428e+01, -1.6189e+01, 2.0572e+02, 3.1622e+01, -1.5719e-01]],
51
+ [[3.8226e+00, 2.9608e+01, 1.4457e+01, 6.8179e+01, -9.1997e-01],
52
+ [2.5003e+01, -4.2490e+01, 9.6007e+01, 4.9086e+01, -1.4786e+00],
53
+ [8.5983e+01, 5.4980e+01, 7.8080e+01, 1.0003e+02, -1.0926e+00],
54
+ [9.9065e+00, 4.1457e+01, 5.9799e+00, 1.7973e+01, -5.6313e-01]]],
55
+ [[[-1.8244e+01, 4.6309e+00, 5.3010e+01, 2.4310e+01, -7.0345e-01],
56
+ [1.9419e+01, 3.6704e+01, 5.2390e+01, 5.4133e+01, -3.7730e-01],
57
+ [5.6387e+01, 2.3752e+01, 9.0441e+00, 1.7792e+01, -1.5583e+00],
58
+ [3.6303e+01, 1.6396e+01, 2.0283e+01, 1.9148e+01, -8.3419e-01]],
59
+ [[3.2169e+01, 3.0521e+01, 2.6283e+01, 1.9680e+02, -3.0454e-01],
60
+ [2.5788e+01, -3.2189e+01, 8.8882e+01, 1.0207e+02, -1.5328e+00],
61
+ [8.4676e+00, -1.6668e+01, 2.4657e+01, 1.1275e+02, -4.0388e-01],
62
+ [-1.0799e+01, 6.0422e+00, 9.5807e+00, 3.3677e+01, -3.5438e-01]],
63
+ [[6.9363e+01, 1.0850e+01, 2.5968e+01, 2.2311e+01, -1.6408e-01],
64
+ [2.8140e+00, 4.6843e+00, 3.1289e+00, 2.1480e+01, -6.7583e-01],
65
+ [2.6661e+01, 4.5290e+01, 6.1679e+00, 3.0005e+01, -8.9806e-01],
66
+ [5.0871e+00, 1.3234e+01, 9.2087e+01, 4.9622e+01, -2.8020e-01]],
67
+ [[-1.2643e+01, 2.5176e+01, 5.0488e+01, 5.4246e+01, -4.4840e-01],
68
+ [-3.4521e+01, 9.8435e-01, 5.2413e+01, 9.7996e+00, -8.4218e-01],
69
+ [4.9829e+01, -1.0808e+01, 2.9848e+01, 7.3579e+01, -6.2672e-01],
70
+ [8.0446e+01, 2.8064e+01, 4.5273e+01, 5.3809e+01, -1.2359e+00]]]],
71
+ device='cuda',
72
+ requires_grad=True)
73
+
74
+ expected_output = torch.tensor([[[[1.1095, -0.2172, -0.5222, -0.6225],
75
+ [0.9144, 0.7662, 1.0487, -0.9690],
76
+ [-0.8949, -1.6384, -0.9093, -0.3961],
77
+ [-0.8604, 0.5062, -0.7947, -0.7397]],
78
+ [[-0.3961, -0.7495, 1.3461, 1.5528],
79
+ [0.2034, 0.5522, -1.6722, 0.5231],
80
+ [-1.0062, 1.1350, 1.4225, -0.3951],
81
+ [-0.4826, -1.6240, 0.1932, 2.7181]],
82
+ [[-2.6436, -1.0276, 0.0578, -0.8344],
83
+ [-0.9684, -1.8151, -2.1843, -1.1938],
84
+ [-1.6744, -1.0121, -0.6556, 1.0073],
85
+ [-0.8474, 0.3671, -0.3731, -0.5347]]],
86
+ [[[0.7035, 0.2089, -0.1774, 3.4670],
87
+ [-0.8505, -0.9278, 1.4714, 0.1644],
88
+ [0.0898, 0.3064, -0.4007, 0.5849],
89
+ [1.2569, -0.2636, -0.5223, 0.0616]],
90
+ [[0.1760, -0.7639, -0.4600, -1.3260],
91
+ [-0.9921, -0.2970, -0.8955, 1.0508],
92
+ [1.3515, -0.6125, 1.9679, 0.5550],
93
+ [-0.3616, 0.6287, 0.4933, 0.3360]],
94
+ [[-0.5860, 0.2124, -0.8700, 2.4200],
95
+ [-0.0551, -1.5103, -1.6779, 0.8399],
96
+ [0.8431, 0.8455, -1.1243, -1.5994],
97
+ [-2.1254, 0.6047, -0.3515,
98
+ 0.7254]]]]).cuda()
99
+
100
+ expected_grad = torch.tensor([[[[1.0000, 1.8507, 1.1493, 1.5222],
101
+ [1.0000, 1.1511, 1.2139, 1.4778],
102
+ [1.0000, 1.2629, 1.3721, 1.0000],
103
+ [3.0000, 1.0000, 1.0000, 2.0000]],
104
+ [[1.0000, 1.8507, 1.1493, 1.5222],
105
+ [1.0000, 1.1511, 1.2139, 1.4778],
106
+ [1.0000, 1.2629, 1.3721, 1.0000],
107
+ [3.0000, 1.0000, 1.0000, 2.0000]],
108
+ [[1.0000, 1.8507, 1.1493, 1.5222],
109
+ [1.0000, 1.1511, 1.2139, 1.4778],
110
+ [1.0000, 1.2629, 1.3721, 1.0000],
111
+ [3.0000, 1.0000, 1.0000, 2.0000]]],
112
+ [[[1.2687, 1.5055, 1.2382, 1.0000],
113
+ [1.1458, 1.4258, 1.4160, 1.0000],
114
+ [1.0000, 1.0000, 1.0000, 1.0000],
115
+ [1.0000, 1.0000, 1.0000, 1.0000]],
116
+ [[1.2687, 1.5055, 1.2382, 1.0000],
117
+ [1.1458, 1.4258, 1.4160, 1.0000],
118
+ [1.0000, 1.0000, 1.0000, 1.0000],
119
+ [1.0000, 1.0000, 1.0000, 1.0000]],
120
+ [[1.2687, 1.5055, 1.2382, 1.0000],
121
+ [1.1458, 1.4258, 1.4160, 1.0000],
122
+ [1.0000, 1.0000, 1.0000, 1.0000],
123
+ [1.0000, 1.0000, 1.0000,
124
+ 1.0000]]]]).cuda()
125
+
126
+ output = rotated_feature_align(
127
+ feature, bbox, spatial_scale=1 / 8, points=1)
128
+ output.backward(torch.ones_like(output))
129
+ assert torch.allclose(output, expected_output, 1e-2)
130
+ assert torch.allclose(feature.grad, expected_grad, 1e-2)
groundingLMM/mmcv/tests/test_ops/test_spconv.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import pytest
3
+ import torch
4
+ from torch import nn
5
+
6
+ from mmcv.cnn import build_conv_layer, build_norm_layer
7
+ from mmcv.ops import (SparseConvTensor, SparseInverseConv3d, SparseSequential,
8
+ SubMConv3d)
9
+
10
+
11
+ def make_sparse_convmodule(in_channels,
12
+ out_channels,
13
+ kernel_size,
14
+ indice_key,
15
+ stride=1,
16
+ padding=0,
17
+ conv_type='SubMConv3d',
18
+ norm_cfg=None,
19
+ order=('conv', 'norm', 'act')):
20
+ """Make sparse convolution module.
21
+
22
+ Args:
23
+ in_channels (int): the number of input channels
24
+ out_channels (int): the number of out channels
25
+ kernel_size (int|tuple(int)): kernel size of convolution
26
+ indice_key (str): the indice key used for sparse tensor
27
+ stride (int|tuple(int)): the stride of convolution
28
+ padding (int or list[int]): the padding number of input
29
+ conv_type (str): sparse conv type in spconv
30
+ norm_cfg (dict[str]): config of normalization layer
31
+ order (tuple[str]): The order of conv/norm/activation layers. It is a
32
+ sequence of "conv", "norm" and "act". Common examples are
33
+ ("conv", "norm", "act") and ("act", "conv", "norm").
34
+
35
+ Returns:
36
+ spconv.SparseSequential: sparse convolution module.
37
+ """
38
+ assert isinstance(order, tuple) and len(order) <= 3
39
+ assert set(order) | {'conv', 'norm', 'act'} == {'conv', 'norm', 'act'}
40
+
41
+ conv_cfg = dict(type=conv_type, indice_key=indice_key)
42
+
43
+ layers = list()
44
+ for layer in order:
45
+ if layer == 'conv':
46
+ if conv_type not in [
47
+ 'SparseInverseConv3d', 'SparseInverseConv2d',
48
+ 'SparseInverseConv1d'
49
+ ]:
50
+ layers.append(
51
+ build_conv_layer(
52
+ conv_cfg,
53
+ in_channels,
54
+ out_channels,
55
+ kernel_size,
56
+ stride=stride,
57
+ padding=padding,
58
+ bias=False))
59
+ else:
60
+ layers.append(
61
+ build_conv_layer(
62
+ conv_cfg,
63
+ in_channels,
64
+ out_channels,
65
+ kernel_size,
66
+ bias=False))
67
+ elif layer == 'norm':
68
+ layers.append(build_norm_layer(norm_cfg, out_channels)[1])
69
+ elif layer == 'act':
70
+ layers.append(nn.ReLU(inplace=True))
71
+
72
+ layers = SparseSequential(*layers)
73
+ return layers
74
+
75
+
76
+ @pytest.mark.skipif(
77
+ not torch.cuda.is_available(), reason='requires CUDA support')
78
+ def test_make_sparse_convmodule():
79
+ voxel_features = torch.tensor([[6.56126, 0.9648336, -1.7339306, 0.315],
80
+ [6.8162713, -2.480431, -1.3616394, 0.36],
81
+ [11.643568, -4.744306, -1.3580885, 0.16],
82
+ [23.482342, 6.5036807, 0.5806964, 0.35]],
83
+ dtype=torch.float32,
84
+ device='cuda') # n, point_features
85
+ coordinates = torch.tensor(
86
+ [[0, 12, 819, 131], [0, 16, 750, 136], [1, 16, 705, 232],
87
+ [1, 35, 930, 469]],
88
+ dtype=torch.int32,
89
+ device='cuda') # n, 4(batch, ind_x, ind_y, ind_z)
90
+
91
+ # test
92
+ input_sp_tensor = SparseConvTensor(voxel_features, coordinates,
93
+ [41, 1600, 1408], 2)
94
+
95
+ sparse_block0 = make_sparse_convmodule(
96
+ 4,
97
+ 16,
98
+ 3,
99
+ 'test0',
100
+ stride=1,
101
+ padding=0,
102
+ conv_type='SubMConv3d',
103
+ norm_cfg=dict(type='BN1d', eps=1e-3, momentum=0.01),
104
+ order=('conv', 'norm', 'act')).cuda()
105
+ assert isinstance(sparse_block0[0], SubMConv3d)
106
+ assert sparse_block0[0].in_channels == 4
107
+ assert sparse_block0[0].out_channels == 16
108
+ assert isinstance(sparse_block0[1], torch.nn.BatchNorm1d)
109
+ assert sparse_block0[1].eps == 0.001
110
+ assert sparse_block0[1].momentum == 0.01
111
+ assert isinstance(sparse_block0[2], torch.nn.ReLU)
112
+
113
+ # test forward
114
+ out_features = sparse_block0(input_sp_tensor)
115
+ assert out_features.features.shape == torch.Size([4, 16])
116
+
117
+ sparse_block1 = make_sparse_convmodule(
118
+ 4,
119
+ 16,
120
+ 3,
121
+ 'test1',
122
+ stride=1,
123
+ padding=0,
124
+ conv_type='SparseInverseConv3d',
125
+ norm_cfg=dict(type='BN1d', eps=1e-3, momentum=0.01),
126
+ order=('norm', 'act', 'conv')).cuda()
127
+ assert isinstance(sparse_block1[0], torch.nn.BatchNorm1d)
128
+ assert isinstance(sparse_block1[1], torch.nn.ReLU)
129
+ assert isinstance(sparse_block1[2], SparseInverseConv3d)
groundingLMM/mmcv/tests/test_ops/test_syncbn.py ADDED
@@ -0,0 +1,295 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import os
3
+ import platform
4
+
5
+ import numpy as np
6
+ import pytest
7
+ import torch
8
+ import torch.distributed as dist
9
+ import torch.nn as nn
10
+
11
+ if platform.system() == 'Windows':
12
+ import regex as re
13
+ else:
14
+ import re
15
+
16
+
17
+ class TestSyncBN(object):
18
+
19
+ def dist_init(self):
20
+ rank = int(os.environ['SLURM_PROCID'])
21
+ world_size = int(os.environ['SLURM_NTASKS'])
22
+ local_rank = int(os.environ['SLURM_LOCALID'])
23
+ node_list = str(os.environ['SLURM_NODELIST'])
24
+
25
+ node_parts = re.findall('[0-9]+', node_list)
26
+ os.environ['MASTER_ADDR'] = (f'{node_parts[1]}.{node_parts[2]}' +
27
+ f'.{node_parts[3]}.{node_parts[4]}')
28
+ os.environ['MASTER_PORT'] = '12341'
29
+ os.environ['WORLD_SIZE'] = str(world_size)
30
+ os.environ['RANK'] = str(rank)
31
+
32
+ dist.init_process_group('nccl')
33
+ torch.cuda.set_device(local_rank)
34
+
35
+ def _test_syncbn_train(self, size=1, half=False):
36
+
37
+ if 'SLURM_NTASKS' not in os.environ or int(
38
+ os.environ['SLURM_NTASKS']) != 4:
39
+ print('must run with slurm has 4 processes!\n'
40
+ 'srun -p test --gres=gpu:4 -n4')
41
+ return
42
+ else:
43
+ print('Running syncbn test')
44
+ from mmcv.ops import SyncBatchNorm
45
+
46
+ assert size in (1, 2, 4)
47
+ if not dist.is_initialized():
48
+ self.dist_init()
49
+ rank = dist.get_rank()
50
+
51
+ torch.manual_seed(9)
52
+ torch.cuda.manual_seed(9)
53
+
54
+ self.x = torch.rand(16, 3, 2, 3).cuda()
55
+ self.y_bp = torch.rand(16, 3, 2, 3).cuda()
56
+
57
+ if half:
58
+ self.x = self.x.half()
59
+ self.y_bp = self.y_bp.half()
60
+ dist.broadcast(self.x, src=0)
61
+ dist.broadcast(self.y_bp, src=0)
62
+
63
+ torch.cuda.synchronize()
64
+ if size == 1:
65
+ groups = [None, None, None, None]
66
+ groups[0] = dist.new_group([0])
67
+ groups[1] = dist.new_group([1])
68
+ groups[2] = dist.new_group([2])
69
+ groups[3] = dist.new_group([3])
70
+ group = groups[rank]
71
+ elif size == 2:
72
+ groups = [None, None, None, None]
73
+ groups[0] = groups[1] = dist.new_group([0, 1])
74
+ groups[2] = groups[3] = dist.new_group([2, 3])
75
+ group = groups[rank]
76
+ elif size == 4:
77
+ group = dist.group.WORLD
78
+ syncbn = SyncBatchNorm(3, group=group).cuda()
79
+ syncbn.weight.data[0] = 0.2
80
+ syncbn.weight.data[1] = 0.5
81
+ syncbn.weight.data[2] = 0.7
82
+ syncbn.train()
83
+
84
+ bn = nn.BatchNorm2d(3).cuda()
85
+ bn.weight.data[0] = 0.2
86
+ bn.weight.data[1] = 0.5
87
+ bn.weight.data[2] = 0.7
88
+ bn.train()
89
+
90
+ sx = self.x[rank * 4:rank * 4 + 4]
91
+ sx.requires_grad_()
92
+ sy = syncbn(sx)
93
+ sy.backward(self.y_bp[rank * 4:rank * 4 + 4])
94
+
95
+ smean = syncbn.running_mean
96
+ svar = syncbn.running_var
97
+ sx_grad = sx.grad
98
+ sw_grad = syncbn.weight.grad
99
+ sb_grad = syncbn.bias.grad
100
+
101
+ if size == 1:
102
+ x = self.x[rank * 4:rank * 4 + 4]
103
+ y_bp = self.y_bp[rank * 4:rank * 4 + 4]
104
+ elif size == 2:
105
+ x = self.x[rank // 2 * 8:rank // 2 * 8 + 8]
106
+ y_bp = self.y_bp[rank // 2 * 8:rank // 2 * 8 + 8]
107
+ elif size == 4:
108
+ x = self.x
109
+ y_bp = self.y_bp
110
+ x.requires_grad_()
111
+ y = bn(x)
112
+ y.backward(y_bp)
113
+
114
+ if size == 2:
115
+ y = y[rank % 2 * 4:rank % 2 * 4 + 4]
116
+ elif size == 4:
117
+ y = y[rank * 4:rank * 4 + 4]
118
+
119
+ mean = bn.running_mean
120
+ var = bn.running_var
121
+ if size == 1:
122
+ x_grad = x.grad
123
+ w_grad = bn.weight.grad
124
+ b_grad = bn.bias.grad
125
+ elif size == 2:
126
+ x_grad = x.grad[rank % 2 * 4:rank % 2 * 4 + 4]
127
+ w_grad = bn.weight.grad / 2
128
+ b_grad = bn.bias.grad / 2
129
+ elif size == 4:
130
+ x_grad = x.grad[rank * 4:rank * 4 + 4]
131
+ w_grad = bn.weight.grad / 4
132
+ b_grad = bn.bias.grad / 4
133
+
134
+ assert np.allclose(mean.data.cpu().numpy(),
135
+ smean.data.cpu().numpy(), 1e-3)
136
+ assert np.allclose(var.data.cpu().numpy(),
137
+ svar.data.cpu().numpy(), 1e-3)
138
+ assert np.allclose(y.data.cpu().numpy(), sy.data.cpu().numpy(), 1e-3)
139
+ assert np.allclose(w_grad.data.cpu().numpy(),
140
+ sw_grad.data.cpu().numpy(), 1e-3)
141
+ assert np.allclose(b_grad.data.cpu().numpy(),
142
+ sb_grad.data.cpu().numpy(), 1e-3)
143
+ assert np.allclose(x_grad.data.cpu().numpy(),
144
+ sx_grad.data.cpu().numpy(), 1e-2)
145
+
146
+ def _test_syncbn_empty_train(self, size=1, half=False):
147
+
148
+ if 'SLURM_NTASKS' not in os.environ or int(
149
+ os.environ['SLURM_NTASKS']) != 4:
150
+ print('must run with slurm has 4 processes!\n'
151
+ 'srun -p test --gres=gpu:4 -n4')
152
+ return
153
+ else:
154
+ print('Running syncbn test')
155
+ from mmcv.ops import SyncBatchNorm
156
+
157
+ assert size in (1, 2, 4)
158
+ if not dist.is_initialized():
159
+ self.dist_init()
160
+ rank = dist.get_rank()
161
+
162
+ torch.manual_seed(9)
163
+ torch.cuda.manual_seed(9)
164
+
165
+ self.x = torch.rand(0, 3, 2, 3).cuda()
166
+ self.y_bp = torch.rand(0, 3, 2, 3).cuda()
167
+
168
+ if half:
169
+ self.x = self.x.half()
170
+ self.y_bp = self.y_bp.half()
171
+ dist.broadcast(self.x, src=0)
172
+ dist.broadcast(self.y_bp, src=0)
173
+
174
+ torch.cuda.synchronize()
175
+ if size == 1:
176
+ groups = [None, None, None, None]
177
+ groups[0] = dist.new_group([0])
178
+ groups[1] = dist.new_group([1])
179
+ groups[2] = dist.new_group([2])
180
+ groups[3] = dist.new_group([3])
181
+ group = groups[rank]
182
+ elif size == 2:
183
+ groups = [None, None, None, None]
184
+ groups[0] = groups[1] = dist.new_group([0, 1])
185
+ groups[2] = groups[3] = dist.new_group([2, 3])
186
+ group = groups[rank]
187
+ elif size == 4:
188
+ group = dist.group.WORLD
189
+
190
+ syncbn = SyncBatchNorm(3, group=group, stats_mode='N').cuda()
191
+ syncbn.weight.data[0] = 0.2
192
+ syncbn.weight.data[1] = 0.5
193
+ syncbn.weight.data[2] = 0.7
194
+ syncbn.train()
195
+
196
+ bn = nn.BatchNorm2d(3).cuda()
197
+ bn.weight.data[0] = 0.2
198
+ bn.weight.data[1] = 0.5
199
+ bn.weight.data[2] = 0.7
200
+ bn.train()
201
+
202
+ sx = self.x[rank * 4:rank * 4 + 4]
203
+ sx.requires_grad_()
204
+ sy = syncbn(sx)
205
+ sy.backward(self.y_bp[rank * 4:rank * 4 + 4])
206
+ smean = syncbn.running_mean
207
+ svar = syncbn.running_var
208
+ sx_grad = sx.grad
209
+ sw_grad = syncbn.weight.grad
210
+ sb_grad = syncbn.bias.grad
211
+
212
+ if size == 1:
213
+ x = self.x[rank * 4:rank * 4 + 4]
214
+ y_bp = self.y_bp[rank * 4:rank * 4 + 4]
215
+ elif size == 2:
216
+ x = self.x[rank // 2 * 8:rank // 2 * 8 + 8]
217
+ y_bp = self.y_bp[rank // 2 * 8:rank // 2 * 8 + 8]
218
+ elif size == 4:
219
+ x = self.x
220
+ y_bp = self.y_bp
221
+ x.requires_grad_()
222
+ y = bn(x)
223
+ y.backward(y_bp)
224
+
225
+ if size == 2:
226
+ y = y[rank % 2 * 4:rank % 2 * 4 + 4]
227
+ elif size == 4:
228
+ y = y[rank * 4:rank * 4 + 4]
229
+
230
+ mean = bn.running_mean
231
+ var = bn.running_var
232
+ if size == 1:
233
+ x_grad = x.grad
234
+ w_grad = bn.weight.grad
235
+ b_grad = bn.bias.grad
236
+ elif size == 2:
237
+ x_grad = x.grad[rank % 2 * 4:rank % 2 * 4 + 4]
238
+ w_grad = bn.weight.grad / 2
239
+ b_grad = bn.bias.grad / 2
240
+ elif size == 4:
241
+ x_grad = x.grad[rank * 4:rank * 4 + 4]
242
+ w_grad = bn.weight.grad / 4
243
+ b_grad = bn.bias.grad / 4
244
+
245
+ assert np.allclose(mean.data.cpu().numpy(),
246
+ smean.data.cpu().numpy(), 1e-3)
247
+ assert np.allclose(var.data.cpu().numpy(),
248
+ svar.data.cpu().numpy(), 1e-3)
249
+ assert np.allclose(y.data.cpu().numpy(), sy.data.cpu().numpy(), 1e-3)
250
+ assert np.allclose(w_grad.data.cpu().numpy(),
251
+ sw_grad.data.cpu().numpy(), 1e-3)
252
+ assert np.allclose(b_grad.data.cpu().numpy(),
253
+ sb_grad.data.cpu().numpy(), 1e-3)
254
+ assert np.allclose(x_grad.data.cpu().numpy(),
255
+ sx_grad.data.cpu().numpy(), 1e-2)
256
+
257
+ # 'stats_mode' only allows 'default' and 'N'
258
+ with pytest.raises(AssertionError):
259
+ SyncBatchNorm(3, group=group, stats_mode='X')
260
+
261
+ def test_syncbn_1(self):
262
+ self._test_syncbn_train(size=1)
263
+
264
+ def test_syncbn_2(self):
265
+ self._test_syncbn_train(size=2)
266
+
267
+ def test_syncbn_4(self):
268
+ self._test_syncbn_train(size=4)
269
+
270
+ def test_syncbn_1_half(self):
271
+ self._test_syncbn_train(size=1, half=True)
272
+
273
+ def test_syncbn_2_half(self):
274
+ self._test_syncbn_train(size=2, half=True)
275
+
276
+ def test_syncbn_4_half(self):
277
+ self._test_syncbn_train(size=4, half=True)
278
+
279
+ def test_syncbn_empty_1(self):
280
+ self._test_syncbn_empty_train(size=1)
281
+
282
+ def test_syncbn_empty_2(self):
283
+ self._test_syncbn_empty_train(size=2)
284
+
285
+ def test_syncbn_empty_4(self):
286
+ self._test_syncbn_empty_train(size=4)
287
+
288
+ def test_syncbn_empty_1_half(self):
289
+ self._test_syncbn_empty_train(size=1, half=True)
290
+
291
+ def test_syncbn_empty_2_half(self):
292
+ self._test_syncbn_empty_train(size=2, half=True)
293
+
294
+ def test_syncbn_empty_4_half(self):
295
+ self._test_syncbn_empty_train(size=4, half=True)