Commit d0140132 authored by Yizhou Wang's avatar Yizhou Wang
Browse files

v1.1 code for RODNet J-STSP version

parent 9266cc35
# RODNet: Radar Object Detection using Cross-Modal Supervision # RODNet: Radar Object Detection Network
This is the official implementation of our RODNet paper at WACV 2021. This is the official implementation of our RODNet papers
at [WACV 2021](https://openaccess.thecvf.com/content/WACV2021/html/Wang_RODNet_Radar_Object_Detection_Using_Cross-Modal_Supervision_WACV_2021_paper.html)
and [IEEE J-STSP 2021](https://ieeexplore.ieee.org/abstract/document/9353210).
[[Paper]](https://openaccess.thecvf.com/content/WACV2021/html/Wang_RODNet_Radar_Object_Detection_Using_Cross-Modal_Supervision_WACV_2021_paper.html) [[Arxiv]](https://arxiv.org/abs/2102.05150)
[[Dataset]](https://www.cruwdataset.org) [[Dataset]](https://www.cruwdataset.org)
[[ROD2021 Challenge]](https://codalab.lisn.upsaclay.fr/competitions/1063)
[[Presentation]](https://youtu.be/UZbxI4o2-7g)
[[Demo]](https://youtu.be/09HaDySa29I)
![RODNet Overview](./assets/images/overview.jpg?raw=true) ![RODNet Overview](./assets/images/overview.jpg?raw=true)
Please cite our WACV 2021 paper if this repository is helpful for your research: Please cite our paper if this repository is helpful for your research:
``` ```
@inproceedings{wang2021rodnet, @inproceedings{wang2021rodnet,
author={Wang, Yizhou and Jiang, Zhongyu and Gao, Xiangyu and Hwang, Jenq-Neng and Xing, Guanbin and Liu, Hui}, author={Wang, Yizhou and Jiang, Zhongyu and Gao, Xiangyu and Hwang, Jenq-Neng and Xing, Guanbin and Liu, Hui},
title={RODNet: Radar Object Detection Using Cross-Modal Supervision}, title={RODNet: Radar Object Detection Using Cross-Modal Supervision},
booktitle={Proceedings of the IEEE/CVF Winter Conference on Applications of Computer Vision (WACV)}, booktitle={Proceedings of the IEEE/CVF Winter Conference on Applications of Computer Vision (WACV)},
month={January}, month={January},
year={2021}, year={2021},
pages={504-513} pages={504-513}
} }
``` ```
```
@article{wang2021rodnet,
title={RODNet: A Real-Time Radar Object Detection Network Cross-Supervised by Camera-Radar Fused Object 3D Localization},
author={Wang, Yizhou and Jiang, Zhongyu and Li, Yudong and Hwang, Jenq-Neng and Xing, Guanbin and Liu, Hui},
journal={IEEE Journal of Selected Topics in Signal Processing},
volume={15},
number={4},
pages={954--967},
year={2021},
publisher={IEEE}
}
```
## Installation ## Installation
Create a conda environment for RODNet. Tested under Python 3.6, 3.7, 3.8. Create a conda environment for RODNet. Tested under Python 3.6, 3.7, 3.8.
``` ```commandline
conda create -n rodnet python=3.* -y conda create -n rodnet python=3.* -y
conda activate rodnet conda activate rodnet
``` ```
Install pytorch. Install pytorch.
``` **Note:** If you are using Temporal Deformable Convolution (TDC), we only tested under `pytorch<=1.4` and `CUDA=10.1`.
conda install pytorch torchvision cudatoolkit=10.1 -c pytorch Without TDC, you should be able to choose the latest versions.
If you met some issues with environment, feel free to raise an issue.
```commandline
conda install pytorch=1.4 torchvision cudatoolkit=10.1 -c pytorch # if using TDC
# OR
conda install pytorch torchvision cudatoolkit=10.1 -c pytorch # if not using TDC
``` ```
Install `cruw-devkit` package. Install `cruw-devkit` package.
Please refer to [`cruw-devit`](https://github.com/yizhou-wang/cruw-devkit) repository for detailed instructions. Please refer to [`cruw-devit`](https://github.com/yizhou-wang/cruw-devkit) repository for detailed instructions.
``` ```commandline
git clone https://github.com/yizhou-wang/cruw-devkit.git git clone https://github.com/yizhou-wang/cruw-devkit.git
cd cruw-devkit cd cruw-devkit
pip install -e . pip install -e .
...@@ -41,13 +64,15 @@ cd .. ...@@ -41,13 +64,15 @@ cd ..
``` ```
Setup RODNet package. Setup RODNet package.
``` ```commandline
pip install -e . pip install -e .
``` ```
**Note:** If you are not using TDC, you can rename script `setup_wo_tdc.py` as `setup.py`, and run the above command.
This should allow you to use the latest cuda and pytorch version.
## Prepare data for RODNet ## Prepare data for RODNet
``` ```commandline
python tools/prepare_dataset/prepare_data.py \ python tools/prepare_dataset/prepare_data.py \
--config configs/<CONFIG_FILE> \ --config configs/<CONFIG_FILE> \
--data_root <DATASET_ROOT> \ --data_root <DATASET_ROOT> \
...@@ -57,7 +82,7 @@ python tools/prepare_dataset/prepare_data.py \ ...@@ -57,7 +82,7 @@ python tools/prepare_dataset/prepare_data.py \
## Train models ## Train models
``` ```commandline
python tools/train.py --config configs/<CONFIG_FILE> \ python tools/train.py --config configs/<CONFIG_FILE> \
--data_dir data/<DATA_FOLDER_NAME> \ --data_dir data/<DATA_FOLDER_NAME> \
--log_dir checkpoints/ --log_dir checkpoints/
...@@ -65,7 +90,7 @@ python tools/train.py --config configs/<CONFIG_FILE> \ ...@@ -65,7 +90,7 @@ python tools/train.py --config configs/<CONFIG_FILE> \
## Inference ## Inference
``` ```commandline
python tools/test.py --config configs/<CONFIG_FILE> \ python tools/test.py --config configs/<CONFIG_FILE> \
--data_dir data/<DATA_FOLDER_NAME> \ --data_dir data/<DATA_FOLDER_NAME> \
--checkpoint <CHECKPOINT_PATH> \ --checkpoint <CHECKPOINT_PATH> \
......
dataset_cfg = dict(
dataset_name='ROD2021',
base_root="/mnt/disk2/CRUW/ROD2021",
data_root="/mnt/disk2/CRUW/ROD2021/sequences",
anno_root="/mnt/disk2/CRUW/ROD2021/annotations",
anno_ext='.txt',
train=dict(
subdir='train',
# seqs=[], # can choose from the subdir folder
),
valid=dict(
subdir='valid',
seqs=[],
),
test=dict(
subdir='test',
# seqs=[], # can choose from the subdir folder
),
demo=dict(
subdir='demo',
seqs=[],
),
)
model_cfg = dict(
type='CDCv2',
name='rodnet-cdc-v2-win16-wobg',
max_dets=20,
peak_thres=0.3,
ols_thres=0.3,
mnet_cfg=(4, 32),
dcn=True,
)
confmap_cfg = dict(
confmap_sigmas={
'pedestrian': 15,
'cyclist': 20,
'car': 30,
# 'van': 40,
# 'truck': 50,
},
confmap_sigmas_interval={
'pedestrian': [5, 15],
'cyclist': [8, 20],
'car': [10, 30],
# 'van': [15, 40],
# 'truck': [20, 50],
},
confmap_length={
'pedestrian': 1,
'cyclist': 2,
'car': 3,
# 'van': 4,
# 'truck': 5,
}
)
train_cfg = dict(
n_epoch=100,
batch_size=4,
lr=0.00001,
lr_step=5, # lr will decrease 10 times after lr_step epoches
win_size=16,
train_step=1,
train_stride=4,
log_step=100,
save_step=10000,
)
test_cfg = dict(
test_step=1,
test_stride=8,
rr_min=1.0, # min radar range
rr_max=20.0, # max radar range
ra_min=-60.0, # min radar angle
ra_max=60.0, # max radar angle
)
dataset_cfg = dict(
dataset_name='ROD2021',
base_root="/mnt/disk2/CRUW/ROD2021",
data_root="/mnt/disk2/CRUW/ROD2021/sequences",
anno_root="/mnt/disk2/CRUW/ROD2021/annotations",
anno_ext='.txt',
train=dict(
subdir='train',
# seqs=[], # can choose from the subdir folder
),
valid=dict(
subdir='valid',
seqs=[],
),
test=dict(
subdir='test',
# seqs=[], # can choose from the subdir folder
),
demo=dict(
subdir='demo',
seqs=[],
),
)
model_cfg = dict(
type='HGv2',
name='rodnet-hg1-v2-win16-wobg',
max_dets=20,
peak_thres=0.4,
ols_thres=0.3,
stacked_num=1,
mnet_cfg=(4, 32),
dcn=True,
)
confmap_cfg = dict(
confmap_sigmas={
'pedestrian': 15,
'cyclist': 20,
'car': 30,
# 'van': 40,
# 'truck': 50,
},
confmap_sigmas_interval={
'pedestrian': [5, 15],
'cyclist': [8, 20],
'car': [10, 30],
# 'van': [15, 40],
# 'truck': [20, 50],
},
confmap_length={
'pedestrian': 1,
'cyclist': 2,
'car': 3,
# 'van': 4,
# 'truck': 5,
}
)
train_cfg = dict(
n_epoch=50,
batch_size=4,
lr=0.00001,
lr_step=5, # lr will decrease 10 times after lr_step epoches
win_size=16,
train_step=1,
train_stride=4,
log_step=100,
save_step=10000,
)
test_cfg = dict(
test_step=1,
test_stride=8,
rr_min=1.0, # min radar range
rr_max=20.0, # max radar range
ra_min=-60.0, # min radar angle
ra_max=60.0, # max radar angle
)
dataset_cfg = dict(
dataset_name='ROD2021',
base_root="/mnt/disk1/CRUW/ROD2021",
data_root="/mnt/disk1/CRUW/ROD2021/sequences",
anno_root="/mnt/disk1/CRUW/ROD2021/annotations",
anno_ext='.txt',
train=dict(
subdir='train',
# seqs=[], # can choose from the subdir folder
),
valid=dict(
subdir='valid',
# seqs=[],
),
test=dict(
subdir='test',
# seqs=[], # can choose from the subdir folder
),
demo=dict(
subdir='demo',
seqs=[],
),
)
model_cfg = dict(
type='HGwIv2',
name='rodnet-hg1wi-v2-win16-wobg',
max_dets=20,
peak_thres=0.3,
ols_thres=0.3,
stacked_num=1,
mnet_cfg=(4, 32),
dcn=True,
)
confmap_cfg = dict(
confmap_sigmas={
'pedestrian': 15,
'cyclist': 20,
'car': 30,
# 'van': 40,
# 'truck': 50,
},
confmap_sigmas_interval={
'pedestrian': [5, 15],
'cyclist': [8, 20],
'car': [10, 30],
# 'van': [15, 40],
# 'truck': [20, 50],
},
confmap_length={
'pedestrian': 1,
'cyclist': 2,
'car': 3,
# 'van': 4,
# 'truck': 5,
}
)
train_cfg = dict(
n_epoch=100,
batch_size=2,
lr=0.00001,
lr_step=5, # lr will decrease 10 times after lr_step epoches
win_size=16,
train_step=1,
train_stride=4,
log_step=100,
save_step=10000,
)
test_cfg = dict(
test_step=1,
test_stride=8,
rr_min=1.0, # min radar range
rr_max=20.0, # max radar range
ra_min=-60.0, # min radar angle
ra_max=60.0, # max radar angle
)
...@@ -5,14 +5,14 @@ import torch ...@@ -5,14 +5,14 @@ import torch
from multiprocessing import Array, Process from multiprocessing import Array, Process
class CRDataLoader(): class CRDataLoader:
def __init__(self, dataset, shuffle=False, num_parallel_batch=2, noise_channel=False): def __init__(self, dataset, shuffle=False, num_parallel_batch=2, noise_channel=False):
# parameters settings # parameters settings
self.dataset = dataset self.dataset = dataset
self.config_dict = self.dataset.config_dict self.config_dict = self.dataset.config_dict
self.n_class = self.config_dict['class_cfg']['n_class'] self.n_class = dataset.dataset.object_cfg.n_class
self.batch_size = self.config_dict['train_cfg']['batch_size'] self.batch_size = self.config_dict['train_cfg']['batch_size']
self.radar_configs = self.config_dict['dataset_cfg']['radar_cfg'] self.radar_configs = self.dataset.dataset.sensor_cfg.radar_cfg
self.model_configs = self.config_dict['model_cfg'] self.model_configs = self.config_dict['model_cfg']
self.ramap_rsize = self.radar_configs['ramap_rsize'] self.ramap_rsize = self.radar_configs['ramap_rsize']
self.ramap_asize = self.radar_configs['ramap_asize'] self.ramap_asize = self.radar_configs['ramap_asize']
......
...@@ -45,10 +45,7 @@ class CRDataset(data.Dataset): ...@@ -45,10 +45,7 @@ class CRDataset(data.Dataset):
if 'mnet_cfg' in self.config_dict['model_cfg']: if 'mnet_cfg' in self.config_dict['model_cfg']:
in_chirps, out_channels = self.config_dict['model_cfg']['mnet_cfg'] in_chirps, out_channels = self.config_dict['model_cfg']['mnet_cfg']
self.n_chirps = in_chirps self.n_chirps = in_chirps
n_radar_chirps = self.config_dict['dataset_cfg']['radar_cfg']['n_chirps'] self.chirp_ids = self.dataset.sensor_cfg.radar_cfg['chirp_ids']
self.chirp_ids = []
for c in range(in_chirps):
self.chirp_ids.append(int(n_radar_chirps / in_chirps * c))
# dataset initialization # dataset initialization
self.image_paths = [] self.image_paths = []
...@@ -105,7 +102,7 @@ class CRDataset(data.Dataset): ...@@ -105,7 +102,7 @@ class CRDataset(data.Dataset):
) )
if self.is_random_chirp: if self.is_random_chirp:
chirp_id = random.randint(0, self.dataset.sensor_cfg.radar_cfg['n_chirps'] - 1) chirp_id = random.randint(0, len(self.chirp_ids) - 1)
else: else:
chirp_id = 0 chirp_id = 0
...@@ -144,12 +141,23 @@ class CRDataset(data.Dataset): ...@@ -144,12 +141,23 @@ class CRDataset(data.Dataset):
else: else:
raise TypeError raise TypeError
elif radar_configs['data_type'] == 'ROD2021': elif radar_configs['data_type'] == 'ROD2021':
radar_npy_win = np.zeros((self.win_size, ramap_rsize, ramap_asize, 2), dtype=np.float32) if isinstance(chirp_id, int):
chirp_id = 0 # only use chirp 0 for training radar_npy_win = np.zeros((self.win_size, ramap_rsize, ramap_asize, 2), dtype=np.float32)
for idx, frameid in enumerate( for idx, frameid in enumerate(
range(data_id, data_id + self.win_size * self.step, self.step)): range(data_id, data_id + self.win_size * self.step, self.step)):
radar_npy_win[idx, :, :, :] = np.load(radar_paths[frameid][chirp_id]) radar_npy_win[idx, :, :, :] = np.load(radar_paths[frameid][chirp_id])
data_dict['image_paths'].append(image_paths[frameid]) data_dict['image_paths'].append(image_paths[frameid])
elif isinstance(chirp_id, list):
radar_npy_win = np.zeros((self.win_size, self.n_chirps, ramap_rsize, ramap_asize, 2),
dtype=np.float32)
for idx, frameid in enumerate(
range(data_id, data_id + self.win_size * self.step, self.step)):
for cid, c in enumerate(chirp_id):
npy_path = radar_paths[frameid][cid]
radar_npy_win[idx, cid, :, :, :] = np.load(npy_path)
data_dict['image_paths'].append(image_paths[frameid])
else:
raise TypeError
else: else:
raise NotImplementedError raise NotImplementedError
except: except:
...@@ -161,21 +169,6 @@ class CRDataset(data.Dataset): ...@@ -161,21 +169,6 @@ class CRDataset(data.Dataset):
with open(os.path.join('./tmp', log_name), 'w') as f_log: with open(os.path.join('./tmp', log_name), 'w') as f_log:
f_log.write('npy path: ' + radar_paths[frameid][chirp_id] + \ f_log.write('npy path: ' + radar_paths[frameid][chirp_id] + \
'\nframe indices: %d:%d:%d' % (data_id, data_id + self.win_size * self.step, self.step)) '\nframe indices: %d:%d:%d' % (data_id, data_id + self.win_size * self.step, self.step))
# radar_npy_win = np.transpose(radar_npy_win, (3, 0, 1, 2))
#
# data_dict['radar_data'] = radar_npy_win
#
# if len(self.confmaps) != 0:
# confmap_gt = this_seq_confmap[data_id:data_id + self.win_size * self.step:self.step]
# confmap_gt = np.transpose(confmap_gt, (1, 0, 2, 3))
# obj_info = this_seq_obj_info[data_id:data_id + self.win_size * self.step:self.step]
#
# data_dict['anno'] = dict(
# obj_infos=obj_info,
# confmaps=confmap_gt,
# )
# else:
# data_dict['anno'] = None
return data_dict return data_dict
# Dataloader for MNet # Dataloader for MNet
......
...@@ -8,7 +8,7 @@ from tqdm import tqdm ...@@ -8,7 +8,7 @@ from tqdm import tqdm
from torch.utils import data from torch.utils import data
from .collate_functions import _cr_collate_npy from .collate_functions import _cr_collate_npy
from .loaders import list_pkl_filenames from .loaders import list_pkl_filenames, list_pkl_filenames_from_prepared
class CRDatasetSM(data.Dataset): class CRDatasetSM(data.Dataset):
...@@ -24,11 +24,12 @@ class CRDatasetSM(data.Dataset): ...@@ -24,11 +24,12 @@ class CRDatasetSM(data.Dataset):
:param is_random: random load or not :param is_random: random load or not
""" """
def __init__(self, data_root, config_dict, split, is_random=True, subset=None, noise_channel=False): def __init__(self, data_dir, dataset, config_dict, split, is_random=True, subset=None, noise_channel=False):
# parameters settings # parameters settings
self.data_root = data_root self.data_dir = data_dir
self.dataset = dataset
self.config_dict = config_dict self.config_dict = config_dict
self.n_class = config_dict['class_cfg']['n_class'] self.n_class = dataset.object_cfg.n_class
self.win_size = config_dict['train_cfg']['win_size'] self.win_size = config_dict['train_cfg']['win_size']
self.split = split self.split = split
if split == 'train' or split == 'valid': if split == 'train' or split == 'valid':
...@@ -45,10 +46,7 @@ class CRDatasetSM(data.Dataset): ...@@ -45,10 +46,7 @@ class CRDatasetSM(data.Dataset):
if 'mnet_cfg' in self.config_dict['model_cfg']: if 'mnet_cfg' in self.config_dict['model_cfg']:
in_chirps, out_channels = self.config_dict['model_cfg']['mnet_cfg'] in_chirps, out_channels = self.config_dict['model_cfg']['mnet_cfg']
self.n_chirps = in_chirps self.n_chirps = in_chirps
n_radar_chirps = self.config_dict['dataset_cfg']['radar_cfg']['n_chirps'] self.chirp_ids = self.dataset.sensor_cfg.radar_cfg['chirp_ids']
self.chirp_ids = []
for c in range(in_chirps):
self.chirp_ids.append(int(n_radar_chirps / in_chirps * c))
# dataset initialization # dataset initialization
self.image_paths = [] self.image_paths = []
...@@ -60,12 +58,13 @@ class CRDatasetSM(data.Dataset): ...@@ -60,12 +58,13 @@ class CRDatasetSM(data.Dataset):
if subset is not None: if subset is not None:
self.data_files = [subset + '.pkl'] self.data_files = [subset + '.pkl']
else: else:
self.data_files = list_pkl_filenames(config_dict['dataset_cfg'], split) # self.data_files = list_pkl_filenames(config_dict['dataset_cfg'], split)
self.data_files = list_pkl_filenames_from_prepared(data_dir, split)
self.seq_names = [name.split('.')[0] for name in self.data_files] self.seq_names = [name.split('.')[0] for name in self.data_files]
self.n_seq = len(self.seq_names) self.n_seq = len(self.seq_names)
for seq_id, data_file in enumerate(tqdm(self.data_files)): for seq_id, data_file in enumerate(tqdm(self.data_files)):
data_file_path = os.path.join(data_root, split, data_file) data_file_path = os.path.join(data_dir, split, data_file)
data_details = pickle.load(open(data_file_path, 'rb')) data_details = pickle.load(open(data_file_path, 'rb'))
if split == 'train' or split == 'valid': if split == 'train' or split == 'valid':
assert data_details['anno'] is not None assert data_details['anno'] is not None
...@@ -78,7 +77,7 @@ class CRDatasetSM(data.Dataset): ...@@ -78,7 +77,7 @@ class CRDatasetSM(data.Dataset):
for data_id in range(n_data_in_seq): for data_id in range(n_data_in_seq):
self.index_mapping.append([seq_id, data_id * self.stride]) self.index_mapping.append([seq_id, data_id * self.stride])
if data_details['anno'] is not None: if data_details['anno'] is not None:
self.obj_infos.append(data_details['anno']['obj_infos']) self.obj_infos.append(data_details['anno']['metadata'])
def __len__(self): def __len__(self):
"""Total number of data/label pairs""" """Total number of data/label pairs"""
...@@ -89,10 +88,10 @@ class CRDatasetSM(data.Dataset): ...@@ -89,10 +88,10 @@ class CRDatasetSM(data.Dataset):
seq_id, data_id = self.index_mapping[index] seq_id, data_id = self.index_mapping[index]
image_paths = self.image_paths[seq_id] image_paths = self.image_paths[seq_id]
radar_paths = self.radar_paths[seq_id] radar_paths = self.radar_paths[seq_id]
this_data_file = os.path.join(self.data_root, self.split, self.data_files[seq_id]) this_data_file = os.path.join(self.data_dir, self.split, self.data_files[seq_id])
this_data_details = pickle.load(open(this_data_file, 'rb')) this_data_details = pickle.load(open(this_data_file, 'rb'))
if this_data_details['anno'] is not None: if this_data_details['anno'] is not None:
this_seq_obj_info = this_data_details['anno']['obj_infos'] this_seq_obj_info = this_data_details['anno']['metadata']
this_seq_confmap = this_data_details['anno']['confmaps'] this_seq_confmap = this_data_details['anno']['confmaps']
data_dict = dict( data_dict = dict(
...@@ -101,7 +100,7 @@ class CRDatasetSM(data.Dataset): ...@@ -101,7 +100,7 @@ class CRDatasetSM(data.Dataset):
) )
if self.is_random: if self.is_random:
chirp_id = random.randint(0, self.config_dict['dataset_cfg']['radar_cfg']['n_chirps'] - 1) chirp_id = random.randint(0, len(self.chirp_ids) - 1)
else: else:
chirp_id = 0 chirp_id = 0
...@@ -109,7 +108,7 @@ class CRDatasetSM(data.Dataset): ...@@ -109,7 +108,7 @@ class CRDatasetSM(data.Dataset):
if 'mnet_cfg' in self.config_dict['model_cfg']: if 'mnet_cfg' in self.config_dict['model_cfg']:
chirp_id = self.chirp_ids chirp_id = self.chirp_ids
radar_configs = self.config_dict['dataset_cfg']['radar_cfg'] radar_configs = self.dataset.sensor_cfg.radar_cfg
ramap_rsize = radar_configs['ramap_rsize'] ramap_rsize = radar_configs['ramap_rsize']
ramap_asize = radar_configs['ramap_asize'] ramap_asize = radar_configs['ramap_asize']
...@@ -139,6 +138,24 @@ class CRDatasetSM(data.Dataset): ...@@ -139,6 +138,24 @@ class CRDatasetSM(data.Dataset):
data_dict['image_paths'].append(image_paths[frameid]) data_dict['image_paths'].append(image_paths[frameid])
else: else:
raise TypeError raise TypeError
elif radar_configs['data_type'] == 'ROD2021':
if isinstance(chirp_id, int):
radar_npy_win = np.zeros((self.win_size, ramap_rsize, ramap_asize, 2), dtype=np.float32)
for idx, frameid in enumerate(
range(data_id, data_id + self.win_size * self.step, self.step)):
radar_npy_win[idx, :, :, :] = np.load(radar_paths[frameid][chirp_id])
data_dict['image_paths'].append(image_paths[frameid])
elif isinstance(chirp_id, list):
radar_npy_win = np.zeros((self.win_size, self.n_chirps, ramap_rsize, ramap_asize, 2),
dtype=np.float32)
for idx, frameid in enumerate(
range(data_id, data_id + self.win_size * self.step, self.step)):
for cid, c in enumerate(chirp_id):
npy_path = radar_paths[frameid][cid]
radar_npy_win[idx, cid, :, :, :] = np.load(npy_path)
data_dict['image_paths'].append(image_paths[frameid])
else:
raise TypeError
else: else:
raise ValueError raise ValueError
...@@ -151,31 +168,13 @@ class CRDatasetSM(data.Dataset): ...@@ -151,31 +168,13 @@ class CRDatasetSM(data.Dataset):
with open(os.path.join('./tmp', log_name), 'w') as f_log: with open(os.path.join('./tmp', log_name), 'w') as f_log:
f_log.write('npy path: ' + radar_paths[frameid][chirp_id] + \ f_log.write('npy path: ' + radar_paths[frameid][chirp_id] + \
'\nframe indices: %d:%d:%d' % (data_id, data_id + self.win_size * self.step, self.step)) '\nframe indices: %d:%d:%d' % (data_id, data_id + self.win_size * self.step, self.step))
# if 'mnet_cfg' in self.config_dict['model_cfg']:
# radar_npy_win = np.transpose(radar_npy_win, (4, 0, 1, 2, 3))
# else:
# radar_npy_win = np.transpose(radar_npy_win, (3, 0, 1, 2))
#
# data_dict['radar_data'] = radar_npy_win
#
# if len(self.confmaps) != 0:
# confmap_gt = this_seq_confmap[data_id:data_id + self.win_size * self.step:self.step]
# confmap_gt = np.transpose(confmap_gt, (1, 0, 2, 3))
# obj_info = this_seq_obj_info[data_id:data_id + self.win_size * self.step:self.step]
#
# data_dict['anno'] = dict(
# obj_infos=obj_info,
# confmaps=confmap_gt,
# )
# else:
# data_dict['anno'] = None
return data_dict return data_dict
# Dataloader for MNet # Dataloader for MNet
if 'mnet_cfg' in self.config_dict['model_cfg']: if 'mnet_cfg' in self.config_dict['model_cfg']:
radar_npy_win = np.transpose(radar_npy_win, (4, 0, 1, 2, 3)) radar_npy_win = np.transpose(radar_npy_win, (4, 0, 1, 2, 3))
assert radar_npy_win.shape == ( assert radar_npy_win.shape == (
2, self.win_size, self.n_chirps, radar_configs['ramap_rsize'], radar_configs['ramap_asize']) 2, self.win_size, self.n_chirps, radar_configs['ramap_rsize'], radar_configs['ramap_asize'])
else: else:
radar_npy_win = np.transpose(radar_npy_win, (3, 0, 1, 2)) radar_npy_win = np.transpose(radar_npy_win, (3, 0, 1, 2))
assert radar_npy_win.shape == (2, self.win_size, radar_configs['ramap_rsize'], radar_configs['ramap_asize']) assert radar_npy_win.shape == (2, self.win_size, radar_configs['ramap_rsize'], radar_configs['ramap_asize'])
......
from .rodnet_cdc import RODNetCDC from .rodnet_cdc import RODNetCDC
from .rodnet_hg import RODNetHG from .rodnet_hg import RODNetHG
from .rodnet_hgwi import RODNetHGwI from .rodnet_hgwi import RODNetHGwI
from .rodnet_cdc_v2 import RODNetCDCDCN
from .rodnet_hg_v2 import RODNetHGDCN
from .rodnet_hgwi_v2 import RODNetHGwIDCN
import torch.nn as nn import torch.nn as nn
class RadarVanilla(nn.Module):
def __init__(self, in_channels, n_class, use_mse_loss=False):
super(RadarVanilla, self).__init__()
self.encoder = RODEncode(in_channels=in_channels)
self.decoder = RODDecode(n_class=n_class)
self.sigmoid = nn.Sigmoid()
self.use_mse_loss = use_mse_loss
def forward(self, x):
x = self.encoder(x)
x = self.decoder(x)
if not self.use_mse_loss:
x = self.sigmoid(x)
return x
class RODEncode(nn.Module): class RODEncode(nn.Module):
def __init__(self, in_channels=2): def __init__(self, in_channels=2):
...@@ -32,7 +49,6 @@ class RODEncode(nn.Module): ...@@ -32,7 +49,6 @@ class RODEncode(nn.Module):
x = self.relu(self.bn2b(self.conv2b(x))) # (B, 128, W/2, 64, 64) -> (B, 128, W/4, 32, 32) x = self.relu(self.bn2b(self.conv2b(x))) # (B, 128, W/2, 64, 64) -> (B, 128, W/4, 32, 32)
x = self.relu(self.bn3a(self.conv3a(x))) # (B, 128, W/4, 32, 32) -> (B, 256, W/4, 32, 32) x = self.relu(self.bn3a(self.conv3a(x))) # (B, 128, W/4, 32, 32) -> (B, 256, W/4, 32, 32)
x = self.relu(self.bn3b(self.conv3b(x))) # (B, 256, W/4, 32, 32) -> (B, 256, W/4, 16, 16) x = self.relu(self.bn3b(self.conv3b(x))) # (B, 256, W/4, 32, 32) -> (B, 256, W/4, 16, 16)
return x return x
......
...@@ -3,11 +3,16 @@ import torch.nn as nn ...@@ -3,11 +3,16 @@ import torch.nn as nn
class RadarStackedHourglass(nn.Module): class RadarStackedHourglass(nn.Module):
def __init__(self, n_class, stacked_num=1, in_channels=2): def __init__(self, in_channels, n_class, stacked_num=1, conv_op=None, use_mse_loss=False):
super(RadarStackedHourglass, self).__init__() super(RadarStackedHourglass, self).__init__()
self.stacked_num = stacked_num self.stacked_num = stacked_num
self.conv1a = nn.Conv3d(in_channels=in_channels, out_channels=32, if conv_op is None:
kernel_size=(9, 5, 5), stride=(1, 1, 1), padding=(4, 2, 2)) self.conv1a = nn.Conv3d(in_channels=in_channels, out_channels=32,
kernel_size=(9, 5, 5), stride=(1, 1, 1), padding=(4, 2, 2))
else:
self.conv1a = conv_op(in_channels=in_channels, out_channels=32,
kernel_size=(5, 3, 3), stride=(1, 1, 1), padding=(2, 1, 1))
self.conv1b = nn.Conv3d(in_channels=32, out_channels=64, self.conv1b = nn.Conv3d(in_channels=32, out_channels=64,
kernel_size=(9, 5, 5), stride=(1, 1, 1), padding=(4, 2, 2)) kernel_size=(9, 5, 5), stride=(1, 1, 1), padding=(4, 2, 2))
...@@ -25,6 +30,7 @@ class RadarStackedHourglass(nn.Module): ...@@ -25,6 +30,7 @@ class RadarStackedHourglass(nn.Module):
self.bn1a = nn.BatchNorm3d(num_features=32) self.bn1a = nn.BatchNorm3d(num_features=32)
self.bn1b = nn.BatchNorm3d(num_features=64) self.bn1b = nn.BatchNorm3d(num_features=64)
self.sigmoid = nn.Sigmoid() self.sigmoid = nn.Sigmoid()
self.use_mse_loss = use_mse_loss
def forward(self, x): def forward(self, x):
x = self.relu(self.bn1a(self.conv1a(x))) x = self.relu(self.bn1a(self.conv1a(x)))
...@@ -35,11 +41,12 @@ class RadarStackedHourglass(nn.Module): ...@@ -35,11 +41,12 @@ class RadarStackedHourglass(nn.Module):
x, x1, x2, x3 = self.hourglass[i][0](x) x, x1, x2, x3 = self.hourglass[i][0](x)
x = self.hourglass[i][1](x, x1, x2, x3) x = self.hourglass[i][1](x, x1, x2, x3)
confmap = self.hourglass[i][2](x) confmap = self.hourglass[i][2](x)
out.append(self.sigmoid(confmap)) if not self.use_mse_loss:
confmap = self.sigmoid(confmap)
out.append(confmap)
if i < self.stacked_num - 1: if i < self.stacked_num - 1:
confmap_ = self.hourglass[i][3](confmap) confmap_ = self.hourglass[i][3](confmap)
x = x + confmap_ x = x + confmap_
return out return out
......
...@@ -4,11 +4,16 @@ import torch.nn as nn ...@@ -4,11 +4,16 @@ import torch.nn as nn
class RadarStackedHourglass(nn.Module): class RadarStackedHourglass(nn.Module):
def __init__(self, n_class, stacked_num=1): def __init__(self, in_channels, n_class, stacked_num=1, conv_op=None, use_mse_loss=False):
super(RadarStackedHourglass, self).__init__() super(RadarStackedHourglass, self).__init__()
self.stacked_num = stacked_num self.stacked_num = stacked_num
self.conv1a = nn.Conv3d(in_channels=2, out_channels=32, if conv_op is None:
kernel_size=(9, 5, 5), stride=(1, 1, 1), padding=(4, 2, 2)) self.conv1a = nn.Conv3d(in_channels=in_channels, out_channels=32,
kernel_size=(9, 5, 5), stride=(1, 1, 1), padding=(4, 2, 2))
else:
self.conv1a = conv_op(in_channels=in_channels, out_channels=32,
kernel_size=(5, 3, 3), stride=(1, 1, 1), padding=(2, 1, 1))
self.conv1b = nn.Conv3d(in_channels=32, out_channels=64, self.conv1b = nn.Conv3d(in_channels=32, out_channels=64,
kernel_size=(9, 5, 5), stride=(1, 1, 1), padding=(4, 2, 2)) kernel_size=(9, 5, 5), stride=(1, 1, 1), padding=(4, 2, 2))
self.conv1c = nn.Conv3d(in_channels=64, out_channels=160, self.conv1c = nn.Conv3d(in_channels=64, out_channels=160,
...@@ -29,6 +34,7 @@ class RadarStackedHourglass(nn.Module): ...@@ -29,6 +34,7 @@ class RadarStackedHourglass(nn.Module):
self.bn1b = nn.BatchNorm3d(num_features=64) self.bn1b = nn.BatchNorm3d(num_features=64)
self.bn1c = nn.BatchNorm3d(num_features=160) self.bn1c = nn.BatchNorm3d(num_features=160)
self.sigmoid = nn.Sigmoid() self.sigmoid = nn.Sigmoid()
self.use_mse_loss = use_mse_loss
def forward(self, x): def forward(self, x):
x = self.relu(self.bn1a(self.conv1a(x))) x = self.relu(self.bn1a(self.conv1a(x)))
...@@ -40,11 +46,12 @@ class RadarStackedHourglass(nn.Module): ...@@ -40,11 +46,12 @@ class RadarStackedHourglass(nn.Module):
x, x1, x2, x3 = self.hourglass[i][0](x) x, x1, x2, x3 = self.hourglass[i][0](x)
x = self.hourglass[i][1](x, x1, x2, x3) x = self.hourglass[i][1](x, x1, x2, x3)
confmap = self.hourglass[i][2](x) confmap = self.hourglass[i][2](x)
out.append(self.sigmoid(confmap)) if not self.use_mse_loss:
confmap = self.sigmoid(confmap)
out.append(confmap)
if i < self.stacked_num - 1: if i < self.stacked_num - 1:
confmap_ = self.hourglass[i][3](confmap) confmap_ = self.hourglass[i][3](confmap)
x = x + confmap_ x = x + confmap_
return out return out
......
import torch.nn as nn import torch.nn as nn
from .backbones.cdc import RODEncode, RODDecode from .backbones.cdc import RadarVanilla
class RODNetCDC(nn.Module): class RODNetCDC(nn.Module):
def __init__(self, n_class): def __init__(self, in_channels, n_class):
super(RODNetCDC, self).__init__() super(RODNetCDC, self).__init__()
self.cdc = RadarVanilla(in_channels, n_class, use_mse_loss=False)
self.c3d_encode = RODEncode()
self.c3d_decode = RODDecode(n_class)
def forward(self, x): def forward(self, x):
x = self.c3d_encode(x) x = self.cdc(x)
dets = self.c3d_decode(x) return x
return dets
import torch.nn as nn import torch.nn as nn
from .backbones.cdc import RODEncode, RODDecode from .backbones.cdc import RadarVanilla
from .modules.mnet import MNet from .modules.mnet import MNet
from ..ops.dcn import DeformConvPack3D from ..ops.dcn import DeformConvPack3D
class RODNetCDCDCN(nn.Module): class RODNetCDCDCN(nn.Module):
def __init__(self, n_class, mnet_cfg=None): def __init__(self, in_channels, n_class, mnet_cfg=None, dcn=True):
super(RODNetCDCDCN, self).__init__() super(RODNetCDCDCN, self).__init__()
self.dcn = dcn
if dcn:
self.conv_op = DeformConvPack3D
else:
self.conv_op = nn.Conv3d
if mnet_cfg is not None: if mnet_cfg is not None:
in_chirps_mnet, out_channels_mnet = mnet_cfg in_chirps_mnet, out_channels_mnet = mnet_cfg
self.mnet = MNet(in_chirps_mnet, out_channels_mnet, conv_op=DeformConvPack3D) assert in_channels == in_chirps_mnet
self.mnet = MNet(in_chirps_mnet, out_channels_mnet, conv_op=self.conv_op)
self.with_mnet = True self.with_mnet = True
self.c3d_encode = RODEncode(in_channels=out_channels_mnet) self.cdc = RadarVanilla(out_channels_mnet, n_class, use_mse_loss=False)
else: else:
self.with_mnet = False self.with_mnet = False
self.c3d_encode = RODEncode() self.cdc = RadarVanilla(in_channels, n_class, use_mse_loss=False)
self.c3d_decode = RODDecode(n_class)
def forward(self, x): def forward(self, x):
if self.with_mnet: if self.with_mnet:
x = self.mnet(x) x = self.mnet(x)
x = self.c3d_encode(x) x = self.cdc(x)
dets = self.c3d_decode(x) return x
return dets
...@@ -4,9 +4,9 @@ from .backbones.hg import RadarStackedHourglass ...@@ -4,9 +4,9 @@ from .backbones.hg import RadarStackedHourglass
class RODNetHG(nn.Module): class RODNetHG(nn.Module):
def __init__(self, n_class, stacked_num=2): def __init__(self, in_channels, n_class, stacked_num=2):
super(RODNetHG, self).__init__() super(RODNetHG, self).__init__()
self.stacked_hourglass = RadarStackedHourglass(n_class, stacked_num=stacked_num) self.stacked_hourglass = RadarStackedHourglass(in_channels, n_class, stacked_num=stacked_num)
def forward(self, x): def forward(self, x):
out = self.stacked_hourglass(x) out = self.stacked_hourglass(x)
......
import torch import torch
import torch.nn as nn import torch.nn as nn
from .backbones.hg_dcn import RadarStackedHourglass from .backbones.hg import RadarStackedHourglass
from .prep_layers.mnet import MNet from .modules.mnet import MNet
from ..ops.dcn import DeformConvPack3D from ..ops.dcn import DeformConvPack3D
class RODNetHGDCNv3(nn.Module): class RODNetHGDCN(nn.Module):
def __init__(self, n_class, stacked_num=2, mnet_cfg=None): def __init__(self, in_channels, n_class, stacked_num=2, mnet_cfg=None, dcn=True):
super(RODNetHGDCNv3, self).__init__() super(RODNetHGDCN, self).__init__()
self.dcn = dcn
if dcn:
self.conv_op = DeformConvPack3D
else:
self.conv_op = nn.Conv3d
if mnet_cfg is not None: if mnet_cfg is not None:
in_chirps_mnet, out_channels_mnet = mnet_cfg in_chirps_mnet, out_channels_mnet = mnet_cfg
self.mnet = MNet(in_chirps_mnet, out_channels_mnet, conv_op=DeformConvPack3D) assert in_channels == in_chirps_mnet
self.mnet = MNet(in_chirps_mnet, out_channels_mnet, conv_op=self.conv_op)
self.with_mnet = True self.with_mnet = True
self.stacked_hourglass = RadarStackedHourglass(n_class, stacked_num=stacked_num, self.stacked_hourglass = RadarStackedHourglass(out_channels_mnet, n_class, stacked_num=stacked_num,
in_channels=out_channels_mnet, conv_op=DeformConvPack3D) conv_op=self.conv_op)
else: else:
self.with_mnet = False self.with_mnet = False
self.stacked_hourglass = RadarStackedHourglass(n_class, stacked_num=stacked_num, conv_op=DeformConvPack3D) self.stacked_hourglass = RadarStackedHourglass(in_channels, n_class, stacked_num=stacked_num,
conv_op=self.conv_op)
def forward(self, x): def forward(self, x):
if self.with_mnet: if self.with_mnet:
x = self.mnet(x) x = self.mnet(x)
out, offsets = self.stacked_hourglass(x) out = self.stacked_hourglass(x)
return out, offsets return out
if __name__ == '__main__': if __name__ == '__main__':
...@@ -44,4 +51,3 @@ if __name__ == '__main__': ...@@ -44,4 +51,3 @@ if __name__ == '__main__':
criterion = nn.BCELoss() criterion = nn.BCELoss()
loss = criterion(output[0], output_gt) loss = criterion(output[0], output_gt)
loss.backward() loss.backward()
...@@ -5,9 +5,9 @@ from .backbones.hgwi import RadarStackedHourglass ...@@ -5,9 +5,9 @@ from .backbones.hgwi import RadarStackedHourglass
class RODNetHGwI(nn.Module): class RODNetHGwI(nn.Module):
def __init__(self, n_class, stacked_num=1): def __init__(self, in_channels, n_class, stacked_num=1):
super(RODNetHGwI, self).__init__() super(RODNetHGwI, self).__init__()
self.stacked_hourglass = RadarStackedHourglass(n_class, stacked_num=stacked_num) self.stacked_hourglass = RadarStackedHourglass(in_channels, n_class, stacked_num=stacked_num)
def forward(self, x): def forward(self, x):
out = self.stacked_hourglass(x) out = self.stacked_hourglass(x)
......
import torch
import torch.nn as nn
from .backbones.hgwi import RadarStackedHourglass
from .modules.mnet import MNet
from ..ops.dcn import DeformConvPack3D
class RODNetHGwIDCN(nn.Module):
def __init__(self, in_channels, n_class, stacked_num=1, mnet_cfg=None, dcn=True):
super(RODNetHGwIDCN, self).__init__()
self.dcn = dcn
if dcn:
self.conv_op = DeformConvPack3D
else:
self.conv_op = nn.Conv3d
if mnet_cfg is not None:
in_chirps_mnet, out_channels_mnet = mnet_cfg
self.mnet = MNet(in_chirps_mnet, out_channels_mnet, conv_op=self.conv_op)
self.with_mnet = True
self.stacked_hourglass = RadarStackedHourglass(out_channels_mnet, n_class, stacked_num=stacked_num,
conv_op=self.conv_op)
else:
self.with_mnet = False
self.stacked_hourglass = RadarStackedHourglass(in_channels, n_class, stacked_num=stacked_num,
conv_op=self.conv_op)
def forward(self, x):
if self.with_mnet:
x = self.mnet(x)
out = self.stacked_hourglass(x)
return out
if __name__ == '__main__':
testModel = RODNetHGwIDCN().cuda()
x = torch.zeros((1, 2, 16, 128, 128)).cuda()
testModel(x)
...@@ -18,3 +18,13 @@ def load_configs_from_file(config_path): ...@@ -18,3 +18,13 @@ def load_configs_from_file(config_path):
if not name.startswith('__') if not name.startswith('__')
} }
return cfg_dict return cfg_dict
def update_config_dict(config_dict, args):
data_root_old = config_dict['dataset_cfg']['base_root']
config_dict['dataset_cfg']['base_root'] = args.data_root
config_dict['dataset_cfg']['data_root'] = config_dict['dataset_cfg']['data_root'].replace(data_root_old,
args.data_root)
config_dict['dataset_cfg']['anno_root'] = config_dict['dataset_cfg']['anno_root'].replace(data_root_old,
args.data_root)
return config_dict
...@@ -6,6 +6,7 @@ from torch.utils.cpp_extension import BuildExtension, CUDAExtension ...@@ -6,6 +6,7 @@ from torch.utils.cpp_extension import BuildExtension, CUDAExtension
os.environ['CFLAGS'] = '-Wno-deprecated-declarations' # suppress warnings in debug mode os.environ['CFLAGS'] = '-Wno-deprecated-declarations' # suppress warnings in debug mode
def readme(): def readme():
with open('README.md', encoding='utf-8') as f: with open('README.md', encoding='utf-8') as f:
content = f.read() content = f.read()
......
import os
from setuptools import setup, find_packages
import torch
from torch.utils.cpp_extension import BuildExtension, CUDAExtension
os.environ['CFLAGS'] = '-Wno-deprecated-declarations' # suppress warnings in debug mode
def readme():
with open('README.md', encoding='utf-8') as f:
content = f.read()
return content
def get_requirements(filename='requirements.txt'):
here = os.path.dirname(os.path.realpath(__file__))
with open(os.path.join(here, filename), 'r') as f:
requires = [line.replace('\n', '') for line in f.readlines()]
return requires
def make_cuda_ext(name, module, sources):
define_macros = []
if torch.cuda.is_available() or os.getenv('FORCE_CUDA', '0') == '1':
define_macros += [('WITH_CUDA', None)]
else:
raise EnvironmentError('CUDA is required to compile RODNet!')
return CUDAExtension(
name='{}.{}'.format(module, name),
sources=[os.path.join(*module.split('.'), p) for p in sources],
define_macros=define_macros,
extra_compile_args={
'cxx': [],
'nvcc': [
'-D__CUDA_NO_HALF_OPERATORS__',
'-D__CUDA_NO_HALF_CONVERSIONS__',
'-D__CUDA_NO_HALF2_OPERATORS__',
]
})
if __name__ == '__main__':
setup(
name='rodnet',
version='1.1',
description='RODNet: Object Detection from Radar Data',
long_description=readme(),
long_description_content_type='text/markdown',
url='https://github.com/yizhou-wang/RODNet',
author='Yizhou Wang',
author_email='ywang26@uw.edu',
classifiers=[
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 3 - Alpha',
# Indicate who your project is intended for
'Intended Audience :: Developers',
'Topic :: Software Development :: Build Tools',
# Pick your license as you wish
'License :: OSI Approved :: MIT License',
# Specify the Python versions you support here. In particular, ensure
# that you indicate whether you support Python 2, Python 3 or both.
# These classifiers are *not* checked by 'pip install'. See instead
# 'python_requires' below.
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
],
keywords='rodnet, object detection, radar, autonomous driving',
packages=find_packages(include=["rodnet.*"]),
# package_data={'rodnet.ops': ['*/*.so']},
python_requires='>=3.6',
install_requires=get_requirements(),
# ext_modules=[
# make_cuda_ext(
# name='deform_conv_2d_cuda',
# module='rodnet.ops.dcn',
# sources=[
# 'src/deform_conv_2d_cuda.cpp',
# 'src/deform_conv_2d_cuda_kernel.cu'
# ]),
# make_cuda_ext(
# name='deform_conv_3d_cuda',
# module='rodnet.ops.dcn',
# sources=[
# 'src/deform_conv_3d_cuda.cpp',
# 'src/deform_conv_3d_cuda_kernel.cu'
# ]),
# make_cuda_ext(
# name='deform_pool_2d_cuda',
# module='rodnet.ops.dcn',
# sources=[
# 'src/deform_pool_2d_cuda.cpp',
# 'src/deform_pool_2d_cuda_kernel.cu'
# ]),
# make_cuda_ext(
# name='deform_pool_3d_cuda',
# module='rodnet.ops.dcn',
# sources=[
# 'src/deform_pool_3d_cuda.cpp',
# 'src/deform_pool_3d_cuda_kernel.cu'
# ]),
# ],
# cmdclass={'build_ext': BuildExtension},
zip_safe=False
)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment