LoginSignup
3

More than 5 years have passed since last update.

Lua版 ゼロから作るDeep Learning その7[バッチ処理]

Last updated at Posted at 2017-06-24

過去記事

Lua版 ゼロから作るDeep Learning その1[パーセプトロンの実装]
Lua版 ゼロから作るDeep Learning その2[活性化関数]
Lua版 ゼロから作るDeep Learning その3[3層ニューラルネットワークの実装]
Lua版 ゼロから作るDeep Learning その4[ソフトマックス関数の実装]
Lua版 ゼロから作るDeep Learning その5[MNIST画像の表示]
Lua版 ゼロから作るDeep Learning その5.5[pklファイルをLua Torchで使えるようにする]
Lua版 ゼロから作るDeep Learning その6[ニューラルネットワークの推論処理]

バッチ処理

 今回は前回のMNIST画像データのNN推論処理にバッチ処理を実装します。
 
 
 スクリプトは以下のようになります。

neuralnet_mnist_batch.lua
require './activationFunc.lua'
require './softmax.lua'
require './exTorch.lua'
npy4th = require 'npy4th' --https://github.com/htwaijry/npy4th (Author:Hani Altwaijry)

---データ取得関数
-- MNISTのデータ取得する。
-- @return テストデータのイメージ ,テストデータのラベル {Type:ByteTensor}
function get_data()
    --画像データ
    local x_test = npy4th.loadnpy('x_test.npy')
    --ラベルデータ
    local t_test = npy4th.loadnpy('t_test.npy')

    return x_test, t_test
end

---ネットワーク生成関数.
-- 重みとバイアスが決定した3層NNを返す。今回はpklで記述された重みを用いる
-- @return 3層NN (Type:table)
function init_network()
    local network = npy4th.loadnpz('sample_weight.npz')

    return network
end

---分類関数.
-- ネットワークにしたがって分類計算を行う。
-- @param network 入力 (Type:torch.table)
-- @param x 入力
-- @return 出力 (Type:torch.DoubleTensor)
function predict(network, x)
    local W1, W2, W3 = network['W1'], network['W2'], network['W3']
    local b1, b2, b3 = network['b1'], network['b2'], network['b3']

    local a1 = mulTensor(x, W1) + makeIterTensor(b1,mulTensor(x, W1):size()[1])
    local z1 = sigmoid(a1)
    local a2 = mulTensor(z1,W2) + makeIterTensor(b2,mulTensor(z1,W2):size()[1])
    local z2 = sigmoid(a2)
    local a3 = mulTensor(z2,W3) + makeIterTensor(b3,mulTensor(z2,W3):size()[1])
    local y = softmax(a3)

    return y

end

local x, t = get_data()
local network = init_network()

local batch_size = 100 --バッチ数
local accuracy_cnt = 0
for i = 1, x:size()[1], batch_size do
    local x_batch = x:sub(i,i+batch_size-1)
    local y_batch = predict(network, x_batch)
    local value, indices = torch.max(y_batch, 2)
    local p = indices - 1
    --要素それぞれを比較して合計を計算
    accuracy_cnt = accuracy_cnt + torch.sum(torch.eq(p:byte(), t:sub(i,i+batch_size-1):byte()))
end

print("Accuracy:"..(accuracy_cnt/x:size()[1]))
出力結果
$ th neuralnet_mnist_batch.lua
Accuracy:0.9352 

 それほど変わりばえはしませんが、細かな部分で工夫が必要です。
 
 まずバッチで指定した分の配列の取得ですが、Tensorはコロン表記i:i+batch_sizeで要素を範囲取得することはできません。代わりに:sub(i,i+batch_size-1)メソッドで部分行列として取得します。また、配列の始まりが1からなので1から始まるならば最後の要素はi+batch_size-1となります。
 
 またpredictの部分では加算をするためにbatch指定した分だけバイアスのベクトルを行方向に重ねた行列が必要になります。numpyのように自動的にはやってくれないので、そのための関数makeIterTensor()を定義しましょう。

makeIterTensor関数(exTorch.lua内に定義)
---行反復行列生成関数
-- 入力されたベクトルをN行反復する行列を生成する
-- @param vector 一次元ベクトル (Type:Tensor)
-- @param iter 反復数 (Type:byte)
-- @return 行反復行列 (Type:DoubleTensor)
function makeIterTensor(vector,iter)
    local iterTensor = torch.DoubleTensor(vector:size()[1],iter)
    local i = 0
    iterTensor:apply(function() --applyで各要素へ値を代入
        i = i + 1
        if vector:size()[1]<i then --ベクトルのインデックスを超えたら初期化
            i = 1
        end
        return vector[i]
    end)

    return iterTensor
end

 これでpredict内の計算が可能となります。
 
 ちなみにTensor対スカラーで演算する場合は演算子で一括で計算してくれます。local p = indices - 1の部分がそれですね。
 
 最後の等価の評価ですが、各要素に対して比較結果をだす場合はtorch.eq()で行う必要があります。型にも厳密ですので:byte()などでキャストしましょう。
 

おわりに

 今回は以上です。簡単な自作関数を定義していくことで冗長にならず意外とまとまった記述になった気がします。

 次回は原書の4章であるNN学習の実装に入っていきます。
 
 ありがとうございました。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3