Torchでdeeplearning その2

#初めに
[前記事](http://qiita.com/perrying/items/c53864d1bd2155a0635d)でTorchの基本的な使い方を紹介したので今回は応用編としてパラメータの初期化やファインチューニング、その他便利ツール、ライブラリについて紹介します。

#パラメータの初期化
torchのパラメータ初期化方法は様々ありますが単純な方法として以下の記述で行うことができます。

```lua
require 'nn'
fc = nn.Linear(10,10)
fc.weight:uniform(-0.1, 0.1)
```

上記コードは入力10ユニット、出力10ユニットの全結合層に対し、重みを[-0.1,0.1]の範囲で初期化しました。uniform関数を他の関数に変えることで様々な方法で初期化を行えます。
また、[nninit](https://github.com/Kaixhin/nninit)と言うlibraryが用意されており、これを使うことでxavierや[Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification](https://arxiv.org/abs/1502.01852)で提案されているような方法など様々な初期化を行うことができます。
上記コードのように毎回初期化してSequentialにadd()するのは面倒なので以下のようにすることで一度に初期化を行うこともできます。

```lua
function weightInit(layerName, model)
  for i, l in pairs(model:findModules(layerName)) do
    l.weight:uniform(-0.1, 0.1)
  end
end

net = nn.Sequential()
net:add(nn.SpatialConvolution(1,1,1,1))
net:add(nn.SpatialConvolution(1,1,1,1))
net:add(nn.View(-1))
net:add(nn.Linear(10,10))

weightInit('nn.SpatialConvolution', net)
```

上記コードは畳み込み２層、全結合層1層からなるネットワークを定義して、畳み込み層の重みを[-0.1,0.1]の範囲の乱数で初期化しました。findModuleはSequentialの任意の名前のModuleを取り出すことができ、layerNameと一致した全ての層の重みを初期化することができます。また、任意の1層のみを初期化したい場合は:get()を使って行うこともできます。

#ファインチューニング
Torchによるファインチューニングの方法を紹介します。すでにtorchの学習済みモデルがある場合は以下のようにして最終層を取り払うことで行えます。

```lua
net = torch.load(pretrainmodel_path) -- pretrainモデルの読み込み
net:remove(#net.modules) -- 最終層の削除
net:add(nn.Linear(nInput, nOutput) -- 目的に合わせた最終層の追加
```
また、torchの学習済みモデルがない場合は[loadcaffe](https://github.com/szagoruyko/loadcaffe)libraryを使うことでcaffeモデルをtorchのmoduleとして読み込むことができます。

```lua
require 'loadcaffe'
net = loadcaffe.load(solverpath, caffemodelpath, 'nn')
net:remove(#net.modules)
net:add(nn.Linear(nInput, nOutput)
```

ただし、loadcaffeはtorchにない層を読み込むことができないので注意が必要です。例えばGoogleNetなどを読み込む場合、標準のnnライブラリにはInceptionモジュールがないためloadcaffeで読み込むとInceptionの中身の畳み込みやプーリングが個別に読み込まれてしまいます。その場合はget()を使って各層を読み込んで別のSequentialにaddしていく必要があります。

#iTorch
[iTorch](https://github.com/facebook/iTorch)はjupyter notebookでtorchを使うためのツールです。jupyter notebookの便利さをtorchでも利用することができます。

#pythonとtorch
- [lutorpy](https://github.com/imodpasteur/lutorpy)を使えばpythonでtorchのmoduleを使うことができます。torchで学習したモデルをpythonで読み込んで使うことができ、おそらく学習もできると思います。学習したモデルの評価などをpythonで行う際に重宝してます。
- [npy4th](https://github.com/htwaijry/npy4th)では.npyファイルのようなnumpyのファイルをtorchで読み込むことができます。また逆にtorch.Tensor()を.npyとして書き出すこともできます。前処理などをnumpyで行ってtorchで読み込む。出力結果を.npyで保存してpythonで可視化を行う、などが気軽にできます。

#拡張ライブラリ
- [inn](https://github.com/szagoruyko/imagine-nn)にはROIPoolingやSpatialPylamidPoolingなど物体検出でよく用いられるmoduleが入っています。
- [dpnn](https://github.com/Element-Research/dpnn)ではGoogleNetのInceptionモジュールや前処理、後処理に使える関数(onehotやwhite noise, k-meansなどなど)、強化学習用のモジュールがあります。
- [rnn](https://github.com/Element-Research/rnn)にはリカレントニューラルネットワークに関する様々なモジュールがあり、また自分で簡単にオリジナルのリカレント入力をする層を定義することもできます。[example](https://github.com/Element-Research/rnn/tree/master/examples)も充実していて、arxivに使い方の[論文](https://arxiv.org/abs/1511.07889)もあります。
- [optnet](https://github.com/fmassa/optimize-net)を使えばmodelのメモリを最適化することができ、GPU使用率を最大80%ほど削減してくれます。ネットワークが大規模になる場合は必須のlibraryです。
- [nngraph](https://github.com/torch/nngraph)では、複雑に分岐したモデルを組む場合にとても便利なlibraryです。イメージとしてはcaffeのような感じで、bottomレイヤーを指定してどこの層とつながっているかを書くことができます。nn.ConcatTableやnn.ParallelTableで記述が難しい場合に重宝します。以下に簡単な記述例を示します。

```lua
require 'nngraph'
-- 最初の()にmoduleの引数、次の()にbottomの指定
inputs = nn.Identity()()
hidden1 = nn.Linear(10, 10)(inputs)
hidden2 = nn.Linear(10, 10)(hidden1)
outputs = nn.Linear(10, 2)(hidden2)
model = nn.gModule({inputs}, {outputs}) -- 最初の引数に入力層、最後の引数に出力層の変数をTableで与える
```

ちなみにnngraphはネットワークの可視化やデバッグも行ってくれます。

#まとめ
その他便利ものがあったり思い出したりしたら順次追加したいと思います。また時間ができたらrnnモジュールの使い方など書いてみようと思います。