はじめに
前回は、複数枚の画像から動作認識ができる 3D-ResNets-PyTorch の学習について説明しました。
今回は、推論プログラムを作成していきます。
github はこちらです。
前提条件
前提条件は以下の通りです。
- Python3.9
- torch == 1.13.0+cu117, torchvision == 0.14.0+cu117
- 作業は WSL2 で実施します
推論プログラムの準備
まずは main.py, inference.py をコピーして main_inference.py, inference_custom.py とします。
main_inference.py の main_worker及びメイン部分
def main_worker(index, opt):
random.seed(opt.manual_seed)
np.random.seed(opt.manual_seed)
torch.manual_seed(opt.manual_seed)
model = generate_model(opt)
model = resume_model(opt.resume_path, opt.arch, model)
model = make_data_parallel(model, opt.distributed, opt.device)
if opt.inference:
inference_loader, inference_class_names = get_inference_utils(opt)
inference_result_path = opt.result_path / '{}.json'.format(
opt.inference_subset)
inference_custom.inference(inference_loader, model, inference_result_path,
inference_class_names, opt.inference_no_average,
opt.output_topk)
if __name__ == '__main__':
opt = get_opt()
main_worker(-1, opt)
main_inference.py の get_opt 関数
def get_opt():
opt = parse_opts()
opt.mean, opt.std = get_mean_std(opt.value_scale, dataset=opt.mean_dataset)
opt.n_input_channels = 3
opt.resume_path = "./results/save_200.pth"
opt.root_path = "./"
opt.device = torch.device('cpu' if opt.no_cuda else 'cuda')
if not opt.no_cuda:
cudnn.benchmark = True
opt.video_path = Path("../UCF101_images/UCF101")
opt.annotation_path = Path("../UCF101_json/ucf101_01.json")
opt.result_path = Path("./results")
opt.dataset = "ucf101"
opt.no_train = True
opt.no_val = True
opt.inference = True
opt.output_topk = 1
opt.inference_batch_size = 1
opt.n_threads = 4
opt.n_classes = 10
opt.model_depth = 50
opt.arch = '{}-{}'.format(opt.model, opt.model_depth)
# print(opt)
with (opt.result_path / 'opts.json').open('w') as opt_file:
json.dump(vars(opt), opt_file, default=json_serial)
return opt
inference_custom.py
import time
import json
from collections import defaultdict
import torch
import torch.nn.functional as F
from utils import AverageMeter
def get_video_results(outputs, class_names, output_topk):
sorted_scores, locs = torch.topk(outputs,
k=min(output_topk, len(class_names)))
video_results = []
for i in range(sorted_scores.size(0)):
video_results.append({
'label': class_names[locs[i].item()],
'score': sorted_scores[i].item()
})
return video_results
def inference(data_loader, model, result_path, class_names, no_average,
output_topk):
print('inference')
model.eval()
batch_time = AverageMeter()
data_time = AverageMeter()
results = {'results': defaultdict(list)}
end_time = time.time()
result_list = []
with torch.no_grad():
for i, (inputs, targets) in enumerate(data_loader):
data_time.update(time.time() - end_time)
video_ids, segments = zip(*targets)
outputs = model(inputs)
outputs = F.softmax(outputs, dim=1).cpu()
for j in range(outputs.size(0)):
results['results'][video_ids[j]].append({
'segment': segments[j],
'output': outputs[j]
})
sorted_scores, locs = torch.topk(torch.mean(outputs, dim=0),
k=min(output_topk, len(class_names)))
result_list.append([sorted_scores.item(), locs.item()])
for r in result_list:
print(r)
batch_time.update(time.time() - end_time)
end_time = time.time()
print('[{}/{}]\t'
'Time {batch_time.val:.3f} ({batch_time.avg:.3f})\t'
'Data {data_time.val:.3f} ({data_time.avg:.3f})\t'.format(
i + 1,
len(data_loader),
batch_time=batch_time,
data_time=data_time))
inference_results = {'results': {}}
if not no_average:
for video_id, video_results in results['results'].items():
video_outputs = [
segment_result['output'] for segment_result in video_results
]
video_outputs = torch.stack(video_outputs)
average_scores = torch.mean(video_outputs, dim=0)
inference_results['results'][video_id] = get_video_results(
average_scores, class_names, output_topk)
with result_path.open('w') as f:
json.dump(inference_results, f)
上記のように変更してください。
推論の実行
以下のコマンドで推論を実行できます。
python3 main_inference.py
以下のように結果が出力されます。
inference
[[0.8918947577476501, 1]]
[1/389] Time 2.642 (2.642) Data 0.383 (0.383)
[[0.8918947577476501, 1], [0.8710216879844666, 1]]
[2/389] Time 0.404 (1.523) Data 0.000 (0.191)
[[0.8918947577476501, 1], [0.8710216879844666, 1], [0.8302087783813477, 1]]
[3/389] Time 0.651 (1.232) Data 0.000 (0.128)
[[0.8918947577476501, 1], [0.8710216879844666, 1], [0.8302087783813477, 1], [0.7876328825950623, 1]]
[4/389] Time 0.616 (1.078) Data 0.000 (0.096)
[[0.8918947577476501, 1], [0.8710216879844666, 1], [0.8302087783813477, 1], [0.7876328825950623, 1], [0.7425323724746704, 1]]
データローダーから 1イテレータ読み出すごとに、動画の分類とスコアが出力されるようになりました。
1イテレータ毎なので、時間変化を追わないといけないのですが、この辺はデータローダーを解析してからにします。
おわりに
今回はここまでとします。
次回は、データローダの出力内容を確認しながら、動画の分類結果を確認していけたらと思います。
コメント