Chainer公式および関連リポジトリで定義されているCNNの比較

[Chainer organization](https://github.com/chainer)やその他のリポジトリで同じCNNが複数実装されていたため比較しました。
執筆時のバージョンは以下のとおりです。

- [Chainer](https://github.com/chainer/chainer): v4.2.0
- [ChainerMN](https://github.com/chainer/chainermn): v1.3.0
- [Chainer Benchmark](https://github.com/chainer/chainer-benchmark): `04eb2aaf9fd85c66a42a6e138209458745ced8b7`
- [convnet-benchmarks](https://github.com/soumith/convnet-benchmarks): `b458aab61c0ac2257c0990119b5de15c1e886f02`

## CNN実装のあるパス
### Chainer
- [chainer/links/model/vision/*.py]()
 - `GoogLeNet`, `VGG16Layers`, `ResNetLayers`, `ResNet[50,101,152]Layers`を定義
 - `chainer.Chain`を継承
 - `__call__(self, x, layers=['prob'])`を実装 (入力`x`からラベル名`layers`の出力を返す)
- [`examples/imagenet/*.py`](https://github.com/chainer/chainer/tree/master/examples/imagenet)
 - `AlexNet`, `AlexFp16`, `GoogLeNet`, `GoogLeNetBN`, `GoogLeNetBNFp16`, `NIN`, `ResNet50`, `ResNeXt50` クラスを実装
 - `chainer.Chain`を継承
 - `__call__(self, x, t)`を実装 (入力`x`, 出力`t`から損失を返す)
- [`examples/modelzoo/download_model.py`](https://github.com/chainer/chainer/tree/master/examples/modelzoo)
 - AlexNet, CaffeNet, GoogLeNet, ResNetのCaffeの学習済みパラメタ・モデル定義をダウンロードするスクリプト
 - `__call__(self, inputs, outputs)`を実装 (入力`{"data":x}`,`{"ラベル名":t}`から出力を返す)
 - モデル定義はCaffeの定義に準拠

### ChainerMN
- [`examples/imagenet/models/*.py`](https://github.com/chainer/chainermn/tree/master/examples/imagenet/models)
 - `AlexNet`, `GoogLeNet`, `GoogLeNetBN`, `NIN`, `ResNet50` クラスを実装 (Chainerの`examples/imagenet/*.py`とほぼ同一)
 - **`GoogLeNetBN`は`inc4c`,`inc4d`の出力数がChainerのものと異なる (それぞれ160→128, 96→64)**
 - **`AlexFp16`, `GoogLeNetBNFp16`, `ResNeXt50` は定義されていない**
 - `ResNet50`では畳み込みのグループ数が指定できなくなっている

### Chainer Benchmark
- [`benchmarks/convnet/nets/*.py`](https://github.com/chainer/chainer-benchmark/tree/master/benchmarks/convnet/nets)
 - `Alex`, `GoogLeNet`, `overfeat`, `vgga`クラスを定義
 - `chainer.Chain`を継承
 - `forward(self, x)`を実装 (入力`x`から最終層の出力を返す)

### convnet-benchmarks
- [`chainer/*.py`](https://github.com/soumith/convnet-benchmarks/tree/master/chainer)
 - Chainer Benchmarkで実装されているモデルと同一

## まとめ

| リポジトリ    | パス                                   | Forward計算            | AlexNet | GoogLeNet | ResNet |
|:---------:|---------------------------------------|------------------------|:-:|:-:|:-:|
| Chainer   | `chainer/links/model/vision/*.py`     | `__call__(self, x)`    | |✔|✔|
| 〃         | `examples/imagenet/*.py`              | `__call__(self, x, t)` |✔|✔|✔|
| 〃         | `examples/modelzoo/download_model.py` | `__call__(self, inputs, outputs)` |✔|✔|✔|
| ChainerMN | `examples/imagenet/models/*.py`       | `__call__(self, x, t)` |✔|✔|✔|
| ChainerBM[^1] | `benchmarks/convnet/nets/*.py`        | `forward(self, x)`     |✔|✔||
| Convenet  | `chainer/*.py`                        | `forward(self, x)`     |✔|✔||

[^1]: Chainer Benchmarkの略

### AlexNetの差異

| リポジトリ | conv1,2のグループ数 | 畳み込み層フィルタ数 | 正規化層 | 入力サイズ | 16 bitモデル |
|:-:|:-:|:-:|:-:|:-:|:-:|
| Chainer (`imagenet`) | 1 | 96,256,384,384,256 | LRN | 227 | ✔ |
| Chainer (`modelzoo`)[^2] | 2 | 96,256,384,384,256 | LRN | 227 | |
| ChainerMN            | 1 | 96,256,384,384,256 | LRN | 227 | |
| ChainerBM            | 1 | 64,192,384,256,256 |     | 224 | |
| Convenet             | 1 | 64,192,384,256,256 |     | 224 | |

[^2]: Caffeの`models/bvlc_alexnet/train_val.prototxt`と`protoc --decode_raw < bvlc_alexnet.caffemodel`から判断

## 感想
ONNXあたりでこういった記述が1つに統一できればいいですね (各FWの設計思想の違いで結局煩雑な変換処理が必要になりそう……)。