kaggle体験記: Global Wheat Detection (物体検出による小麦の穂の検出)
8月4日まで開催されていたkaggleの「Global Wheat Detection」コンペの体験談と学んだことをまとめます。
このコンペは様々な地域で撮影された写真から小麦の穂を検出するという物体検出の課題でした。
なお、僕は物体検出はもちろん深層学習もほぼ初心者のため、このエントリーでは技術的に深い内容は書けていないと思います。
逆にこれからkaggle始める、深層学習を使い始める、物体検出を始める、という方に近い内容となっております。
初めてのエントリーでわかりにくいところもあるかと思います。
ご指摘いただけますと幸いです。
目次
- 1. コンペ概要
- 2. 参戦動機
- 3. 結果として経験になったこと
- 4. EDA
- 5. 重要だった前処理
- 6. よく利用されていたアルゴリズム
- 7. 苦労したこと
- 8. 反省・これから頑張りたいこと
- 9. 基礎知識
1. コンペ概要
https://www.kaggle.com/c/global-wheat-detection
小麦は世界中の食卓に使われていて、植物学的にも農業的にも小麦の分布を知るということが重要らしい。
ただし、これまでの物体検出の取り組みでは地域によってことなる小麦を同じモデルでは検出できていなかった。
このコンペでは複数の地域の小麦の画像を混ぜたデータセットを用いて一つのモデルで小麦を検出できることを目指す。
ということから、地域によるバイアスがかからない柔軟なモデルを構築する必要があります。一昔前に問題になった人種バイアス・性別バイアスにも通じますね。
画像データサマリ
学習データ画像
- 3422件
評価データ画像
- 10件(公開データの件数、非公開なデータでは1000件)
評価方法
評価指標
- MAP(Mean Average Precision)
このコンペでは小麦の穂の検出箇所を示すバウンディングボックスという枠の位置・幅・高さが検証データセットとどれだけ近いか、ということを競います。
https://www.kaggle.com/c/global-wheat-detection/overview/evaluation
ノートブックの規定
このコンペはノートブックを提出する必要があります。
https://www.kaggle.com/c/global-wheat-detection/overview/code-requirements
- CPUだけを使う場合は9時間以内に実行が終了すること
- GPUを使う場合は6時間に実行が終了すること
- TPUは使用不可
- 提出するノートブックについてインターネットは使用不可
→kaggle kernel標準でインストールされていないライブラリなどをインターネットからpipすることは不可(whlファイルなどをデータセットとしてアップロードしておくことや、gitレポジトリをあらかじめcloneしてデータセットとしてアップロードしておくことは可) - 学習済みモデルなど外部データを使うことは可
- kaggle kernel内でライブラリを編集することは不可
- 提出ファイル名は「submission.csv」であること
2. 参戦動機
scikit-learnやSQLを使った統計的機械学習はこれまでの業務で経験したり勉強してきましたが、深層学習はありませんでした。
画像処理や物体検出は将来アプリ開発をしてみたく、今のうちに経験しておこうという動機です。
具体的には下記となります。
- PyTorchを使えるようになりたい
- 深層学習の勉強をしたい
- 物体検出の経験を積みたい
- 画像処理の経験を積みたい
- (将来的に)メダルが欲しい
→今回上位50%にやっと入った程度なので、力不足でした、、
3. 結果として経験になったこと
- PyTorchで学習済みモデルを使った再学習の標準的な流れ
- FasterRCNNとYOLOv5の使い方
→YOLOv5は使ってみたけど最終的にはライセンスの問題で使用不可となりました - 画像の前処理のライブラリ(albumentation, OpenCV)の使い方
- 画像の代表的な前処理(DataAugumentation)
- kaggle kernelの使い方
・datasetのアップロード方法
・internet使用不可の場合のライブラリ追加方法
4. EDA
小麦画像可視化
バウンディングボックスの位置・幅・高さは画像ごとに下記のようにCSVで与えられています。
"width", "height"列は画像自体のサイズで、1024px x 1024pxの画像ということです。
"x", "y" は各バウンディングボックスの左上の座標で、"w", "h"がその幅と高さです。
これらを基に下記のような画像を作ることでバウンディングボックスの形状や配置を理解することができます。
異常な大きさのバウンディングボックス
バウンディングボックスのCSVから面積の分布を観察しました。
上のグラフからは面積50万平方pxということで、1024px四方にも関わらず700px x 700px程度の大きさもありうることが示唆され、また逆に下の図からは数平方pxの非常に小さいバウンディングボックスが存在することがわかります。
実際に対象の画像を可視化すると下記のようになっていました。
最大面積のバウンディングボックスの方は見ての通りですが、最小面積の方は右下をよく見ると
という点のようなバウンディングボックスがあります。
これらは教師データとしてはノイズとなるので、除外します。
具体的には面積をあらかじめ計算し、観察した結果から上限・下限を決め打ちし、範囲外のバウンディングボックスを除外します。
また、学習用のデータセットの画像はより大きな画像から切り出された画像であることが元の論文からわかるそうです。(僕は未着手です)
なんとかして切り貼りして元の画像を復元することで新しい画像を作り出すこともできたようです。
https://www.kaggle.com/c/global-wheat-detection/discussion/149805
5. 重要だった前処理
画像処理
用いたライブラリ
- albumentations
https://albumentations.readthedocs.io/en/latest/
画像のデータ拡張のために作られたライブラリで、PyTorchのDatasetクラスのtransform関数に直接組み込めたり、最終的にPyTorchで実行する為に必要なtorch.Tensorクラスに変換することができる。
何ができるかは下記の記事がよくまとまっています。
https://qiita.com/Takayoshi_Makabe/items/79c8a5ba692aa94043f7 - OpenCV
https://opencv.org/
定番の画像処理ライブラリ - NumPy
https://numpy.org/
定番の行列計算ライブラリ
numpyのメソッドで画像処理ができるわけではないけど、画像データを配列として要素の入れ替えなどしました
前処理の種類
アフィン変換
- 回転
- 拡大・縮小
- 上下左右反転(マイナス倍の拡大縮小)
- せん断(やってない)
- 平行移動
https://imagingsolution.blog.fc2.com/blog-entry-284.html
の画像がわかりやすく、大きく4種類です。
画像の一部分を切り出すこと
HSV変換
画像データの表現方法の一つ、HSV(Hue-Sturation-Value=色相-彩度-明度)を調整すること
モザイク
ここでのモザイクは画像をぼかすことではなく、複数(今回は四枚)の画像を切り貼りして一つの画像とすることでした
cut-out
CNNの正則化手法の一つで、画像の一部を塗りつぶして欠落させること
これらを試した結果の前後が下図です。
画像処理後、範囲外やcut-outで画像が小麦がなくなった箇所のバウンディングボックスは削除や変形が必要です。
albumentationsを用いた場合には自動で処理してくれるメソッドもありますが、してくれないメソッドもあります。
- バウンディングボックスを処理してくれる:
https://www.kaggle.com/c/global-wheat-detection/discussion/149805 - バウンディングボックスを処理してくれない:
https://www.kaggle.com/c/global-wheat-detection/discussion/149805
なのでcut-outやモザイクは下記のノートブックのように自作関数で処理しています。
https://www.kaggle.com/nvnnghia/awesome-augmentation#Augmentation-functions
また、僕は今回適用する時間がなかったのですが下記のmix-upも有効だったようです。
mix-up
2つの画像を透過させる形で重ね合わせる手法です。
概要は下記の記事をご参照ください。
https://qiita.com/yu4u/items/70aa007346ec73b7ff05
https://www.kaggle.com/kaushal2896/data-augmentation-tutorial-basic-cutout-mixup#Let's-define-new-augmentations
Pseudo-labeling(擬似ラベリング)
COCOなどで作成された事前学習モデルから今回の小麦データで再学習する前に、検証用のpublicの画像データにバウンディングボックスを推論し、検証用データも学習データに含めること。
データの水増しとエントロピー減少に役立つらしい。
ノートブック
https://www.kaggle.com/nvnnghia/fasterrcnn-pseudo-labeling
元論文
http://deeplearning.net/wp-content/uploads/2013/03/pseudo_label_final.pdf
6. よく利用されていたアルゴリズム
Faster-RCNN
https://qiita.com/mshinoda88/items/9770ee671ea27f2c81a9#2-5-faster-r-cnn
EfficientDet
https://www.kaggle.com/shonenkov/training-efficientdet
YOLOv5(ライセンスの問題で使用不可)
https://github.com/ultralytics/yolov5
7. 苦労したこと
データ拡張のハイパーパラメータ調整
上記の前処理ではHSV・回転角・平行移動の距離などを元の画像からどれだけ変調するかというのがパラメータでした。
またここで紹介した以外にもコントラスト・ブライトネスの調整した方がいいのかなど、public scoreを見てみないとわかりませんでしたので、試したものを全て記録・比較しました。
実行した結果がどのノートブックかわかるように「ver」で管理していました。
albumentationsでのデータ拡張とそれ以外のデータ拡張を組み合わせること
top kernelの方々を参考にしつつ上記の要領で前処理を試しては追加しました。
この時の実行順やデータ型が適切でなくてエラーになったり、バウンディングボックスの座標が崩れました。
特に順番に決まりはないと思いますが、自作関数で前処理を追加した前後ではバウンディングボックスの数・位置・サイズを確認し、削除されるべきものが削除されているかなど確認しました。
dataloderのreturnではtorch.Tensorになっているようにしました。
YOLOv5など外部レポジトリを用いてモデル作成するときのバージョン管理
特にYOLOv5が日々アップデートされていたからですが、後から追いつこうとした場合に採用しているpytorchなどのバージョンが異なっていて、あるべきメソッドがなかったり、CUDAがうまく使えなかったです。
discussionやノートブックが共有されたら早めにキャッチアップしましょう。
8. 反省・これから頑張りたいこと
- PyTorchのお作法を学ぶ
・入力データのTensorのndimやshapeがどうあるべきか
・DatasetやDataloaderの挙動を理解する
・学習済みモデルの重みのセーブ・ロードの方法に何パターンかあり、状況に応じて使い分けられるようになる - (既存の手法を組み合わせるとしても)ゼロからスクリプトを書けるようになること
・今回はtop kernelのノートブックをforkしてそのまま使わせていただいたので、自分で必要と思う処理を探してきて、インターフェースに気をつけながら自分で組み合わせられるようになる - top kernelのノートブックを鮮度が新しいうちに真似すること
・時間が経つとノートブック内で参照されている外部レポジトリがアップデートされて、ノートブックだけforkしてもそのままでは実行できない状態になっている。その結果デバッグに無駄な時間を費やす(結果的に勉強にはなるのだけど、コンペ向きではない)
9. 基礎知識
kaggleカーネル
- データセット
外部ファイルなどをノートブックで使えるようにするには、kernelの右側で「add data」でできます。
- pip
インターネットが使えるコンペであればいつものこれです!pip install ライブラリ名
手元で実行している分にはこれでいいですが、submitする場合にはこれではダメです。
これはあらかじめwhlファイルを取得してkaggle datasetにアップロードしておくことで対処できます。
https://www.kaggle.com/c/severstal-steel-defect-detection/discussion/113195 - GitHub連携
データセットアップロード画面にGitHubの項目があります。
- 読み取り・書き込み権限
・inputフォルダ:予めデータセットとしてデータを格納することが可能。
しかし、後からファイル保存や書き込みは不可。
・outputフォルダ:予めデータを格納することは不可。
しかし、後からファイル保存や書き込みは可能。
使用するレポジトリの都合でファイルが作成される場合などはこちらに出力するようにしておく必要がある。 - ノートブックから「.py」ファイル中でCUDAを実行するための環境構築
コンペ終了直前でPyTorchが1.6.0にアップデートされました。
そのままYOLOv5などのスクリプトを実行しようとすると、CUDAが認識されませんでした。
原因は不明ですが、下記のノートの通りに「torch==1.6.0+cu101」であれば実行可能でした。
https://www.kaggle.com/okeaditya/what-s-new-in-pytorch-1-6
評価指標
- MAP(Mean Average Precision):
・物体検出の評価指標の一つ
・検出された物体のうちラベルが正解だったものの割合がPrecision
・IoUの閾値を0~1で変化させた時の平均がAverage Precision
・全ての画像についてAverage Precisionを平均したのがMean Average Precision - IoU(Intersection of Union) :
・物体検出の評価指標の一つ
・教師データと推論したバウンディングボックスの重なりの正確さを示す
・(教師データと推論結果の領域の積集合) / (教師データと推論結果の領域の和集合)
・全く重なっている部分がなければ0、ぴったり重なっていれば1、一部分が重なっていたり領域が包含関係にある場合には0~1の間となる。