無料なのにGPUリソースを活用できるGoogle Colaboratoryは、機械学習に携わるなら活用しない手はない、と言ってもいいくらい便利な環境です。
Colaboratoryと機械学習の組み合わせはもはや常識と言ってもいいくらい知られていることで、記事にするには今更感もあるような気がしたのですが、(昨日までの僕のように)使い方がよく分からなくて使ったことがない、という方が少しでも少なくなればという想いを込めて、AlexeyAB/darknet YOLOv4をColaboratory上で使う手順をご紹介します。
Colaboratoryの基本的な説明と、darknetのColaboratory上でのビルド手順を省略せずに紹介したうえで、最後にはPythonプログラムからdarknetをロードして物体検出してみる、といった内容になっています。
Colaboratory環境を用意する
Google Colaboratoryは、Googleドライブから利用できる対話型Pythonインタープリタです。Jupyter Notebook(次世代としてJupyterLabになった)にGPUリソースが追加されたもの、と思ってもらえれば概ね間違いないです。
ということでGoogle Colaboratoryの環境を準備しましょう。
Google Colaboratoryは、Googleドライブから利用します。

まだ一度もColaboratoryを使ったことがない人は、Colaboratoryをインストールして有効にしておきましょう。


Colaboratoryがインストールされていれば、新規→その他→Google Colaboratoryと選択することで使い始めることができます。

Colaboratoryの使い方の基本
Colaboratoryを使ったことがない人にとっては、使い方がイメージしにくいと思うので、基本的な使い方を紹介しておきます。
pythonコードの実行
Pythonプログラムコードを入力して、左側の再生マークをクリックするか、Shift+Enterを押すと、Pythonプログラムが実行されて結果が下に表示されます。

print()関数を使わなくても、変数だけの行は、その変数の内容を気の利いた感じで表示してくれます。

メモ
Pythonプログラムを入力する場所のことを、コードセルといいます。
Linuxコマンドの実行
! から始まる行は、Linuxコマンドとして解釈されます。

この後darknetをビルドするときに使うmakeやsedなどの高度なコマンドも、 ! の後に記述すれば使うことができます。
cdコマンドなどのコードセルの処理が終わった後も状態を保存しておく必要があるものは、%cd として使う必要があります。

この辺りの公式のドキュメントはShell command等の使い方です。
GPUリソースを活用できるように設定する
さて、対話的にPythonプログラムの実行ができるというだけでも便利なツールだということが理解してもらえたと思いますが、GPUリソースも使えるようにしておきましょう。
ランタイム→ランタイムのタイプを変更

「None」→「GPU」に変更→保存

TPUはTensor Processing Unitのことで、おそらくGPUよりかなり高速ですが、無料とはいえ共有リソースなので不要なときは使わないように配慮しておきましょう。
画面右上の「接続」をクリックすると接続されます。ここでいう接続というのは、作業用の仮想スペースを作成し、GPUなどのリソースを占有しておくことで、いつでもプログラムを実行できる状態にスタンバイする、といった感じです。(たぶん)

これで、GPUが有効になったColaboratory上でdarknetをビルドして使用するための準備が整いました。
darknetをビルドする
ここから、GPUが有効になっているColaboratory上でdarknetをビルドしていきます。これ以降の操作はColaboratoryのコードセルに対して入力・実行しているものとして読んでいって下さい。
AlexeyAB/darknetのリポジトリからdarknetをダウンロードします。ダウンロードしたら、カレントディレクトリをdarknetフォルダに移動しておきます。cdコマンドだけは!cdではなく%cdとする必要があるので間違えないように注意です。
!git clone https://github.com/AlexeyAB/darknet.git
%cd darknet
GPUを有効にして、OpenCVも有効にして、Pythonから利用するためにlibdarknet.soを作成したいので、Makefileを修正します。それぞれ、Makefileの中のGPU=0をGPU=1に置換するような処理をしています。ちょっと面倒ですけど、nanoなどのテキストエディタが使えないのでしょうがないですね。
!sed -i -e s/GPU=0/GPU=1/ Makefile
!sed -i -e s/CUDNN=0/CUDNN=1/ Makefile
!sed -i -e s/OPENCV=0/OPENCV=1/ Makefile
!sed -i -e s/LIBSO=0/LIBSO=1/ Makefile
置換できたか確認しておきましょう。
!head -n 10 Makefile
出力:
GPU=1
CUDNN=1
CUDNN_HALF=0
OPENCV=1
AVX=0
OPENMP=0
LIBSO=1
ZED_CAMERA=0
ZED_CAMERA_v2_8=0
意図どおり置換されていることが確認できたら、あとはmakeコマンドを実行すればビルドされます。
!make
darknet(実行ファイル)やlibdarknet.so(Pythonからdarknetを使うためのライブラリファイル)が作成されたか確認しておきましょう。
!ls -l
出力:
...省略
-rwxr-xr-x 1 root root 5308128 May 4 09:40 darknet
...省略
-rwxr-xr-x 1 root root 5581000 May 4 09:40 libdarknet.so
...省略
ビルドオプションが反映されたビルドになっているか確認しておきましょう。
!./darknet -h
出力:
CUDA-version: 11000 (11020), cuDNN: 7.6.5, GPU count: 1
OpenCV version: 3.2.0
Not an option: -h
YOLOv4を動かすために、yolov4.weightsファイルをダウンロードしておきます。
!wget https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights
これで、darknet上でYOLOv4を動作させる準備が整いました。
YOLOv4を動かしてみる
準備が整ったら、せっかくPythonを対話形式で実行できるColaboratory環境なので、Pythonから物体検出をしてみましょう。
使用するライブラリをインポートします。darknetとdarknet_imagesは、同じフォルダにあるdarknet.pyとdarknet_images.pyファイルのことです。matplotlib.pyplotは、画像を表示するために使用します。
import darknet
import darknet_images as dkimg
import matplotlib.pyplot as plt
モデル情報と検出したい画像のパスを定数として定義しておきます。これらの材料はdarknetコマンドから画像検出するときにも必要となるものと同じです。
COCO_FILE = 'cfg/coco.data'
CFG_FILE = 'cfg/yolov4.cfg'
WEIGHTS_FILE = 'yolov4.weights'
IMAGE_TO_PREDICT = 'data/dog.jpg'
いよいよ画像検出です。darknet.load_network()関数についてはdarknet.pyを、dkimg.image_detection()関数についてはdarknet_images.pyを見ると、なんとなく使い方がわかると思います。
# darknetをロード
loaded = darknet.load_network(CFG_FILE, COCO_FILE, WEIGHTS_FILE)
network, class_names, colors = loaded
# 画像から物体検出
predicted, detections = dkimg.image_detection(
IMAGE_TO_PREDICT, network, class_names, colors, 0.15)
検出した結果の画像はpredicted変数に保持しているので、これをmatplotlib.pyplotの機能を使って表示します。
# 表示する画像のサイズが少し大きくなるように設定
plt.figure(dpi=150)
# XとYの目盛りを表示しないように設定
plt.axes(frame_on=True, xticks=[], yticks=[])
# 画像を表示 acpect='auto'を指定しないと縦横比が保たれない
plt.imshow(predicted, aspect='auto')

検出、できてますね!純粋な検出時間だけでいえば1秒かからないくらいです。いっぽう、GPUを無効にして試してみたところ、検出時間は10秒以上かかっていました。
さいごに、darknetを開放します。適切に解放しておかないとColaboratoryのカーネルがクラッシュする原因にもなります。
darknet.free_network_ptr(network)
あとがき
いかがでしたか?この記事を読んだことで、Google Colaboratory…なんて使えるヤツなんだ!と思っていただけたなら、嬉しいです。
具体的に思いつくColaboratoryの活用例としては、何千枚もの画像や動画を用意しておいてGPUを使っていっきに検出作業をかけたり、学習処理をColaboratory上で実行しておいて、作成されたモデルをダウンロードしてローカル環境などで活用する、といった使い方ができそうです。