|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import torch |
|
|
import torch.nn as nn |
|
|
import torch.nn.functional as F |
|
|
import numpy as np |
|
|
|
|
|
|
|
|
|
|
|
import os |
|
|
import random |
|
|
|
|
|
|
|
|
|
|
|
SEED1 = 1337 |
|
|
NEW_LINE = "\n" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def set_seed(seed): |
|
|
torch.manual_seed(seed) |
|
|
torch.cuda.manual_seed_all(seed) |
|
|
torch.backends.cudnn.deterministic = True |
|
|
torch.backends.cudnn.benchmark = False |
|
|
random.seed(seed) |
|
|
os.environ['PYTHONHASHSEED'] = str(seed) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
POINTS = 1081 |
|
|
IMG_SIZE = 80 |
|
|
SEQ_LEN = 10 |
|
|
class NavDataset(torch.utils.data.Dataset): |
|
|
def __init__(self, img_path, file_name): |
|
|
|
|
|
self.npy_names = [] |
|
|
self.lengths = [] |
|
|
|
|
|
|
|
|
self.s_mu = 4.518406 |
|
|
self.s_std = 8.2914915 |
|
|
self.g_mu = 0.30655652 |
|
|
self.g_std = 0.5378557 |
|
|
self.i_mu = 3081.8167 |
|
|
self.i_std = 1529.4413 |
|
|
self.a_mu = 0.5959513 |
|
|
self.a_std = 0.4783924 |
|
|
|
|
|
|
|
|
fp_folder = open(img_path+'dataset.txt','r') |
|
|
|
|
|
|
|
|
for folder_line in fp_folder.read().split(NEW_LINE): |
|
|
if('-' in folder_line): |
|
|
npy_name = [] |
|
|
folder_path = folder_line |
|
|
fp_file = open(img_path+folder_path+'/'+file_name+'.txt', 'r') |
|
|
for line in fp_file.read().split(NEW_LINE): |
|
|
if('.npy' in line): |
|
|
npy_name.append(img_path+folder_path+line) |
|
|
|
|
|
self.lengths.append(len(npy_name)) |
|
|
self.npy_names.append(npy_name) |
|
|
|
|
|
fp_file.close() |
|
|
|
|
|
|
|
|
fp_folder.close() |
|
|
|
|
|
self.length = np.sum(self.lengths) |
|
|
self.cumsum_lengths = np.cumsum(self.lengths).tolist() |
|
|
|
|
|
print("dataset length: ", self.length) |
|
|
|
|
|
|
|
|
def __len__(self): |
|
|
return self.length |
|
|
|
|
|
def __getitem__(self, idx): |
|
|
|
|
|
|
|
|
folder_id = np.searchsorted(self.cumsum_lengths, idx, side='right') |
|
|
start = 0 if folder_id == 0 else self.cumsum_lengths[folder_id - 1] |
|
|
data_len = self.lengths[folder_id] |
|
|
npy_list = self.npy_names[folder_id] |
|
|
|
|
|
|
|
|
npy_path_name = npy_list[idx - start] |
|
|
npy_path = npy_path_name[:-11] |
|
|
idx_num = int(npy_path_name[-11:-4]) |
|
|
|
|
|
if idx_num + SEQ_LEN < data_len: |
|
|
idx_s = idx_num |
|
|
elif idx_num - SEQ_LEN > 0: |
|
|
idx_s = idx_num - SEQ_LEN |
|
|
else: |
|
|
idx_s = data_len // 2 |
|
|
|
|
|
|
|
|
end_str = f"{idx_s + SEQ_LEN - 1:07d}.npy" |
|
|
|
|
|
|
|
|
sub_goal = np.load(f"{npy_path}/sub_goals_local/{end_str}") |
|
|
velocity = np.load(f"{npy_path}/velocities/{end_str}") |
|
|
|
|
|
|
|
|
|
|
|
scan_avg = np.zeros((SEQ_LEN * 2, IMG_SIZE), dtype=np.float32) |
|
|
semantic_avg = np.zeros((SEQ_LEN * 2, IMG_SIZE), dtype=np.float32) |
|
|
|
|
|
|
|
|
slice_idx = np.arange(0, IMG_SIZE * 9, 9).reshape(-1, 1) + np.arange(9) |
|
|
|
|
|
for n in range(SEQ_LEN): |
|
|
frame_idx = f"{idx_s + n:07d}.npy" |
|
|
|
|
|
scan = np.load(f"{npy_path}/scans_lidar/{frame_idx}")[180:-180] |
|
|
semantic = np.load(f"{npy_path}/semantic_label/{frame_idx}")[180:-180] |
|
|
|
|
|
|
|
|
bins_scan = scan[slice_idx] |
|
|
bins_sem = semantic[slice_idx] |
|
|
|
|
|
|
|
|
mins = bins_scan.min(axis=1) |
|
|
min_idx = bins_scan.argmin(axis=1) |
|
|
sem_min = bins_sem[np.arange(IMG_SIZE), min_idx] |
|
|
|
|
|
scan_avg[2 * n] = mins |
|
|
semantic_avg[2 * n] = sem_min |
|
|
|
|
|
|
|
|
scan_avg[2 * n + 1] = bins_scan.mean(axis=1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
counts = np.apply_along_axis(np.bincount, 1, bins_sem.astype(int), minlength=256) |
|
|
semantic_avg[2 * n + 1] = counts.argmax(axis=1) |
|
|
|
|
|
|
|
|
scan_map = np.repeat(scan_avg.reshape(-1), 4) |
|
|
semantic_map = np.repeat(semantic_avg.reshape(-1), 4) |
|
|
|
|
|
|
|
|
sub_goal[np.isnan(sub_goal)] = 0. |
|
|
sub_goal[np.isinf(sub_goal)] = 0. |
|
|
|
|
|
velocity[np.isnan(velocity)] = 0. |
|
|
velocity[np.isinf(velocity)] = 0. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scan_map = (scan_map - self.s_mu) / self.s_std |
|
|
|
|
|
|
|
|
|
|
|
sub_goal = (sub_goal - self.g_mu) / self.g_std |
|
|
|
|
|
|
|
|
scan_tensor = torch.FloatTensor(scan_map) |
|
|
semantic_tensor = torch.FloatTensor(semantic_map) |
|
|
sub_goal_tensor = torch.FloatTensor(sub_goal) |
|
|
velocity_tensor = torch.FloatTensor(velocity) |
|
|
|
|
|
data = { |
|
|
'scan_map': scan_tensor, |
|
|
'semantic_map': semantic_tensor, |
|
|
'sub_goal': sub_goal_tensor, |
|
|
'velocity': velocity_tensor, |
|
|
} |
|
|
|
|
|
return data |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1): |
|
|
"""3x3 convolution with padding""" |
|
|
return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, |
|
|
padding=dilation, groups=groups, bias=False, dilation=dilation) |
|
|
|
|
|
def conv1x1(in_planes, out_planes, stride=1): |
|
|
"""1x1 convolution""" |
|
|
return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False) |
|
|
|
|
|
class Bottleneck(nn.Module): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expansion = 2 |
|
|
|
|
|
def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, |
|
|
base_width=64, dilation=1, norm_layer=None): |
|
|
super(Bottleneck, self).__init__() |
|
|
if norm_layer is None: |
|
|
norm_layer = nn.BatchNorm2d |
|
|
width = int(planes * (base_width / 64.)) * groups |
|
|
|
|
|
self.conv1 = conv1x1(inplanes, width) |
|
|
self.bn1 = norm_layer(width) |
|
|
self.conv2 = conv3x3(width, width, stride, groups, dilation) |
|
|
self.bn2 = norm_layer(width) |
|
|
self.conv3 = conv1x1(width, planes * self.expansion) |
|
|
self.bn3 = norm_layer(planes * self.expansion) |
|
|
self.relu = nn.ReLU(inplace=True) |
|
|
self.downsample = downsample |
|
|
self.stride = stride |
|
|
|
|
|
def forward(self, x): |
|
|
identity = x |
|
|
|
|
|
out = self.conv1(x) |
|
|
out = self.bn1(out) |
|
|
out = self.relu(out) |
|
|
|
|
|
out = self.conv2(out) |
|
|
out = self.bn2(out) |
|
|
out = self.relu(out) |
|
|
|
|
|
out = self.conv3(out) |
|
|
out = self.bn3(out) |
|
|
|
|
|
if self.downsample is not None: |
|
|
identity = self.downsample(x) |
|
|
|
|
|
out += identity |
|
|
out = self.relu(out) |
|
|
|
|
|
return out |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SemanticCNN(nn.Module): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, block, layers, num_classes=2, zero_init_residual=True, |
|
|
groups=1, width_per_group=64, replace_stride_with_dilation=None, |
|
|
norm_layer=None): |
|
|
|
|
|
|
|
|
|
|
|
super(SemanticCNN, self).__init__() |
|
|
|
|
|
|
|
|
|
|
|
if norm_layer is None: |
|
|
norm_layer = nn.BatchNorm2d |
|
|
self._norm_layer = norm_layer |
|
|
|
|
|
self.inplanes = 64 |
|
|
self.dilation = 1 |
|
|
if replace_stride_with_dilation is None: |
|
|
|
|
|
|
|
|
replace_stride_with_dilation = [False, False, False] |
|
|
if len(replace_stride_with_dilation) != 3: |
|
|
raise ValueError("replace_stride_with_dilation should be None " |
|
|
"or a 3-element tuple, got {}".format(replace_stride_with_dilation)) |
|
|
self.groups = groups |
|
|
self.base_width = width_per_group |
|
|
self.conv1 = nn.Conv2d(2, self.inplanes, kernel_size=3, stride=1, padding=1, |
|
|
bias=False) |
|
|
self.bn1 = norm_layer(self.inplanes) |
|
|
self.relu = nn.ReLU(inplace=True) |
|
|
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=1, padding=1) |
|
|
self.layer1 = self._make_layer(block, 64, layers[0]) |
|
|
self.layer2 = self._make_layer(block, 128, layers[1], stride=2, |
|
|
dilate=replace_stride_with_dilation[0]) |
|
|
self.layer3 = self._make_layer(block, 256, layers[2], stride=2, |
|
|
dilate=replace_stride_with_dilation[1]) |
|
|
|
|
|
self.conv2_2 = nn.Sequential( |
|
|
nn.Conv2d(in_channels=256, out_channels=128, kernel_size=(1, 1), stride=(1,1), padding=(0, 0)), |
|
|
nn.BatchNorm2d(128), |
|
|
nn.ReLU(inplace=True), |
|
|
|
|
|
nn.Conv2d(in_channels=128, out_channels=128, kernel_size=(3, 3), stride=(1,1), padding=(1, 1)), |
|
|
nn.BatchNorm2d(128), |
|
|
nn.ReLU(inplace=True), |
|
|
|
|
|
nn.Conv2d(in_channels=128, out_channels=256, kernel_size=(1, 1), stride=(1,1), padding=(0, 0)), |
|
|
nn.BatchNorm2d(256) |
|
|
) |
|
|
self.downsample2 = nn.Sequential( |
|
|
nn.Conv2d(in_channels=128, out_channels=256, kernel_size=(1, 1), stride=(2,2), padding=(0, 0)), |
|
|
nn.BatchNorm2d(256) |
|
|
) |
|
|
self.relu2 = nn.ReLU(inplace=True) |
|
|
|
|
|
self.conv3_2 = nn.Sequential( |
|
|
nn.Conv2d(in_channels=512, out_channels=256, kernel_size=(1, 1), stride=(1,1), padding=(0, 0)), |
|
|
nn.BatchNorm2d(256), |
|
|
nn.ReLU(inplace=True), |
|
|
|
|
|
nn.Conv2d(in_channels=256, out_channels=256, kernel_size=(3, 3), stride=(1,1), padding=(1, 1)), |
|
|
nn.BatchNorm2d(256), |
|
|
nn.ReLU(inplace=True), |
|
|
|
|
|
nn.Conv2d(in_channels=256, out_channels=512, kernel_size=(1, 1), stride=(1,1), padding=(0, 0)), |
|
|
nn.BatchNorm2d(512) |
|
|
) |
|
|
self.downsample3 = nn.Sequential( |
|
|
nn.Conv2d(in_channels=64, out_channels=512, kernel_size=(1, 1), stride=(4,4), padding=(0, 0)), |
|
|
nn.BatchNorm2d(512) |
|
|
) |
|
|
self.relu3 = nn.ReLU(inplace=True) |
|
|
|
|
|
|
|
|
|
|
|
self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) |
|
|
self.fc = nn.Linear(256 * block.expansion + 2, num_classes) |
|
|
|
|
|
for m in self.modules(): |
|
|
if isinstance(m, nn.Conv2d): |
|
|
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') |
|
|
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): |
|
|
nn.init.constant_(m.weight, 1) |
|
|
nn.init.constant_(m.bias, 0) |
|
|
elif isinstance(m, nn.BatchNorm1d): |
|
|
nn.init.constant_(m.weight, 1) |
|
|
nn.init.constant_(m.bias, 0) |
|
|
elif isinstance(m, nn.Linear): |
|
|
nn.init.xavier_normal_(m.weight) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if zero_init_residual: |
|
|
for m in self.modules(): |
|
|
if isinstance(m, Bottleneck): |
|
|
nn.init.constant_(m.bn3.weight, 0) |
|
|
|
|
|
def _make_layer(self, block, planes, blocks, stride=1, dilate=False): |
|
|
norm_layer = self._norm_layer |
|
|
downsample = None |
|
|
previous_dilation = self.dilation |
|
|
if dilate: |
|
|
self.dilation *= stride |
|
|
stride = 1 |
|
|
if stride != 1 or self.inplanes != planes * block.expansion: |
|
|
downsample = nn.Sequential( |
|
|
conv1x1(self.inplanes, planes * block.expansion, stride), |
|
|
norm_layer(planes * block.expansion), |
|
|
) |
|
|
|
|
|
layers = [] |
|
|
layers.append(block(self.inplanes, planes, stride, downsample, self.groups, |
|
|
self.base_width, previous_dilation, norm_layer)) |
|
|
self.inplanes = planes * block.expansion |
|
|
for _ in range(1, blocks): |
|
|
layers.append(block(self.inplanes, planes, groups=self.groups, |
|
|
base_width=self.base_width, dilation=self.dilation, |
|
|
norm_layer=norm_layer)) |
|
|
|
|
|
return nn.Sequential(*layers) |
|
|
|
|
|
def _forward_impl(self, scan, semantics, goal): |
|
|
|
|
|
scan_in = scan.reshape(-1,1,80,80) |
|
|
semantics_in = semantics.reshape(-1,1,80,80) |
|
|
fusion_in = torch.cat((scan_in, semantics_in), dim=1) |
|
|
|
|
|
|
|
|
x = self.conv1(fusion_in) |
|
|
x = self.bn1(x) |
|
|
x = self.relu(x) |
|
|
x = self.maxpool(x) |
|
|
|
|
|
identity3 = self.downsample3(x) |
|
|
|
|
|
x = self.layer1(x) |
|
|
|
|
|
identity2 = self.downsample2(x) |
|
|
|
|
|
x = self.layer2(x) |
|
|
|
|
|
x = self.conv2_2(x) |
|
|
x += identity2 |
|
|
x = self.relu2(x) |
|
|
|
|
|
|
|
|
x = self.layer3(x) |
|
|
|
|
|
|
|
|
x = self.conv3_2(x) |
|
|
x += identity3 |
|
|
x = self.relu3(x) |
|
|
|
|
|
x = self.avgpool(x) |
|
|
fusion_out = torch.flatten(x, 1) |
|
|
|
|
|
|
|
|
|
|
|
goal_in = goal.reshape(-1,2) |
|
|
goal_out = torch.flatten(goal_in, 1) |
|
|
|
|
|
|
|
|
fc_in = torch.cat((fusion_out, goal_out), dim=1) |
|
|
x = self.fc(fc_in) |
|
|
|
|
|
return x |
|
|
|
|
|
def forward(self, scan, semantics, goal): |
|
|
return self._forward_impl(scan, semantics, goal) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|