※現在、ブログ記事を移行中のため一部表示が崩れる場合がございます。
順次修正対応にあたっておりますので何卒ご了承いただけますよう、お願い致します。

Deep Learningの Backpropagationはどのくらい高速か?


2016年 11月 30日

from_zero_deep_learning (283x400).jpgだいぶ前に紹介した『ゼロからつくるDeep Learning』のコメントで、パラメータの勾配を求めるのに数値微分の方法が紹介され、ソースコードも載っている。

第4章ニューラルネットワークの学習
4.5 学習アルゴリズムの実装 (112ページ〜)

とても簡単な2層のニューラルネットワークを作って試そうという訳である。
学習に使うデータは、手書き数字のデータとして有名なMNISTデータセットを利用する。


以下が、今回試してみようという関数 train_neuralnet.py の一部である。

for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]

    # 勾配の計算
    t0 = time.time()
    grad = network.numerical_gradient(x_batch, t_batch)    # 遅い
    #grad = network.gradient(x_batch, t_batch)             # 速い
    te = time.time()-t0

    # パラメータの更新
    for key in ('W1', 'b1', 'W2', 'b2'):
        network.params[key] -= learning_rate * grad[key]

    loss = network.loss(x_batch, t_batch)
    train_loss_list.append(loss)

    if i % iter_per_epoch == 0:
        train_acc = network.accuracy(x_train, t_train)
        test_acc = network.accuracy(x_test, t_test)
        train_acc_list.append(train_acc)
        test_acc_list.append(test_acc)
        print("{0:d}\t{1:f}\t{2:f}\t{3:f}".format(i,te,train_acc,test_acc))

この中の勾配の計算の部分の前後で時間を計測し、勾配の計算時間を求める。
結果の表示は、1エポック(データ全体を1回学習に使用すると1エポック)毎に表示している。
表示は、エポック番号、勾配計算時間、訓練精度、テスト精度になっている。

 117ページのヒント「鳥の絵」には、数値微分はとても遅いので、数値微分ではなくBackpropagation(誤差逆伝搬法)のプログラムも用意しているので、そちらを使って実験するようにと書かれていた。
コード中には、2つの勾配計算方法の呼び出しが併記されていた。

―――となると、つい、どのくらいの速度差が出るのか試してみたくなって、やってみた。

grad = network.gradient(x_batch, t_batch)

In [13]: run train_nueralnet.py
0    0.001145    0.104417    0.102800
1    0.001112    0.099150    0.100900
2    0.001019    0.112367    0.113500
3    0.001067    0.112367    0.113500
4    0.001076    0.112367    0.113500
5    0.001022    0.112367    0.113500
6    0.001126    0.104417    0.102800
7    0.001148    0.104417    0.102800
8    0.001018    0.089583    0.093700
9    0.001133    0.112367    0.113500


grad = network.numerical_gradient(x_batch, t_batch)

In [18]: run train_nueralnet.py
0    39.711862   0.098717    0.098000
1    40.883988   0.098717    0.098000
2    42.274781   0.098717    0.098000
3    40.617868   0.098717    0.098000
4    40.499471   0.098717    0.098000
5    40.557489   0.098717    0.098000
6    41.622460   0.112367    0.113500
7    40.826519   0.116450    0.118000
8    40.555552   0.112367    0.113500
9    40.555557   0.112367    0.113500

これを見ると、前半の誤差逆伝搬(高速)版では、1エポックが約1ミリ秒に対し、後半の数値微分(低速)版では40秒程度になっている。
つまり、約40,000倍速度向上が実現できている。
確かに、これは画期的である。


誤差逆伝搬法の説明は長くなるので、ここでは行わない。この本では直感的でわかりやすい計算グラフを使って説明している。
 この方法で計算を行えるようになり Deep Learning が使い物になった。