今回はRotation-InvariantというDOTAデータセットを使って研究開発されているモデルを動かしてみたいと思います。
- 深層学習の物体検出モデル
- 出力に回転も考慮出来る
- DOTAというデータセットを使って研究されている
目次
DOTAデータセットについて
物体検出では画像に対して水平なバウンディングボックスで出力されることがおおいのですが、衛星画像だと水平だと一部の情報が失われてしまいます。例えば船であれば船首の向きがわかれば、どこに向かっているか方向がわかります。飛行機もそうですね。
こういったターゲットの回転に対応したRotation-Invariantなモデルが研究されていて、コードが公開されています。
なかでもDOTAデータセットはRotation-Invariantの学習が可能なデータセットになっています。DOTAデータセットは、15種類のターゲットに対応しているオープンデータセットです。詳しくは本家サイトをご確認ください。
今回はこのRotation-Invariantモデルを動かしてみます。
環境は過去記事で使ってきた環境を使います。
EC2は立ち上げているとどんどんお金が請求されていきます!
DOTAデータのダウンロード
先ずはDOTAのデータ(DOTA-v1.0)をダウンロードします。データはこちらからダウンロードできます。
GoogleDriveはコマンドからダウンロードできるみたいですが、色々めんどくさそうなので、私はとりあえずブラウザからダウンロードしました。
ダウンロードした後はzipを解凍して、以下のようなディレクトリ配置にしておきます。
./DOTA/
├── test
│ └── images
├── train
│ ├── images
│ └── labelTxt
│ ├── DOTA-v1.5_train
│ ├── DOTA-v1.5_train_hbb
│ ├── labelTxt
│ └── trainset_reclabelTxt
└── val
├── images
└── labelTxt
├── DOTA-v1.5_val
├── DOTA-v1.5_val_hbb
├── labelTxt
└── valset_reclabelTxt
これのディレクトリを丸ごとzipに固めて、今度は自分のS3に上げました。
リポジトリのfork
forkしたリポジトリは自分の環境にクローン(/home/ubuntu/work/
以下)しておきました。
学習済モデルのダウンロード
学習済のモデルをダウンロードしておきます。
ダウンロード先はリポジトリのREADMEに以下のような記載があるので、それに従ってダウンロードすればOKです。
モデル | 取得先 |
---|---|
resnet_v1d | GoogleDrive |
resnet_v1b | resnet_v1dと同じ |
resnet50_v1 | GoogleDrive |
resnet101_v1 | resnet50_v1と同じ |
resnet152_v1 | resnet50_v1と同じ |
efficientnet | resnet50_v1と同じ ※BO0からBO5までダウンロード |
mobilenet_v2 | resnet50_v1と同じ |
darknet53 | resnet50_v1と同じ |
元のリポジトリにはオプション的な書かれ方をしていますが、tensorflow版だとresnet50_v1dがなかったりとpytorch以外は全部入れておいた方が良さげです。
保存した重みはpretrained_weightsというディレクトリに以下のディレクトリ構成で入れておきます。
├── pretrained_weight
│ ├── darknet
│ ├── checkpoint
│ ├── darknet.ckpt.data-00000-of-00001
│ ├── darknet.ckpt.index
│ ├── darknet.ckpt.meta
│ ├── efficientnet
│ ├── efficientnet-b0
│ ├── checkpoint
│ ├── model.ckpt.data-00000-of-00001
│ ├── model.ckpt.index
│ ├── model.ckpt.meta
│ ├── mobilenet
│ ├── mobilenet_v1_0.25_128.ckpt.data-00000-of-00001
│ ├── mobilenet_v1_0.25_128.ckpt.index
│ ├── mobilenet_v1_0.25_128.ckpt.meta
│ ├── mobilenet_v1_0.25_128.tflite
│ ├── mobilenet_v1_0.25_128_eval.pbtxt
│ ├── mobilenet_v1_0.25_128_frozen.pb
│ ├── mobilenet_v1_0.25_128_info.txt
│ ├── resnet_v1_50.ckpt
│ ├── resnet50_v1d.ckpt.index
│ ├── resnet50_v1d.ckpt.data-00000-of-00001
│ ├── resnet50_v1d.ckpt.meta
│ ├── resnet50.npy
…
全体の中でこことDOTAデータセットの配置が一番面倒だったかも。
Python仮想環境の構築
今回必要な環境はtensorflowの1系なので新しく環境を作成します。
conda create -n rotationdetection --clone tensorflow_p37
作成したらactivateして、必要なライブラリを入れていきます。
conda install -c conda-forge opencv
conda install -c conda-forge tqdm
conda install -c conda-forge shapely
pip install git+https://github.com/wookayin/tensorflow-plot.git@master
設定ファイルを準備する
このリポジトリは沢山モデルが実装されていますが、今回はRetinaNet-Rを使ってみることにしました。
./RotationDetection/libs/configs/DOTA/retinanet/cfgs_res50_dota_v8.py
にあるデータをコピーしておきます。
cp ./RotationDetection/libs/configs/DOTA/retinanet/cfgs_res50_dota_v8.py ./RotationDetection/libs/configs/DOTA/retinanet/kazushi_cfgs_res50_dota_v8.py
動作確認したいだけなので、中身20行目あたりの以下だけ変更します。
# dataset
DATASET_NAME = 'DOTA1.5'
これを
# dataset
DATASET_NAME = 'DOTA1.0'
こんな感じで変更。
cfgファイルを所定のディレクトリに入れますが、その前にオリジナルファイルを保存しておきます。
mv ./RotationDetection/libs/configs/cfgs.py ./RotationDetection/libs/configs/cfgs_ori.py
cp ./RotationDetection/libs/configs/DOTA/retinanet/kazushi_cfgs_res50_dota_v8.py ./RotationDetection/libs/configs/cfgs.py
データをEC2にもってくる
先ほど用意したDOTAデータをEC2に持ってきて、以下のように配置します。
./RotationDetection/dataloader/dataset/DOTA/
├── data_crop.py
├── data_slicer.py
├── test
│ ├── images
│ └── test_info.json
├── train
│ ├── images
│ └── labelTxt
├── val
│ ├── images
│ └── labelTxt
└── val_set.txt
データを分割する
DOTA元データは大きいのでデータをcropする。
./RotationDetection/dataloader/dataset/DOTA/data_crop.py
にあるファイルの211行目あたりの
raw_data = '/data/dataset/DOTA/val/'
raw_images_dir = os.path.join(raw_data, 'images', 'images')
raw_label_dir = os.path.join(raw_data, 'labelTxt', 'labelTxt')
save_dir = '/data/dataset/DOTA/DOTA1.0/trainval_easy/'
これを自分の環境に合わせて変更しておきます。
raw_data = '/home/ubuntu/work/RotationDetection/dataloader/dataset/DOTA/val/'
raw_images_dir = os.path.join(raw_data, 'images')
raw_label_dir = os.path.join(raw_data, 'labelTxt', 'labelTxt')
save_dir = '/home/ubuntu/work/RotationDetection/dataloader/dataset/DOTA/DOTA1.0/val/'
変更したらrotationdetectionに実行環境を変更して実行します。
cd /home/ubuntu/work/RotationDetection/dataloader/dataset/DOTA
conda activate rotationdetection
python data_crop.py
上記はvalだけですが、trainも同様に処理しておきます。
DOTAデータの前処理
DOTAデータをモデルに入力可能な形に前処理していきます。
前処理コードは./RotationDetection/dataloader/dataset/convert_data_to_tfrecord.py
にあります。
実行時の引数が多かったのでシェルスクリプトを作成しました。
python /home/ubuntu/work/RotationDetection/dataloader/dataset/convert_data_to_tfrecord.py \
--root_dir='/home/ubuntu/work/RotationDetection/dataloader/dataset/DOTA/DOTA1.0/' \
--xml_dir='train/labeltxt' \
--image_dir='train/images' \
--save_name='train' \
--img_format='.png' \
--dataset='DOTA1.0'
これを./RotationDetection/dataloader/dataset/
に移動して実行。
Cythonのコンパイル
Cpythonのコンパイルをしておきます。本家のReadmeにある通りにすればOK。
cd $PATH_ROOT/libs/utils/cython_utils
rm *.so
rm *.c
rm *.cpp
python setup.py build_ext --inplace (or make)
cd $PATH_ROOT/libs/utils/
rm *.so
rm *.c
rm *.cpp
python setup.py build_ext --inplace
Tensorbord用のポート開放設定をする
このリポジトリはTensorbordがサポートされているみたいなので、実行してみたい。
EC2のセキュリティグループのインバウンドルールを以下のように設定しておきます。
学習の実行
./RotationDetection/tools/retinanet
で以下を実行します。
python train.py
するとこんな感じで学習が進む。
************************************************************************
2021-08-19 02:25:06: global_step:20 current_step:20
speed: 6.735s, remaining training time: 20:22:43:58
total_losses:2.039
cls_loss:1.305
reg_loss:0.734
************************************************************************
2021-08-19 02:25:32: global_step:40 current_step:40
speed: 1.022s, remaining training time: 03:04:15:48
total_losses:1.576
cls_loss:1.139
reg_loss:0.437
************************************************************************
2021-08-19 02:25:53: global_step:60 current_step:60
speed: 0.986s, remaining training time: 03:01:36:59
total_losses:1.591
cls_loss:1.146
reg_loss:0.445
************************************************************************
Tensorbordの起動
Tensorbordは./RotationDetection/output/summary
に移動して、以下を実行するだけ。
tensorboard --logdir=.
これで出てくるURLではアクセスできない。
私はIPを固定してるので、http://ip-XXX-XX-XX-XX:6006/
となっているURLをhttp://XXX.XXX.XXX.XXX:6006/
に書き換えてアクセス。
しばし待つ
しばし待つ。
このリポジトリはEary Stoppingの設定がされておらず、学習が無限に回る様子。
設定ファイル/RotationDetection/libs/configs/DOTA/retinanet/kazushi_cfgs_res50_dota_v8.py
の以下のエポック回れば、/RotationDetection/output/trained_weights
以下のディレクトリに学習結果が保存される。
SAVE_WEIGHTS_INTE = 30000
回ったのを確認して止めた。
テストする
学習が終わったのでテストする。
テストは、/RotationDetection/tools/retinanet/
に移動して、以下のコマンドで実行できます。
/RotationDetection/dataloader/dataset/DOTA/test/images_pickup/
にtrainから2枚画像を選びました。
(ちなみにtestから選んだりもしたが、検出性能がそこまででてなかったので、動作確認の意味でtrainから選んだ。)
python test_dota.py --test_dir='/home/ubuntu/work/RotationDetection/dataloader/dataset/DOTA/test/images_pickup/' \
--gpus=0 \
-s
毎回打ちたくないので、私はまたbashを書いた。
テスト結果
テスト結果は/RotationDetection/tools/retinanet/test_dota
以下に保存される。
RarePlanesの画像でも試してみる。
学習データに含まれていないのでちょっと厳しいか。
おまけ:描画メモ
/RotationDetection/libs/utils/draw_box_in_img.py
の241行目あたりをコメントアウトするとスコアを消せる。