@@ -1,40 +1,117 @@
-"""RefineNet
-
-RefineNet PyTorch for non-commercial purposes
-
-Copyright (c) 2018, Vladimir Nekrasov (vladimir.nekrasov@adelaide.edu.au)
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""
-
+# Copyright 2021 Huawei Technologies Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============================================================================
import torch.nn as nn
import torch.nn.functional as F
import torch
import numpy as np
-from utils.helpers import maybe_download
-from utils.layer_factory import conv1x1, conv3x3, CRPBlock, RCUBlock
+IMG_SCALE = 1./255
+IMG_MEAN = np.array([0.485, 0.456, 0.406]).reshape((1, 1, 3))
+IMG_STD = np.array([0.229, 0.224, 0.225]).reshape((1, 1, 3))
+
+def maybe_download(model_name, model_url, model_dir=None, map_location=None):
+ import os, sys
+ from six.moves import urllib
+ if model_dir is None:
+ torch_home = os.path.expanduser(os.getenv('TORCH_HOME', '~/.torch'))
+ model_dir = os.getenv('TORCH_MODEL_ZOO', os.path.join(torch_home, 'models'))
+ if not os.path.exists(model_dir):
+ os.makedirs(model_dir)
+ filename = '{}.pth.tar'.format(model_name)
+ cached_file = os.path.join(model_dir, filename)
+ if not os.path.exists(cached_file):
+ url = model_url
+ sys.stderr.write('Downloading: "{}" to {}\n'.format(url, cached_file))
+ urllib.request.urlretrieve(url, cached_file)
+ return torch.load(cached_file, map_location=map_location)
+
+def prepare_img(img):
+ return (img * IMG_SCALE - IMG_MEAN) / IMG_STD
+
+def batchnorm(in_planes):
+ "batch norm 2d"
+ return nn.BatchNorm2d(in_planes, affine=True, eps=1e-5, momentum=0.1)
+
+def conv3x3(in_planes, out_planes, stride=1, bias=False):
+ "3x3 convolution with padding"
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=1, bias=bias)
+
+def conv1x1(in_planes, out_planes, stride=1, bias=False):
+ "1x1 convolution"
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride,
+ padding=0, bias=bias)
+
+def convbnrelu(in_planes, out_planes, kernel_size, stride=1, groups=1, act=True):
+ "conv-batchnorm-relu"
+ if act:
+ return nn.Sequential(nn.Conv2d(in_planes, out_planes, kernel_size, stride=stride, padding=int(kernel_size / 2.), groups=groups, bias=False),
+ batchnorm(out_planes),
+ nn.ReLU6(inplace=True))
+ else:
+ return nn.Sequential(nn.Conv2d(in_planes, out_planes, kernel_size, stride=stride, padding=int(kernel_size / 2.), groups=groups, bias=False),
+ batchnorm(out_planes))
+
+class CRPBlock(nn.Module):
+
+ def __init__(self, in_planes, out_planes, n_stages, max_pooling=True):
+ super(CRPBlock, self).__init__()
+ for i in range(n_stages):
+ setattr(self, '{}_{}'.format(i + 1, 'outvar_dimred'),
+ conv3x3(in_planes if (i == 0) else out_planes,
+ out_planes, stride=1,
+ bias=False))
+ self.stride = 1
+ self.n_stages = n_stages
+ if max_pooling: self.maxpool = nn.MaxPool2d(kernel_size=5, stride=1, padding=2)
+ else: self.maxpool = nn.MaxPool2d(kernel_size=1, stride=1, padding=0)
+
+ def forward(self, x):
+ top = x
+ for i in range(self.n_stages):
+ top = self.maxpool(top)
+ top = getattr(self, '{}_{}'.format(i + 1, 'outvar_dimred'))(top)
+ x = top + x
+ return x
+
+stages_suffixes = {0 : '_conv',
+ 1 : '_conv_relu_varout_dimred'}
+
+class RCUBlock(nn.Module):
+
+ def __init__(self, in_planes, out_planes, n_blocks, n_stages):
+ super(RCUBlock, self).__init__()
+ for i in range(n_blocks):
+ for j in range(n_stages):
+ setattr(self, '{}{}'.format(i + 1, stages_suffixes[j]),
+ conv3x3(in_planes if (i == 0) and (j == 0) else out_planes,
+ out_planes, stride=1,
+ bias=(j == 0)))
+ self.stride = 1
+ self.n_blocks = n_blocks
+ self.n_stages = n_stages
+
+ def forward(self, x):
+ for i in range(self.n_blocks):
+ residual = x
+ for j in range(self.n_stages):
+ x = F.relu(x)
+ x = getattr(self, '{}{}'.format(i + 1, stages_suffixes[j]))(x)
+ x += residual
+ return x
data_info = {
21: 'VOC',
@@ -154,14 +231,14 @@ class RefineNet(nn.Module):
self.p_ims1d2_outl4_dimred = conv3x3(256, 256, bias=False)
self.adapt_stage4_b = self._make_rcu(256, 256, 2, 2)
self.adapt_stage4_b2_joint_varout_dimred = conv3x3(256, 256, bias=False)
- self.mflow_conv_g4_pool = self._make_crp(256, 256, 4)
+ self.mflow_conv_g4_pool = self._make_crp(256, 256, 4, max_pooling=False)
self.mflow_conv_g4_b = self._make_rcu(256, 256, 3, 2)
self.clf_conv = nn.Conv2d(256, num_classes, kernel_size=3, stride=1,
padding=1, bias=True)
- def _make_crp(self, in_planes, out_planes, stages):
- layers = [CRPBlock(in_planes, out_planes,stages)]
+ def _make_crp(self, in_planes, out_planes, stages, max_pooling=True):
+ layers = [CRPBlock(in_planes, out_planes, stages, max_pooling)]
return nn.Sequential(*layers)
def _make_rcu(self, in_planes, out_planes, blocks, stages):
@@ -199,6 +276,7 @@ class RefineNet(nn.Module):
l4 = self.do(l4)
l3 = self.do(l3)
+
x4 = self.p_ims1d2_outl1_dimred(l4)
x4 = self.adapt_stage1_b(x4)
x4 = self.relu(x4)
@@ -227,11 +305,13 @@ class RefineNet(nn.Module):
x2 = self.mflow_conv_g3_b3_joint_varout_dimred(x2)
x2 = nn.Upsample(size=l1.size()[2:], mode='bilinear', align_corners=True)(x2)
+
x1 = self.p_ims1d2_outl4_dimred(l1)
x1 = self.adapt_stage4_b(x1)
x1 = self.adapt_stage4_b2_joint_varout_dimred(x1)
x1 = x1 + x2
x1 = F.relu(x1)
+
x1 = self.mflow_conv_g4_pool(x1)
x1 = self.mflow_conv_g4_b(x1)
x1 = self.do(x1)