Initial snapshot: hand motion pipeline (Dyn-HaMR + dex-retargeting + SPIDER)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
# Copyright (c) OpenMMLab. All rights reserved.
|
||||
import argparse
|
||||
import json
|
||||
from collections import defaultdict
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import seaborn as sns
|
||||
|
||||
|
||||
def cal_train_time(log_dicts, args):
|
||||
for i, log_dict in enumerate(log_dicts):
|
||||
print(f'{"-" * 5}Analyze train time of {args.json_logs[i]}{"-" * 5}')
|
||||
all_times = []
|
||||
for epoch in log_dict.keys():
|
||||
if args.include_outliers:
|
||||
all_times.append(log_dict[epoch]['time'])
|
||||
else:
|
||||
all_times.append(log_dict[epoch]['time'][1:])
|
||||
all_times = np.array(all_times)
|
||||
epoch_ave_time = all_times.mean(-1)
|
||||
slowest_epoch = epoch_ave_time.argmax()
|
||||
fastest_epoch = epoch_ave_time.argmin()
|
||||
std_over_epoch = epoch_ave_time.std()
|
||||
print(f'slowest epoch {slowest_epoch + 1}, '
|
||||
f'average time is {epoch_ave_time[slowest_epoch]:.4f}')
|
||||
print(f'fastest epoch {fastest_epoch + 1}, '
|
||||
f'average time is {epoch_ave_time[fastest_epoch]:.4f}')
|
||||
print(f'time std over epochs is {std_over_epoch:.4f}')
|
||||
print(f'average iter time: {np.mean(all_times):.4f} s/iter')
|
||||
print()
|
||||
|
||||
|
||||
def plot_curve(log_dicts, args):
|
||||
if args.backend is not None:
|
||||
plt.switch_backend(args.backend)
|
||||
sns.set_style(args.style)
|
||||
# if legend is None, use {filename}_{key} as legend
|
||||
legend = args.legend
|
||||
if legend is None:
|
||||
legend = []
|
||||
for json_log in args.json_logs:
|
||||
for metric in args.keys:
|
||||
legend.append(f'{json_log}_{metric}')
|
||||
assert len(legend) == (len(args.json_logs) * len(args.keys))
|
||||
metrics = args.keys
|
||||
|
||||
num_metrics = len(metrics)
|
||||
for i, log_dict in enumerate(log_dicts):
|
||||
epochs = list(log_dict.keys())
|
||||
for j, metric in enumerate(metrics):
|
||||
print(f'plot curve of {args.json_logs[i]}, metric is {metric}')
|
||||
if metric not in log_dict[epochs[0]]:
|
||||
raise KeyError(
|
||||
f'{args.json_logs[i]} does not contain metric {metric}')
|
||||
xs = []
|
||||
ys = []
|
||||
num_iters_per_epoch = log_dict[epochs[0]]['iter'][-1]
|
||||
for epoch in epochs:
|
||||
iters = log_dict[epoch]['iter']
|
||||
if log_dict[epoch]['mode'][-1] == 'val':
|
||||
iters = iters[:-1]
|
||||
xs.append(np.array(iters) + (epoch - 1) * num_iters_per_epoch)
|
||||
ys.append(np.array(log_dict[epoch][metric][:len(iters)]))
|
||||
xs = np.concatenate(xs)
|
||||
ys = np.concatenate(ys)
|
||||
plt.xlabel('iter')
|
||||
plt.plot(xs, ys, label=legend[i * num_metrics + j], linewidth=0.5)
|
||||
plt.legend()
|
||||
if args.title is not None:
|
||||
plt.title(args.title)
|
||||
if args.out is None:
|
||||
plt.show()
|
||||
else:
|
||||
print(f'save curve to: {args.out}')
|
||||
plt.savefig(args.out)
|
||||
plt.cla()
|
||||
|
||||
|
||||
def add_plot_parser(subparsers):
|
||||
parser_plt = subparsers.add_parser(
|
||||
'plot_curve', help='parser for plotting curves')
|
||||
parser_plt.add_argument(
|
||||
'json_logs',
|
||||
type=str,
|
||||
nargs='+',
|
||||
help='path of train log in json format')
|
||||
parser_plt.add_argument(
|
||||
'--keys',
|
||||
type=str,
|
||||
nargs='+',
|
||||
default=['top1_acc'],
|
||||
help='the metric that you want to plot')
|
||||
parser_plt.add_argument('--title', type=str, help='title of figure')
|
||||
parser_plt.add_argument(
|
||||
'--legend',
|
||||
type=str,
|
||||
nargs='+',
|
||||
default=None,
|
||||
help='legend of each plot')
|
||||
parser_plt.add_argument(
|
||||
'--backend', type=str, default=None, help='backend of plt')
|
||||
parser_plt.add_argument(
|
||||
'--style', type=str, default='dark', help='style of plt')
|
||||
parser_plt.add_argument('--out', type=str, default=None)
|
||||
|
||||
|
||||
def add_time_parser(subparsers):
|
||||
parser_time = subparsers.add_parser(
|
||||
'cal_train_time',
|
||||
help='parser for computing the average time per training iteration')
|
||||
parser_time.add_argument(
|
||||
'json_logs',
|
||||
type=str,
|
||||
nargs='+',
|
||||
help='path of train log in json format')
|
||||
parser_time.add_argument(
|
||||
'--include-outliers',
|
||||
action='store_true',
|
||||
help='include the first value of every epoch when computing '
|
||||
'the average time')
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description='Analyze Json Log')
|
||||
# currently only support plot curve and calculate average train time
|
||||
subparsers = parser.add_subparsers(dest='task', help='task parser')
|
||||
add_plot_parser(subparsers)
|
||||
add_time_parser(subparsers)
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def load_json_logs(json_logs):
|
||||
# load and convert json_logs to log_dict, key is epoch, value is a sub dict
|
||||
# keys of sub dict is different metrics, e.g. memory, top1_acc
|
||||
# value of sub dict is a list of corresponding values of all iterations
|
||||
log_dicts = [dict() for _ in json_logs]
|
||||
for json_log, log_dict in zip(json_logs, log_dicts):
|
||||
with open(json_log, 'r') as log_file:
|
||||
for line in log_file:
|
||||
log = json.loads(line.strip())
|
||||
# skip lines without `epoch` field
|
||||
if 'epoch' not in log:
|
||||
continue
|
||||
epoch = log.pop('epoch')
|
||||
if epoch not in log_dict:
|
||||
log_dict[epoch] = defaultdict(list)
|
||||
for k, v in log.items():
|
||||
log_dict[epoch][k].append(v)
|
||||
return log_dicts
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
json_logs = args.json_logs
|
||||
for json_log in json_logs:
|
||||
assert json_log.endswith('.json')
|
||||
|
||||
log_dicts = load_json_logs(json_logs)
|
||||
|
||||
eval(args.task)(log_dicts, args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) OpenMMLab. All rights reserved.
|
||||
import argparse
|
||||
import time
|
||||
|
||||
import torch
|
||||
from mmcv import Config
|
||||
from mmcv.cnn import fuse_conv_bn
|
||||
from mmcv.parallel import MMDataParallel
|
||||
from mmcv.runner.fp16_utils import wrap_fp16_model
|
||||
|
||||
from mmpose.datasets import build_dataloader, build_dataset
|
||||
from mmpose.models import build_posenet
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='MMPose benchmark a recognizer')
|
||||
parser.add_argument('config', help='test config file path')
|
||||
parser.add_argument(
|
||||
'--log-interval', default=10, help='interval of logging')
|
||||
parser.add_argument(
|
||||
'--fuse-conv-bn',
|
||||
action='store_true',
|
||||
help='Whether to fuse conv and bn, this will slightly increase'
|
||||
'the inference speed')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
cfg = Config.fromfile(args.config)
|
||||
# set cudnn_benchmark
|
||||
if cfg.get('cudnn_benchmark', False):
|
||||
torch.backends.cudnn.benchmark = True
|
||||
|
||||
# build the dataloader
|
||||
dataset = build_dataset(cfg.data.val)
|
||||
data_loader = build_dataloader(
|
||||
dataset,
|
||||
samples_per_gpu=1,
|
||||
workers_per_gpu=cfg.data.workers_per_gpu,
|
||||
dist=False,
|
||||
shuffle=False)
|
||||
|
||||
# build the model and load checkpoint
|
||||
model = build_posenet(cfg.model)
|
||||
fp16_cfg = cfg.get('fp16', None)
|
||||
if fp16_cfg is not None:
|
||||
wrap_fp16_model(model)
|
||||
if args.fuse_conv_bn:
|
||||
model = fuse_conv_bn(model)
|
||||
model = MMDataParallel(model, device_ids=[0])
|
||||
|
||||
# the first several iterations may be very slow so skip them
|
||||
num_warmup = 5
|
||||
pure_inf_time = 0
|
||||
|
||||
# benchmark with total batch and take the average
|
||||
for i, data in enumerate(data_loader):
|
||||
|
||||
torch.cuda.synchronize()
|
||||
start_time = time.perf_counter()
|
||||
with torch.no_grad():
|
||||
model(return_loss=False, **data)
|
||||
|
||||
torch.cuda.synchronize()
|
||||
elapsed = time.perf_counter() - start_time
|
||||
|
||||
if i >= num_warmup:
|
||||
pure_inf_time += elapsed
|
||||
if (i + 1) % args.log_interval == 0:
|
||||
its = (i + 1 - num_warmup) / pure_inf_time
|
||||
print(f'Done item [{i + 1:<3}], {its:.2f} items / s')
|
||||
print(f'Overall average: {its:.2f} items / s')
|
||||
print(f'Total time: {pure_inf_time:.2f} s')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) OpenMMLab. All rights reserved.
|
||||
"""This file is for benchmark data loading process. It can also be used to
|
||||
refresh the memcached cache. The command line to run this file is:
|
||||
|
||||
$ python -m cProfile -o program.prof tools/analysis/benchmark_processing.py
|
||||
configs/task/method/[config filename]
|
||||
|
||||
Note: When debugging, the `workers_per_gpu` in the config should be set to 0
|
||||
during benchmark.
|
||||
|
||||
It use cProfile to record cpu running time and output to program.prof
|
||||
To visualize cProfile output program.prof, use Snakeviz and run:
|
||||
$ snakeviz program.prof
|
||||
"""
|
||||
import argparse
|
||||
|
||||
import mmcv
|
||||
from mmcv import Config
|
||||
|
||||
from mmpose import __version__
|
||||
from mmpose.datasets import build_dataloader, build_dataset
|
||||
from mmpose.utils import get_root_logger
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Benchmark data loading')
|
||||
parser.add_argument('config', help='train config file path')
|
||||
args = parser.parse_args()
|
||||
cfg = Config.fromfile(args.config)
|
||||
|
||||
# init logger before other steps
|
||||
logger = get_root_logger()
|
||||
logger.info(f'MMPose Version: {__version__}')
|
||||
logger.info(f'Config: {cfg.text}')
|
||||
|
||||
dataset = build_dataset(cfg.data.train)
|
||||
data_loader = build_dataloader(
|
||||
dataset,
|
||||
samples_per_gpu=1,
|
||||
workers_per_gpu=cfg.data.workers_per_gpu,
|
||||
dist=False,
|
||||
shuffle=False)
|
||||
|
||||
# Start progress bar after first 5 batches
|
||||
prog_bar = mmcv.ProgressBar(
|
||||
len(dataset) - 5 * cfg.data.samples_per_gpu, start=False)
|
||||
for i, data in enumerate(data_loader):
|
||||
if i == 5:
|
||||
prog_bar.start()
|
||||
for _ in data['img']:
|
||||
if i < 5:
|
||||
continue
|
||||
prog_bar.update()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,103 @@
|
||||
# Copyright (c) OpenMMLab. All rights reserved.
|
||||
import argparse
|
||||
from functools import partial
|
||||
|
||||
import torch
|
||||
|
||||
from mmpose.apis.inference import init_pose_model
|
||||
|
||||
try:
|
||||
from mmcv.cnn import get_model_complexity_info
|
||||
except ImportError:
|
||||
raise ImportError('Please upgrade mmcv to >0.6.2')
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description='Train a recognizer')
|
||||
parser.add_argument('config', help='train config file path')
|
||||
parser.add_argument(
|
||||
'--shape',
|
||||
type=int,
|
||||
nargs='+',
|
||||
default=[256, 192],
|
||||
help='input image size')
|
||||
parser.add_argument(
|
||||
'--input-constructor',
|
||||
'-c',
|
||||
type=str,
|
||||
choices=['none', 'batch'],
|
||||
default='none',
|
||||
help='If specified, it takes a callable method that generates '
|
||||
'input. Otherwise, it will generate a random tensor with '
|
||||
'input shape to calculate FLOPs.')
|
||||
parser.add_argument(
|
||||
'--batch-size', '-b', type=int, default=1, help='input batch size')
|
||||
parser.add_argument(
|
||||
'--not-print-per-layer-stat',
|
||||
'-n',
|
||||
action='store_true',
|
||||
help='Whether to print complexity information'
|
||||
'for each layer in a model')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def batch_constructor(flops_model, batch_size, input_shape):
|
||||
"""Generate a batch of tensors to the model."""
|
||||
batch = {}
|
||||
|
||||
img = torch.ones(()).new_empty(
|
||||
(batch_size, *input_shape),
|
||||
dtype=next(flops_model.parameters()).dtype,
|
||||
device=next(flops_model.parameters()).device)
|
||||
|
||||
batch['img'] = img
|
||||
return batch
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
args = parse_args()
|
||||
|
||||
if len(args.shape) == 1:
|
||||
input_shape = (3, args.shape[0], args.shape[0])
|
||||
elif len(args.shape) == 2:
|
||||
input_shape = (3, ) + tuple(args.shape)
|
||||
else:
|
||||
raise ValueError('invalid input shape')
|
||||
|
||||
model = init_pose_model(args.config)
|
||||
|
||||
if args.input_constructor == 'batch':
|
||||
input_constructor = partial(batch_constructor, model, args.batch_size)
|
||||
else:
|
||||
input_constructor = None
|
||||
|
||||
if args.input_constructor == 'batch':
|
||||
input_constructor = partial(batch_constructor, model, args.batch_size)
|
||||
else:
|
||||
input_constructor = None
|
||||
|
||||
if hasattr(model, 'forward_dummy'):
|
||||
model.forward = model.forward_dummy
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
'FLOPs counter is currently not currently supported with {}'.
|
||||
format(model.__class__.__name__))
|
||||
|
||||
flops, params = get_model_complexity_info(
|
||||
model,
|
||||
input_shape,
|
||||
input_constructor=input_constructor,
|
||||
print_per_layer_stat=(not args.not_print_per_layer_stat))
|
||||
split_line = '=' * 30
|
||||
input_shape = (args.batch_size, ) + input_shape
|
||||
print(f'{split_line}\nInput shape: {input_shape}\n'
|
||||
f'Flops: {flops}\nParams: {params}\n{split_line}')
|
||||
print('!!!Please be cautious if you use the results in papers. '
|
||||
'You may need to check if all ops are supported and verify that the '
|
||||
'flops computation is correct.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,27 @@
|
||||
# Copyright (c) OpenMMLab. All rights reserved.
|
||||
import argparse
|
||||
|
||||
from mmcv import Config, DictAction
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description='Print the whole config')
|
||||
parser.add_argument('config', help='config file path')
|
||||
parser.add_argument(
|
||||
'--options', nargs='+', action=DictAction, help='arguments in dict')
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
cfg = Config.fromfile(args.config)
|
||||
if args.options is not None:
|
||||
cfg.merge_from_dict(args.options)
|
||||
print(f'Config:\n{cfg.pretty_text}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) OpenMMLab. All rights reserved.
|
||||
import argparse
|
||||
import time
|
||||
|
||||
import torch
|
||||
from mmcv import Config
|
||||
from mmcv.cnn import fuse_conv_bn
|
||||
from mmcv.parallel import MMDataParallel
|
||||
from mmcv.runner.fp16_utils import wrap_fp16_model
|
||||
|
||||
from mmpose.datasets import build_dataloader, build_dataset
|
||||
from mmpose.models import build_posenet
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='MMPose benchmark a recognizer')
|
||||
parser.add_argument('config', help='test config file path')
|
||||
parser.add_argument('--bz', default=32, type=int, help='test config file path')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
cfg = Config.fromfile(args.config)
|
||||
|
||||
# Since we only care about the forward speed of the network
|
||||
cfg.model.pretrained=None
|
||||
cfg.model.test_cfg.flip_test=False
|
||||
cfg.model.test_cfg.use_udp=False
|
||||
cfg.model.test_cfg.post_process='none'
|
||||
|
||||
# set cudnn_benchmark
|
||||
if cfg.get('cudnn_benchmark', False):
|
||||
torch.backends.cudnn.benchmark = True
|
||||
|
||||
# build the dataloader
|
||||
dataset = build_dataset(cfg.data.val)
|
||||
data_loader = build_dataloader(
|
||||
dataset,
|
||||
samples_per_gpu=args.bz,
|
||||
workers_per_gpu=cfg.data.workers_per_gpu,
|
||||
dist=False,
|
||||
shuffle=False)
|
||||
|
||||
# build the model and load checkpoint
|
||||
model = build_posenet(cfg.model)
|
||||
model = MMDataParallel(model, device_ids=[0])
|
||||
model.eval()
|
||||
|
||||
# get the example data
|
||||
for i, data in enumerate(data_loader):
|
||||
break
|
||||
|
||||
# the first several iterations may be very slow so skip them
|
||||
num_warmup = 100
|
||||
inference_times = 100
|
||||
|
||||
with torch.no_grad():
|
||||
start_time = time.perf_counter()
|
||||
|
||||
for i in range(num_warmup):
|
||||
torch.cuda.synchronize()
|
||||
model(return_loss=False, **data)
|
||||
torch.cuda.synchronize()
|
||||
|
||||
elapsed = time.perf_counter() - start_time
|
||||
print(f'warmup cost {elapsed} time')
|
||||
|
||||
start_time = time.perf_counter()
|
||||
|
||||
for i in range(inference_times):
|
||||
torch.cuda.synchronize()
|
||||
model(return_loss=False, **data)
|
||||
torch.cuda.synchronize()
|
||||
|
||||
elapsed = time.perf_counter() - start_time
|
||||
fps = args.bz * inference_times / elapsed
|
||||
print(f'the fps is {fps}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user