LoginSignup
1
1

More than 5 years have passed since last update.

Lua版 ゼロから作るDeep Learning その3[3層ニューラルネットワークの実装]

Last updated at Posted at 2017-06-10

過去記事

Lua版 ゼロから作るDeep Learning その1[パーセプトロンの実装]
Lua版 ゼロから作るDeep Learning その2[活性化関数]

活性化関数の実装

 今回は3層ニューラルネットワークの実装です。

 スクリプトは以下の通りです。

activationFunc.lua
---ステップ関数.
-- 入力の各成分が0を超えたときに1を返す
-- @param x 入力 (Type:torch.DoubleTensor)
-- @return 1 or 0 (Type:torch.ByteTensor)
function step_function(x)
    local y = torch.gt(x, 0)    -- '>' 演算子の代わり (greater -> gt )
    return y
end

---シグモイド関数.
-- 入力の各成分に対するゲイン1の標準シグモイド関数(1/(1+exp(x)))の値を返す
-- @param x 入力 (Type:torch.DoubleTensor)
-- @return torch.DoubleTensor
function sigmoid(x)
    y = x:clone():fill(1)
    return torch.cdiv(y , (1 + torch.exp(-x)))
end

---ReLU(Rectified Linear Unit)関数.
-- 入力の各成分が0以下ならば0、0よりも高いならばそのままの値を返す
-- @param x 入力 (Type:torch.DoubleTensor)
-- @return torch.DoubleTensor
function relu(x)
    y = x:clone():fill(0)
    return torch.cmax(y, x)
end
three-layeredNN.lua
require './activationFunc.lua'

---恒等関数.
-- 出力層の活性化関数。
-- @param network 入力
-- @return 出力
function identity_function(x)
    return x
end

---ネットワーク生成関数.
-- 重みとバイアスが決定した3層NNを返す。
-- @return 3層NN (Type:table)
function init_network(x)
    local network = {};
    network['W1'] = torch.Tensor({{0.1, 0.3, 0.5}, {0.2, 0.4, 0.6}})
    network['b1'] = torch.Tensor({{0.1, 0.2, 0.3}})
    network['W2'] = torch.Tensor({{0.1, 0.4}, {0.2, 0.5}, {0.3, 0.6}})
    network['b2'] = torch.Tensor({{0.1, 0.2}})
    network['W3'] = torch.Tensor({{0.1, 0.3}, {0.2, 0.4}})
    network['b3'] = torch.Tensor({{0.1, 0.2}})

    return network
end

---順方向伝達関数.
-- 入力から出力までの伝達処理を行う。
-- @param network 入力 (Type:torch.table)
-- @param x 入力
-- @return 出力 (Type:torch.DoubleTensor)
function forward(network, x)
    local W1, W2, W3 = network['W1'], network['W2'], network['W3']
    local b1, b2, b3 = network['b1'], network['b2'], network['b3']

    local a1 = torch.mm(x, W1) + b1 --a1 = x * W1 + b1 でもよい
    local z1 = sigmoid(a1)
    local a2 = torch.mm(z1,W2) + b2
    local z2 = sigmoid(a2)
    local a3 = torch.mm(z2,W3) + b3
    local y = identity_function(a3)

    return y

end

local network = init_network()
local x = torch.Tensor({{1.0, 0.5}}) --1×2 マトリックス
local y = forward(network, x)
print(y)

実行例

bashでの実行例
$th three-layeredNN.lua
 0.3168  0.6963
[torch.DoubleTensor of size 1x2]

 ほとんどpython の場合と変わらないと思います。
 
 ただ一点だけ注意点としてはnumpy.dot(A,B) をtorchでは torch.mm(A,B)と書く点です。
 torch にもtorch.dot(A, B) が存在しますが、この場合のA、B は1次元ベクトルとみなされます。
 torch の積はベクトルとマトリックスを区別しており、
 1次元ベクトル×1次元ベクトルならば、torch.dot(A, B)
 マトリックス×1次元ベクトルならば、torch.mv(A, B)
 マトリックス×マトリックスならば、torch.mm(A, B)
 となっています。
 そして残念なことに1次元ベクトル×マトリックスの計算は標準ではサポートされていないようです。
 そのため上では1次元ベクトルではなく、1×2マトリックスとして計算しています。
 
 また、入力をベクトルとして計算したい場合は転置t()を使って以下のように書けば大丈夫です。

activationFunc2.lua
require './activationFunc.lua'

---恒等関数.
-- 出力層の活性化関数。
-- @param network 入力
-- @return 出力
function identity_function(x)
    return x
end

---ネットワーク生成関数.
-- 重みとバイアスが決定した3層NNを返す。
-- @return 3層NN (Type:table)
function init_network(x)
    local network = {};
    network['W1'] = torch.Tensor({{0.1, 0.3, 0.5}, {0.2, 0.4, 0.6}})
    network['b1'] = torch.Tensor({0.1, 0.2, 0.3})
    network['W2'] = torch.Tensor({{0.1, 0.4}, {0.2, 0.5}, {0.3, 0.6}})
    network['b2'] = torch.Tensor({0.1, 0.2})
    network['W3'] = torch.Tensor({{0.1, 0.3}, {0.2, 0.4}})
    network['b3'] = torch.Tensor({0.1, 0.2})

    return network
end

---順方向伝達関数.
-- 入力から出力までの伝達処理を行う。
-- @param network 入力 (Type:torch.table)
-- @param x 入力
-- @return 出力 (Type:torch.DoubleTensor)
function forward(network, x)
    local W1, W2, W3 = network['W1'], network['W2'], network['W3']
    local b1, b2, b3 = network['b1'], network['b2'], network['b3']

    local a1 = torch.mv(W1:t(), x) + b1 --a1 = W1:t() * x + b1 でも大丈夫です
    local z1 = sigmoid(a1)
    local a2 = torch.mv(W2:t(), z1) + b2
    local z2 = sigmoid(a2)
    local a3 = torch.mv(W3:t(), z2) + b3
    local y = identity_function(a3)

    return y

end

local network = init_network()
local x = torch.Tensor({1.0, 0.5})
local y = forward(network, x)
print(y)
bashでの実行例
$th three-layeredNN2.lua
 0.3168
 0.6963
[torch.DoubleTensor of size 2]

おわりに

 今回は以上です。

 最初に示したやり方は少し概念的な部分で違う計算かもしれませんが、目的どおりの出力を得ることができました。
 二番目のものは計算として忠実ですが、転置するせいで分かりづらい感じがします。転置を内部でカバーする関数を独自に定義したほうがいいかもしれません。

 次回はソフトマックス関数を実装していきます。ありがとうございました。

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