物体検出で軽量なモデルとして有効という話のPeleeNetをKerasで実装してみました。CIFAR-10で確かめた結果、簡単なData Augmentationで95%近い精度が出せることが確認できました。
元論文
R. J. Wang, X. Li, C. X. Ling. Pelee: A Real-Time Object Detection System on Mobile Devices. NIPS. 2018.
https://arxiv.org/abs/1804.06882
論文の解説とか
https://qiita.com/saneatsu/items/b372a2d71a33616f7355
図だけ読んで適当にやったら実装できたので、読み飛ばしている部分があるかもしれません。
コード
オリジナルのCaffeをもとに自分がKerasに実装したものです。
https://github.com/koshian2/PeleeNet-Keras
あらまし
PeleeNetと呼ばれるDenseNetベースの軽量化なモデル。係数が2.8Mと少ないながら、ImageNetでMobileNetV2以上の精度を出しています。PeleeNetがTop1:72.6%、MobileNetV2がTop1:72.0%。
このような構造。Stem BlockとDense Block, Transition Layerで構成されます。
StemBlockは入力のダウンサンプリング用のブロック。DenseBlockとはDenseNetの「知識の積み重ね、集約」といったConcatで少しずつチャンネル数が増えていく構造のブロック。Transition Layerとは全体に1x1Convを掛けてダウンサンプリングするレイヤー。ここらへんの発想はDenseNetと同じです。
この図はDenseNetの論文より
Stem Block
入力のダウンサンプリング用のブロック。
224→56へのダウンサンプリングですが、この構造がかなり精度に効いているようです。他のモデルに使いまわしできるのではないかと思います。論文内のImageNetの実験でも、StemBlockの有無でTop1精度が75.8%→76.8%と1%向上。
Dense Layer
PeleeNetでは右図の「2-way dense layer」というのを使っています。左図はDenseNetのオリジナルで使われているDense Block。
この図だと若干混乱しやすいのですが、Filter concatenateでは「Previous layer」と「左側の3x3 k/2, conv」「右側の3x3, k/2, conv」の3つのレイヤーを連結します。ここでkはDenseNetにおける成長率(growth rate)で、実際の結合後のレイヤーの数とは異なります。PeleeNetでは成長率は32を使っています。詳細はコード参照。
MobileNetとの違い
「軽量で精度の出るモデルならMobileNetでいいじゃん」という疑問はもっともなのですが、PeleeNetの論文いわく、「MobileNetで使っているDepthwiseConvやSeparableConvはFP16だと高速化されない」とのこと。普段FP32のKerasでやってると「そんなことはないじゃん。DepthwiseやSeparableははええよ」と言いたくなるのですが、FP16で推論のような特殊な事情だとそうなのでしょう。
そのかわりに、PeleeNetでの高速化のポイントは、1x1畳み込みを非常に多く使って理論的な計算量を減らしていること。これ自体はResNet派生やGoogLeNet時代からあるので、比較的使い古された手法です。やっていることはただのConv2Dなので、FP16でも対応できるはずです。
実験
CIFAR-10で以下の4パターンを計測しました。詳細な条件はコード見てください。
- Data Augmentationあり / Stem blockあり
- Data Augmentationあり / Stem blockなし
- Data Augmentationなし / Stem blockあり
- Data Augmentationなし / Stem blockなし
Data Augmentationは4ピクセル上下に動かして左右反転入れる、Standard Data Augmentation。
Stem blockの有無は、入力解像度・出力解像度が変わります。Stem blockありが本来のPeleeNetの構造です。なしの場合は、いきなりDenseLayerに入ります。
- Stem blockあり→入力 224 x 224 x 3:出力 7 x 7 x 704
- Stem blockなし→入力 32 x 32 x 3 : 出力 4 x 4 x 704
Stemありの場合は32→224に7倍のアップサンプリングを前処理に入れています。
各モデルのsummaryは自分のgithubを見てください。
- CIFAR-10, Stem blockあり https://github.com/koshian2/PeleeNet-Keras/blob/master/summary/cifar10_use_stem.txt
- CIFAR-10, Stem blockなし https://github.com/koshian2/PeleeNet-Keras/blob/master/summary/cifar10_no_stem.txt
結果(weight decayなし)
論文ではWeight Decayのパラメーター特になかったので、そのまま訓練しました。
あれ、なんか低くない?? 8割出ないってAlexNet以下では……。
ResNet系の論文でCIFAR-10にはWeight Decay入れてたのを思い出したので、Weight Decayを入れて再訓練してみました(ちなみにPeleeNetの論文にはCIFARに対する言及はありません)。
結果(weight decayあり)
5e-4のWeight Decay(L2正則化)を入れて訓練します。値は適当に入れたらうまく行ったものです。
95%近く出た。わーい! これならMobileNetといい勝負じゃないかと思います。
精度比較
Augmentation | Stem Block | No weight Decay | 5e-4 Weight Decay |
---|---|---|---|
☓ | ☓ | 0.7633 | 0.9247 |
☓ | ○ | 0.8280 | 0.9218 |
○ | ☓ | 0.8881 | 0.9446 |
○ | ○ | 0.8996 | 0.9410 |
Weight Decayありのほうは、Stem Blockがない方が精度が上がってしまいましたが、これはStem Blockなしのほうで7倍のアップサンプリングという少し特殊なことをしているので、ImageNetのような高解像度の入力一般で成立する現象ではないと思います(Weight DecayでStem Blockの有用性が減っている感は否めないけど)。
まとめ
PeleeNet遊びで訓練した割には結構強かったです。精度や速度どうこうという視点も良いですが、DenseNetのような「知識の積み重ね・集約」構造をお手軽に再現したいときは特に使えるモデルではないかと思われます。
少しモデルが深いのでWeight Decayや学習率の調整は難しいかもしれませんが、2.8Mという小型なモデルなので、普段使いにも便利そう。高速化手法も、1x1Convという割とありふれた手法ですからね。
ちなみに、DenseNet特有のGrowth rateに応じたちびちびFilter Concatenateをやめて、前のレイヤー全部をDense Layerに通す(係数は増えますが深くする必要性は減ります)構造も試してみましたが、あまりうまく行きませんでした(Weight Decay入れても7~8割)。なのでPeeleNetのDense Layerの構造は、DenseNetライクの構造ありきではないかと思います。
MobileNetとどっちがいいという話は、好きなほう使えばいいんじゃない? という感じでした。MobileNetも進化してますからね。FP16ならPeleeNetありだと思います。