1
+ import math
2
+ import torch
3
+ import torch .nn as nn
4
+ import torch .nn .functional as F
5
+ import torch .utils .model_zoo as model_zoo
6
+
7
+ pretrained_settings = {
8
+ 'cafferesnet101' : {
9
+ 'imagenet' : {
10
+ 'url' : 'http://data.lip6.fr/cadene/pretrainedmodels/cafferesnet101-9cf32c75.pth' ,
11
+ 'input_space' : 'BGR' ,
12
+ 'input_size' : [3 , 224 , 224 ],
13
+ 'input_range' : [0 , 255 ],
14
+ 'mean' : [102.9801 , 115.9465 , 122.7717 ],
15
+ 'std' : [1 , 1 , 1 ],
16
+ 'num_classes' : 1000
17
+ }
18
+ }
19
+ }
20
+
21
+
22
+ def conv3x3 (in_planes , out_planes , stride = 1 ):
23
+ "3x3 convolution with padding"
24
+ return nn .Conv2d (in_planes , out_planes , kernel_size = 3 , stride = stride ,
25
+ padding = 1 , bias = False )
26
+
27
+
28
+ class BasicBlock (nn .Module ):
29
+ expansion = 1
30
+
31
+ def __init__ (self , inplanes , planes , stride = 1 , downsample = None ):
32
+ super (BasicBlock , self ).__init__ ()
33
+ self .conv1 = conv3x3 (inplanes , planes , stride )
34
+ self .bn1 = nn .BatchNorm2d (planes )
35
+ self .relu = nn .ReLU (inplace = True )
36
+ self .conv2 = conv3x3 (planes , planes )
37
+ self .bn2 = nn .BatchNorm2d (planes )
38
+ self .downsample = downsample
39
+ self .stride = stride
40
+
41
+ def forward (self , x ):
42
+ residual = x
43
+
44
+ out = self .conv1 (x )
45
+ out = self .bn1 (out )
46
+ out = self .relu (out )
47
+
48
+ out = self .conv2 (out )
49
+ out = self .bn2 (out )
50
+
51
+ if self .downsample is not None :
52
+ residual = self .downsample (x )
53
+
54
+ out += residual
55
+ out = self .relu (out )
56
+
57
+ return out
58
+
59
+
60
+ class Bottleneck (nn .Module ):
61
+ expansion = 4
62
+
63
+ def __init__ (self , inplanes , planes , stride = 1 , downsample = None ):
64
+ super (Bottleneck , self ).__init__ ()
65
+ self .conv1 = nn .Conv2d (inplanes , planes , kernel_size = 1 , stride = stride , bias = False ) # change
66
+ self .bn1 = nn .BatchNorm2d (planes )
67
+ self .conv2 = nn .Conv2d (planes , planes , kernel_size = 3 , stride = 1 , # change
68
+ padding = 1 , bias = False )
69
+ self .bn2 = nn .BatchNorm2d (planes )
70
+ self .conv3 = nn .Conv2d (planes , planes * 4 , kernel_size = 1 , bias = False )
71
+ self .bn3 = nn .BatchNorm2d (planes * 4 )
72
+ self .relu = nn .ReLU (inplace = True )
73
+ self .downsample = downsample
74
+ self .stride = stride
75
+
76
+ def forward (self , x ):
77
+ residual = x
78
+
79
+ out = self .conv1 (x )
80
+ out = self .bn1 (out )
81
+ out = self .relu (out )
82
+
83
+ out = self .conv2 (out )
84
+ out = self .bn2 (out )
85
+ out = self .relu (out )
86
+
87
+ out = self .conv3 (out )
88
+ out = self .bn3 (out )
89
+
90
+ if self .downsample is not None :
91
+ residual = self .downsample (x )
92
+
93
+ out += residual
94
+ out = self .relu (out )
95
+
96
+ return out
97
+
98
+
99
+ class ResNet (nn .Module ):
100
+
101
+ def __init__ (self , block , layers , num_classes = 1000 ):
102
+ self .inplanes = 64
103
+ super (ResNet , self ).__init__ ()
104
+ self .conv1 = nn .Conv2d (3 , 64 , kernel_size = 7 , stride = 2 , padding = 3 ,
105
+ bias = False )
106
+ self .bn1 = nn .BatchNorm2d (64 )
107
+ self .relu = nn .ReLU (inplace = True )
108
+ self .maxpool = nn .MaxPool2d (kernel_size = 3 , stride = 2 , padding = 0 , ceil_mode = True ) # change
109
+ self .layer1 = self ._make_layer (block , 64 , layers [0 ])
110
+ self .layer2 = self ._make_layer (block , 128 , layers [1 ], stride = 2 )
111
+ self .layer3 = self ._make_layer (block , 256 , layers [2 ], stride = 2 )
112
+ self .layer4 = self ._make_layer (block , 512 , layers [3 ], stride = 2 )
113
+ # it is slightly better whereas slower to set stride = 1
114
+ # self.layer4 = self._make_layer(block, 512, layers[3], stride=1)
115
+ self .avgpool = nn .AvgPool2d (7 )
116
+ self .fc = nn .Linear (512 * block .expansion , num_classes )
117
+
118
+ for m in self .modules ():
119
+ if isinstance (m , nn .Conv2d ):
120
+ n = m .kernel_size [0 ] * m .kernel_size [1 ] * m .out_channels
121
+ m .weight .data .normal_ (0 , math .sqrt (2. / n ))
122
+ elif isinstance (m , nn .BatchNorm2d ):
123
+ m .weight .data .fill_ (1 )
124
+ m .bias .data .zero_ ()
125
+
126
+ def _make_layer (self , block , planes , blocks , stride = 1 ):
127
+ downsample = None
128
+ if stride != 1 or self .inplanes != planes * block .expansion :
129
+ downsample = nn .Sequential (
130
+ nn .Conv2d (self .inplanes , planes * block .expansion ,
131
+ kernel_size = 1 , stride = stride , bias = False ),
132
+ nn .BatchNorm2d (planes * block .expansion ),
133
+ )
134
+
135
+ layers = []
136
+ layers .append (block (self .inplanes , planes , stride , downsample ))
137
+ self .inplanes = planes * block .expansion
138
+ for i in range (1 , blocks ):
139
+ layers .append (block (self .inplanes , planes ))
140
+
141
+ return nn .Sequential (* layers )
142
+
143
+ def forward (self , x ):
144
+ x = self .conv1 (x )
145
+ x = self .bn1 (x )
146
+ x = self .relu (x )
147
+ x = self .maxpool (x )
148
+
149
+ x = self .layer1 (x )
150
+ x = self .layer2 (x )
151
+ x = self .layer3 (x )
152
+ x = self .layer4 (x )
153
+
154
+ x = self .avgpool (x )
155
+ x = x .view (x .size (0 ), - 1 )
156
+ x = self .fc (x )
157
+
158
+ return x
159
+
160
+
161
+ def cafferesnet101 (num_classes = 1000 , pretrained = 'imagenet' ):
162
+ """Constructs a ResNet-101 model.
163
+ Args:
164
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
165
+ """
166
+ model = ResNet (Bottleneck , [3 , 4 , 23 , 3 ], num_classes = num_classes )
167
+ if pretrained is not None :
168
+ settings = pretrained_settings ['cafferesnet101' ][pretrained ]
169
+ assert num_classes == settings ['num_classes' ], \
170
+ "num_classes should be {}, but is {}" .format (settings ['num_classes' ], num_classes )
171
+ model .load_state_dict (model_zoo .load_url (settings ['url' ]))
172
+ model .input_space = settings ['input_space' ]
173
+ model .input_size = settings ['input_size' ]
174
+ model .input_range = settings ['input_range' ]
175
+ model .mean = settings ['mean' ]
176
+ model .std = settings ['std' ]
177
+ return model
0 commit comments