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には、チュートリアルが豊富に載っています。
- Training LeNet on MNIST
- Alex's CIFAR-10 tutorial in Mocha
- CNN系のcuda-convnetのモデルをCIFAR-10のデータに適用
- Image Classification with Pre-trained Model
- CNN系のCaffeから引き継いだ学習済みモデルをilsvrc_2012のデータに適用
- Pre-training with Stacked De-noising Auto-encoders
- Autoencoder系のStacked De-noising Auto-encoders(SDA)のモデルをMNISTのデータに適用
■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
□ネットワークの各層の定義
ここでは以下の深層ネットワーク構造を構築。
- 畳み込み層1(conv=~):フィルター=20, カーネル=5×5
- →プーリング層1(pool=~):カーネル=2×2, ストライド=2×2
- →畳み込み層2(conv2=~):フィルター=50, カーネル=5×5
- →プーリング層2(pool2=~):カーネル=2×2, ストライド=2×2
上記のフィルター、カーネル、ストライドのパラメータの意味については、この資料の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)
以上です。他のチュートリアルやパラメータいじりもやっていきたいですね。