LoginSignup
1
2

More than 5 years have passed since last update.

Lua版 ゼロから作るDeep Learning その6[ニューラルネットワークの推論処理]

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で使えるようにする]

ニューラルネットワークの推論処理

 今回はMNIST画像データのNN推論処理を行います。
 
 原書ではあらかじめ重みとバイアスを決定したpklファイルを読み込んで行なっていますので、今回はこのpklファイルを用いてTorchで同様の処理を行いました。
 pklファイルの読み込みについてはLua版 ゼロから作るDeep Learning その5.5[pklファイルをLua Torchで使えるようにする]をご参照ください。
 
 スクリプトは以下のようになります。

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

---データ取得関数
-- MNISTのデータ取得する。
-- @return テストデータのイメージ ,テストデータのラベル {Type:ByteTensor}
function get_data()
    --download
    local tar = 'http://torch7.s3-website-us-east-1.amazonaws.com/data/mnist.t7.tgz'
    if not paths.dirp('mnist.t7') then
    os.execute('wget ' .. tar)
    os.execute('tar xvf ' .. paths.basename(tar))
    end
    --get data
    local test_file = 'mnist.t7/test_32x32.t7'
    local testData = torch.load(test_file,'ascii')

    return testData['data'], testData['labels']
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']

    --最初の入力ではnumpy形式に合わせるためにテンソルを一次元化
    local a1 = mulTensor(x:resize(1,W1:size()[1]), W1) + b1:double()
    local z1 = sigmoid(a1)
    local a2 = mulTensor(z1,W2) + b2:double()
    local z2 = sigmoid(a2)
    local a3 = mulTensor(z2,W3) + b3:double()
    local y = softmax(a3)

    return y

end

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

local accuracy_cnt = 0
for i = 1, x:size()[1] do
    scaledx = image.scale(x[i],28,28) --32x32 を 28x28 に縮小
    local y = predict(network, scaledx)
    local value, indices = torch.max(y, 2) -- torch.max( , 2) でrow 方向での最大値を取得
    local p = tensor2scalar(indices) --テンソルなのでスカラーへ変換
    if p == t[i] then
        accuracy_cnt = accuracy_cnt + 1
    end
end

print("Accuracy:"..(accuracy_cnt/x:size()[1]))

 原書では28x28 のMMISTデータでしたが、今回使う画像は32x32 となっています。そのためimage.scale(画像データ,28,28) というように縮小させたデータを推論処理にかけています。このため結果は原書とは異なるものになる点に注意しましょう。
 
 activationFunc.luasoftmax.luaは過去の記事を参照してください。
 exTorch.lua では可読性の向上のために補助的に定義した関数が入っています。

exTorch.lua
---テンソル間の積の計算関数
-- 各次元に対応したテンソルの積ABを行う。
-- @param A A (Type:Tensor)
-- @param B B (Type:Tensor)
-- @return AB (Type:torch.DoubleTensor)
function mulTensor(A, B)
    A = A:double()
    B = B:double()
    local AB = nil;
    if (A:dim() == 1 and B:dim() ~= 1) then
        --1Dvector・matrix
        AB = torch.mv(B:t(), A)
    else
        --others
        AB = A*B
    end
    return AB
end

---テンソルをスカラー変換関数
-- 1x1テンソルをスカラーへ変換する。
-- @param tensor 1x1テンソル (Type:Tensor)
-- @return スカラー (Type:number)
function tensor2scalar(tensor)
    return tensor[1]
end
実行例
$ th neuralnet_mnist.lua
Accuracy:0.8616 

 縮小しているのでpythonでの結果とは異なっていますが、ちゃんと推論自体はできていそうです。
 
 今回はpythonのデータに無理やり合わせた処理が多くなっていますが、それがなければ推論処理は原書と同様の手間で行えると思います。ただ一つ注意するならば、型の扱いはpythonよりも気をつけるべきかもしれません。pythonでは暗黙の型変換をわりとしてくれますが、Luaの型の扱い方はわりと標準的なので違っていればエラーが返ってきます。
 
 型は整数での計算であることがわかっているならば、byteやlongなどの整数型、小数を交えた計算ならばdouble型を使いましょう。
 基本的なことではありますがコンピュータの小数計算には常に誤差が伴うのでfloat型はできる限り避けた方が良いです。ご存知ないという方は以下のコードを試してみてください。

cancellation.lua
local floatT = torch.Tensor(1):fill(0):float()
for i = 1, 1000000 do
    floatT = floatT + torch.Tensor(1):fill(0.000001):float()
end
local doubleT = torch.Tensor(1):fill(0):double()
for i = 1, 1000000 do
    doubleT = doubleT + torch.Tensor(1):fill(0.000001):double()
end
print("float : ")
print(floatT)
print("double : ")
print(doubleT)
実行例
$ th cancellation.lua
float :     
 1.0090
[torch.FloatTensor of size 1]

double :    
 1.0000
[torch.DoubleTensor of size 1]

これは本来はどちらも1となるのが正しい計算ですが、floatでは誤差が生じるため結果がずれてしまいます。doubleでもこのような誤差は生じますがfloatよりは安全です。
 

おわりに

 今回は以上です。

 次回はこの推論処理にバッチ処理を実装してみようと思います。
 
 ありがとうございました。
 

追記(2017/06/24)

 縮小した結果で行うのは気持ち悪い気もするので、いっそのことMMISTデータもpythonから取り出してしまいましょう。
 原書付録のファイルの中からdatasetディレクトリをカレントディレクトリにコピーし、以下のスクリプトを実行します。

saveMMISTtest.py
# coding: utf-8
import sys, os
import numpy as np
import pickle
from dataset.mnist import load_mnist

(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)

np.save("x_test",x_test)
np.save("t_test",t_test)
実行例
$ python3 saveMMISTtest.py

x_test.npy とt_test.npy が出力されるのでこれをget_data()で読み込む形にします。

neuralnet_mnist2.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 (Typetable)
function init_network()
    local network = npy4th.loadnpz('sample_weight.npz')

    return network
end

---分類関数.
-- ネットワークにしたがって分類計算を行う
-- @param network 入力 (Typetorch.table)
-- @param x 入力
-- @return 出力 (Typetorch.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']

    --最初の入力ではnumpy形式に合わせるためにテンソルを一次元化
    local a1 = mulTensor(x, W1) + b1:double()
    local z1 = sigmoid(a1)
    local a2 = mulTensor(z1,W2) + b2:double()
    local z2 = sigmoid(a2)
    local a3 = mulTensor(z2,W3) + b3:double()
    local y = softmax(a3)

    return y

end

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

local accuracy_cnt = 0
for i = 1, x:size()[1] do
    local y = predict(network, x[i])
    local value, indices = torch.max(y, 1) -- torch.max( , 1) でcol 方向での最大値を取得
    local p = tensor2scalar(indices) -1 --python出力なので配列の開始が0Luaの配列(table型)は1から開始なので1だけずらす
    if p == t[i] then
        accuracy_cnt = accuracy_cnt + 1
    end
end

print("Accuracy:"..(accuracy_cnt/x:size()[1]))
実行例
$ th neuralnet_mnist2.lua
Accuracy:0.9352

これで原書と同じ出力を出すことができました。

1
2
0

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
1
2