graft-pytorch 0.1.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,197 @@
1
+ '''EfficientNet in PyTorch.
2
+
3
+ Reference
4
+ EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks
5
+ https://github.com/keras-team/keras-applications/blob/master/keras_applications/efficientnet.py
6
+ '''
7
+ import torch
8
+ import torch.nn as nn
9
+ import torch.nn.functional as F
10
+
11
+
12
+ def swish(x):
13
+ return x * x.sigmoid()
14
+
15
+
16
+ def drop_connect(x, drop_ratio):
17
+ keep_ratio = 1.0 - drop_ratio
18
+ mask = torch.empty([x.shape[0], 1, 1, 1], dtype=x.dtype, device=x.device)
19
+ mask.bernoulli_(keep_ratio)
20
+ x.div_(keep_ratio)
21
+ x.mul_(mask)
22
+ return x
23
+
24
+
25
+ class SE(nn.Module):
26
+ '''Squeeze-and-Excitation block with Swish.'''
27
+
28
+ def __init__(self, in_channels, se_channels):
29
+ super(SE, self).__init__()
30
+ self.se1 = nn.Conv2d(in_channels, se_channels,
31
+ kernel_size=1, bias=True)
32
+ self.se2 = nn.Conv2d(se_channels, in_channels,
33
+ kernel_size=1, bias=True)
34
+
35
+
36
+ def forward(self, x):
37
+ out = F.adaptive_avg_pool2d(x, (1, 1))
38
+ out = swish(self.se1(out))
39
+ out = self.se2(out).sigmoid()
40
+ out = x * out
41
+ return out
42
+
43
+
44
+ class Block(nn.Module):
45
+ '''expansion + depthwise + pointwise + squeeze-excitation'''
46
+
47
+ def __init__(self,
48
+ in_channels,
49
+ out_channels,
50
+ kernel_size,
51
+ stride,
52
+ expand_ratio=1,
53
+ se_ratio=0.,
54
+ drop_rate=0.):
55
+ super(Block, self).__init__()
56
+ self.stride = stride
57
+ self.drop_rate = drop_rate
58
+ self.expand_ratio = expand_ratio
59
+
60
+ # Expansion
61
+ channels = expand_ratio * in_channels
62
+ self.conv1 = nn.Conv2d(in_channels,
63
+ channels,
64
+ kernel_size=1,
65
+ stride=1,
66
+ padding=0,
67
+ bias=False)
68
+ self.bn1 = nn.BatchNorm2d(channels)
69
+
70
+ # Depthwise conv
71
+ self.conv2 = nn.Conv2d(channels,
72
+ channels,
73
+ kernel_size=kernel_size,
74
+ stride=stride,
75
+ padding=(1 if kernel_size == 3 else 2),
76
+ groups=channels,
77
+ bias=False)
78
+ self.bn2 = nn.BatchNorm2d(channels)
79
+
80
+ # SE layers
81
+ se_channels = int(in_channels * se_ratio)
82
+ self.se = SE(channels, se_channels)
83
+
84
+ # Output
85
+ self.conv3 = nn.Conv2d(channels,
86
+ out_channels,
87
+ kernel_size=1,
88
+ stride=1,
89
+ padding=0,
90
+ bias=False)
91
+ self.bn3 = nn.BatchNorm2d(out_channels)
92
+
93
+ # Skip connection if in and out shapes are the same (MV-V2 style)
94
+ self.has_skip = (stride == 1) and (in_channels == out_channels)
95
+
96
+
97
+ def forward(self, x):
98
+ out = x if self.expand_ratio == 1 else swish(self.bn1(self.conv1(x)))
99
+ out = swish(self.bn2(self.conv2(out)))
100
+ out = self.se(out)
101
+ out = self.bn3(self.conv3(out))
102
+ if self.has_skip:
103
+ if self.training and self.drop_rate > 0:
104
+ out = drop_connect(out, self.drop_rate)
105
+ out = out + x
106
+ return out
107
+
108
+
109
+ class EfficientNet(nn.Module):
110
+ def __init__(self, cfg, num_classes=10):
111
+ super(EfficientNet, self).__init__()
112
+ self.cfg = cfg
113
+ self.conv1 = nn.Conv2d(3,
114
+ 32,
115
+ kernel_size=3,
116
+ stride=1,
117
+ padding=1,
118
+ bias=False)
119
+ self.embDim = cfg['out_channels'][-1]
120
+ self.bn1 = nn.BatchNorm2d(32)
121
+ self.layers = self._make_layers(in_channels=32)
122
+ self.linear = nn.Linear(cfg['out_channels'][-1], num_classes)
123
+
124
+
125
+ def _make_layers(self, in_channels):
126
+ layers = []
127
+ cfg = [self.cfg[k] for k in ['expansion', 'out_channels', 'num_blocks', 'kernel_size',
128
+ 'stride']]
129
+ b = 0
130
+ blocks = sum(self.cfg['num_blocks'])
131
+ for expansion, out_channels, num_blocks, kernel_size, stride in zip(*cfg):
132
+ strides = [stride] + [1] * (num_blocks - 1)
133
+ for stride in strides:
134
+ drop_rate = self.cfg['drop_connect_rate'] * b / blocks
135
+ layers.append(
136
+ Block(in_channels,
137
+ out_channels,
138
+ kernel_size,
139
+ stride,
140
+ expansion,
141
+ se_ratio=0.25,
142
+ drop_rate=drop_rate))
143
+ in_channels = out_channels
144
+ return nn.Sequential(*layers)
145
+
146
+
147
+ def forward(self, x, last=False, freeze=False):
148
+ if freeze:
149
+ with torch.no_grad():
150
+ out = swish(self.bn1(self.conv1(x)))
151
+ out = self.layers(out)
152
+ out = F.adaptive_avg_pool2d(out, 1)
153
+ e = out.view(out.size(0), -1)
154
+ dropout_rate = self.cfg['dropout_rate']
155
+ if self.training and dropout_rate > 0:
156
+ e = F.dropout(e, p=dropout_rate)
157
+ else:
158
+ out = swish(self.bn1(self.conv1(x)))
159
+ out = self.layers(out)
160
+ out = F.adaptive_avg_pool2d(out, 1)
161
+ e = out.view(out.size(0), -1)
162
+ dropout_rate = self.cfg['dropout_rate']
163
+ if self.training and dropout_rate > 0:
164
+ e = F.dropout(e, p=dropout_rate)
165
+ out = self.linear(e)
166
+ if last:
167
+ return out, e
168
+ else:
169
+ return out
170
+
171
+
172
+ def get_embedding_dim(self):
173
+ return self.embDim
174
+
175
+
176
+ def EfficientNetB0(num_classes=10):
177
+ cfg = {
178
+ 'num_blocks': [1, 2, 2, 3, 3, 4, 1],
179
+ 'expansion': [1, 6, 6, 6, 6, 6, 6],
180
+ 'out_channels': [16, 24, 40, 80, 112, 192, 320],
181
+ 'kernel_size': [3, 3, 5, 3, 5, 5, 3],
182
+ 'stride': [1, 2, 2, 2, 1, 2, 1],
183
+ 'dropout_rate': 0.2,
184
+ 'drop_connect_rate': 0.2,
185
+ }
186
+ return EfficientNet(cfg, num_classes)
187
+
188
+
189
+ def test():
190
+ net = EfficientNetB0()
191
+ x = torch.randn(2, 3, 32, 32)
192
+ y = net(x)
193
+ print(y.shape)
194
+
195
+
196
+ if __name__ == '__main__':
197
+ test()
@@ -0,0 +1,268 @@
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ from torch.autograd import Variable
5
+
6
+ import math
7
+
8
+ class Swish(nn.Module):
9
+ def __init__(self):
10
+ super(Swish, self).__init__()
11
+
12
+ self.sigmoid = nn.Sigmoid()
13
+
14
+ def forward(self, x):
15
+ return x * self.sigmoid(x)
16
+
17
+ def _RoundChannels(c, divisor=8, min_value=None):
18
+ if min_value is None:
19
+ min_value = divisor
20
+ new_c = max(min_value, int(c + divisor / 2) // divisor * divisor)
21
+ if new_c < 0.9 * c:
22
+ new_c += divisor
23
+ return new_c
24
+
25
+ def _RoundRepeats(r):
26
+ return int(math.ceil(r))
27
+
28
+ def _DropPath(x, drop_prob, training):
29
+ if drop_prob > 0 and training:
30
+ keep_prob = 1 - drop_prob
31
+ if x.is_cuda:
32
+ mask = Variable(torch.cuda.FloatTensor(x.size(0), 1, 1, 1).bernoulli_(keep_prob))
33
+ else:
34
+ mask = Variable(torch.FloatTensor(x.size(0), 1, 1, 1).bernoulli_(keep_prob))
35
+ x.div_(keep_prob)
36
+ x.mul_(mask)
37
+
38
+ return x
39
+
40
+ def _BatchNorm(channels, eps=1e-3, momentum=0.01):
41
+ return nn.BatchNorm2d(channels, eps=eps, momentum=momentum)
42
+
43
+ def _Conv3x3Bn(in_channels, out_channels, stride):
44
+ return nn.Sequential(
45
+ nn.Conv2d(in_channels, out_channels, 3, stride, 1, bias=False),
46
+ _BatchNorm(out_channels),
47
+ Swish()
48
+ )
49
+
50
+ def _Conv1x1Bn(in_channels, out_channels):
51
+ return nn.Sequential(
52
+ nn.Conv2d(in_channels, out_channels, 1, 1, 0, bias=False),
53
+ _BatchNorm(out_channels),
54
+ Swish()
55
+ )
56
+
57
+ class SqueezeAndExcite(nn.Module):
58
+ def __init__(self, channels, squeeze_channels, se_ratio):
59
+ super(SqueezeAndExcite, self).__init__()
60
+
61
+ squeeze_channels = squeeze_channels * se_ratio
62
+ if not squeeze_channels.is_integer():
63
+ raise ValueError('channels must be divisible by 1/ratio')
64
+
65
+ squeeze_channels = int(squeeze_channels)
66
+ self.se_reduce = nn.Conv2d(channels, squeeze_channels, 1, 1, 0, bias=True)
67
+ self.non_linear1 = Swish()
68
+ self.se_expand = nn.Conv2d(squeeze_channels, channels, 1, 1, 0, bias=True)
69
+ self.non_linear2 = nn.Sigmoid()
70
+
71
+ def forward(self, x):
72
+ y = torch.mean(x, (2, 3), keepdim=True)
73
+ y = self.non_linear1(self.se_reduce(y))
74
+ y = self.non_linear2(self.se_expand(y))
75
+ y = x * y
76
+
77
+ return y
78
+
79
+ class MBConvBlock(nn.Module):
80
+ def __init__(self, in_channels, out_channels, kernel_size, stride, expand_ratio, se_ratio, drop_path_rate):
81
+ super(MBConvBlock, self).__init__()
82
+
83
+ expand = (expand_ratio != 1)
84
+ expand_channels = in_channels * expand_ratio
85
+ se = (se_ratio != 0.0)
86
+ self.residual_connection = (stride == 1 and in_channels == out_channels)
87
+ self.drop_path_rate = drop_path_rate
88
+
89
+ conv = []
90
+
91
+ if expand:
92
+ # expansion phase
93
+ pw_expansion = nn.Sequential(
94
+ nn.Conv2d(in_channels, expand_channels, 1, 1, 0, bias=False),
95
+ _BatchNorm(expand_channels),
96
+ Swish()
97
+ )
98
+ conv.append(pw_expansion)
99
+
100
+ # depthwise convolution phase
101
+ dw = nn.Sequential(
102
+ nn.Conv2d(
103
+ expand_channels,
104
+ expand_channels,
105
+ kernel_size,
106
+ stride,
107
+ kernel_size//2,
108
+ groups=expand_channels,
109
+ bias=False
110
+ ),
111
+ _BatchNorm(expand_channels),
112
+ Swish()
113
+ )
114
+ conv.append(dw)
115
+
116
+ if se:
117
+ # squeeze and excite
118
+ squeeze_excite = SqueezeAndExcite(expand_channels, in_channels, se_ratio)
119
+ conv.append(squeeze_excite)
120
+
121
+ # projection phase
122
+ pw_projection = nn.Sequential(
123
+ nn.Conv2d(expand_channels, out_channels, 1, 1, 0, bias=False),
124
+ _BatchNorm(out_channels)
125
+ )
126
+ conv.append(pw_projection)
127
+
128
+ self.conv = nn.Sequential(*conv)
129
+
130
+ def forward(self, x):
131
+ if self.residual_connection:
132
+ return x + _DropPath(self.conv(x), self.drop_path_rate, self.training)
133
+ else:
134
+ return self.conv(x)
135
+
136
+ class EfficientNet(nn.Module):
137
+ config = [
138
+ #(in_channels, out_channels, kernel_size, stride, expand_ratio, se_ratio, repeats)
139
+ [32, 16, 3, 1, 1, 0.25, 1],
140
+ [16, 24, 3, 2, 6, 0.25, 2],
141
+ [24, 40, 5, 2, 6, 0.25, 2],
142
+ [40, 80, 3, 2, 6, 0.25, 3],
143
+ [80, 112, 5, 1, 6, 0.25, 3],
144
+ [112, 192, 5, 2, 6, 0.25, 4],
145
+ [192, 320, 3, 1, 6, 0.25, 1]
146
+ ]
147
+
148
+ def __init__(self, param, num_classes=100, stem_channels=32, feature_size=1280, drop_connect_rate=0.2):
149
+ super(EfficientNet, self).__init__()
150
+
151
+ # scaling width
152
+ width_coefficient = param[0]
153
+ if width_coefficient != 1.0:
154
+ stem_channels = _RoundChannels(stem_channels*width_coefficient)
155
+ for conf in self.config:
156
+ conf[0] = _RoundChannels(conf[0]*width_coefficient)
157
+ conf[1] = _RoundChannels(conf[1]*width_coefficient)
158
+
159
+ # scaling depth
160
+ depth_coefficient = param[1]
161
+ if depth_coefficient != 1.0:
162
+ for conf in self.config:
163
+ conf[6] = _RoundRepeats(conf[6]*depth_coefficient)
164
+
165
+ # scaling resolution
166
+ input_size = param[2]
167
+
168
+ # stem convolution
169
+ self.stem_conv = _Conv3x3Bn(3, stem_channels, 2)
170
+
171
+ # total #blocks
172
+ total_blocks = 0
173
+ for conf in self.config:
174
+ total_blocks += conf[6]
175
+
176
+ # mobile inverted bottleneck
177
+ blocks = []
178
+ for in_channels, out_channels, kernel_size, stride, expand_ratio, se_ratio, repeats in self.config:
179
+ # drop connect rate based on block index
180
+ drop_rate = drop_connect_rate * (len(blocks) / total_blocks)
181
+ blocks.append(MBConvBlock(in_channels, out_channels, kernel_size, stride, expand_ratio, se_ratio, drop_rate))
182
+ for _ in range(repeats-1):
183
+ drop_rate = drop_connect_rate * (len(blocks) / total_blocks)
184
+ blocks.append(MBConvBlock(out_channels, out_channels, kernel_size, 1, expand_ratio, se_ratio, drop_rate))
185
+ self.blocks = nn.Sequential(*blocks)
186
+
187
+ # last several layers
188
+ self.head_conv = _Conv1x1Bn(self.config[-1][1], feature_size)
189
+ #self.avgpool = nn.AvgPool2d(input_size//32, stride=1)
190
+ self.dropout = nn.Dropout(param[3])
191
+ self.classifier = nn.Linear(feature_size, num_classes)
192
+
193
+ self._initialize_weights()
194
+
195
+ def forward(self, x, last=False, freeze=False):
196
+ if freeze:
197
+ with torch.no_grad():
198
+ x = self.stem_conv(x)
199
+ x = self.blocks(x)
200
+ x = self.head_conv(x)
201
+ #x = self.avgpool(x)
202
+ #x = x.view(x.size(0), -1)
203
+ x = torch.mean(x, (2, 3))
204
+ e = self.dropout(x)
205
+ # x = self.classifier(x)
206
+ else:
207
+ x = self.stem_conv(x)
208
+ x = self.blocks(x)
209
+ x = self.head_conv(x)
210
+ #x = self.avgpool(x)
211
+ #x = x.view(x.size(0), -1)
212
+ x = torch.mean(x, (2, 3))
213
+ e = self.dropout(x)
214
+ out = self.classifier(x)
215
+ if last:
216
+ return out, e
217
+ else:
218
+ return out
219
+
220
+ def _initialize_weights(self):
221
+ for m in self.modules():
222
+ if isinstance(m, nn.Conv2d):
223
+ n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
224
+ m.weight.data.normal_(0, math.sqrt(2.0 / n))
225
+ if m.bias is not None:
226
+ m.bias.data.zero_()
227
+ elif isinstance(m, nn.BatchNorm2d):
228
+ m.weight.data.fill_(1)
229
+ m.bias.data.zero_()
230
+ elif isinstance(m, nn.Linear):
231
+ n = m.weight.size(1)
232
+ m.weight.data.normal_(0, 0.01)
233
+ m.bias.data.zero_()
234
+
235
+ def EfficientNetB7(num_classes=100):
236
+ net_param = {
237
+ # 'efficientnet type': (width_coef, depth_coef, resolution, dropout_rate)
238
+ 'efficientnet-b0': (1.0, 1.0, 224, 0.2),
239
+ 'efficientnet-b1': (1.0, 1.1, 240, 0.2),
240
+ 'efficientnet-b2': (1.1, 1.2, 260, 0.3),
241
+ 'efficientnet-b3': (1.2, 1.4, 300, 0.3),
242
+ 'efficientnet-b4': (1.4, 1.8, 380, 0.4),
243
+ 'efficientnet-b5': (1.6, 2.2, 456, 0.4),
244
+ 'efficientnet-b6': (1.8, 2.6, 528, 0.5),
245
+ 'efficientnet-b7': (2.0, 3.1, 600, 0.5)
246
+ }
247
+
248
+ param = net_param['efficientnet-b7']
249
+ #net = EfficientNet(param)
250
+ return EfficientNet(param, num_classes)
251
+
252
+ if __name__ == '__main__':
253
+ net_param = {
254
+ # 'efficientnet type': (width_coef, depth_coef, resolution, dropout_rate)
255
+ 'efficientnet-b0': (1.0, 1.0, 224, 0.2),
256
+ 'efficientnet-b1': (1.0, 1.1, 240, 0.2),
257
+ 'efficientnet-b2': (1.1, 1.2, 260, 0.3),
258
+ 'efficientnet-b3': (1.2, 1.4, 300, 0.3),
259
+ 'efficientnet-b4': (1.4, 1.8, 380, 0.4),
260
+ 'efficientnet-b5': (1.6, 2.2, 456, 0.4),
261
+ 'efficientnet-b6': (1.8, 2.6, 528, 0.5),
262
+ 'efficientnet-b7': (2.0, 3.1, 600, 0.5)
263
+ }
264
+
265
+ param = net_param['efficientnet-b0']
266
+ net = EfficientNet(param)
267
+ x_image = Variable(torch.randn(1, 3, param[2], param[2]))
268
+ y = net(x_image)
@@ -0,0 +1,69 @@
1
+ import torch.nn as nn
2
+ import torch
3
+ from torch import Tensor
4
+
5
+
6
+ class FashionCNN(nn.Module):
7
+
8
+ def __init__(self,in_channels, num_classes):
9
+ super(FashionCNN, self).__init__()
10
+
11
+ self.layer1 = nn.Sequential(
12
+ nn.Conv2d(in_channels=in_channels, out_channels=32, kernel_size=3, padding=1),
13
+ nn.BatchNorm2d(32),
14
+ nn.ReLU(),
15
+ nn.MaxPool2d(kernel_size=2, stride=2)
16
+ )
17
+
18
+ self.layer2 = nn.Sequential(
19
+ nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3),
20
+ nn.BatchNorm2d(64),
21
+ nn.ReLU(),
22
+ nn.MaxPool2d(2)
23
+ )
24
+
25
+ self.fc1 = nn.Linear(in_features=64*6*6, out_features=600)
26
+ self.drop = nn.Dropout2d(0.25)
27
+ self.fc2 = nn.Linear(in_features=600, out_features=120)
28
+ self.fc3 = nn.Linear(in_features=120, out_features=num_classes)
29
+
30
+ # def forward(self, x):
31
+ # out = self.layer1(x)
32
+ # out = self.layer2(out)
33
+ # out = out.view(out.size(0), -1)
34
+ # out = self.fc1(out)
35
+ # out = self.drop(out)
36
+ # out = self.fc2(out)
37
+ # out = self.fc3(out)
38
+
39
+ # return out
40
+
41
+ def forward(self, x: Tensor, last=False, freeze=False) -> Tensor:
42
+ # See note [TorchScript super()]
43
+ if freeze:
44
+ with torch.no_grad():
45
+ self.eval()
46
+ x = self.layer1(x)
47
+ x = self.layer2(x)
48
+ x = x.view(x.size(0), -1)
49
+ x = self.fc1(x)
50
+ x = self.drop(x)
51
+ x = self.fc2(x)
52
+ # x = self.fc3(x)
53
+ features = torch.flatten(x, 1)
54
+ self.train()
55
+ else:
56
+ x = self.layer1(x)
57
+ x = self.layer2(x)
58
+ x = x.view(x.size(0), -1)
59
+ x = self.fc1(x)
60
+ x = self.drop(x)
61
+ x = self.fc2(x)
62
+ # x = self.fc3(x)
63
+ features = torch.flatten(x, 1)
64
+
65
+ out = self.fc3(features)
66
+ if last:
67
+ return out, features
68
+ else:
69
+ return out
@@ -0,0 +1,83 @@
1
+ '''MobileNet in PyTorch.
2
+
3
+ Reference
4
+ MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications
5
+ https://arxiv.org/abs/1704.04861
6
+ '''
7
+
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+
13
+
14
+ class Block(nn.Module):
15
+ '''Depthwise conv + Pointwise conv'''
16
+
17
+ def __init__(self, in_planes, out_planes, stride=1):
18
+ super(Block, self).__init__()
19
+ self.conv1 = nn.Conv2d(in_planes, in_planes, kernel_size=3, stride=stride, padding=1, groups=in_planes, bias=False)
20
+ self.bn1 = nn.BatchNorm2d(in_planes)
21
+ self.conv2 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
22
+ self.bn2 = nn.BatchNorm2d(out_planes)
23
+
24
+
25
+ def forward(self, x):
26
+ out = F.relu(self.bn1(self.conv1(x)))
27
+ out = F.relu(self.bn2(self.conv2(out)))
28
+ return out
29
+
30
+
31
+ class MobileNet(nn.Module):
32
+ # (128,2) means conv planes=128, conv stride=2, by default conv stride=1
33
+ cfg = [64, (128,2), 128, (256,2), 256, (512,2), 512, 512, 512, 512, 512, (1024,2), 1024]
34
+
35
+ def __init__(self, num_classes=10):
36
+ super(MobileNet, self).__init__()
37
+ self.embDim = 1024
38
+
39
+ self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1, bias=False)
40
+ self.bn1 = nn.BatchNorm2d(32)
41
+ self.layers = self._make_layers(in_planes=32)
42
+ self.linear = nn.Linear(1024, num_classes)
43
+
44
+
45
+ def _make_layers(self, in_planes):
46
+ layers = []
47
+ for x in self.cfg:
48
+ out_planes = x if isinstance(x, int) else x[0]
49
+ stride = 1 if isinstance(x, int) else x[1]
50
+ layers.append(Block(in_planes, out_planes, stride))
51
+ in_planes = out_planes
52
+ return nn.Sequential(*layers)
53
+
54
+
55
+ def forward(self, x, last=False, freeze=False):
56
+ if freeze:
57
+ with torch.no_grad():
58
+ out = F.relu(self.bn1(self.conv1(x)))
59
+ out = self.layers(out)
60
+ out = F.avg_pool2d(out, 2)
61
+ e = out.view(out.size(0), -1)
62
+ else:
63
+ out = F.relu(self.bn1(self.conv1(x)))
64
+ out = self.layers(out)
65
+ out = F.avg_pool2d(out, 2)
66
+ e = out.view(out.size(0), -1)
67
+ out = self.linear(e)
68
+ if last:
69
+ return out, e
70
+ else:
71
+ return out
72
+
73
+ def get_embedding_dim(self):
74
+ return self.embDim
75
+
76
+
77
+ def test():
78
+ net = MobileNet()
79
+ x = torch.randn(1, 3, 32, 32)
80
+ y = net(x)
81
+ print(y.size())
82
+
83
+ # test()