過去記事
Lua版 ゼロから作るDeep Learning その1[パーセプトロンの実装]
Lua版 ゼロから作るDeep Learning その2[活性化関数]
Lua版 ゼロから作るDeep Learning その3[3層ニューラルネットワークの実装]
[Lua版 ゼロから作るDeep Learning その4[ソフトマックス関数の実装]]
(http://qiita.com/Kazuki-Nakamae/items/20e53a02a8b759583d31)
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で使えるようにする]をご参照ください。
スクリプトは以下のようになります。
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.lua、softmax.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型はできる限り避けた方が良いです。ご存知ないという方は以下のコードを試してみてください。
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ディレクトリをカレントディレクトリにコピーし、以下のスクリプトを実行します。
# 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()で読み込む形にします。
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']
--最初の入力では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出力なので配列の開始が0、Luaの配列(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
これで原書と同じ出力を出すことができました。