RIP Theano - 開発中止のアナウンスを受けて

Deep Learning Framework の先駆け，"Theano" の開発中止が発表されました．

https://groups.google.com/forum/#!topic/theano-users/7Poq8BZutbY
> ### MILA and the future of Theano
>
> Dear users and developers, 
>
> After almost ten years of development, we have the regret to announce that we will put an end to our Theano development after the 1.0 release, which is due in the next few weeks. We will continue minimal maintenance to keep it working for one year, but we will stop actively implementing new features. Theano will continue to be available afterwards, as per our engagement towards open source software, but MILA does not commit to spend time on maintenance or support after that time frame. 
>
> (後略)

ネットでは，これまでの仕事に対する謝辞や，哀悼の意(RIP=rest in peace)のメッセージが数多く発信されています．私もDeep Learningフレームワークは，"Theano"から入った一人ですが，Googleから"TensorFlow"がリリースされた後は，徐々に"Theano"は使わなくなって行きました．最近のDeep Learning フレームワークが次々とリリースされる状況下で，Theanoを継続させることは，リソースの関係から難しくなってきたのかも知れません．（ご存知の方も多いと思いますが，Theanoは，企業でなくアカデミック(MILA=Montreal Institute for Learning Algorithms)が開発してきた，数少ないライブラリです．）

ここでは，”Theano"に影響を受けた者として，最後(?) に簡単なTheanoコードを作成し，"Theano"とは何だったのか，振り返ってみたいと思います．

## Deep Learning をPythonでやろうとした場合，Theanoしかなかった
私がTheanoの学習を始めたのが2015年でしたが，その頃の状況は，「やっぱりTheanoが"Defo"(default)でしょう」という感じでした．Chainerの最初のリリースが2015年の6月でしたので，そちらから始める環境に（私は）あったのかも知れませんが，2015年のChainerはまだ，ユーザ数も多くなかったと記憶しています．（記憶違いでしたら，申し訳ありません．）またChainerリリース以前では，それこそ Theano しかなかったという状況だったと思います．(Python以外では caffe, torchがあります．）

Theanoを学ぶ際，誰もが見るサイトが，関係者が公開した "Deep Learning Tutorials" (DeepLearning 0.1 documentation) でした．
http://deeplearning.net/tutorial/

日本語ドキュメントは，当時，ほとんどありませんでしたが，アンテナ感度の高い方々は，いち早くQiitaやその他ブログで，Theanoを取り上げており，それらの記事を，参考にしながらTheanoの勉強しました．

その後，Chainer, TensorFlowを初め，数々のDeep Learning用フレームワークがリリースされた後の状況は，皆さんの知るところだと思います．

## Theanoコードをまた書いてみた
最近，ご無沙汰だったので，今一度，Theanoのコードを書いてみました．モデルは，基本的なMLP(Multi-layer Perceptron)です．題材は，最近，MNISTオルタナティブとして公開された"Fashion MNIST"です．
https://github.com/zalandoresearch/fashion-mnist

Theanoには，合わせて使う”Lasagne"というHigh-level APIのライブラリがあるのですが，これを使うにも一定の学習コストが必要だったので，”Lasagne"無しで書くケースも多いと思います．


```py
class HiddenLayer(object):
    """ 
      Fully connected hidden layer
    """
    def __init__(self, input, n_in, n_out, rng, W=None, b=None,
                 activation=T.nnet.relu):
        self.input = input

        if W is None:
            W_values = np.asarray(
                rng.uniform(
                    low=-np.sqrt(6. / (n_in + n_out)),
                    high=np.sqrt(6. / (n_in + n_out)),
                    size=(n_in, n_out)
                ),
                dtype=theano.config.floatX
            )
            if activation == T.nnet.sigmoid:
                W_values *= 4

            W = theano.shared(value=W_values, name='W', borrow=True)

        if b is None:
            b_values = np.zeros((n_out,), dtype=theano.config.floatX)
            b = theano.shared(value=b_values, name='b', borrow=True)

        self.W = W
        self.b = b

        lin_output = T.dot(input, self.W) + self.b
        self.output = (
            lin_output if activation is None
            else activation(lin_output)
        )
        # parameters of the model
        self.params = [self.W, self.b]
```

ほぼ，"DeepLearing 0.1 documentation" の写経ですが，全結合のレイヤー・クラスはこんな感じになります．（もはや，今からTheanoを始めようという人は皆無と思われますので，解説はしません．懐かしさを感じていただければと思います.)

"Theano"は，とにかく「難解」といった印象が強いのですが，難しさの一因が，**theano.function()** でした．

```py
# こんな感じ
# Theano Functions
    gparams = [T.grad(cost, param) for param in params]
    updates = [(param, param - learning_rate * gparam)
               for param, gparam in zip(params, gparams)]

    train_model = theano.function(
        inputs=[index],
        outputs=cost,
        updates=updates,
        givens={
            x: train_set_x[index * batch_size: (index + 1) * batch_size],
            y: train_set_y[index * batch_size: (index + 1) * batch_size]
        }
    )

    validate_model = theano.function(
        inputs=[index],
        outputs=[cost, errors],
        givens={
            x: valid_set_x[index * batch_size:(index + 1) * batch_size],
            y: valid_set_y[index * batch_size:(index + 1) * batch_size]
        }
    )

```

今では，上記コードを見て内容を理解できますが，最初に **theano.function** を見た時には，定義するタイミングもよく分からなかったし，オプションのkey word (inputs, outpus, givens等)も多く，かなり悩みました．

**theano.function** も難しかったですが，それに輪をかけて難しいのが **theano.scan** でした．これは，Recurrent Neural Network（RNN) モデルの実装に必要となる"しくみ"なのですが，未だにその全容について理解できていません．**theano.scan** 関係では，過去Qiitaに「基本的なRecurrent Neural Networkモデルを実装してみた」という解説記事を投稿してるのですが，白状いたします，「**theano.scan**，今でもよくわかっていません...」私のあいまいな理解では，グラフ・ネットワークの構造に自由度，柔軟性を持たせるための機能，ということになります．実は，TensorFlowにも **tf.scan()** があるバージョンからサポートされているのですが，**theano.scan()** の仕様はそのまま移植されておらず，その一部のみを引き継ぐものとなっているようです．（漏れた機能は，tensorflowの他の高階関数，control-flow-ops で補完できるはずです．）

今回のコードはMLPモデルですので，"theano.scan"は登場しません．
コード全体は，[Gist](https://gist.github.com/tomokishii/02fa43683fd5df1f13414909494aaaf7) にアップロードしました．

コードの実行結果は，次のようになりました．

```text
 . . .
（前略）
 . . .
epoch[   18] : cost =    0.5986
validation: cost =    0.5776, accuracy=    0.8350
epoch[   19] : cost =    0.6814
epoch[   19] : cost =    0.8262
epoch[   19] : cost =    0.6020
epoch[   19] : cost =    0.5807
epoch[   19] : cost =    0.5938
validation: cost =    0.5735, accuracy=    0.8372
epoch[   20] : cost =    0.6730
epoch[   20] : cost =    0.8231
epoch[   20] : cost =    0.5985
epoch[   20] : cost =    0.5747
epoch[   20] : cost =    0.5889
validation: cost =    0.5698, accuracy=    0.8380
```

20 epochでのaccuracy（正答率）は，約 84％でした．データセットが，手書き数字分類のMNISTでなくFashin MNISTを使用したのでやや難易度が上がり，分類の成績は悪くなっています．但し，Fashion MNISTのドキュメントによると，MLPモデルでも約 90％ まで，到達できるとのことなので，まだ，パラメータの調整も必要なようです．（もちろん，畳み込みネットワーク等では，よりよい分類精度を得られるようです．）


## Theano周辺のこれから
以下，Theano及びTheano周辺のライブラリについて情報を確認しておきます．

- Theanoの現バージョンは 0.10.x ですが(本記事執筆時点)，Theano 1.0 が数週間の内にリリースされるそうです．
- Kerasは，backend のオプションとして，Theano もサポートされていますが，これは，Keras のバージョン更新のあるタイミングでTheanoサポートが打ち切られると推定されます．（根拠となる情報はありませんが．）
- PyMC3 は，現在 backend に Theano を使用していますが，キー・プログラマーの Dr. Thomas Wieckiは，他のDeep Learning Framework へのbackend切り替え検討を始めたところのようです．
（PyMC3がこの手のbackendを必要とする理由が今ひとつ分かっていませんが...）
- Lasagneは，TheanoのHigh-level APIなので，開発中断は間違いないでしょう．

Theanoとは何だったのか？ですが，単なるDeep Learningのインプリメンテーション手段であっただけでなく，この界隈の研究者が各自のアイディアを交換するツールでもあったように見えます．Theanoの開発は中止されますが，Theanoで書かれた優れたコードは，GitHub等に残るはずです．論文からのリンクでコードを調べる機会は，これからもあると思いますので，コードを読める程度の知識はkeepしたいものです．移り変わりの激しいDeep Learning界隈ですが，この隆盛に大きく貢献し，大きな刺激を与えてくれた"Theano" 関係者に，私も謝意を表したいと思います．