Safemotion Lib
Loading...
Searching...
No Matches
resnest.py
Go to the documentation of this file.
1# encoding: utf-8
2# based on:
3# https://github.com/zhanghang1989/ResNeSt/blob/master/resnest/torch/resnest.py
4"""ResNeSt models"""
5
6import logging
7import math
8
9import torch
10from torch import nn
11
12from fastreid.layers import (
13 IBN,
14 Non_local,
15 SplAtConv2d,
16 get_norm,
17)
18from fastreid.utils.checkpoint import get_unexpected_parameters_message, get_missing_parameters_message
19from .build import BACKBONE_REGISTRY
20
21logger = logging.getLogger(__name__)
22_url_format = 'https://s3.us-west-1.wasabisys.com/resnest/torch/{}-{}.pth'
23
24_model_sha256 = {name: checksum for checksum, name in [
25 ('528c19ca', 'resnest50'),
26 ('22405ba7', 'resnest101'),
27 ('75117900', 'resnest200'),
28 ('0cc87c48', 'resnest269'),
29]}
30
31
32def short_hash(name):
33 if name not in _model_sha256:
34 raise ValueError('Pretrained model for {name} is not available.'.format(name=name))
35 return _model_sha256[name][:8]
36
37
38model_urls = {name: _url_format.format(name, short_hash(name)) for
39 name in _model_sha256.keys()
40 }
41
42
43class Bottleneck(nn.Module):
44 """ResNet Bottleneck
45 """
46 # pylint: disable=unused-argument
47 expansion = 4
48
49 def __init__(self, inplanes, planes, bn_norm, with_ibn=False, stride=1, downsample=None,
50 radix=1, cardinality=1, bottleneck_width=64,
51 avd=False, avd_first=False, dilation=1, is_first=False,
52 rectified_conv=False, rectify_avg=False,
53 dropblock_prob=0.0, last_gamma=False):
54 super(Bottleneck, self).__init__()
55 group_width = int(planes * (bottleneck_width / 64.)) * cardinality
56 self.conv1 = nn.Conv2d(inplanes, group_width, kernel_size=1, bias=False)
57 if with_ibn:
58 self.bn1 = IBN(group_width, bn_norm)
59 else:
60 self.bn1 = get_norm(bn_norm, group_width)
61 self.dropblock_prob = dropblock_prob
62 self.radix = radix
63 self.avd = avd and (stride > 1 or is_first)
64 self.avd_first = avd_first
65
66 if self.avd:
67 self.avd_layer = nn.AvgPool2d(3, stride, padding=1)
68 stride = 1
69
70 if radix > 1:
72 group_width, group_width, kernel_size=3,
73 stride=stride, padding=dilation,
74 dilation=dilation, groups=cardinality, bias=False,
75 radix=radix, rectify=rectified_conv,
76 rectify_avg=rectify_avg,
77 norm_layer=bn_norm,
78 dropblock_prob=dropblock_prob)
79 elif rectified_conv:
80 from rfconv import RFConv2d
81 self.conv2 = RFConv2d(
82 group_width, group_width, kernel_size=3, stride=stride,
83 padding=dilation, dilation=dilation,
84 groups=cardinality, bias=False,
85 average_mode=rectify_avg)
86 self.bn2 = get_norm(bn_norm, group_width)
87 else:
88 self.conv2 = nn.Conv2d(
89 group_width, group_width, kernel_size=3, stride=stride,
90 padding=dilation, dilation=dilation,
91 groups=cardinality, bias=False)
92 self.bn2 = get_norm(bn_norm, group_width)
93
95 group_width, planes * 4, kernel_size=1, bias=False)
96 self.bn3 = get_norm(bn_norm, planes * 4)
97
98 if last_gamma:
99 from torch.nn.init import zeros_
100 zeros_(self.bn3.weight)
101 self.relu = nn.ReLU(inplace=True)
102 self.downsample = downsample
103 self.dilation = dilation
104 self.stride = stride
105
106 def forward(self, x):
107 residual = x
108
109 out = self.conv1(x)
110 out = self.bn1(out)
111 if self.dropblock_prob > 0.0:
112 out = self.dropblock1(out)
113 out = self.relu(out)
114
115 if self.avd and self.avd_first:
116 out = self.avd_layer(out)
117
118 out = self.conv2(out)
119 if self.radix == 1:
120 out = self.bn2(out)
121 if self.dropblock_prob > 0.0:
122 out = self.dropblock2(out)
123 out = self.relu(out)
124
125 if self.avd and not self.avd_first:
126 out = self.avd_layer(out)
127
128 out = self.conv3(out)
129 out = self.bn3(out)
130 if self.dropblock_prob > 0.0:
131 out = self.dropblock3(out)
132
133 if self.downsample is not None:
134 residual = self.downsample(x)
135
136 out += residual
137 out = self.relu(out)
138
139 return out
140
141
142class ResNest(nn.Module):
143 """ResNet Variants ResNest
144 Parameters
145 ----------
146 block : Block
147 Class for the residual block. Options are BasicBlockV1, BottleneckV1.
148 layers : list of int
149 Numbers of layers in each block
150 classes : int, default 1000
151 Number of classification classes.
152 dilated : bool, default False
153 Applying dilation strategy to pretrained ResNet yielding a stride-8 model,
154 typically used in Semantic Segmentation.
155 norm_layer : object
156 Normalization layer used in backbone network (default: :class:`mxnet.gluon.nn.BatchNorm`;
157 for Synchronized Cross-GPU BachNormalization).
158 Reference:
159 - He, Kaiming, et al. "Deep residual learning for image recognition." Proceedings of the IEEE conference on computer vision and pattern recognition. 2016.
160 - Yu, Fisher, and Vladlen Koltun. "Multi-scale context aggregation by dilated convolutions."
161 """
162
163 # pylint: disable=unused-variable
164 def __init__(self, last_stride, bn_norm, with_ibn, with_nl, block, layers, non_layers, radix=1,
165 groups=1,
166 bottleneck_width=64,
167 dilated=False, dilation=1,
168 deep_stem=False, stem_width=64, avg_down=False,
169 rectified_conv=False, rectify_avg=False,
170 avd=False, avd_first=False,
171 final_drop=0.0, dropblock_prob=0,
172 last_gamma=False):
173 self.cardinality = groups
174 self.bottleneck_width = bottleneck_width
175 # ResNet-D params
176 self.inplanes = stem_width * 2 if deep_stem else 64
177 self.avg_down = avg_down
178 self.last_gamma = last_gamma
179 # ResNeSt params
180 self.radix = radix
181 self.avd = avd
182 self.avd_first = avd_first
183
184 super().__init__()
185 self.rectified_conv = rectified_conv
186 self.rectify_avg = rectify_avg
187 if rectified_conv:
188 from rfconv import RFConv2d
189 conv_layer = RFConv2d
190 else:
191 conv_layer = nn.Conv2d
192 conv_kwargs = {'average_mode': rectify_avg} if rectified_conv else {}
193 if deep_stem:
194 self.conv1 = nn.Sequential(
195 conv_layer(3, stem_width, kernel_size=3, stride=2, padding=1, bias=False, **conv_kwargs),
196 get_norm(bn_norm, stem_width),
197 nn.ReLU(inplace=True),
198 conv_layer(stem_width, stem_width, kernel_size=3, stride=1, padding=1, bias=False, **conv_kwargs),
199 get_norm(bn_norm, stem_width),
200 nn.ReLU(inplace=True),
201 conv_layer(stem_width, stem_width * 2, kernel_size=3, stride=1, padding=1, bias=False, **conv_kwargs),
202 )
203 else:
204 self.conv1 = conv_layer(3, 64, kernel_size=7, stride=2, padding=3,
205 bias=False, **conv_kwargs)
206 self.bn1 = get_norm(bn_norm, self.inplanes)
207 self.relu = nn.ReLU(inplace=True)
208 self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
209 self.layer1 = self._make_layer(block, 64, layers[0], 1, bn_norm, with_ibn=with_ibn, is_first=False)
210 self.layer2 = self._make_layer(block, 128, layers[1], 2, bn_norm, with_ibn=with_ibn)
211 if dilated or dilation == 4:
212 self.layer3 = self._make_layer(block, 256, layers[2], 1, bn_norm, with_ibn=with_ibn,
213 dilation=2, dropblock_prob=dropblock_prob)
214 self.layer4 = self._make_layer(block, 512, layers[3], 1, bn_norm, with_ibn=with_ibn,
215 dilation=4, dropblock_prob=dropblock_prob)
216 elif dilation == 2:
217 self.layer3 = self._make_layer(block, 256, layers[2], 2, bn_norm, with_ibn=with_ibn,
218 dilation=1, dropblock_prob=dropblock_prob)
219 self.layer4 = self._make_layer(block, 512, layers[3], 1, bn_norm, with_ibn=with_ibn,
220 dilation=2, dropblock_prob=dropblock_prob)
221 else:
222 self.layer3 = self._make_layer(block, 256, layers[2], 2, bn_norm, with_ibn=with_ibn,
223 dropblock_prob=dropblock_prob)
224 self.layer4 = self._make_layer(block, 512, layers[3], last_stride, bn_norm, with_ibn=with_ibn,
225 dropblock_prob=dropblock_prob)
226
227 for m in self.modules():
228 if isinstance(m, nn.Conv2d):
229 n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
230 m.weight.data.normal_(0, math.sqrt(2. / n))
231 elif isinstance(m, nn.BatchNorm2d):
232 m.weight.data.fill_(1)
233 m.bias.data.zero_()
234
235 # fmt: off
236 if with_nl: self._build_nonlocal(layers, non_layers, bn_norm)
237 else: self.NL_1_idx = self.NL_2_idx = self.NL_3_idx = self.NL_4_idx = []
238 # fmt: on
239
240 def _make_layer(self, block, planes, blocks, stride=1, bn_norm="BN", with_ibn=False,
241 dilation=1, dropblock_prob=0.0, is_first=True):
242 downsample = None
243 if stride != 1 or self.inplanes != planes * block.expansion:
244 down_layers = []
245 if self.avg_down:
246 if dilation == 1:
247 down_layers.append(nn.AvgPool2d(kernel_size=stride, stride=stride,
248 ceil_mode=True, count_include_pad=False))
249 else:
250 down_layers.append(nn.AvgPool2d(kernel_size=1, stride=1,
251 ceil_mode=True, count_include_pad=False))
252 down_layers.append(nn.Conv2d(self.inplanes, planes * block.expansion,
253 kernel_size=1, stride=1, bias=False))
254 else:
255 down_layers.append(nn.Conv2d(self.inplanes, planes * block.expansion,
256 kernel_size=1, stride=stride, bias=False))
257 down_layers.append(get_norm(bn_norm, planes * block.expansion))
258 downsample = nn.Sequential(*down_layers)
259
260 layers = []
261 if dilation == 1 or dilation == 2:
262 layers.append(block(self.inplanes, planes, bn_norm, with_ibn, stride, downsample=downsample,
263 radix=self.radix, cardinality=self.cardinality,
264 bottleneck_width=self.bottleneck_width,
265 avd=self.avd, avd_first=self.avd_first,
266 dilation=1, is_first=is_first, rectified_conv=self.rectified_conv,
267 rectify_avg=self.rectify_avg,
268 dropblock_prob=dropblock_prob,
269 last_gamma=self.last_gamma))
270 elif dilation == 4:
271 layers.append(block(self.inplanes, planes, bn_norm, with_ibn, stride, downsample=downsample,
272 radix=self.radix, cardinality=self.cardinality,
273 bottleneck_width=self.bottleneck_width,
274 avd=self.avd, avd_first=self.avd_first,
275 dilation=2, is_first=is_first, rectified_conv=self.rectified_conv,
276 rectify_avg=self.rectify_avg,
277 dropblock_prob=dropblock_prob,
278 last_gamma=self.last_gamma))
279 else:
280 raise RuntimeError("=> unknown dilation size: {}".format(dilation))
281
282 self.inplanes = planes * block.expansion
283 for i in range(1, blocks):
284 layers.append(block(self.inplanes, planes, bn_norm, with_ibn,
285 radix=self.radix, cardinality=self.cardinality,
286 bottleneck_width=self.bottleneck_width,
287 avd=self.avd, avd_first=self.avd_first,
288 dilation=dilation, rectified_conv=self.rectified_conv,
289 rectify_avg=self.rectify_avg,
290 dropblock_prob=dropblock_prob,
291 last_gamma=self.last_gamma))
292
293 return nn.Sequential(*layers)
294
295 def _build_nonlocal(self, layers, non_layers, bn_norm):
296 self.NL_1 = nn.ModuleList(
297 [Non_local(256, bn_norm) for _ in range(non_layers[0])])
298 self.NL_1_idx = sorted([layers[0] - (i + 1) for i in range(non_layers[0])])
299 self.NL_2 = nn.ModuleList(
300 [Non_local(512, bn_norm) for _ in range(non_layers[1])])
301 self.NL_2_idx = sorted([layers[1] - (i + 1) for i in range(non_layers[1])])
302 self.NL_3 = nn.ModuleList(
303 [Non_local(1024, bn_norm) for _ in range(non_layers[2])])
304 self.NL_3_idx = sorted([layers[2] - (i + 1) for i in range(non_layers[2])])
305 self.NL_4 = nn.ModuleList(
306 [Non_local(2048, bn_norm) for _ in range(non_layers[3])])
307 self.NL_4_idx = sorted([layers[3] - (i + 1) for i in range(non_layers[3])])
308
309 def forward(self, x):
310 x = self.conv1(x)
311 x = self.bn1(x)
312 x = self.relu(x)
313 x = self.maxpool(x)
314
315 NL1_counter = 0
316 if len(self.NL_1_idx) == 0:
317 self.NL_1_idx = [-1]
318 for i in range(len(self.layer1)):
319 x = self.layer1[i](x)
320 if i == self.NL_1_idx[NL1_counter]:
321 _, C, H, W = x.shape
322 x = self.NL_1[NL1_counter](x)
323 NL1_counter += 1
324 # Layer 2
325 NL2_counter = 0
326 if len(self.NL_2_idx) == 0:
327 self.NL_2_idx = [-1]
328 for i in range(len(self.layer2)):
329 x = self.layer2[i](x)
330 if i == self.NL_2_idx[NL2_counter]:
331 _, C, H, W = x.shape
332 x = self.NL_2[NL2_counter](x)
333 NL2_counter += 1
334 # Layer 3
335 NL3_counter = 0
336 if len(self.NL_3_idx) == 0:
337 self.NL_3_idx = [-1]
338 for i in range(len(self.layer3)):
339 x = self.layer3[i](x)
340 if i == self.NL_3_idx[NL3_counter]:
341 _, C, H, W = x.shape
342 x = self.NL_3[NL3_counter](x)
343 NL3_counter += 1
344 # Layer 4
345 NL4_counter = 0
346 if len(self.NL_4_idx) == 0:
347 self.NL_4_idx = [-1]
348 for i in range(len(self.layer4)):
349 x = self.layer4[i](x)
350 if i == self.NL_4_idx[NL4_counter]:
351 _, C, H, W = x.shape
352 x = self.NL_4[NL4_counter](x)
353 NL4_counter += 1
354
355 return x
356
357
358@BACKBONE_REGISTRY.register()
360 """
361 Create a ResNest instance from config.
362 Returns:
363 ResNet: a :class:`ResNet` instance.
364 """
365
366 # fmt: off
367 pretrain = cfg.MODEL.BACKBONE.PRETRAIN
368 pretrain_path = cfg.MODEL.BACKBONE.PRETRAIN_PATH
369 last_stride = cfg.MODEL.BACKBONE.LAST_STRIDE
370 bn_norm = cfg.MODEL.BACKBONE.NORM
371 with_ibn = cfg.MODEL.BACKBONE.WITH_IBN
372 with_se = cfg.MODEL.BACKBONE.WITH_SE
373 with_nl = cfg.MODEL.BACKBONE.WITH_NL
374 depth = cfg.MODEL.BACKBONE.DEPTH
375 # fmt: on
376
377 num_blocks_per_stage = {
378 "50x": [3, 4, 6, 3],
379 "101x": [3, 4, 23, 3],
380 "200x": [3, 24, 36, 3],
381 "269x": [3, 30, 48, 8],
382 }[depth]
383
384 nl_layers_per_stage = {
385 "50x": [0, 2, 3, 0],
386 "101x": [0, 2, 3, 0],
387 "200x": [0, 2, 3, 0],
388 "269x": [0, 2, 3, 0],
389 }[depth]
390
391 stem_width = {
392 "50x": 32,
393 "101x": 64,
394 "200x": 64,
395 "269x": 64,
396 }[depth]
397
398 model = ResNest(last_stride, bn_norm, with_ibn, with_nl, Bottleneck, num_blocks_per_stage,
399 nl_layers_per_stage, radix=2, groups=1, bottleneck_width=64,
400 deep_stem=True, stem_width=stem_width, avg_down=True,
401 avd=True, avd_first=False)
402 if pretrain:
403 # Load pretrain path if specifically
404 if pretrain_path:
405 try:
406 state_dict = torch.load(pretrain_path, map_location=torch.device('cpu'))
407 logger.info(f"Loading pretrained model from {pretrain_path}")
408 except FileNotFoundError as e:
409 logger.info(f'{pretrain_path} is not found! Please check this path.')
410 raise e
411 except KeyError as e:
412 logger.info("State dict keys error! Please check the state dict.")
413 raise e
414 else:
415 state_dict = torch.hub.load_state_dict_from_url(
416 model_urls['resnest' + depth[:-1]], progress=True, check_hash=True, map_location=torch.device('cpu'))
417
418 incompatible = model.load_state_dict(state_dict, strict=False)
419 if incompatible.missing_keys:
420 logger.info(
421 get_missing_parameters_message(incompatible.missing_keys)
422 )
423 if incompatible.unexpected_keys:
424 logger.info(
425 get_unexpected_parameters_message(incompatible.unexpected_keys)
426 )
427 return model
__init__(self, inplanes, planes, bn_norm, with_ibn=False, stride=1, downsample=None, radix=1, cardinality=1, bottleneck_width=64, avd=False, avd_first=False, dilation=1, is_first=False, rectified_conv=False, rectify_avg=False, dropblock_prob=0.0, last_gamma=False)
Definition resnest.py:53
__init__(self, last_stride, bn_norm, with_ibn, with_nl, block, layers, non_layers, radix=1, groups=1, bottleneck_width=64, dilated=False, dilation=1, deep_stem=False, stem_width=64, avg_down=False, rectified_conv=False, rectify_avg=False, avd=False, avd_first=False, final_drop=0.0, dropblock_prob=0, last_gamma=False)
Definition resnest.py:172
_make_layer(self, block, planes, blocks, stride=1, bn_norm="BN", with_ibn=False, dilation=1, dropblock_prob=0.0, is_first=True)
Definition resnest.py:241
_build_nonlocal(self, layers, non_layers, bn_norm)
Definition resnest.py:295