Skip to content

Commit f5ad03e

Browse files
authored
Merge pull request #955 from wannature/singa_v13
add resent implementation for largedataset
2 parents 4772246 + ee21978 commit f5ad03e

1 file changed

Lines changed: 300 additions & 0 deletions

File tree

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one
3+
# or more contributor license agreements. See the NOTICE file
4+
# distributed with this work for additional information
5+
# regarding copyright ownership. The ASF licenses this file
6+
# to you under the Apache License, Version 2.0 (the
7+
# "License"); you may not use this file except in compliance
8+
# with the License. You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing,
13+
# software distributed under the License is distributed on an
14+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
# KIND, either express or implied. See the License for the
16+
# specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
20+
# the code is modified from
21+
# https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py
22+
23+
from singa import layer
24+
from singa import model
25+
26+
27+
def conv3x3(in_planes, out_planes, stride=1):
28+
"""3x3 convolution with padding"""
29+
return layer.Conv2d(
30+
in_planes,
31+
out_planes,
32+
3,
33+
stride=stride,
34+
padding=1,
35+
bias=False,
36+
)
37+
38+
39+
class BasicBlock(layer.Layer):
40+
expansion = 1
41+
42+
def __init__(self, inplanes, planes, stride=1, downsample=None):
43+
super(BasicBlock, self).__init__()
44+
self.conv1 = conv3x3(inplanes, planes, stride)
45+
self.bn1 = layer.BatchNorm2d(planes)
46+
self.conv2 = conv3x3(planes, planes)
47+
self.bn2 = layer.BatchNorm2d(planes)
48+
self.relu1 = layer.ReLU()
49+
self.add = layer.Add()
50+
self.relu2 = layer.ReLU()
51+
self.downsample = downsample
52+
self.stride = stride
53+
54+
def forward(self, x):
55+
residual = x
56+
57+
out = self.conv1(x)
58+
out = self.bn1(out)
59+
out = self.relu1(out)
60+
61+
out = self.conv2(out)
62+
out = self.bn2(out)
63+
64+
if self.downsample is not None:
65+
residual = self.downsample(x)
66+
67+
out = self.add(out, residual)
68+
out = self.relu2(out)
69+
70+
return out
71+
72+
73+
class Bottleneck(layer.Layer):
74+
expansion = 4
75+
76+
def __init__(self, inplanes, planes, stride=1, downsample=None):
77+
super(Bottleneck, self).__init__()
78+
self.conv1 = layer.Conv2d(inplanes, planes, 1, bias=False)
79+
self.bn1 = layer.BatchNorm2d(planes)
80+
self.relu1 = layer.ReLU()
81+
self.conv2 = layer.Conv2d(planes,
82+
planes,
83+
3,
84+
stride=stride,
85+
padding=1,
86+
bias=False)
87+
self.bn2 = layer.BatchNorm2d(planes)
88+
self.relu2 = layer.ReLU()
89+
self.conv3 = layer.Conv2d(planes,
90+
planes * self.expansion,
91+
1,
92+
bias=False)
93+
self.bn3 = layer.BatchNorm2d(planes * self.expansion)
94+
95+
self.add = layer.Add()
96+
self.relu3 = layer.ReLU()
97+
98+
self.downsample = downsample
99+
self.stride = stride
100+
101+
def forward(self, x):
102+
residual = x
103+
104+
out = self.conv1(x)
105+
out = self.bn1(out)
106+
out = self.relu1(out)
107+
108+
out = self.conv2(out)
109+
out = self.bn2(out)
110+
out = self.relu2(out)
111+
112+
out = self.conv3(out)
113+
out = self.bn3(out)
114+
115+
if self.downsample is not None:
116+
residual = self.downsample(x)
117+
118+
out = self.add(out, residual)
119+
out = self.relu3(out)
120+
121+
return out
122+
123+
124+
__all__ = [
125+
'ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152'
126+
]
127+
128+
129+
class ResNet(model.Model):
130+
131+
def __init__(self, block, layers, num_classes=10, num_channels=3):
132+
self.inplanes = 64
133+
super(ResNet, self).__init__()
134+
self.num_classes = num_classes
135+
self.input_size = 224
136+
self.dimension = 4
137+
self.conv1 = layer.Conv2d(num_channels,
138+
64,
139+
7,
140+
stride=2,
141+
padding=3,
142+
bias=False)
143+
self.bn1 = layer.BatchNorm2d(64)
144+
self.relu = layer.ReLU()
145+
self.maxpool = layer.MaxPool2d(kernel_size=3, stride=2, padding=1)
146+
self.layer1, layers1 = self._make_layer(block, 64, layers[0])
147+
self.layer2, layers2 = self._make_layer(block, 128, layers[1], stride=2)
148+
self.layer3, layers3 = self._make_layer(block, 256, layers[2], stride=2)
149+
self.layer4, layers4 = self._make_layer(block, 512, layers[3], stride=2)
150+
self.avgpool = layer.AvgPool2d(7, stride=1)
151+
self.flatten = layer.Flatten()
152+
self.fc = layer.Linear(num_classes)
153+
self.softmax_cross_entropy = layer.SoftMaxCrossEntropy()
154+
155+
self.register_layers(*layers1, *layers2, *layers3, *layers4)
156+
157+
def _make_layer(self, block, planes, blocks, stride=1):
158+
downsample = None
159+
if stride != 1 or self.inplanes != planes * block.expansion:
160+
conv = layer.Conv2d(
161+
self.inplanes,
162+
planes * block.expansion,
163+
1,
164+
stride=stride,
165+
bias=False,
166+
)
167+
bn = layer.BatchNorm2d(planes * block.expansion)
168+
169+
def _downsample(x):
170+
return bn(conv(x))
171+
172+
downsample = _downsample
173+
174+
layers = []
175+
layers.append(block(self.inplanes, planes, stride, downsample))
176+
self.inplanes = planes * block.expansion
177+
for i in range(1, blocks):
178+
layers.append(block(self.inplanes, planes))
179+
180+
def forward(x):
181+
for layer in layers:
182+
x = layer(x)
183+
return x
184+
185+
return forward, layers
186+
187+
def forward(self, x):
188+
x = self.conv1(x)
189+
x = self.bn1(x)
190+
x = self.relu(x)
191+
x = self.maxpool(x)
192+
193+
x = self.layer1(x)
194+
x = self.layer2(x)
195+
x = self.layer3(x)
196+
x = self.layer4(x)
197+
198+
x = self.avgpool(x)
199+
x = self.flatten(x)
200+
x = self.fc(x)
201+
202+
return x
203+
204+
def train_one_batch(self, x, y, dist_option, spars):
205+
out = self.forward(x)
206+
loss = self.softmax_cross_entropy(out, y)
207+
208+
if dist_option == 'plain':
209+
self.optimizer(loss)
210+
elif dist_option == 'half':
211+
self.optimizer.backward_and_update_half(loss)
212+
elif dist_option == 'partialUpdate':
213+
self.optimizer.backward_and_partial_update(loss)
214+
elif dist_option == 'sparseTopK':
215+
self.optimizer.backward_and_sparse_update(loss,
216+
topK=True,
217+
spars=spars)
218+
elif dist_option == 'sparseThreshold':
219+
self.optimizer.backward_and_sparse_update(loss,
220+
topK=False,
221+
spars=spars)
222+
return out, loss
223+
224+
def set_optimizer(self, optimizer):
225+
self.optimizer = optimizer
226+
227+
228+
def resnet18(pretrained=False, **kwargs):
229+
"""Constructs a ResNet-18 model.
230+
231+
Args:
232+
pretrained (bool): If True, returns a model pre-trained on ImageNet.
233+
234+
Returns:
235+
The created ResNet-18 model.
236+
"""
237+
model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)
238+
239+
return model
240+
241+
242+
def resnet34(pretrained=False, **kwargs):
243+
"""Constructs a ResNet-34 model.
244+
245+
Args:
246+
pretrained (bool): If True, returns a model pre-trained on ImageNet.
247+
248+
Returns:
249+
The created ResNet-34 model.
250+
"""
251+
model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs)
252+
253+
return model
254+
255+
256+
def resnet50(pretrained=False, **kwargs):
257+
"""Constructs a ResNet-50 model.
258+
259+
Args:
260+
pretrained (bool): If True, returns a model pre-trained on ImageNet.
261+
262+
Returns:
263+
The created ResNet-50 model.
264+
"""
265+
model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs)
266+
267+
return model
268+
269+
270+
def resnet101(pretrained=False, **kwargs):
271+
"""Constructs a ResNet-101 model.
272+
273+
Args:
274+
pretrained (bool): If True, returns a model pre-trained on ImageNet.
275+
276+
Returns:
277+
The created ResNet-101 model.
278+
"""
279+
model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs)
280+
281+
return model
282+
283+
284+
def resnet152(pretrained=False, **kwargs):
285+
"""Constructs a ResNet-152 model.
286+
287+
Args:
288+
pretrained (bool): If True, returns a model pre-trained on ImageNet.
289+
290+
Returns:
291+
The created ResNet-152 model.
292+
"""
293+
model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs)
294+
295+
return model
296+
297+
298+
__all__ = [
299+
'ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152'
300+
]

0 commit comments

Comments
 (0)