YOLOv4をRaspberryPi上で動かせなかった件まとめ


1.この記事の内容

darknetのYOLOv4,YOLOv4-tinyをRaspberryPi上で動作させ,COCO Evaluation Serverを用いてmAP算出しようと試みましたが,YOLOv4はRaspberryPiのメモリ不足による強制終了,YOLOv4-tinyは処理時間が長すぎることで断念しました.
代わりに,PC上(Windows Subsystem for Linux)での推論及びCOCO Evaluation ServerでのmAP算出までを実施しました.

環境構築からmAP算出までの内容をまとめます.

1-1.使用環境

  • darknet
    • YOLOv4
    • YOLOv4-tiny
  • Raspberry Pi 3 Model B+
  • Windows10
    • WSL2
    • Ubuntu 18.04

2.darknetの取得・ビルドからCOCO Evaluation Serverまで

MS COCO test-dev2017 datasetの推論結果をCOCO Evaluation Server上でmAP算出する手順を紹介します.
本説明で記載する各ディレクトリは下記の表記とします.


$ export WORK_DIR=<path to your work dir>
$ export DATASET_DIR=<path to your dataset dir>
$ export PRETRAINED_MODEL_DIR=<path to your pretrained model dir>

2-1.darknetコードの準備とPretrainedモデルの取得(RaspberryPi, WSL共通)

darknetコードの取得


$ mkdir -p ${WORK_DIR}
$ cd ${WORK_DIR}
$ git clone https://github.com/AlexeyAB/darknet.git

ビルド


$ cd darknet
※GPU, CUDNN, OPENCV等を有効にする場合は,Makefileを編集する
 RaspberryPi上ではすべて0のまま.PC上で動作する場合に1にセットする
GPU=0
CUDNN=0
OPENCV=0
 ↓
GPU=1
CUDNN=1
OPENCV=1
$ make

Pretrainedモデルの取得

  • YOLO v4
    ${PRETRAINED_MODEL_DIR}へYOLOv4 model zooからダウンロードしたモデルを格納する. YOLOv4 model zooではGoogle Drive上でモデルが公開されており,wgetで取得ができない.
  • YOLOv4-tiny
    YOLOv4-tinyのPretrainedモデルはgithub上で公開されており,wgetで取得することができます.
    
    wget https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov4-tiny.cfg
    wget https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.weights
    

2-2.MS COCO dataset の準備(RaspberryPi, WSL共通)

Windows PC上で,公式サイトのダウンロードページから,「2017 Test images [41K/6GB]」をダウンロードして解凍します.解凍したフォルダは共有フォルダに設定します(2-3でRaspberryPiからマウントできるようにします).

「2017 Test images [41K/6GB]」ファイルサイズ及びファイル数が大きいため,FAT32フォーマットのストレージで扱うことができず,RaspberryPiに接続するmicroSDカードやUSBメモリには格納できません.

共有フォルダの設定方法及びRaspberryPi上でのマウント方法については,2-3を参照してください.

2-3.RaspberryPiでWindowsの共有フォルダをマウントする(RaspberryPiのみの手順)

RaspberryPiでWindowsの共有フォルダをマウントするに記載の手順で,2-2で解凍した「2017 Test images [41K/6GB]」をマウントします.

2-4.推論実行(RaspberryPi, WSL共通)

  1. 推論対象画像リストの取得とパスの変更
    githubからtestdev2017.txtを取得して,ファイル内のパスを自身の環境に合わせて変更します
    
    $ cd ${DATASET_DIR}
    $ wget https://raw.githubusercontent.com/AlexeyAB/darknet/master/scripts/testdev2017.txt
    
  2. cfg/coco.dataの編集
    cfg/coco.dataのvalid(testdev2017.txtのパス)を自身の環境に合わせて変更します
  3. 推論実行
    下記コマンドで推論処理を実行します.
    処理が完了するとresults以下に推論結果(jsonファイル)が格納されます.
    RaspberryPiでは推論結果が得られず,2-5のmAP算出はWindows PCでの実行結果を用いたものとなります.
    • YOLOv4
      
      $ mkdir results
      $ ./darknet detector valid cfg/coco.data ${PRETRAINED_MODEL_DIR}/yolov4.cfg ${PRETRAINED_MODEL_DIR}/yolov4.weights
      
    • YOLOv4-tiny
      
      $ mkdir results
      $ ./darknet detector valid cfg/coco.data ${PRETRAINED_MODEL_DIR}/yolov4-tiny.cfg ${PRETRAINED_MODEL_DIR}/yolov4-tiny.weights
      

2-5.mAP算出(COCO Evaluation Serverへのアップロード)

resultsディレクトリ以下に出力されるjsonファイルをzip圧縮して,COCO Evaluation ServerへSubmitします.

  1. jsonファイルのzip圧縮
    
    $ cd results
    $ mv coco_results.json detections_test-dev2017_yolov4_results.json
    $ zip detections_test-dev2017_yolov4_results.zip detections_test-dev2017_yolov4_results.json
    
  2. COCO Detection Challenge (Bounding Box)へのアップロード
    1. ユーザ登録します(未登録の人)
    2. Participateタブから必要事項を記入してSubmitをクリックします
    3. ファイル選択画面が開くので,detections_test-dev2017_yolov4_results.zipを指定します
    4. 一覧表に追加されて,STATUSがRunningと表記され,評価中の状態になります
    5. サーバ上で評価が完了するとSTATUSがFinishedに変わり,SCOREが得られます
      Finishedには自動では変わらないので,10分程度経過後にブラウザをリロードして確認します
    6. "View scoring output log"をクリックすると,評価結果の詳細を確認できます
      
      overall performance
      Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.436
      Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.644
      Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.479
      Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.247
      Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.468
      Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.557
      Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.340
      Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.557
      Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.597
      Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.389
      Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.641
      Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.757
      Done (t=404.87s)
      

3.補足:推論処理実行結果について

RaspberryPi上で推論結果を出力できなかった件について,補足として記載します.

RaspberryPi上でのYOLOv4動作について

RaspberryPi上でYOLOv4の推論を実行すると「強制終了」のメッセージとともに,darknetが落ちました.


$ ./darknet detector valid cfg/coco.data pretrained_model/yolov4/yolov4.cfg pretrained_model/yolov4/yolov4.weights
 GPU isn't used
 OpenCV isn't used - data augmentation will be slow
results: Using default 'results'
mini_batch = 1, batch = 8, time_steps = 1, train = 0
   layer   filters  size/strd(dil)      input                output
   0 conv     32       3 x 3/ 1    512 x 512 x   3 ->  512 x 512 x  32 0.453 BF
   1 conv     64       3 x 3/ 2    512 x 512 x  32 ->  256 x 256 x  64 2.416 BF
   2 conv     64       1 x 1/ 1    256 x 256 x  64 ->  256 x 256 x  64 0.537 BF
   3 route  1                                      ->  256 x 256 x  64
   4 conv     64       1 x 1/ 1    256 x 256 x  64 ->  256 x 256 x  64 0.537 BF
   5 conv     32       1 x 1/ 1    256 x 256 x  64 ->  256 x 256 x  32 0.268 BF
   6 conv     64       3 x 3/ 1    256 x 256 x  32 ->  256 x 256 x  64 2.416 BF

・・・(中略)

Loading weights from pretrained_model/yolov4/yolov4.weights...
 seen 64, trained: 0 K-images (0 Kilo-batches_64)
Done! Loaded 162 layers from weights-file
Learning Rate: 0.00261, Momentum: 0.949, Decay: 0.0005
 Detection layer: 139 - type = 28
 Detection layer: 150 - type = 28
 Detection layer: 161 - type = 28
4
強制終了

Netdataでモニタリングするとメモリ消費により落ちている傾向があり,メモリ不足により実行できなかったと考えられます.

RaspberryPiでのYOLOv4-tiny動作について

YOLOv4-tinyはメモリ不足による強制終了は発生しませんが,画像1枚あたり約36秒かかる(約0.028[fps])為,全20288枚に要する推論時間は約8日となります.
私の都合で8日間連続動作させることができませんでしたので,推論結果は出さずに保留しました.連続動作させれば推論結果を得ることができると思いますので,可能な方は実施してみてもらえればと思います.

  • モニタリングの結果
  • 推論時間計測結果

    時間計測用のコード変更内容は下記のとおりです.
    
    diff --git a/src/detector.c b/src/detector.c
    index a2fdf0b..b6f1368 100644
    --- a/src/detector.c
    +++ b/src/detector.c
    @@ -662,7 +662,7 @@ void validate_detector(char *datacfg, char *cfgfile, char *weightfile, char *out
         layer lk = net.layers[k];
         if (lk.type == YOLO || lk.type == GAUSSIAN_YOLO || lk.type == REGION) {
             l = lk;
    -            printf(" Detection layer: %d - type = %d \n", k, l.type);
    +            printf(" Detection layer: %d - type = %d (in validate_detector())\n", k, l.type);
         }
     }
     int classes = l.classes;
    @@ -747,8 +747,9 @@ void validate_detector(char *datacfg, char *cfgfile, char *weightfile, char *out
         thr[t] = load_data_in_thread(args);
     }
     time_t start = time(0);
    +    printf("m + nthreads = %d\n", m + nthreads);
     for (i = nthreads; i < m + nthreads; i += nthreads) {
    -        fprintf(stderr, "%d\n", i);
    +        fprintf(stderr, "i %d, elapsed_time %f [sec]\n", i, (double)time(0) - start);
         for (t = 0; t < nthreads && i + t - nthreads < m; ++t) {
             pthread_join(thr[t], 0);
             val[t] = buf[t];
    

4.さいごに

推論結果はWindows PC(WSL, RTX 2070 SUPER)で出力したもので,YOLOv4 model zooと推論実行環境が異なる為,結果の一致はしませんでしたが,YOLOv4 model zoog記載の数値(AP=43.0,AP_50=64.9,AP_75=46.5,…)とほぼ同程度の結果が得られましたので,環境構築手順及び実行手順,結果は妥当なものと思います.

Raspberry Pi 3 Model B+上での推論結果算出は断念しましたが,Raspberry Pi 4B メモリ8GB版などを購入した際に試行できれば,追記したいと思います.

5.関連リンク