JuliaでDeep Learning vol.0

Deep Learningにはすでに各種の実装が用意されています。

ここでは、Juliaでの実装(Juliaで書かれていて、Juliaで記述する実装)である

を使ってみます。

■Mochaとは

MochaのGitHubより。

Mocha is a Deep Learning framework for Julia, inspired by the C++ framework Caffe.

文字通り、Juliaのためのディープラーニングフレームワークであり、また、Caffeに影響を受けて作られたものです。(実際、記述方法などはCaffeと似ています)

■利用できる手法

同じくMochaのGitHubより。

Effcient implementation of general stochastic gradient solvers and common layers in Mocha could be used to train deep / shallow (convolutional) neural networks, with optinal unsupervised pre-training via (stacked) auto-encoders.

現状のディープラーニングは、大きく以下に2分出来るかと思いますが、

  • Full-Connected系

    • いわゆる(?)ディープラーニング
    • Pre-Training必須
    • 更にRestricted Boltzmann Machine(RBM)系とAutoencoder系がある
  • Convolutional Neural Network(CNN)系

    • 畳み込み+プーリングを多層にしたもの
    • Pre-Training不要

上述を読むと、Mochaでは、Autoencoder系CNN系ができるみたいです。
RBM系はMochaのDocにもなさそうですが、また今度追いたいと思います。

■豊富なチュートリアル

MochaのDocには、チュートリアルが豊富に載っています。

  1. Training LeNet on MNIST
    • CNN系のLeNetのモデルをMNISTのデータに適用
  2. Alex's CIFAR-10 tutorial in Mocha
  3. Image Classification with Pre-trained Model
  4. Pre-training with Stacked De-noising Auto-encoders

■Training LeNet on MNISTの実践

ここでは、チュートリアルの最初に挙げられるTraining LeNet on MNISTに沿ってMochaを使っていきます。
これは0~9の手書き数字文字であるMNISTを、CNN系で分類するタスクです。

□データセットの整備

MochaからマスターごとDownroad.zipして、以下のシェルスクリプトを実行すると、

\Mocha.jl-master\examples\mnist\get-mnist.sh

データの場所を示す「train.txt」「test.txt」の2つのファイルと、 実際のMNISTデータである「train.hdf5」「test.hdf5」が出来て準備完了です。

シェルスクリプトが使えない環境の場合は、シェルスクリプトに書いてある手順を手動を踏んで、データを用意しましょう。

□Mochaのインストール

Pkg.add("Mocha") #初回のみ実行
using Mocha

□ネットワークの各層の定義

ここでは以下の深層ネットワーク構造を構築。

上記のフィルター、カーネルストライドのパラメータの意味については、この資料のP.26がわかり易いです。

また、層1, 層2間の伝搬関数にはRectified Linear Unitを指定します。
(fc1~のneuron=Neurons.ReLU()の部分)

#まずランダムシードの設定
srand(12345678)

#まず学習データを指定。ミニバッチは64に指定
data_layer  = HDF5DataLayer(name="train-data", source="data/train.txt", batch_size=64, shuffle=@windows ? false : true)

#ネットワークの各層の定義
conv_layer  = ConvolutionLayer(name="conv1", n_filter=20, kernel=(5,5), bottoms=[:data], tops=[:conv])
pool_layer  = PoolingLayer(name="pool1", kernel=(2,2), stride=(2,2), bottoms=[:conv], tops=[:pool])
conv2_layer = ConvolutionLayer(name="conv2", n_filter=50, kernel=(5,5), bottoms=[:pool], tops=[:conv2])
pool2_layer = PoolingLayer(name="pool2", kernel=(2,2), stride=(2,2), bottoms=[:conv2], tops=[:pool2])
fc1_layer   = InnerProductLayer(name="ip1", output_dim=500, neuron=Neurons.ReLU(), bottoms=[:pool2], tops=[:ip1])
fc2_layer   = InnerProductLayer(name="ip2", output_dim=10, bottoms=[:ip1], tops=[:ip2])

#学習のための損失関数も定義
loss_layer  = SoftmaxLossLayer(name="loss", bottoms=[:ip2,:label])

□CPUバックエンドの設定

ここでGPUBackend()を指定することも可能

backend = CPUBackend()
init(backend)

□ネットワークの定義

ネットワーク名、先ほど作った各層、バックエンドを指定してネットワークを定義。

#先ほど作った各層をまとめる
common_layers = [conv_layer, pool_layer, conv2_layer, pool2_layer, fc1_layer, fc2_layer]

#ネットワーク名、各層をまとめたもの、バックエンドを指定
net = Net("MNIST-train", backend, [data_layer, common_layers..., loss_layer])

SGD(確率的勾配降下法)ソルバーの設定

各パラメータの説明は、Training LeNet on MNISTに記載があります。
max_iterは最大イテレーション数、regu_coefは正則化係数など。

exp_dir = "snapshots"

params = SolverParameters(max_iter=10000, regu_coef=0.0005,
    mom_policy=MomPolicy.Fixed(0.9),
    lr_policy=LRPolicy.Inv(0.01, 0.0001, 0.75),
    load_from=exp_dir)
solver = SGD(params)

SGDソルバー実行内容、学習状態保存のタイミングを指定

# 1000イテレーションごとに学習の統計情報を返す
setup_coffee_lounge(solver, save_into="$exp_dir/statistics.jld", every_n_iter=1000)

# 100イテレーションごとに学習のサマリーを返す
add_coffee_break(solver, TrainingSummary(), every_n_iter=100)

# 5000イテレーションごとにスナップショットを返す
add_coffee_break(solver, Snapshot(exp_dir), every_n_iter=5000)

□学習とテスト

テストデータを指定し、精度評価の指標にaccuracyを指定して、やっと学習の実行。

#テストデータを指定。ミニバッチは100に指定
data_layer_test = HDF5DataLayer(name="test-data", source="data/test.txt", batch_size=100)

#テストデータに対するパフォーマンスは、accuracyで測定
acc_layer = AccuracyLayer(name="test-accuracy", bottoms=[:ip2, :label])

#ネットワーク名、各層をまとめたもの、バックエンドを指定
test_net = Net("MNIST-test", backend, [data_layer_test, common_layers..., acc_layer])

# 1000イテレーションごとにテストデータに対する精度を返す
add_coffee_break(solver, ValidationPerformance(test_net), every_n_iter=1000)

# 学習とテストの実行
solve(solver, net)

最大イテレーション数の10000回を行い、精度は以下のようになりました。
なんと98.9%

01-1 03:40:17:INFO:root:## Performance on Validation Set after 10000 iterations
01-1 03:40:17:INFO:root:---------------------------------------------------------
01-1 03:40:17:INFO:root:  Accuracy (avg over 10000) = 98.9100%
01-1 03:40:17:INFO:root:---------------------------------------------------------

□ネットワークとバックエンドを閉じる

destroy(net)
destroy(test_net)
shutdown(backend)

以上です。他のチュートリアルやパラメータいじりもやっていきたいですね。

■参考文献