refactor evaluation and training

This commit is contained in:
Lorenzo 2020-12-03 14:35:39 +01:00
parent 2c97f20fe9
commit 89d860df2a
7 changed files with 152 additions and 133 deletions

View File

@ -129,7 +129,7 @@ by the image name to easily access ground truth files for evaluation and predict
# Training # Training
Provide the json file containing the preprocess joints as argument. Provide the json file containing the preprocess joints as argument.
As simple as `python3 -m monstereo.run train --joints <json file path>` As simple as `python3 -m monstereo.run train --joints <json file path> `
All the hyperparameters options can be checked at `python3 -m monstereo.run train --help`. All the hyperparameters options can be checked at `python3 -m monstereo.run train --help`.
# Evaluation (KITTI Dataset) # Evaluation (KITTI Dataset)

View File

@ -73,3 +73,13 @@ python -m monstereo.run eval --activity \
--model <MonoLoco++ model path> --dir_ann <pifpaf annotations directory> --model <MonoLoco++ model path> --dir_ann <pifpaf annotations directory>
``` ```
## Training
We train on KITTI or nuScenes dataset specifying the path of the input joints.
Our results are obtained with:
`python -m monstereo.run train --lr 0.001 --joints data/arrays/joints-kitti-201202-1743.json --save --monocular`
For a more extensive list of available parameters, run:
`python -m monstereo.run train --help`

View File

@ -25,7 +25,7 @@ class EvalKitti:
'27', '29', '31', '49') '27', '29', '31', '49')
ALP_THRESHOLDS = ('<0.5m', '<1m', '<2m') ALP_THRESHOLDS = ('<0.5m', '<1m', '<2m')
OUR_METHODS = ['geometric', 'monoloco', 'monoloco_pp', 'pose', 'reid', 'monstereo'] OUR_METHODS = ['geometric', 'monoloco', 'monoloco_pp', 'pose', 'reid', 'monstereo']
METHODS_MONO = ['m3d', 'monopsr'] METHODS_MONO = ['m3d', 'monopsr', 'monodis', 'smoke']
METHODS_STEREO = ['3dop', 'psf', 'pseudo-lidar', 'e2e', 'oc-stereo'] METHODS_STEREO = ['3dop', 'psf', 'pseudo-lidar', 'e2e', 'oc-stereo']
BASELINES = ['task_error', 'pixel_error'] BASELINES = ['task_error', 'pixel_error']
HEADERS = ('method', '<0.5', '<1m', '<2m', 'easy', 'moderate', 'hard', 'all') HEADERS = ('method', '<0.5', '<1m', '<2m', 'easy', 'moderate', 'hard', 'all')
@ -56,6 +56,8 @@ class EvalKitti:
self.dic_thresh_conf['monopsr'] += 0.3 self.dic_thresh_conf['monopsr'] += 0.3
self.dic_thresh_conf['e2e-pl'] = -100 # They don't have enough detections self.dic_thresh_conf['e2e-pl'] = -100 # They don't have enough detections
self.dic_thresh_conf['oc-stereo'] = -100 self.dic_thresh_conf['oc-stereo'] = -100
self.dic_thresh_conf['smoke'] = -100
self.dic_thresh_conf['monodis'] = -100
# Extract validation images for evaluation # Extract validation images for evaluation
names_gt = tuple(os.listdir(self.dir_gt)) names_gt = tuple(os.listdir(self.dir_gt))

View File

@ -1,9 +1,10 @@
#pylint: disable=too-many-branches # pylint: disable=too-many-branches
""" """
Run MonoLoco/MonStereo and converts annotations into KITTI format Run MonoLoco/MonStereo and converts annotations into KITTI format
""" """
from typing import Dict, List
import os import os
import math import math
@ -22,42 +23,35 @@ from .reid_baseline import get_reid_features, ReID
class GenerateKitti: class GenerateKitti:
METHODS = ['monstereo', 'monoloco_pp', 'monoloco', 'geometric'] dir_gt = os.path.join('data', 'kitti', 'gt')
dir_gt_new = os.path.join('data', 'kitti', 'gt_new')
dir_kk = os.path.join('data', 'kitti', 'calib')
dir_byc = '/data/lorenzo-data/kitti/object_detection/left'
monoloco_checkpoint = 'data/models/monoloco-190717-0952.pkl'
baselines = {'mono': [], 'stereo': []}
def __init__(self, model, dir_ann, p_dropout=0.2, n_dropout=0, hidden_size=1024): def __init__(self, args):
self.dir_ann = dir_ann # Load Network
assert os.listdir(self.dir_ann), "Annotation directory is empty" self.net = args.net
assert args.net in ('monstereo', 'monoloco_pp'), "net not recognized"
# Load monoloco
use_cuda = torch.cuda.is_available() use_cuda = torch.cuda.is_available()
device = torch.device("cuda" if use_cuda else "cpu") device = torch.device("cuda" if use_cuda else "cpu")
self.model = Loco(
if 'monstereo' in self.METHODS: model=args.model,
self.monstereo = Loco(model=model, net='monstereo', device=device, n_dropout=n_dropout, p_dropout=p_dropout, net=args.net,
linear_size=hidden_size) device=device,
# model_mono_pp = 'data/models/monoloco-191122-1122.pkl' # KITTI_p n_dropout=args.n_dropout,
# model_mono_pp = 'data/models/monoloco-191018-1459.pkl' # nuScenes_p p_dropout=args.dropout,
# model_mono_pp = 'data/models/stereoloco-200604-0949.pkl' # KITTI_pp linear_size=args.hidden_size
model_mono_pp = 'data/models/monstereo-201202-1745.pkl' )
# model_mono_pp = 'data/models/stereoloco-200608-1550.pkl' # nuScenes_pp
if 'monoloco_pp' in self.METHODS:
self.monoloco_pp = Loco(model=model_mono_pp, net='monoloco_pp', device=device, n_dropout=n_dropout,
p_dropout=p_dropout)
if 'monoloco' in self.METHODS:
model_mono = 'data/models/monoloco-190717-0952.pkl' # KITTI
# model_mono = 'data/models/monoloco-190719-0923.pkl' # NuScenes
self.monoloco = Loco(model=model_mono, net='monoloco', device=device, n_dropout=n_dropout,
p_dropout=p_dropout, linear_size=256)
# Extract list of pifpaf files in validation images # Extract list of pifpaf files in validation images
self.dir_gt = os.path.join('data', 'kitti', 'gt') self.dir_ann = args.dir_ann
self.dir_gt_new = os.path.join('data', 'kitti', 'gt_new') self.generate_official = args.generate_official
self.set_basename = factory_basename(dir_ann, self.dir_gt) assert os.listdir(self.dir_ann), "Annotation directory is empty"
self.dir_kk = os.path.join('data', 'kitti', 'calib') self.set_basename = factory_basename(args.dir_ann, self.dir_gt)
self.dir_byc = '/data/lorenzo-data/kitti/object_detection/left'
# For quick testing # For quick testing
# ------------------------------------------------------------------------------------------------------------ # ------------------------------------------------------------------------------------------------------------
@ -65,33 +59,48 @@ class GenerateKitti:
# self.set_basename = ('002282',) # self.set_basename = ('002282',)
# ------------------------------------------------------------------------------------------------------------ # ------------------------------------------------------------------------------------------------------------
# Calculate stereo baselines # Add monocular and stereo baselines (they require monoloco as backbone)
# self.baselines = ['pose', 'reid'] if args.baselines:
self.baselines = []
self.cnt_disparity = defaultdict(int) # Load MonoLoco
self.cnt_no_stereo = 0 self.baselines['mono'] = ['monoloco', 'geometric']
self.dir_images = os.path.join('data', 'kitti', 'images') self.monoloco = Loco(
self.dir_images_r = os.path.join('data', 'kitti', 'images_r') model=self.monoloco_checkpoint,
# ReID Baseline net='monoloco',
if 'reid' in self.baselines: device=device,
weights_path = 'data/models/reid_model_market.pkl' n_dropout=args.n_dropout,
self.reid_net = ReID(weights_path=weights_path, device=device, num_classes=751, height=256, width=128) p_dropout=args.dropout,
linear_size=256
)
# Stereo baselines
if args.net == 'monstereo':
self.baselines['stereo'] = ['pose', 'reid']
self.cnt_disparity = defaultdict(int)
self.cnt_no_stereo = 0
self.dir_images = os.path.join('data', 'kitti', 'images')
self.dir_images_r = os.path.join('data', 'kitti', 'images_r')
# ReID Baseline
weights_path = 'data/models/reid_model_market.pkl'
self.reid_net = ReID(weights_path=weights_path, device=device, num_classes=751, height=256, width=128)
def run(self): def run(self):
"""Run Monoloco and save txt files for KITTI evaluation""" """Run Monoloco and save txt files for KITTI evaluation"""
cnt_ann = cnt_file = cnt_no_file = 0 cnt_ann = cnt_file = cnt_no_file = 0
dir_out = {key: os.path.join('data', 'kitti', key) for key in self.METHODS}
print("\n")
for key in self.METHODS:
make_new_directory(dir_out[key])
for key in self.baselines: # Prepare empty folder
dir_out[key] = os.path.join('data', 'kitti', key) di = os.path.join('data', 'kitti', self.net)
make_new_directory(dir_out[key]) make_new_directory(di)
print("Created empty output directory for {}".format(key)) dir_out = {self.net: di}
# Run monoloco over the list of images for mode, names in self.baselines.items():
for name in names:
di = os.path.join('data', 'kitti', name)
make_new_directory(di)
dir_out[name] = di
# Run the model
for basename in self.set_basename: for basename in self.set_basename:
path_calib = os.path.join(self.dir_kk, basename + '.txt') path_calib = os.path.join(self.dir_kk, basename + '.txt')
annotations, kk, tt = factory_file(path_calib, self.dir_ann, basename) annotations, kk, tt = factory_file(path_calib, self.dir_ann, basename)
@ -101,58 +110,58 @@ class GenerateKitti:
annotations_r, _, _ = factory_file(path_calib, self.dir_ann, basename, mode='right') annotations_r, _, _ = factory_file(path_calib, self.dir_ann, basename, mode='right')
_, keypoints_r = preprocess_pifpaf(annotations_r, im_size=(1242, 374)) _, keypoints_r = preprocess_pifpaf(annotations_r, im_size=(1242, 374))
if self.net == 'monstereo':
dic_out = self.model.forward(keypoints, kk, keypoints_r=keypoints_r)
elif self.net == 'monoloco_pp':
dic_out = self.model.forward(keypoints, kk)
all_outputs = {self.net: [dic_out['xyzd'], dic_out['bi'], dic_out['epi'],
dic_out['yaw'], dic_out['h'], dic_out['w'], dic_out['l']]}
zzs = [float(el[2]) for el in dic_out['xyzd']]
# Save txt files
params = [kk, tt]
path_txt = os.path.join(dir_out[self.net], basename + '.txt')
save_txts(path_txt, boxes, all_outputs[self.net], params, mode=self.net, cat=cat)
cnt_ann += len(boxes) cnt_ann += len(boxes)
cnt_file += 1 cnt_file += 1
all_inputs, all_outputs = {}, {}
# STEREOLOCO # MONO (+ STEREO BASELINES)
dic_out = self.monstereo.forward(keypoints, kk, keypoints_r=keypoints_r) if self.baselines['mono']:
all_outputs['monstereo'] = [dic_out['xyzd'], dic_out['bi'], dic_out['epi'], # MONOLOCO
dic_out['yaw'], dic_out['h'], dic_out['w'], dic_out['l']]
# MONOLOCO++
if 'monoloco_pp' in self.METHODS:
dic_out = self.monoloco_pp.forward(keypoints, kk)
all_outputs['monoloco_pp'] = [dic_out['xyzd'], dic_out['bi'], dic_out['epi'],
dic_out['yaw'], dic_out['h'], dic_out['w'], dic_out['l']]
zzs = [float(el[2]) for el in dic_out['xyzd']]
# MONOLOCO
if 'monoloco' in self.METHODS:
dic_out = self.monoloco.forward(keypoints, kk) dic_out = self.monoloco.forward(keypoints, kk)
zzs_geom, xy_centers = geometric_coordinates(keypoints, kk, average_y=0.48) zzs_geom, xy_centers = geometric_coordinates(keypoints, kk, average_y=0.48)
all_outputs['monoloco'] = [dic_out['d'], dic_out['bi'], dic_out['epi']] + [zzs_geom, xy_centers] all_outputs['monoloco'] = [dic_out['d'], dic_out['bi'], dic_out['epi']] + [zzs_geom, xy_centers]
all_outputs['geometric'] = all_outputs['monoloco'] all_outputs['geometric'] = all_outputs['monoloco']
params = [kk, tt] # monocular baselines
for key in self.baselines['mono']:
path_txt = {key: os.path.join(dir_out[key], basename + '.txt')}
save_txts(path_txt[key], boxes, all_outputs[key], params, mode=key, cat=cat)
for key in self.METHODS: # stereo baselines
path_txt = {key: os.path.join(dir_out[key], basename + '.txt')} if self.baselines['stereo']:
save_txts(path_txt[key], boxes, all_outputs[key], params, mode=key, cat=cat) all_inputs = {}
dic_xyz = self._run_stereo_baselines(basename, boxes, keypoints, zzs, path_calib)
# STEREO BASELINES for key in dic_xyz:
if self.baselines: all_outputs[key] = all_outputs['monoloco'].copy()
dic_xyz = self._run_stereo_baselines(basename, boxes, keypoints, zzs, path_calib) all_outputs[key][0] = dic_xyz[key]
all_inputs[key] = boxes
for key in dic_xyz:
all_outputs[key] = all_outputs['monoloco'].copy()
all_outputs[key][0] = dic_xyz[key]
all_inputs[key] = boxes
path_txt[key] = os.path.join(dir_out[key], basename + '.txt') path_txt[key] = os.path.join(dir_out[key], basename + '.txt')
save_txts(path_txt[key], all_inputs[key], all_outputs[key], params, mode='baseline', cat=cat) save_txts(path_txt[key], all_inputs[key], all_outputs[key], params, mode='baseline', cat='cat')
print("\nSaved in {} txt {} annotations. Not found {} images".format(cnt_file, cnt_ann, cnt_no_file)) print("\nSaved in {} txt {} annotations. Not found {} images".format(cnt_file, cnt_ann, cnt_no_file))
if 'monstereo' in self.METHODS: if self.net == 'monstereo':
print("STEREO:") print("STEREO:")
for key in self.baselines: for key in self.baselines['stereo']:
print("Annotations corrected using {} baseline: {:.1f}%".format( print("Annotations corrected using {} baseline: {:.1f}%".format(
key, self.cnt_disparity[key] / cnt_ann * 100)) key, self.cnt_disparity[key] / cnt_ann * 100))
print("Maximum possible stereo associations: {:.1f}%".format(self.cnt_disparity['max'] / cnt_ann * 100))
print("Not found {}/{} stereo files".format(self.cnt_no_stereo, cnt_file)) print("Not found {}/{} stereo files".format(self.cnt_no_stereo, cnt_file))
create_empty_files(dir_out) # Create empty files for official evaluation if self.generate_official:
create_empty_files(dir_out, self.net) # Create empty files for official evaluation
def _run_stereo_baselines(self, basename, boxes, keypoints, zzs, path_calib): def _run_stereo_baselines(self, basename, boxes, keypoints, zzs, path_calib):
@ -247,11 +256,10 @@ def save_txts(path_txt, all_inputs, all_outputs, all_params, mode='monoloco', ca
ff.write("\n") ff.write("\n")
def create_empty_files(dir_out): def create_empty_files(dir_out, net):
"""Create empty txt files to run official kitti metrics on MonStereo and all other methods""" """Create empty txt files to run official kitti metrics on MonStereo and all other methods"""
methods = ['pseudo-lidar', 'monopsr', '3dop', 'm3d', 'oc-stereo', 'e2e'] methods = ['pseudo-lidar', 'monopsr', '3dop', 'm3d', 'oc-stereo', 'e2e', 'monodis', 'smoke']
methods = []
dirs = [os.path.join('data', 'kitti', method) for method in methods] dirs = [os.path.join('data', 'kitti', method) for method in methods]
dirs_orig = [os.path.join('data', 'kitti', method + '-orig') for method in methods] dirs_orig = [os.path.join('data', 'kitti', method + '-orig') for method in methods]
@ -266,8 +274,7 @@ def create_empty_files(dir_out):
# If the file exits, rewrite in new folder, otherwise create empty file # If the file exits, rewrite in new folder, otherwise create empty file
read_and_rewrite(path_orig, path) read_and_rewrite(path_orig, path)
for method in ('monoloco_pp', 'monstereo'): for i in range(7481):
for i in range(7481): name = "0" * (6 - len(str(i))) + str(i) + '.txt'
name = "0" * (6 - len(str(i))) + str(i) + '.txt' ff = open(os.path.join(dir_out[net], name), "a+")
ff = open(os.path.join(dir_out[method], name), "a+") ff.close()
ff.close()

View File

@ -70,7 +70,7 @@ def cli():
# Training # Training
training_parser.add_argument('--joints', help='Json file with input joints', training_parser.add_argument('--joints', help='Json file with input joints',
default='data/arrays/joints-nuscenes_teaser-190513-1846.json') default='data/arrays/joints-nuscenes_teaser-190513-1846.json')
training_parser.add_argument('--save', help='whether to not save model and log file', action='store_true') training_parser.add_argument('--no_save', help='to not save model and log file', action='store_true')
training_parser.add_argument('-e', '--epochs', type=int, help='number of epochs to train for', default=500) training_parser.add_argument('-e', '--epochs', type=int, help='number of epochs to train for', default=500)
training_parser.add_argument('--bs', type=int, default=512, help='input batch size') training_parser.add_argument('--bs', type=int, default=512, help='input batch size')
training_parser.add_argument('--monocular', help='whether to train monoloco', action='store_true') training_parser.add_argument('--monocular', help='whether to train monoloco', action='store_true')
@ -83,7 +83,9 @@ def cli():
training_parser.add_argument('--hyp', help='run hyperparameters tuning', action='store_true') training_parser.add_argument('--hyp', help='run hyperparameters tuning', action='store_true')
training_parser.add_argument('--multiplier', type=int, help='Size of the grid of hyp search', default=1) training_parser.add_argument('--multiplier', type=int, help='Size of the grid of hyp search', default=1)
training_parser.add_argument('--r_seed', type=int, help='specify the seed for training and hyp tuning', default=1) training_parser.add_argument('--r_seed', type=int, help='specify the seed for training and hyp tuning', default=1)
training_parser.add_argument('--activity', help='new', action='store_true') training_parser.add_argument('--print_loss', help='print training and validation losses', action='store_true')
training_parser.add_argument('--auto_tune_mtl', help='whether to use uncertainty to autotune losses',
action='store_true')
# Evaluation # Evaluation
eval_parser.add_argument('--dataset', help='datasets to evaluate, kitti or nuscenes', default='kitti') eval_parser.add_argument('--dataset', help='datasets to evaluate, kitti or nuscenes', default='kitti')
@ -104,6 +106,9 @@ def cli():
eval_parser.add_argument('--variance', help='evaluate keypoints variance', action='store_true') eval_parser.add_argument('--variance', help='evaluate keypoints variance', action='store_true')
eval_parser.add_argument('--activity', help='evaluate activities', action='store_true') eval_parser.add_argument('--activity', help='evaluate activities', action='store_true')
eval_parser.add_argument('--net', help='Choose network: monoloco, monoloco_p, monoloco_pp, monstereo') eval_parser.add_argument('--net', help='Choose network: monoloco, monoloco_p, monoloco_pp, monstereo')
eval_parser.add_argument('--baselines', help='whether to evaluate stereo baselines', action='store_true')
eval_parser.add_argument('--generate_official', help='whether to add empty txt files for official evaluation',
action='store_true')
args = parser.parse_args() args = parser.parse_args()
return args return args
@ -141,10 +146,7 @@ def main():
else: else:
from .train import Trainer from .train import Trainer
training = Trainer(joints=args.joints, epochs=args.epochs, bs=args.bs, training = Trainer(args)
monocular=args.monocular, dropout=args.dropout, lr=args.lr, sched_step=args.sched_step,
n_stage=args.n_stage, sched_gamma=args.sched_gamma, hidden_size=args.hidden_size,
r_seed=args.r_seed, save=args.save)
_ = training.train() _ = training.train()
_ = training.evaluate() _ = training.evaluate()
@ -171,8 +173,7 @@ def main():
else: else:
if args.generate: if args.generate:
from .eval.generate_kitti import GenerateKitti from .eval.generate_kitti import GenerateKitti
kitti_txt = GenerateKitti(args.model, args.dir_ann, p_dropout=args.dropout, n_dropout=args.n_dropout, kitti_txt = GenerateKitti(args)
hidden_size=args.hidden_size)
kitti_txt.run() kitti_txt.run()
if args.dataset == 'kitti': if args.dataset == 'kitti':
@ -183,7 +184,7 @@ def main():
elif 'nuscenes' in args.dataset: elif 'nuscenes' in args.dataset:
from .train import Trainer from .train import Trainer
training = Trainer(joints=args.joints, hidden_size=args.hidden_size) training = Trainer(args)
_ = training.evaluate(load=True, model=args.model, debug=False) _ = training.evaluate(load=True, model=args.model, debug=False)
else: else:

View File

@ -34,10 +34,9 @@ class Trainer:
tasks = ('d', 'x', 'y', 'h', 'w', 'l', 'ori', 'aux') tasks = ('d', 'x', 'y', 'h', 'w', 'l', 'ori', 'aux')
val_task = 'd' val_task = 'd'
lambdas = (1, 1, 1, 1, 1, 1, 1, 1) lambdas = (1, 1, 1, 1, 1, 1, 1, 1)
clusters = ['10', '20', '30', '40']
def __init__(self, joints, epochs=100, bs=256, dropout=0.2, lr=0.002, def __init__(self, args):
sched_step=20, sched_gamma=1, hidden_size=256, n_stage=3, r_seed=0, n_samples=100,
monocular=False, save=False, print_loss=True):
""" """
Initialize directories, load the data and parameters for the training Initialize directories, load the data and parameters for the training
""" """
@ -49,31 +48,29 @@ class Trainer:
dir_logs = os.path.join('data', 'logs') dir_logs = os.path.join('data', 'logs')
if not os.path.exists(dir_logs): if not os.path.exists(dir_logs):
warnings.warn("Warning: default logs directory not found") warnings.warn("Warning: default logs directory not found")
assert os.path.exists(joints), "Input file not found" assert os.path.exists(args.joints), "Input file not found"
self.joints = joints self.joints = args.joints
self.num_epochs = epochs self.num_epochs = args.epochs
self.save = save self.no_save = args.no_save
self.print_loss = print_loss self.print_loss = args.print_loss
self.monocular = monocular self.monocular = args.monocular
self.lr = lr self.lr = args.lr
self.sched_step = sched_step self.sched_step = args.sched_step
self.sched_gamma = sched_gamma self.sched_gamma = args.sched_gamma
self.clusters = ['10', '20', '30', '40'] self.hidden_size = args.hidden_size
self.hidden_size = hidden_size self.n_stage = args.n_stage
self.n_stage = n_stage
self.dir_out = dir_out self.dir_out = dir_out
self.n_samples = n_samples self.r_seed = args.r_seed
self.r_seed = r_seed self.auto_tune_mtl = args.auto_tune_mtl
self.auto_tune_mtl = False
# Select the device # Select the device
use_cuda = torch.cuda.is_available() use_cuda = torch.cuda.is_available()
self.device = torch.device("cuda" if use_cuda else "cpu") self.device = torch.device("cuda" if use_cuda else "cpu")
print('Device: ', self.device) print('Device: ', self.device)
torch.manual_seed(r_seed) torch.manual_seed(self.r_seed)
if use_cuda: if use_cuda:
torch.cuda.manual_seed(r_seed) torch.cuda.manual_seed(self.r_seed)
# Remove auxiliary task if monocular # Remove auxiliary task if monocular
if self.monocular and self.tasks[-1] == 'aux': if self.monocular and self.tasks[-1] == 'aux':
@ -95,25 +92,28 @@ class Trainer:
input_size = 34 input_size = 34
output_size = 9 output_size = 9
name = 'monoloco_pp' if self.monocular else 'monstereo'
now = datetime.datetime.now() now = datetime.datetime.now()
now_time = now.strftime("%Y%m%d-%H%M")[2:] now_time = now.strftime("%Y%m%d-%H%M")[2:]
name_out = 'monstereo-' + now_time name_out = name + '-' + now_time
if self.save: if not self.no_save:
self.path_model = os.path.join(dir_out, name_out + '.pkl') self.path_model = os.path.join(dir_out, name_out + '.pkl')
self.logger = set_logger(os.path.join(dir_logs, name_out)) self.logger = set_logger(os.path.join(dir_logs, name_out))
self.logger.info("Training arguments: \nepochs: {} \nbatch_size: {} \ndropout: {}" self.logger.info("Training arguments: \nepochs: {} \nbatch_size: {} \ndropout: {}"
"\nmonocular: {} \nlearning rate: {} \nscheduler step: {} \nscheduler gamma: {} " "\nmonocular: {} \nlearning rate: {} \nscheduler step: {} \nscheduler gamma: {} "
"\ninput_size: {} \noutput_size: {}\nhidden_size: {} \nn_stages: {} " "\ninput_size: {} \noutput_size: {}\nhidden_size: {} \nn_stages: {} "
"\nr_seed: {} \nlambdas: {} \ninput_file: {}" "\nr_seed: {} \nlambdas: {} \ninput_file: {}"
.format(epochs, bs, dropout, self.monocular, lr, sched_step, sched_gamma, input_size, .format(args.epochs, args.bs, args.dropout, self.monocular,
output_size, hidden_size, n_stage, r_seed, self.lambdas, self.joints)) args.lr, args.sched_step, args.sched_gamma, input_size,
output_size, args.hidden_size, args.n_stage, args.r_seed,
self.lambdas, self.joints))
else: else:
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
# Dataloader # Dataloader
self.dataloaders = {phase: DataLoader(KeypointsDataset(self.joints, phase=phase), self.dataloaders = {phase: DataLoader(KeypointsDataset(self.joints, phase=phase),
batch_size=bs, shuffle=True) for phase in ['train', 'val']} batch_size=args.bs, shuffle=True) for phase in ['train', 'val']}
self.dataset_sizes = {phase: len(KeypointsDataset(self.joints, phase=phase)) self.dataset_sizes = {phase: len(KeypointsDataset(self.joints, phase=phase))
for phase in ['train', 'val']} for phase in ['train', 'val']}
@ -122,15 +122,15 @@ class Trainer:
self.logger.info('Sizes of the dataset: {}'.format(self.dataset_sizes)) self.logger.info('Sizes of the dataset: {}'.format(self.dataset_sizes))
print(">>> creating model") print(">>> creating model")
self.model = MonStereoModel(input_size=input_size, output_size=output_size, linear_size=hidden_size, self.model = MonStereoModel(input_size=input_size, output_size=output_size, linear_size=args.hidden_size,
p_dropout=dropout, num_stage=self.n_stage, device=self.device) p_dropout=args.dropout, num_stage=self.n_stage, device=self.device)
self.model.to(self.device) self.model.to(self.device)
print(">>> model params: {:.3f}M".format(sum(p.numel() for p in self.model.parameters()) / 1000000.0)) print(">>> model params: {:.3f}M".format(sum(p.numel() for p in self.model.parameters()) / 1000000.0))
print(">>> loss params: {}".format(sum(p.numel() for p in self.mt_loss.parameters()))) print(">>> loss params: {}".format(sum(p.numel() for p in self.mt_loss.parameters())))
# Optimizer and scheduler # Optimizer and scheduler
all_params = chain(self.model.parameters(), self.mt_loss.parameters()) all_params = chain(self.model.parameters(), self.mt_loss.parameters())
self.optimizer = torch.optim.Adam(params=all_params, lr=lr) self.optimizer = torch.optim.Adam(params=all_params, lr=args.lr)
self.scheduler = lr_scheduler.ReduceLROnPlateau(self.optimizer, 'min') self.scheduler = lr_scheduler.ReduceLROnPlateau(self.optimizer, 'min')
self.scheduler = lr_scheduler.StepLR(self.optimizer, step_size=self.sched_step, gamma=self.sched_gamma) self.scheduler = lr_scheduler.StepLR(self.optimizer, step_size=self.sched_step, gamma=self.sched_gamma)
@ -243,7 +243,7 @@ class Trainer:
self.cout_stats(dic_err['val'], size_eval, clst=clst) self.cout_stats(dic_err['val'], size_eval, clst=clst)
# Save the model and the results # Save the model and the results
if self.save and not load: if not (self.no_save or load):
torch.save(self.model.state_dict(), self.path_model) torch.save(self.model.state_dict(), self.path_model)
print('-' * 120) print('-' * 120)
self.logger.info("\nmodel saved: {} \n".format(self.path_model)) self.logger.info("\nmodel saved: {} \n".format(self.path_model))
@ -265,7 +265,6 @@ class Trainer:
# Distance # Distance
errs = torch.abs(extract_outputs(outputs)['d'] - extract_labels(labels)['d']) errs = torch.abs(extract_outputs(outputs)['d'] - extract_labels(labels)['d'])
assert rel_frac > 0.99, "Variance of errors not supported with partial evaluation" assert rel_frac > 0.99, "Variance of errors not supported with partial evaluation"
# Uncertainty # Uncertainty

View File

@ -58,7 +58,7 @@ def make_new_directory(dir_out):
if os.path.exists(dir_out): if os.path.exists(dir_out):
shutil.rmtree(dir_out) shutil.rmtree(dir_out)
os.makedirs(dir_out) os.makedirs(dir_out)
print("Created empty output directory for {} txt files".format(dir_out)) print("Created empty output directory {} ".format(dir_out))
def normalize_hwl(lab): def normalize_hwl(lab):