LoginSignup
11
9

More than 1 year has passed since last update.

YOLOv4 - condaでのクイックセットアップとGPUで学習する

Posted at

依存関係はシステム全体ではなく、conda 環境のみでインストールされます。

前書き

エッジデバイスでの高速物体検出のためにYOLOv4モデルを学習させようと考え、YOLOv3 DarknetリポジトリからフォークされたYOLOv4公式リポジトリを見つけました 。
DarknetはC言語とCUDAで書かれたニューラルネットワークフレームワークです。GPU用のセットアップは明示的に説明されていませんが、OpenCVとCUDA-Toolkitの公式サイトにリンクされ、システム全体にインストールするためのセットアップガイドが提供されています。私はPC1台で複数ニューラルネットワークのフレームワーク(Pytorch、Tensorflow 1と2など)を使用しているため、依存関係のあるライブラリをシステム全体にインストールすると、バージョンの競合を引き起こす可能性が高くなります。それにシステム全体にインストールされたライブラリーのアンインストール方法が統一されておらず、正しいアンインストール方法の調査時間も必要です。Anacondaを使用するとセットアップ環境を分離できます。conda環境でのGPU学習のためのDarknetのセットアップに関するガイドを見つけることができなかったため、このガイドを書くことにしました。

conda について

conda は 公式 Web ページ にあるように、多くのプログラミング言語用のパッケージ、依存関係、環境管理ツールです。python の場合、 pip に比べて、 conda は python ライブラリとその依存パッケージだけでなく、CUDA-Toolkit や cuDNN ライブラリのような他の言語で書かれた依存パッケージも環境にインストールすることが可能です。パッケージは環境にインストールされるため、1つのパッケージの複数のバージョンを環境毎に分けておき、切り替えて使えるという利点があります。conda のパッケージの削除は、アンインストールスクリプトなどが必要なく、以下のコマンドで特定の環境を削除するだけで十分です。

conda env remove -n <環境名>

セットアップ

Ubuntu 20.04 LTSにMinicondaをインストールしたPCでセットアップをテストしました。セットアップは非常に簡単で、インターネット環境にもよりますが、10分程度で完了します。また、CUDA-ToolkitとcuDNNライブラリには最低2GBのメモリが必要です。Darknetのニューラルネットワークフレームワークを構築するための要件にはOpenCVが含まれており、これもcondaを使用してインストールします。

conda環境の作成

YOLOv4_conda という conda 環境を作成し、ターミナルで以下のコマンドを実行して python 3.7 と OpenCV 3.x をインストールします。

conda create -n YOLOv4_conda python=3.7 opencv=3

CUDA-Toolkit ドキュメントの説明に従って、以下のターミナルコマンドでnvidiaチャンネルからCUDA-ToolkitとcuDNNライブラリをインストールします。

conda install cuda cudnn -c nvidia -n YOLOv4_conda

cuda パッケージは、GPU で動作する Darknet CUDA コードをビルドするための CUDA-ToolkitNVCC (NVIDIA CUDA Compiler) をインストールするパッケージです。

nvidiaチャンネルにはcuda-toolkitパッケージもあり、一般にTensorflowやPytorchなどのpythonベースの機械学習フレームワークのGPU学習に使用されますが、このパッケージにはcuda-toolkitだけが含まれ、NVCCは含まれません。

最後に、新しく作成した環境に切り替えます。

conda activate YOLOv4_conda

Darknet YOLOv4 プロジェクトをクローンします。

ターミナルでクローンしてリポジトリに切り替えます。

git clone https://github.com/AlexeyAB/darknet.git
cd darknet

今後の環境構築のために、ターミナルでクローンしたバージョンを確認します。

git --no-pager log --oneline -1

以下のようなコミットを返します。

8a0bf84 (HEAD -> master, origin/master, origin/HEAD) various fixes (#8398)

Darknetの設定

テキストエディタに Makefile を読み込んで、以下の3箇所を修正します。

  1. 1~4行目:GPU ビルド、OpenCVとcuDNN を有効にする。

GPU=1
CUDNN=1
CUDNN_HALF=1
OPENCV=1
  1. 27~58行目:GPUの計算能力をアンコメントする(例:RTX 3090 GPU で学習する場合、以下をアンコメントしてください)。

`#` GeForce RTX 3070, 3080, 3090
ARCH= -gencode arch=compute_86,code=[sm_86,compute_86]
  1. 80行目: conda環境にインストールされているヘッダーファイルのパスを追加する (CONDA_PREFIX 変数に格納されます)

COMMON= -Iinclude/ -I3rdparty/stb/include -I$(CONDA_PREFIX)/include

Darknet のビルド

Darknet をビルドするのに必要なパッケージを pkgconfig で見つけられるように、ターミナルで検索パス(またCONDA_PREFIX 変数を使います)に環境変数を一時的に追加します (現在のターミナルセッションでのみ)。

export PKG_CONFIG_PATH=$CONDA_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH

ビルドコマンドを実行する。

make

ビルド中にエラーが発生した場合、以下のような表示でビルド処理が停止します。

make: *** [Makefile:176: darknet] Error 1

ビルドエラーを修正するための解決策については、トラブルシューティングを参照してください。

データセットの準備

Darknet のドキュメントでは、データセットは build/darknet/x64/data フォルダに作成することになっていますが、実際には darknet リポジトリフォルダ内の任意の場所に配置することができます。ドキュメントには、./darknet実行ファイルとデータセットを格納するフォルダの場所についての説明に矛盾があります。私の環境の場合、./darknet実行ファイルはリポジトリのルートフォルダにあり、それに関しては、リポジトリのルートフォルダ内のdataフォルダにデータセットを作成します。テスト用に、COCOデータセットから収集した画像で、小さなカスタムデータセット street_views_yolo を作成しました。

アノテーションについて

データセットフォルダ内に、データセットで使われるすべてのクラス名を含むファイル classes.txt を作成します。今回のテストデータセットでは、3つのクラスを使っているので、classes.txtファイルは次のような内容になっています。

car
bus
person

画像のアノテーションは、画像のファイル名と同じで、末尾が.txtのファイルに保存されます。アノテーションは、画像が保存されているフォルダに保存してください。アノテーションのフォーマットは、1行に1バウンディングボックスで、以下のような構造になっています。

<object-class> <x_center> <y_center> <width> <height>

<object-class> は, classes.txt ファイル内の0から (car) 始まるクラス番号です.<x_center><y_center> は、0 から 1 の間で正規化されたバウンディングボックスの中心点を含みます(それぞれ画像の幅と高さで割る)。<width><height> は、バウンディングボックスの幅と高さを表し、0から1の間で正規化されます。

bbox.png

例として、2つのバウンディングボックス(carbus)を持つ画像 street1.jpg に対するアノテーションは、以下の内容を持つファイル street1.txt に格納されます。

0 0.5072916666666667 0.54453125 0.43125 0.3484375
1 0.5135416666666667 0.2875 0.40625 0.26875

アノテーションは Labelimg のようなアノテーションツールで行うことができ、すでに Darknet のアノテーションフォーマットが提供されています。インストールは、以下のコマンドを使用して conda で簡単に行うことができます。

conda install labelimg -c conda-forge

データセットの分割

学習用画像と検証用画像は trainval フォルダに格納されます。すべての学習画像を一覧するファイル train.txt と検証用を一覧するファイル val.txt が必要です。一覧(JPEG画像の場合)は以下のコマンドで作成することができます。

ls train/*.jpg > train.txt
ls val/*.jpg > val.txt

データセットに関するすべての情報をまとめるためのインデックスファイル index.txt を以下の内容で作成します。

classes = 3
train  = train.txt
valid  = val.txt
names = classes.txt
backup = backup

classes は検出するクラスの数、 trainvalid は学習画像と検証画像の一覧ファイルの場所、 names はクラス名を含むファイルの場所と backup はトレーニング中にモデルの重みが保存されるフォルダを指します。データセットのフォルダ構造は以下のようになっているはずです。

street_views_yolo/
├── classes.txt
├── index.txt
├── train/
│   ├── street1.jpg
│   ├── street1.txt
│   ├── ...
│   ├── street50.jpg
│   └── street50.txt
├── train.txt
├── val/
│   ├── street2.jpg
│   ├── street2.txt
│   ├── ...
│   ├── street10.jpg
│   └── street10.txt
├── val.txt
└── yolov4-custom.cfg

学習

モデルをゼロから学習させるのではなく、既に学習させたモデルの微調整をします。これは転移学習と呼ばれ、学習時間を大幅に短縮することができる。
上記のデータセットでYOLOv4モデルを学習させます。この学習マニュアルによると、検出するカスタムクラスの数に合わせて、学習済みモデルのいくつかのレイヤーを変更する必要があります。カスタムデータセットでYOLOv4を学習するための設定ファイル yolov4-custom.cfgcfg フォルダの中に既に用意されているので、それを修正して使用します。

ネットワークの修正

まず、yolov4-custom.cfgファイルを以下のコマンドでデータセットフォルダにコピーします。

cp cfg/yolov4-custom.cfg data/street_views_yolo/.

次に、コピーした yolov4-custom.cfg の行を学習マニュアルに説明されているように調整します。
基本的には、設定ファイルにある3つのYOLO-layerをyoloというキーワードで検索するだけです。そして、3つの [yolo] レイヤーのそれぞれで、 classes=80classes=3 の3つのクラスの上記データセットを合わせて変更します。そしてそれぞれの [yolo] レイヤーの上にある [convolutional] レイヤーでは、 filters=255filters=24 ((クラス数 + 5) * 3) に変更します。最後に、必要であれば、 [net] 層の画像入力 widthheight を、 width=608height=608 を 32 で割り切れるサイズ(例えば、 width=416height=416 )に変更することも可能です。

学習済みの重みファイルのダウンロード

YOLOv4の場合、学習マニュアルでリンクされた学習済みの重みファイル yolov4.conv.137 をダウンロードし、親フォルダ data に保存しておけば、他のデータセットで学習する際に学習済みの重みファイルを再利用できます。ファイルとフォルダの構成は以下のようになります。

darknet/
├── build/
├── cfg/
│   ├── ...
│   └── yolov4-custom.cfg
├── darknet
├── ...
└── data/
    ├── ...
    ├── street_views_yolo/
    │   ├── classes.txt
    │   ├── index.txt
    │   ├── train/
    │   ├── train.txt
    │   ├── val/
    │   ├── val.txt
    │   └── yolov4-custom.cfg
    └── yolov4.conv.137

学習の開始

darknet が conda 環境にインストールされた CUDA と cuDNN ライブラリを見つけるために、一時的に(現在のターミナルセッションでのみ)ターミナル内のライブラリパスに環境変数を追加します(ここでも CONDA_PREFIX 変数をを使います)。

export LD_LIBRARY_PATH=$CONDA_PREFIX/lib:$LD_LIBRARY_PATH

データセット内の画像へのパスは darknet 実行ファイルからの相対パスに合わせる必要があります。現在、データセット内の画像へのパスは street_views_yolo のデータセットフォルダからの相対パスになっていますが、darknet 実行ファイルはリポジトリのルートフォルダに配置されています。
実行ファイルがデータセットのインデックスファイルに記載したデータセットの画像を見つけるために、データセットフォルダ内で実行します。まず、dataset フォルダに移動します。

cd data/street_views_yolo

そして、datasetのフォルダに相対パスで以下のコマンドで学習を開始します。

../../darknet detector train \
  index.txt \
  yolov4-custom.cfg \
  ../yolov4.conv.137 \
  -dont_show -map -mjpeg_port 8090

学習実行中にエラーが発生した場合は、トラブルシューティングを参照して対処してください。

-mjpeg のパラメータにより、ブラウザで URL http://ip-address:8090 にアクセスすると、以下のようなグラフが表示され、学習の進捗確認ができます。

chart_yolov4-custom.png

青線は損失、赤線は mean Average Precision (mAP) を表す。

学習の成果

学習終了後、結果はデータセット内の backup フォルダに保存されます。

street_views_yolo/
└── backup/
    ├── yolov4-custom_10000.weights
    ├── yolov4-custom_best.weights
    ├── yolov4-custom_final.weights
    └── yolov4-custom_last.weights

yolov4-custom_best.weights は、平均精度が最も高い重みファイルになります。

クリーンアップ

CUDA、cuDNN、OpenCVなどのインストールされているパッケージやライブラリを全てアンインストールするには、以下のコマンドで作成したconda環境を削除するだけです。

conda env remove -n YOLOv4_conda

そして、ローカルにクローンした darknet リポジトリフォルダを削除します。
これで完了です。

トラブルシューティング

Darknetの構築について

問題: Darknetのビルドが以下のようなエラーで停止する。

No package 'opencv' found
/usr/bin/ld: cannot find -lcudart
/usr/bin/ld: cannot find -lcublas
/usr/bin/ld: cannot find -lcurand
collect2: error: ld returned 1 exit status
make: *** [Makefile:176: darknet] Error 1

解決方法: 以下のコマンドで、PKG_CONFIG_PATHにconda環境を追加してください。この設定は、現在のターミナルセッションを閉じると消えます。新しいセッションでは再度コマンド実行することを忘れないでください。

export PKG_CONFIG_PATH=$CONDA_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH

Darknetの学習について

問題: 学習が以下のようなエラーで停止する。

error while loading shared libraries: libopencv_dnn.so.<version>: cannot open shared object file: No such file or directory

解決方法: 以下のコマンドで、conda 環境を LD_LIBRARY_PATH に追加します。この設定は、現在のターミナルセッションを閉じると消えます。新しいセッションでは再度コマンド実行することを忘れないでください。

export LD_LIBRARY_PATH=$CONDA_PREFIX/lib:$LD_LIBRARY_PATH

問題: 学習が以下のようなエラーで停止する。

 Error in load_data_detection() - OpenCV Cannot load image <path_to_image>

解決方法:
train.txtまたはval.txtの画像のパスが正しく設定されていません。画像を保存するフォルダ構造が両方のファイルの画像パスと一致しているかを確認してください。パスはデータセットフォルダからの相対パスになります。

11
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
9