Lua版 ゼロから作るDeep Learning その１６［単純なレイヤの実装］


過去記事まとめ
--
[Lua版 ゼロから作るDeep Learning まとめ](http://qiita.com/Kazuki-Nakamae/items/e1d79bf10f433c4aca54)

使用スクリプトのダウンロード
--
```
git clone https://github.com/Kazuki-Nakamae/Lua_DLfromScratch
```


はじめに
--
　前回は原書4章の二層ニューラルネットワークを実装し、それによるMNISTの学習処理を実装することになっていましたが、現状の数値微分による勾配算出では遅すぎるため、まず誤差逆伝搬法の実装をしてから学習実装したいと思います。
　今回はまず単純な加算レイヤと乗算レイヤ実装です。スクリプトは以下の通りです。


```Lua:layer_naive.lua
--Copyright (C) 2017  Kazuki Nakamae
--Released under MIT License
--license available in LICENSE file

--- MulLayerクラス（オブジェクト）
-- 乗算レイヤを実装
MulLayer={}
MulLayer.new = function()
    local obj = {}

    --メンバ変数
    obj.x = nil
    obj.y = nil

    -- @function self.forward()
    -- 順伝搬
    -- @param x 入力１{Type:number}
    -- @param x 入力２{Type:number}
    -- @return 乗算結果{Type:number}
    obj.forward = function(self, x, y)
        self.x = x
        self.y = y
        local out = x * y

        return out
    end

    -- @function self.backward()
    -- 逆伝搬
    -- @param dout 層の出力に対する微分{Type:number}
    -- @return 層の各入力に対する微分{Type:number}
    obj.backward = function(self, dout)
        local dx = dout * self.y
        local dy = dout * self.x

        return dx, dy
    end

    return obj
end

--- AddLayerクラス（オブジェクト）
-- 加算レイヤを実装
AddLayer={}
AddLayer.new = function()
    local obj = {}

    -- @function self.forward()
    -- 順伝搬
    -- @param x 入力１{Type:number}
    -- @param x 入力２{Type:number}
    -- @return 加算結果{Type:number}
    obj.forward = function(self, x, y)
        local out = x + y

        return out
    end

    -- @function self.backward()
    -- 逆伝搬
    -- @param dout 層の出力に対する微分{Type:number}
    -- @return 層の各入力に対する微分{Type:number}
    obj.backward = function(self, dout)
        local dx = dout * 1
        local dy = dout * 1

        return dx, dy
    end

    return obj
end
```
　順伝搬は入力をそのまま加算したり乗算したりしますが、逆伝搬では層の出力(z(x,y))に対する微分dL/dzから層の出力(x,y)に対する微分dL/dx, dL/dy を求めます。合成関数の知識がいるので忘れている方は思い出していただけるとよいかと思います。

　
　これを用いた原書p140での計算は以下の通りになります。


```Lua:buy_apple_orange.lua
--Copyright (C) 2017  Kazuki Nakamae
--Released under MIT License
--license available in LICENSE file

require './layer_naive'

local apple = 100
local apple_num = 2
local orange = 150
local orange_num = 3
local tax = 1.1

-- layerの宣言
local mul_apple_layer = MulLayer.new()
local mul_orange_layer = MulLayer.new()
local add_apple_orange_layer = AddLayer.new()
local mul_tax_layer = MulLayer.new()

-- forward
local apple_price = mul_apple_layer:forward(apple, apple_num)  -- (1層)
local orange_price = mul_orange_layer:forward(orange, orange_num)  -- (2層)
local all_price = add_apple_orange_layer:forward(apple_price, orange_price)  -- (3層)
local price = mul_tax_layer:forward(all_price, tax)  -- (4層)

-- backward
local dprice = 1
local dall_price, dtax = mul_tax_layer:backward(dprice)  -- (4層)
local dapple_price, dorange_price = add_apple_orange_layer:backward(dall_price)  -- (3層)
local dorange, dorange_num = mul_orange_layer:backward(dorange_price)  -- (2層)
local dapple, dapple_num = mul_apple_layer:backward(dapple_price)  -- (1層)

-- 結果
print("price:"..price)
print("dApple:"..dapple)
print("dApple_num:"..dapple_num)
print("dOrange:"..dorange)
print("dOrange_num:"..dorange_num)
print("dTax:"..dtax)
```
```bash:実行結果
$ th buy_apple_orange.lua
price:715	
dApple:2.2	
dApple_num:110	
dOrange:3.3	
dOrange_num:165	
dTax:650	

```


おわりに
--

　今回は以上です。

　次回からは続いて活性化レイヤを実装していきましょう。
　
　ありがとうございました。