世の中にはもうすでにYOLOをcolab上で動かす情報が転がっているけど,備忘録も兼ねて.
実行環境
記事執筆中のcolabの環境はこんな感じ.ローカルはMacOS, python3.
! nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2019 NVIDIA Corporation
Built on Sun_Jul_28_19:07:16_PDT_2019
Cuda compilation tools, release 10.1, V10.1.243
! dpkg -l | grep "cudnn"
hi libcudnn7 7.6.5.32-1+cuda10.1 amd64 cuDNN runtime libraries
ii libcudnn7-dev 7.6.5.32-1+cuda10.1 amd64 cuDNN development libraries and headers
import tensorflow as tf; print(tf.__version__)
2.2.0
学習データ準備(local)
darknetをcloneする
まだGoogle colabは用いずにローカルで作業をおこなう.私は作業しやすいからローカルでcloneしたけど,colab上でもできる.
git clone https://github.com/AlexeyAB/darknet.git
cd darknet
ちなみに,こちらは御本家ではないがいろいろ機能が追加されていて,オプションをつけると学習状況をプロットしてくれたりする.また,さらに強くしたyolov4作ったで〜みたいなことも書いてあるので,興味があればそっちでやってもいいと思う,今回はv3で.一応,公式に載っている通りやる場合は以下.
git clone https://github.com/pjreddie/darknet
cd darknet
とりあえず,私はこの中に今回のtask用のディレクトリを作った.さらにその下に画像とか入れる場所をdataという名前で作成し,この中に学習データとなるjpgファイルを入れる.
mkdir task1 | cd task1
mkdir data
必要ファイルの準備
YOLOで学習させるのに必要になってくるファイルは以下.
- yolov3-obj.cfg
- obj.names
- train.txt
- test.txt
- obj.data
yolov3-obj.cfg
まずはcfgファイルから準備する.今回は元々あるyolov3.cfgをコピーして書き換えていく.
cp cfg/yolov3.cfg task1/yolov3-obj.cfg
READMEにある様に自分の学習させたいクラスの数とかに従って書き換えていく.基本的には以下.
- Trainingのコメントアウトを外してTestingをコメントに(2-7行目).batch=64, subdivisions=16とする.
- 20行目max_batchesをclasses*2000の数に.ただし,学習させる画像の数や6000回を下回らない様に.
- 22行目にstepsをmax_batchesの80%と90%に.
- 610, 696, 783行目のclassesをクラス数に変える.
- 603, 689, 776行目のfilters=255を(classes + 5)x3の数に変える.yolo層の前のconvolutional層にある
私はクラスが1個なので,max_batches=6000, steps = 4800,5400, classes=1, filters=18となる.
obj.names
クラスの名前をきちんとクラスの数だけ書く.私はクラスが1個なので1個だけ.
target
train.txtとtest.txt
これはそれぞれに画像へのパスを書いてあげれば良い.ただ,面倒なのでこちらに載っているprocess.pyを使ってtrain.txtとtest.txtを作成した.colabで再度実行することを考えて少し手を加えたものが以下.テストデータの割合を変えたい場合はpercentage_testを変える.
import glob, os
# Current directory
current_dir = os.path.dirname(os.path.abspath(__file__))
task_name = os.path.join(current_dir, 'task1/')
# Directory where the data will reside, relative to 'darknet.exe'
path_data = task_name + 'data/'
# Percentage of images to be used for the test set
percentage_test = 20;
# Create and/or truncate train.txt and test.txt
file_train = open(task_name + 'train.txt', 'w')
file_test = open(task_name + 'test.txt', 'w')
# Populate train.txt and test.txt
counter = 1
index_test = round(100 / percentage_test)
for pathAndFilename in glob.iglob(os.path.join(path_data, "*.jpg")):
title, ext = os.path.splitext(os.path.basename(pathAndFilename))
if counter == index_test:
counter = 1
file_test.write(path_data + title + '.jpg' + "\n")
else:
file_train.write(path_data + title + '.jpg' + "\n")
counter = counter + 1
python process.py
obj.data
以下の様なファイルを作る.
classes=1
train=task1/train.txt
valid=task1/test.txt
names=task1/obj.names
backup = task1/backup/
その他もろもろ
task1下にbackupディレクトリを作る.
mkdir task1/backup
また,学習に使うので使うのでdarknet53モデルを持ってきておく.
wget https://pjreddie.com/media/files/darknet53.conv.74
最後に,GPUを使うためにMakefileの1~4行目を書き換える.
GPU=1
CUDNN=1
CUDNN_HALF=1
OPENCV=1
また,これはお好みだが,デフォルトでweightは1000回ごとに保存される様になっている.これを変えたい場合はsrc/detector.cの363行目を変更してあげれば良い.私は1000回以下の時は100回ごと,1000回を超えると1000回ごと保存される様にした.
// if (iteration >= (iter_save + 1000) || iteration % 1000 == 0) {
if (iteration % 1000 == 0 || (iteration < 1000 && iteration % 100 == 0)) {
現在,こんな感じになっているはず.
darknet
├── task1
│ ├── backup
│ ├── yolov3-obj.cfg
│ ├── train.txt
│ ├── test.txt
│ ├── obj.names
│ ├── fugaobj.data
│ └── data
│ ├── 1.jpg
│ ├── 2.jpg
│ ├── ...
│
├── cfg
│ ├── yolov3.cfg
│ ├── ...
│
├── src
│ ├── detector.c
│ ├── ...
│
├── Makefile
├── process.py
├── Makefile
├── darknet53.conv.74
├── ...
アノテーション
今回はアノテーションツールとして,labelImgを使った.pipで入れれる.pipじゃなくても入れれる.pipを使うと以下の様な感じ.
pip install pyqt5 lxml # Install qt and lxml by pip
make qt5py3
python labelImg.py task1/data task1/obj.names
labelImgの使い方は割と直感でななんとかなると思う.わかんなくても調べたら情報はたくさん出てくるはず.また,起動したままアノテーションするとYOLO形式では保存されないので,左側にあるラベルの種類をYOLOに変える.dataの中にtxtができていればおけ.
darknet
├── task1
│ ├── ...
│ ├──data
│ ├── 1.jpg
│ ├── 1.txt
│ ├── 2.jpg
│ ├── 2.txt
│ ├── ...
これでローカルでの準備は完了.
学習させる
学習準備 on colab
今作ったdarknet以下を丸ごとgoogle driveにあげる.画像がたくさんあったら時間がかかってしまうかも.私は十数枚(しかない)ので割と早めにアップロード完了.
次にgoogle colabの新規ノートブックを立ち上げ,ランタイムのタイムをGPUにする.google driveをマウントするのはとても簡単で,左側に並んでいるアイコンのフォルダをクリックすると"ドライブをマウントする"が現れるのでクリック.マウントできたら先ほどアップロードしたdarknetの中に入る.
% cd '/content/drive/My Drive/darknet'
そしたらmakeする.最初はmakeだけで大丈夫だけど,2回目とかだとmake cleanが必要になるので注意.ちなみに結構warningが出てきて心配になるが,問題はなさそう.
# ! make clean
! make
chmod +x *.sh
g++ -std=c++11 -std=c++11 -Iinclude/ -I3rdparty/stb/include -DGPU -I/usr/local/cuda/include/ -DCUDNN -Wall -Wfatal-errors -Wno-unused-result -Wno-unknown-pragmas -fPIC -Ofast -DGPU -DCUDNN -I/usr/local/cudnn/include -c ./src/image_opencv.cpp -o obj/image_opencv.o
g++ -std=c++11 -std=c++11 -Iinclude/ -I3rdparty/stb/include -DGPU -I/usr/local/cuda/include/ -DCUDNN -Wall -Wfatal-errors -Wno-unused-result -Wno-unknown-pragmas -fPIC -Ofast -DGPU -DCUDNN -I/usr/local/cudnn/include -c ./src/http_stream.cpp -o obj/http_stream.o
./src/http_stream.cpp: In member function ‘bool JSON_sender::write(const char*)’:
./src/http_stream.cpp:249:21: warning: unused variable ‘n’ [-Wunused-variable]
int n = _write(client, outputbuf, outlen);
^
gcc -Iinclude/ -I3rdparty/stb/include -DGPU -I/usr/local/cuda/include/ -DCUDNN -Wall -Wfatal-errors -Wno-unused-result -Wno-unknown-pragmas -fPIC -Ofast -DGPU -DCUDNN -I/usr/local/cudnn/include -c ./src/gemm.c -o obj/gemm.o
./src/gemm.c: In function ‘convolution_2d’:
...
次に,google driveにアップロードした関係でパスが変化したので,process.pyを実行する.結局,python実行するならファイルにじゃなくてセルにそのまま貼り付けてしまっても良かったな
! python process.py
これで,train.txtとtest.txtが更新されたはずなので,気になる人はgoogle driveの方から覗いてみると良いかも.
準備はできた.
学習開始 on colab
以下のコマンドを実行すると学習が開始される.もしpermission deniedとかでたら,make cleanしてmakeしなおしてみて.また,MakefileにOPENCV=1を入れておくと,100iterationごとにLoss-chart,-mapをつけるとmAP & Loss-chartがchar.pngとして保存される.
! ./darknet detector train task1/crater.data task1/yolov3.cfg darknet53.conv.74 -dont_show -map
weightはtask1/backupの中に保存されていく.仮に途中で終わってしまって学習を再開させたい場合は以下の様にすればおけ.(この時,-mapつけてきちんと続きからplotされるのかは試していないのでわからない,つけて損はなさそうだけど)
! ./darknet detector train task1/crater.data task1/yolov3.cfg task1/backup/yolov3_last.weights
確認
モデルができたらcolab上で試しても良いし,driveからダウンロードしてローカルで使っても.
ただ,検出の時にはcfgファイルの最初のところを少し書き換える必要があるらしい.
cfgは書き換えなくても良いかもしれない.学習に使ったcfgを使った方が良いかも.
# Testing
batch=1
subdivisions=1
# Training
# batch=64
# subdivisions=8
test.jpgをcolab上で確認するにはこんな感じ.
!./darknet detector test task1/obj.data task1/obj.cfg yolov3_6000.weights test.jpg
predictions.pngができているはずなので,そちらを確認する.
参考サイト
参考にさせていただいたサイト
公式: https://pjreddie.com/darknet/yolo/
今回使ったコード元: https://github.com/AlexeyAB/darknet
process.pyの元: https://timebutt.github.io/static/how-to-train-yolov2-to-detect-custom-objects/