複数枚の画像から動作認識できる 3D-ResNets-PyTorch -2-【Python】

スポンサーリンク

スポンサーリンク

はじめに

前回は、複数枚の画像から動作認識ができる 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イテレータ毎なので、時間変化を追わないといけないのですが、この辺はデータローダーを解析してからにします。

おわりに

今回はここまでとします。

次回は、データローダの出力内容を確認しながら、動画の分類結果を確認していけたらと思います。

コメント

タイトルとURLをコピーしました