みらいテックラボ

音声・画像認識や機械学習など, 週末プログラマである管理人が興味のある技術の紹介や実際にトライしてみた様子などメモしていく.

最近の物体検知を試してみる(YOLOX編①)

最近, YOLOv5, YOLOXやDetectron2などを少し触る機会があったので, YOLOv5に続き今回はYOLOXについて少しまとめておく.


1. インストール[1]
以前使っていたYOLOv3では, Darknetと呼ばる機械学習フレームワークが使われていて, 使うにはソースコードのビルドから始める必要があった.
しかし, YOLOXは前回紹介したYOLOv5同様にPyTorchベースとなっており, 導入は至って簡単になっていた.

git clone https://github.com/Megvii-BaseDetection/YOLOX
cd YOLOX
pip3 install -v -e . 

また, 学習済みモデルはGitHubのBencmarkの各モデルのweightsからダウンロードできる.


2. 推論
2.1 まずは動かす[1]
YOLOX/toolsにある demo.py を使うことで簡単に試すことができる.
demo.pyの主な使い方:

usage: YOLOX Demo! [-h] [-expn EXPERIMENT_NAME] [-n NAME] [--path PATH]
                   [--camid CAMID] [--save_result] [-f EXP_FILE] [-c CKPT]
                   [--device DEVICE] [--conf CONF] [--nms NMS] [--tsize TSIZE]
                   [--fp16] [--legacy] [--fuse] [--trt]
                   demo

positional arguments:
  demo                  demo type, eg. image, video and webcam

optional arguments:
  -h, --help            show this help message and exit
  -expn EXPERIMENT_NAME, --experiment-name EXPERIMENT_NAME
  -n NAME, --name NAME  model name
  --path PATH           path to images or video
  --camid CAMID         webcam demo camera id
  --save_result         whether to save the inference result of image/video
  -f EXP_FILE, --exp_file EXP_FILE
                        please input your experiment description file
  -c CKPT, --ckpt CKPT  ckpt for eval
  --device DEVICE       device to run our model, can either be cpu or gpu
  --conf CONF           test conf
  --nms NMS             test nms threshold
  --tsize TSIZE         test img size
  --fp16                Adopting mix precision evaluating.
  --legacy              To be compatible with older versions
  --fuse                Fuse conv and bn for testing.
  --trt                 Using TensorRT model for testing.

実際に, asset/dog.jpgに対して試してみる.

$ python tools/demo.py image -n yolox-m -c weights/yolox_m.pth --path assets/dog.jpg --conf 0.25 --nms 0.45 --tsize 640 --save_result --device gpu
2022-08-06 18:12:19.988 | INFO     | __main__:main:259 - Args: Namespace(camid=0, ckpt='weights/yolox_m.pth', conf=0.25, demo='image', device='gpu', exp_file=None, experiment_name='yolox_m', fp16=False, fuse=False, legacy=False, name='yolox-m', nms=0.45, path='assets/dog.jpg', save_result=True, trt=False, tsize=640)
2022-08-06 18:12:20.338 | INFO     | __main__:main:269 - Model Summary: Params: 25.33M, Gflops: 73.76
2022-08-06 18:12:23.475 | INFO     | __main__:main:282 - loading checkpoint
2022-08-06 18:12:23.634 | INFO     | __main__:main:286 - loaded checkpoint done.
2022-08-06 18:12:23.689 | INFO     | __main__:inference:165 - Infer time: 0.0458s
2022-08-06 18:12:23.690 | INFO     | __main__:image_demo:202 - Saving detection result in ./YOLOX_outputs/yolox_m/vis_res/2022_08_06_18_12_23/dog.jpg

実行結果は, YOLOX_outputs/yolox_m/vis_res/<実行日時>の下に保存される.
[実行結果]

このdemo.pyは, videoファイルやWebCamに対応しているので, ちょっとYOLOXを試すには便利である.
また, videoファイルやWebCamの場合に, 結果をファイルではなく画面表示にしたい場合, --save_resultオプションをはずせばよいようである.


2.2 プログラムに組み込む
hubconf.pyをみるとtorch.hub.load()でモデル読み込みできそうである.
以下のようなコードで少し試してみたが, モデルから返されるものが何を表しているのか, まだ理解できていない.
tools/demo.pyのコード内でも, モデルからの戻り値をdecoderやpostprocessといった処理で最終的な結果を求めるいるようなので, そのあたりのコードを読むのが早いかも...

[コード]

from PIL import Image

import torch
from torchvision import transforms

model = torch.hub.load('Megvii-BaseDetection/YOLOX', 'yolox_m')
model.eval()

size = 640
mean = (0.485, 0.456, 0.406)
std = (0.229, 0.224, 0.225)

transform = transforms.Compose([
    transforms.Resize((size, size)),
    transforms.ToTensor(),
    transforms.Normalize(mean, std)
])

# Images
path = './assets/dog.jpg'

img = Image.open(path)
img = transform(img)
img = img.unsqueeze(0)
print(img.size())
img = img.cuda()
# Inference
outputs = model(img)
print(len(outputs[0]))
for i, o in enumerate(outputs[0]):
    print(o)
    if i > 5:
        break

[実行結果]

$ python test.py 
Using cache found in /home/aska/.cache/torch/hub/Megvii-BaseDetection_YOLOX_main
torch.Size([1, 3, 640, 640])
8400
tensor([7.6943e+00, 9.3128e+00, 1.2603e+01, 1.2553e+01, 7.9179e-06, 1.0559e-01,
        1.7156e-03, 1.7036e-03, 6.0711e-04, 1.5599e-03, 7.1275e-04, 1.8696e-03,
        1.4855e-03, 6.7176e-04, 5.1386e-02, 1.9798e-03, 1.8498e-02, 3.0284e-03,
        3.7629e-03, 6.7058e-03, 2.8468e-03, 3.4253e-03, 4.2198e-03, 5.8339e-04,
        3.2932e-03, 1.8269e-03, 1.8186e-03, 5.0404e-04, 1.7456e-03, 5.2425e-03,
        7.6647e-03, 5.1070e-03, 9.7925e-03, 3.3584e-03, 5.3853e-03, 1.1997e-03,
        5.0846e-03, 2.1916e-03, 6.6734e-03, 4.8659e-03, 1.7003e-02, 7.2317e-03,
        1.3732e-03, 1.2921e-02, 2.8179e-03, 1.5988e-03, 3.3012e-03, 7.8191e-04,
        3.7639e-03, 2.4020e-03, 3.1916e-03, 7.9135e-04, 7.8313e-04, 5.7559e-04,
        1.0090e-03, 2.4977e-04, 6.8479e-04, 5.4240e-04, 1.1124e-03, 1.6486e-03,
        7.0233e-04, 1.9160e-02, 1.6596e-03, 3.9372e-03, 5.1253e-04, 7.8131e-04,
        1.5905e-03, 2.9914e-03, 1.7840e-03, 6.2621e-04, 7.2095e-04, 4.9870e-04,
        2.8188e-03, 2.2828e-03, 2.3395e-03, 6.2264e-04, 2.4125e-03, 1.6030e-03,
        4.4610e-03, 5.8182e-03, 2.2958e-03, 1.8902e-03, 1.7898e-03, 2.3416e-03,
        9.0996e-04], device='cuda:0', grad_fn=<UnbindBackward0>)
tensor([2.2949e+01, 8.5213e+00, 4.2867e+01, 1.2101e+01, 1.7648e-06, 1.6438e-02,
        1.5249e-03, 5.2015e-03, 3.6679e-04, 2.0792e-03, 3.4202e-03, 6.6716e-03,
        4.2036e-03, 8.7390e-04, 5.3193e-02, 2.0351e-03, 2.8528e-02, 3.8327e-03,
        5.1659e-03, 2.4324e-03, 2.4824e-03, 3.2313e-03, 3.4182e-03, 6.1571e-04,
        5.8827e-03, 3.8910e-03, 3.0409e-03, 8.1738e-04, 2.2858e-03, 1.8199e-03,
        3.1528e-02, 1.0869e-03, 5.4345e-03, 3.0550e-03, 7.7136e-03, 1.1963e-03,
        7.6420e-03, 1.1206e-03, 4.5149e-03, 6.2085e-03, 1.1080e-02, 1.0567e-02,
        1.7915e-03, 9.5486e-03, 1.3000e-03, 5.8328e-04, 2.3635e-03, 3.8680e-04,
        5.5275e-03, 1.1935e-03, 4.6446e-03, 4.6616e-04, 6.0694e-04, 7.5986e-04,
        9.7805e-04, 2.1388e-04, 5.4047e-04, 5.6278e-04, 2.6507e-03, 3.6365e-03,
        1.2007e-03, 1.2623e-02, 2.2846e-03, 4.2138e-03, 8.9710e-04, 1.0120e-03,
        1.1891e-03, 4.4692e-03, 1.2388e-03, 5.6764e-04, 8.1628e-04, 7.2471e-04,
        1.7150e-03, 3.6226e-03, 2.1823e-03, 7.0995e-04, 3.7664e-03, 2.1221e-03,
        3.5067e-03, 7.2453e-03, 2.3956e-03, 1.4497e-03, 1.4111e-03, 2.8024e-03,
        7.5300e-04], device='cuda:0', grad_fn=<UnbindBackward0>)
tensor([3.0990e+01, 4.6883e+00, 1.5855e+01, 6.4811e+00, 1.4170e-05, 8.6946e-03,
        1.2113e-03, 2.4587e-03, 1.3645e-04, 4.6962e-04, 2.0894e-03, 3.8880e-03,
        1.1078e-03, 8.3650e-04, 2.1454e-02, 8.7250e-04, 3.3684e-02, 2.1571e-03,
        1.2821e-03, 2.1637e-03, 2.9243e-03, 2.1645e-03, 1.9676e-03, 4.2340e-04,
        2.8897e-03, 4.2441e-03, 1.8476e-03, 7.2218e-04, 2.6540e-03, 2.5790e-03,
        8.7263e-02, 2.1359e-03, 3.4852e-03, 2.0922e-03, 1.2078e-02, 3.7539e-04,
        2.7293e-03, 1.1292e-03, 2.2371e-03, 2.1612e-03, 1.0905e-02, 6.9181e-03,
        2.5917e-03, 1.1423e-02, 9.4351e-04, 1.2758e-04, 3.7867e-04, 9.0897e-05,
        1.2057e-03, 2.9571e-04, 2.7592e-03, 4.7380e-04, 4.9917e-04, 2.9768e-04,
        5.5765e-04, 1.4890e-04, 3.1898e-04, 3.0378e-04, 2.9442e-03, 3.0063e-03,
        7.6892e-04, 3.8691e-03, 6.6299e-04, 4.7491e-03, 4.2853e-04, 2.8883e-04,
        5.0121e-04, 2.0367e-03, 3.5951e-04, 3.5951e-04, 4.9021e-04, 4.5855e-04,
        5.2348e-04, 1.7271e-03, 8.1902e-04, 4.5790e-04, 1.2905e-03, 5.4477e-04,
        1.7166e-03, 1.5913e-02, 1.8985e-03, 6.5737e-04, 6.5588e-04, 1.7405e-03,
        1.8999e-04], device='cuda:0', grad_fn=<UnbindBackward0>)
tensor([2.5376e+01, 4.0762e+00, 1.3846e+01, 6.1333e+00, 1.0600e-05, 2.0251e-02,
        5.3332e-03, 4.4227e-03, 8.3353e-04, 5.5645e-04, 2.9111e-03, 5.4296e-03,
        2.3911e-03, 1.7596e-03, 1.5120e-02, 1.1515e-03, 2.9016e-02, 2.9078e-03,
        2.1932e-03, 3.3128e-03, 5.6649e-03, 4.7033e-03, 5.1827e-03, 6.0941e-04,
        2.9631e-03, 5.5180e-03, 2.2740e-03, 1.5990e-03, 2.5645e-03, 4.6219e-03,
        5.4289e-02, 4.2163e-03, 1.9492e-03, 4.6035e-03, 8.7890e-03, 4.4365e-04,
        2.5614e-03, 1.3223e-03, 1.9735e-03, 9.8936e-04, 9.4190e-03, 1.1180e-02,
        4.6972e-03, 9.9733e-03, 9.8692e-04, 2.3109e-04, 4.8360e-04, 8.4651e-05,
        4.5905e-04, 2.4309e-04, 4.6909e-03, 5.8992e-04, 4.0057e-04, 2.4423e-04,
        3.1995e-04, 1.4784e-04, 1.6616e-04, 2.4884e-04, 1.9574e-03, 1.5605e-03,
        7.3846e-04, 4.1165e-03, 1.1137e-03, 5.2221e-03, 6.2287e-04, 5.9351e-04,
        8.5668e-04, 3.2289e-03, 6.6670e-04, 4.5442e-04, 4.8352e-04, 5.8179e-04,
        4.9103e-04, 2.5232e-03, 1.5868e-03, 7.7611e-04, 1.5224e-03, 6.4201e-04,
        1.9740e-03, 3.9136e-02, 2.2274e-03, 6.2510e-04, 9.0220e-04, 1.4826e-03,
        1.0536e-04], device='cuda:0', grad_fn=<UnbindBackward0>)
tensor([4.3150e+01, 5.2217e+00, 5.9237e+01, 8.0409e+00, 4.6026e-05, 7.6650e-03,
        9.3881e-03, 3.0306e-03, 1.1037e-03, 3.5843e-04, 1.7287e-03, 2.4262e-03,
        1.5754e-03, 1.3448e-03, 8.0362e-03, 9.1478e-04, 2.5736e-02, 1.7464e-03,
        1.1918e-03, 3.3403e-03, 9.0058e-03, 8.1845e-03, 4.9690e-03, 6.9315e-04,
        1.5067e-03, 1.8837e-03, 1.8848e-03, 1.2245e-03, 1.9018e-03, 5.0851e-03,
        5.8064e-02, 6.4580e-03, 3.6262e-03, 4.4940e-03, 1.1461e-02, 5.8232e-04,
        2.1260e-03, 1.3372e-03, 2.8567e-03, 4.3420e-04, 6.0142e-03, 1.1562e-02,
        4.4855e-03, 9.3040e-03, 8.6017e-04, 1.7465e-04, 3.5207e-04, 4.3454e-05,
        1.4765e-04, 1.3268e-04, 4.6232e-03, 1.3393e-03, 3.8129e-04, 3.6249e-04,
        5.2603e-04, 1.2832e-04, 1.4509e-04, 2.6718e-04, 3.4162e-03, 1.9768e-03,
        7.0401e-04, 2.6826e-03, 8.2029e-04, 4.2563e-03, 1.0339e-03, 7.0778e-04,
        9.0938e-04, 2.5714e-03, 8.2799e-04, 2.9149e-04, 5.7309e-04, 7.6391e-04,
        3.5676e-04, 1.6000e-03, 1.0712e-03, 5.4328e-04, 1.4536e-03, 4.8885e-04,
        6.1925e-03, 7.7357e-02, 1.5593e-03, 5.5400e-04, 1.8614e-03, 1.3672e-03,
        1.0399e-04], device='cuda:0', grad_fn=<UnbindBackward0>)
tensor([4.3672e+01, 4.9796e+00, 5.4695e+01, 8.4110e+00, 4.2378e-05, 3.7152e-02,
        7.2609e-03, 5.4186e-03, 1.0996e-03, 2.2893e-04, 1.7855e-03, 9.0443e-04,
        1.2738e-03, 1.1458e-03, 4.6043e-03, 6.0362e-04, 1.4263e-02, 1.2580e-03,
        8.3318e-04, 4.5226e-03, 1.4170e-02, 1.1542e-02, 3.8123e-03, 6.7803e-04,
        5.9718e-04, 8.6085e-04, 1.2595e-03, 8.8931e-04, 9.2011e-04, 5.9601e-03,
        4.6583e-02, 1.3595e-02, 5.1310e-03, 2.8466e-03, 6.3721e-03, 2.6255e-04,
        5.3050e-04, 2.0953e-03, 2.9236e-03, 1.3605e-04, 2.4887e-03, 4.1262e-03,
        1.8811e-03, 3.5800e-03, 1.8986e-03, 2.8937e-04, 1.0560e-03, 3.5190e-05,
        6.7044e-05, 8.9578e-05, 7.0565e-03, 1.4208e-03, 3.8181e-04, 3.7486e-04,
        3.1603e-04, 9.5690e-05, 1.1850e-04, 2.8025e-04, 2.8111e-03, 1.6525e-03,
        8.7420e-04, 3.0143e-03, 1.0234e-03, 3.6514e-03, 1.8194e-03, 1.1660e-03,
        7.7848e-04, 6.1609e-03, 1.1899e-03, 3.2464e-04, 1.4838e-03, 9.0994e-04,
        4.4033e-04, 1.6511e-03, 6.7473e-04, 5.1200e-04, 1.0060e-03, 3.7450e-04,
        1.8343e-02, 1.2636e-01, 2.7297e-03, 2.9586e-04, 6.5780e-03, 1.4009e-03,
        1.1390e-04], device='cuda:0', grad_fn=<UnbindBackward0>)
tensor([4.5466e+01, 5.0685e+00, 4.0250e+01, 7.7549e+00, 3.9817e-05, 2.4447e-02,
        6.0872e-03, 4.5984e-03, 1.0590e-03, 1.9622e-04, 1.8204e-03, 6.7255e-04,
        8.0434e-04, 1.2053e-03, 4.2662e-03, 3.8003e-04, 8.0306e-03, 8.9485e-04,
        1.2357e-03, 2.7095e-03, 1.2295e-02, 8.6489e-03, 2.7488e-03, 5.9257e-04,
        3.3415e-04, 6.6812e-04, 9.6260e-04, 5.4891e-04, 4.9030e-04, 3.9388e-03,
        2.7665e-02, 1.5951e-02, 3.5841e-03, 4.0708e-03, 2.7535e-03, 1.6875e-04,
        2.2656e-04, 1.7948e-03, 2.1046e-03, 1.0515e-04, 1.3151e-03, 2.4002e-03,
        1.1338e-03, 1.6914e-03, 1.5343e-03, 5.7032e-04, 2.4214e-03, 3.9016e-05,
        7.5202e-05, 8.6900e-05, 8.9044e-03, 1.2577e-03, 4.8342e-04, 4.1056e-04,
        4.2154e-04, 8.7507e-05, 1.0438e-04, 2.5445e-04, 2.7925e-03, 1.3228e-03,
        8.0930e-04, 6.8353e-03, 1.8464e-03, 3.6939e-03, 3.0071e-03, 3.2028e-03,
        7.8906e-04, 1.8844e-02, 2.8863e-03, 5.0880e-04, 2.3517e-03, 1.8288e-03,
        6.0317e-04, 2.4827e-03, 7.6710e-04, 5.8524e-04, 1.2037e-03, 5.4698e-04,
        6.6327e-02, 1.3798e-01, 4.9280e-03, 2.5574e-04, 7.5485e-03, 1.0157e-03,
        8.8340e-05], device='cuda:0', grad_fn=<UnbindBackward0>))

現状では, プログラムにYOLOXを組み込んで利用する場合, tools/demo.pyをベースに改良するのが早そうである.

プログラムでの利用という点では, YOLOv5に比べかなり使いにくそうな感じである.


最後に, 少し面白そうな記事[2]を見つけたので, 紹介しておく.
qiita.com

----
参照URL:
[1] GitHub - Megvii-BaseDetection/YOLOX
[2] YOLOシリーズの速度比較をしてみました - Qiita







PyTorchではじめるAI開発

PyTorchではじめるAI開発

Amazon