Bin-0815's picture
Release all GRADE models, checkpoints, and reviewed evaluation code (part 2)
f348660 verified
Raw History Blame Contribute Delete
20.2 kB
# Copyright (C) 2019 Jin Han Lee
#
# This file is a part of BTS.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
import torch
import torch.nn as nn
import torch.nn.functional as torch_nn_func
import math
def bn_init_as_tf(m):
if isinstance(m, nn.BatchNorm2d):
m.track_running_stats = True # These two lines enable using stats (moving mean and var) loaded from pretrained model
m.eval() # or zero mean and variance of one if the batch norm layer has no pretrained values
m.affine = True
m.requires_grad = True
def weights_init_xavier(m):
if isinstance(m, nn.Conv2d):
torch.nn.init.xavier_uniform_(m.weight)
if m.bias is not None:
torch.nn.init.zeros_(m.bias)
class atrous_conv(nn.Sequential):
def __init__(self, in_channels, out_channels, dilation, apply_bn_first=True):
super(atrous_conv, self).__init__()
self.atrous_conv = torch.nn.Sequential()
if apply_bn_first:
self.atrous_conv.add_module('first_bn', nn.BatchNorm2d(in_channels, momentum=0.01, affine=True, track_running_stats=True, eps=1.1e-5))
self.atrous_conv.add_module('aconv_sequence', nn.Sequential(nn.ReLU(),
nn.Conv2d(in_channels=in_channels, out_channels=out_channels*2, bias=False, kernel_size=1, stride=1, padding=0),
nn.BatchNorm2d(out_channels*2, momentum=0.01, affine=True, track_running_stats=True),
nn.ReLU(),
nn.Conv2d(in_channels=out_channels * 2, out_channels=out_channels, bias=False, kernel_size=3, stride=1,
padding=(dilation, dilation), dilation=dilation)))
def forward(self, x):
return self.atrous_conv.forward(x)
class upconv(nn.Module):
def __init__(self, in_channels, out_channels, ratio=2):
super(upconv, self).__init__()
self.elu = nn.ELU()
self.conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, bias=False, kernel_size=3, stride=1, padding=1)
self.ratio = ratio
def forward(self, x):
up_x = torch_nn_func.interpolate(x, scale_factor=self.ratio, mode='nearest')
out = self.conv(up_x)
out = self.elu(out)
return out
class reduction_1x1(nn.Sequential):
def __init__(self, num_in_filters, num_out_filters, max_depth, is_final=False):
super(reduction_1x1, self).__init__()
self.max_depth = max_depth
self.is_final = is_final
self.sigmoid = nn.Sigmoid()
self.reduc = torch.nn.Sequential()
while num_out_filters >= 4:
if num_out_filters < 8:
if self.is_final:
self.reduc.add_module('final', torch.nn.Sequential(nn.Conv2d(num_in_filters, out_channels=1, bias=False,
kernel_size=1, stride=1, padding=0),
nn.Sigmoid()))
else:
self.reduc.add_module('plane_params', torch.nn.Conv2d(num_in_filters, out_channels=3, bias=False,
kernel_size=1, stride=1, padding=0))
break
else:
self.reduc.add_module('inter_{}_{}'.format(num_in_filters, num_out_filters),
torch.nn.Sequential(nn.Conv2d(in_channels=num_in_filters, out_channels=num_out_filters,
bias=False, kernel_size=1, stride=1, padding=0),
nn.ELU()))
num_in_filters = num_out_filters
num_out_filters = num_out_filters // 2
def forward(self, net):
net = self.reduc.forward(net)
if not self.is_final:
theta = self.sigmoid(net[:, 0, :, :]) * math.pi / 3
phi = self.sigmoid(net[:, 1, :, :]) * math.pi * 2
dist = self.sigmoid(net[:, 2, :, :]) * self.max_depth
n1 = torch.mul(torch.sin(theta), torch.cos(phi)).unsqueeze(1)
n2 = torch.mul(torch.sin(theta), torch.sin(phi)).unsqueeze(1)
n3 = torch.cos(theta).unsqueeze(1)
n4 = dist.unsqueeze(1)
net = torch.cat([n1, n2, n3, n4], dim=1)
return net
class local_planar_guidance(nn.Module):
def __init__(self, upratio):
super(local_planar_guidance, self).__init__()
self.upratio = upratio
self.u = torch.arange(self.upratio).reshape([1, 1, self.upratio]).float()
self.v = torch.arange(int(self.upratio)).reshape([1, self.upratio, 1]).float()
self.upratio = float(upratio)
def forward(self, plane_eq, focal):
plane_eq_expanded = torch.repeat_interleave(plane_eq, int(self.upratio), 2)
plane_eq_expanded = torch.repeat_interleave(plane_eq_expanded, int(self.upratio), 3)
n1 = plane_eq_expanded[:, 0, :, :]
n2 = plane_eq_expanded[:, 1, :, :]
n3 = plane_eq_expanded[:, 2, :, :]
n4 = plane_eq_expanded[:, 3, :, :]
u = self.u.repeat(plane_eq.size(0), plane_eq.size(2) * int(self.upratio), plane_eq.size(3)).cuda()
u = (u - (self.upratio - 1) * 0.5) / self.upratio
v = self.v.repeat(plane_eq.size(0), plane_eq.size(2), plane_eq.size(3) * int(self.upratio)).cuda()
v = (v - (self.upratio - 1) * 0.5) / self.upratio
return n4 / (n1 * u + n2 * v + n3)
class bts_gated_fuse(nn.Module):
def __init__(self, params, feat_out_channels, feat_out_channels_rad, num_features=512):
super(bts_gated_fuse, self).__init__()
self.params = params
self.weight5 = torch.nn.Sequential(nn.Conv2d(feat_out_channels_rad[4], feat_out_channels[4], 1, 1, bias=False),
nn.Sigmoid())
self.project5 = torch.nn.Sequential(nn.Conv2d(feat_out_channels_rad[4], feat_out_channels[4], 1, 1, bias=False),
nn.ReLU())
self.upconv5 = upconv(feat_out_channels[4], num_features)
self.bn5 = nn.BatchNorm2d(num_features, momentum=0.01, affine=True, eps=1.1e-5)
self.conv5 = torch.nn.Sequential(nn.Conv2d(num_features + feat_out_channels[3], num_features, 3, 1, 1, bias=False),
nn.ELU())
self.weight4 = torch.nn.Sequential(nn.Conv2d(feat_out_channels_rad[3], num_features, 1, 1, bias=False),
nn.Sigmoid())
self.project4 = torch.nn.Sequential(nn.Conv2d(feat_out_channels_rad[3], num_features, 1, 1, bias=False),
nn.ReLU())
self.upconv4 = upconv(num_features, num_features // 2)
self.bn4 = nn.BatchNorm2d(num_features // 2, momentum=0.01, affine=True, eps=1.1e-5)
self.conv4 = torch.nn.Sequential(nn.Conv2d(num_features // 2 + feat_out_channels[2], num_features // 2, 3, 1, 1, bias=False),
nn.ELU())
self.bn4_2 = nn.BatchNorm2d(num_features // 2, momentum=0.01, affine=True, eps=1.1e-5)
self.daspp_3 = atrous_conv(num_features // 2, num_features // 4, 3, apply_bn_first=False)
self.daspp_6 = atrous_conv(num_features // 2 + num_features // 4 + feat_out_channels[2], num_features // 4, 6)
self.daspp_12 = atrous_conv(num_features + feat_out_channels[2], num_features // 4, 12)
self.daspp_18 = atrous_conv(num_features + num_features // 4 + feat_out_channels[2], num_features // 4, 18)
self.daspp_24 = atrous_conv(num_features + num_features // 2 + feat_out_channels[2], num_features // 4, 24)
self.daspp_conv = torch.nn.Sequential(nn.Conv2d(num_features + num_features // 2 + num_features // 4, num_features // 4, 3, 1, 1, bias=False),
nn.ELU())
self.reduc8x8 = reduction_1x1(num_features // 4, num_features // 4, self.params.max_depth)
self.lpg8x8 = local_planar_guidance(8)
self.weight3 = torch.nn.Sequential(nn.Conv2d(feat_out_channels_rad[2], num_features // 4, 1, 1, bias=False),
nn.Sigmoid())
self.project3 = torch.nn.Sequential(nn.Conv2d(feat_out_channels_rad[2], num_features // 4, 1, 1, bias=False),
nn.ReLU())
self.upconv3 = upconv(num_features // 4, num_features // 4)
self.bn3 = nn.BatchNorm2d(num_features // 4, momentum=0.01, affine=True, eps=1.1e-5)
self.conv3 = torch.nn.Sequential(nn.Conv2d(num_features // 4 + feat_out_channels[1] + 1, num_features // 4, 3, 1, 1, bias=False),
nn.ELU())
self.reduc4x4 = reduction_1x1(num_features // 4, num_features // 8, self.params.max_depth)
self.lpg4x4 = local_planar_guidance(4)
self.weight2 = torch.nn.Sequential(nn.Conv2d(feat_out_channels_rad[1], num_features // 4, 1, 1, bias=False),
nn.Sigmoid())
self.project2 = torch.nn.Sequential(nn.Conv2d(feat_out_channels_rad[1], num_features // 4, 1, 1, bias=False),
nn.ReLU())
self.upconv2 = upconv(num_features // 4, num_features // 8)
self.bn2 = nn.BatchNorm2d(num_features // 8, momentum=0.01, affine=True, eps=1.1e-5)
self.conv2 = torch.nn.Sequential(nn.Conv2d(num_features // 8 + feat_out_channels[0] + 1, num_features // 8, 3, 1, 1, bias=False),
nn.ELU())
self.reduc2x2 = reduction_1x1(num_features // 8, num_features // 16, self.params.max_depth)
self.lpg2x2 = local_planar_guidance(2)
self.weight1 = torch.nn.Sequential(nn.Conv2d(feat_out_channels_rad[0], num_features // 8, 1, 1, bias=False),
nn.Sigmoid())
self.project1 = torch.nn.Sequential(nn.Conv2d(feat_out_channels_rad[0], num_features // 8, 1, 1, bias=False),
nn.ReLU())
self.upconv1 = upconv(num_features // 8, num_features // 16)
self.reduc1x1 = reduction_1x1(num_features // 16, num_features // 32, self.params.max_depth, is_final=True)
self.conv1 = torch.nn.Sequential(nn.Conv2d(num_features // 16 + 4, num_features // 16, 3, 1, 1, bias=False),
nn.ELU())
self.get_depth = torch.nn.Sequential(nn.Conv2d(num_features // 16, 1, 3, 1, 1, bias=False),
nn.Sigmoid())
self.pool5 = torch.nn.AvgPool2d(32, 32)
self.pool4 = torch.nn.AvgPool2d(16, 16)
self.pool3 = torch.nn.AvgPool2d(8, 8)
self.pool2 = torch.nn.AvgPool2d(4, 4)
self.pool1 = torch.nn.AvgPool2d(2, 2)
def forward(self, img_features, rad_features, focal, radar_confidence):
skip0, skip1, skip2, skip3 = img_features[0], img_features[1], img_features[2], img_features[3]
rad_skip0, rad_skip1, rad_skip2, rad_skip3 = rad_features[0], rad_features[1], rad_features[2], rad_features[3]
# prepare radar confidence
radar_confidence5 = self.pool5(radar_confidence)
radar_confidence4 = self.pool4(radar_confidence)
radar_confidence3 = self.pool3(radar_confidence)
radar_confidence2 = self.pool2(radar_confidence)
radar_confidence1 = self.pool1(radar_confidence)
rad_weight5 = self.weight5(rad_features[4])
rad_project5 = self.project5(rad_features[4])
dense_features = torch.nn.ReLU()(img_features[4])
dense_features = dense_features + rad_weight5*rad_project5*radar_confidence5
upconv5 = self.upconv5(dense_features) # H/16
upconv5 = self.bn5(upconv5)
concat5 = torch.cat([upconv5, skip3], dim=1)
iconv5 = self.conv5(concat5)
rad_weight4 = self.weight4(rad_skip3)
rad_project4 = self.project4(rad_skip3)
iconv5 = iconv5 + rad_weight4*rad_project4*radar_confidence4
upconv4 = self.upconv4(iconv5) # H/8
upconv4 = self.bn4(upconv4)
concat4 = torch.cat([upconv4, skip2], dim=1)
iconv4 = self.conv4(concat4)
iconv4 = self.bn4_2(iconv4)
daspp_3 = self.daspp_3(iconv4)
concat4_2 = torch.cat([concat4, daspp_3], dim=1)
daspp_6 = self.daspp_6(concat4_2)
concat4_3 = torch.cat([concat4_2, daspp_6], dim=1)
daspp_12 = self.daspp_12(concat4_3)
concat4_4 = torch.cat([concat4_3, daspp_12], dim=1)
daspp_18 = self.daspp_18(concat4_4)
concat4_5 = torch.cat([concat4_4, daspp_18], dim=1)
daspp_24 = self.daspp_24(concat4_5)
concat4_daspp = torch.cat([iconv4, daspp_3, daspp_6, daspp_12, daspp_18, daspp_24], dim=1)
daspp_feat = self.daspp_conv(concat4_daspp)
rad_weight3 = self.weight3(rad_skip2)
rad_project3 = self.project3(rad_skip2)
daspp_feat = daspp_feat + rad_weight3*rad_project3*radar_confidence3
reduc8x8 = self.reduc8x8(daspp_feat)
plane_normal_8x8 = reduc8x8[:, :3, :, :]
plane_normal_8x8 = torch_nn_func.normalize(plane_normal_8x8, 2, 1)
plane_dist_8x8 = reduc8x8[:, 3, :, :]
plane_eq_8x8 = torch.cat([plane_normal_8x8, plane_dist_8x8.unsqueeze(1)], 1)
depth_8x8 = self.lpg8x8(plane_eq_8x8, focal)
depth_8x8_scaled = depth_8x8.unsqueeze(1) / self.params.max_depth
depth_8x8_scaled_ds = torch_nn_func.interpolate(depth_8x8_scaled, scale_factor=0.25, mode='nearest')
upconv3 = self.upconv3(daspp_feat) # H/4
upconv3 = self.bn3(upconv3)
concat3 = torch.cat([upconv3, skip1, depth_8x8_scaled_ds], dim=1)
iconv3 = self.conv3(concat3)
rad_weight2 = self.weight2(rad_skip1)
rad_project2 = self.project2(rad_skip1)
iconv3 = iconv3 + rad_weight2*rad_project2*radar_confidence2
reduc4x4 = self.reduc4x4(iconv3)
plane_normal_4x4 = reduc4x4[:, :3, :, :]
plane_normal_4x4 = torch_nn_func.normalize(plane_normal_4x4, 2, 1)
plane_dist_4x4 = reduc4x4[:, 3, :, :]
plane_eq_4x4 = torch.cat([plane_normal_4x4, plane_dist_4x4.unsqueeze(1)], 1)
depth_4x4 = self.lpg4x4(plane_eq_4x4, focal)
depth_4x4_scaled = depth_4x4.unsqueeze(1) / self.params.max_depth
depth_4x4_scaled_ds = torch_nn_func.interpolate(depth_4x4_scaled, scale_factor=0.5, mode='nearest')
upconv2 = self.upconv2(iconv3) # H/2
upconv2 = self.bn2(upconv2)
concat2 = torch.cat([upconv2, skip0, depth_4x4_scaled_ds], dim=1)
iconv2 = self.conv2(concat2)
rad_weight1 = self.weight1(rad_skip0)
rad_project1 = self.project1(rad_skip0)
iconv2 = iconv2 + rad_weight1*rad_project1*radar_confidence1
reduc2x2 = self.reduc2x2(iconv2)
plane_normal_2x2 = reduc2x2[:, :3, :, :]
plane_normal_2x2 = torch_nn_func.normalize(plane_normal_2x2, 2, 1)
plane_dist_2x2 = reduc2x2[:, 3, :, :]
plane_eq_2x2 = torch.cat([plane_normal_2x2, plane_dist_2x2.unsqueeze(1)], 1)
depth_2x2 = self.lpg2x2(plane_eq_2x2, focal)
depth_2x2_scaled = depth_2x2.unsqueeze(1) / self.params.max_depth
rad_weight1 = self.weight1(rad_skip0)
rad_project1 = self.project1(rad_skip0)
upconv1 = self.upconv1(iconv2)
reduc1x1 = self.reduc1x1(upconv1)
concat1 = torch.cat([upconv1, reduc1x1, depth_2x2_scaled, depth_4x4_scaled, depth_8x8_scaled], dim=1)
iconv1 = self.conv1(concat1)
final_depth = self.params.max_depth * self.get_depth(iconv1)
return depth_8x8_scaled, depth_4x4_scaled, depth_2x2_scaled, reduc1x1, final_depth
class encoder_image(nn.Module):
def __init__(self, params):
super(encoder_image, self).__init__()
self.params = params
import torchvision.models as models
if params.encoder == 'densenet121_bts':
self.base_model = models.densenet121(pretrained=False).features
self.feat_names = ['relu0', 'pool0', 'transition1', 'transition2', 'norm5']
self.feat_out_channels = [64, 64, 128, 256, 1024]
elif params.encoder == 'densenet161_bts':
self.base_model = models.densenet161(pretrained=False).features
self.feat_names = ['relu0', 'pool0', 'transition1', 'transition2', 'norm5']
self.feat_out_channels = [96, 96, 192, 384, 2208]
elif params.encoder == 'resnet50_bts':
self.base_model = models.resnet50(pretrained=False)
self.feat_names = ['relu', 'layer1', 'layer2', 'layer3', 'layer4']
self.feat_out_channels = [64, 256, 512, 1024, 2048]
elif params.encoder == 'resnet34_bts':
self.base_model = models.resnet34(pretrained=False)
self.feat_names = ['relu', 'layer1', 'layer2', 'layer3', 'layer4']
self.feat_out_channels = [64, 64, 128, 256, 512]
elif params.encoder == 'resnet18_bts':
self.base_model = models.resnet18(pretrained=False)
self.feat_names = ['relu', 'layer1', 'layer2', 'layer3', 'layer4']
self.feat_out_channels = [64, 64, 128, 256, 512]
elif params.encoder == 'resnet101_bts':
self.base_model = models.resnet101(pretrained=False)
self.feat_names = ['relu', 'layer1', 'layer2', 'layer3', 'layer4']
self.feat_out_channels = [64, 256, 512, 1024, 2048]
elif params.encoder == 'resnext50_bts':
self.base_model = models.resnext50_32x4d(pretrained=False)
self.feat_names = ['relu', 'layer1', 'layer2', 'layer3', 'layer4']
self.feat_out_channels = [64, 256, 512, 1024, 2048]
elif params.encoder == 'resnext101_bts':
self.base_model = models.resnext101_32x8d(pretrained=False)
self.feat_names = ['relu', 'layer1', 'layer2', 'layer3', 'layer4']
self.feat_out_channels = [64, 256, 512, 1024, 2048]
elif params.encoder == 'mobilenetv2_bts':
self.base_model = models.mobilenet_v2(pretrained=False).features
self.feat_inds = [2, 4, 7, 11, 19]
self.feat_out_channels = [16, 24, 32, 64, 1280]
self.feat_names = []
else:
print('Not supported encoder: {}'.format(params.encoder))
def forward(self, x):
feature = x
skip_feat = []
i = 1
for k, v in self.base_model._modules.items():
if 'fc' in k or 'avgpool' in k:
continue
feature = v(feature)
if self.params.encoder == 'mobilenetv2_bts':
if i == 2 or i == 4 or i == 7 or i == 11 or i == 19:
skip_feat.append(feature)
else:
if any(x in k for x in self.feat_names):
skip_feat.append(feature)
i = i + 1
return skip_feat