Lua版 ゼロから作るDeep Learning その１[パーセプトロンの実装]


はじめに
--

　[ゼロから作るDeep Learning](https://www.amazon.co.jp/%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E4%BD%9C%E3%82%8BDeep-Learning-%E2%80%95Python%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0%E3%81%AE%E7%90%86%E8%AB%96%E3%81%A8%E5%AE%9F%E8%A3%85-%E6%96%8E%E8%97%A4-%E5%BA%B7%E6%AF%85/dp/4873117585)を購入していたのですが、よい本だなーと思いつつも放置していました。

　ところで最近、Luaを使う機会があったのですが、Luaでも深層学習のライブラリとして[Torch](http://torch.ch/)というものがあり、なおかつ行列計算にも幅広く対応しているということでした。

　なので自分の勉強も兼ねて「ゼロから作るDeep Learning」で紹介されている手法をLuaバージョンで書いていこうと思います。

　本記事はどちらかというと自分用のメモ書きに近く、なおかつ私はディープラーニングの専門家でもなければ情報科学系出身でさえないアマチュアなので、至らない部分が多いかもしれませんがご了承いただけると助かります。気になる点がありましたらぜひご意見をいただきたいと思っております。

　今回はTorchをすでにインストールした前提で話を進めます。
　Torchのインストールに関しては以下の記事をご参照ください。

　[Torchでdeep learning](http://qiita.com/perrying/items/c53864d1bd2155a0635d)

　インストール後パスを再度読み込むのを忘れないようにしましょう。マックならば

```bash
source ~/.profile
```
　もしくは、bashの再起動が必要です。

　パスを読み込んだら以下のコマンドを入力し、

```bash
th
```

　以下の表示がだせたら大丈夫です。（終了は```exit```）

```txt
 
  ______             __   |  Torch7 
 /_  __/__  ________/ /   |  Scientific computing for Lua. 
  / / / _ \/ __/ __/ _ \  |  Type ? for help 
 /_/  \___/_/  \__/_//_/  |  https://github.com/torch 
                          |  http://torch.ch 
```


論理ゲートの実装
--
　まず基礎事項の説明の１章は飛ばして２章から入ります。

　論理ゲートを実装しましょう。

```lua:logic_gate.lua

---ANDゲート関数.
-- 入力１、２の両方が入力されたときに１を返す
-- @param x1 入力1
-- @param x2 入力2
-- @return 1 or 0
function AND(x1, x2)
    local x = torch.Tensor({x1, x2})
    local w = torch.Tensor({0.5,0.5}) --重み
    local b = -0.7  --バイアス
    local temp = w:dot(x)+b -- torch.sum(w:cmul(x))+b とも書ける
    if temp <= 0 then
        return 0
    else
        return 1
    end
end

---NANDゲート関数.
-- 入力１、２の両方が入力されたときに０を返す
-- @param x1 入力1
-- @param x2 入力2
-- @return 1 or 0
function NAND(x1, x2)
    local x = torch.Tensor({x1, x2})
    local w = torch.Tensor({-0.5,-0.5}) --重み
    local b = 0.7  --閾値
    local temp = w:dot(x)+b
    if temp <= 0 then
        return 0
    else
        return 1
    end
end

---ORゲート関数.
-- 入力１、２のいずれかが入力されたときに１を返す
-- @param x1 入力1
-- @param x2 入力2
-- @return 1 or 0
function OR(x1, x2)
    local x = torch.Tensor({x1, x2})
    local w = torch.Tensor({0.5,0.5}) --重み
    local b = -0.2  --閾値
    local temp = w:dot(x)+b
    if temp <= 0 then
        return 0
    else
        return 1
    end
end

---XORゲート関数.
-- 入力１、２のいずれかが入力されたときのみ１を返す
-- @param x1 入力1
-- @param x2 入力2
-- @return 1 or 0
function XOR(x1, x2)
    local s1 = NAND(x1, x2)
    local s2 = OR(x1, x2)
    local y = AND(s1, s2)
    return y
end

--確認
print("ANDゲート")
print("AND(0, 0):"..AND(0, 0))
print("AND(1, 0):"..AND(1, 0))
print("AND(0, 1):"..AND(0, 1))
print("AND(1, 1):"..AND(1, 1))

print("NANDゲート")
print("NAND(0, 0):"..NAND(0, 0))
print("NAND(1, 0):"..NAND(1, 0))
print("NAND(0, 1):"..NAND(0, 1))
print("NAND(1, 1):"..NAND(1, 1))

print("ORゲート")
print("OR(0, 0):"..OR(0, 0))
print("OR(1, 0):"..OR(1, 0))
print("OR(0, 1):"..OR(0, 1))
print("OR(1, 1):"..OR(1, 1))

print("XORゲート")
print("XOR(0, 0):"..XOR(0, 0))
print("XOR(1, 0):"..XOR(1, 0))
print("XOR(0, 1):"..XOR(0, 1))
print("XOR(1, 1):"..XOR(1, 1))
```

　Torchがnumpyと違う点についていくつか列挙していきます。

　内積\<A,B>は、numpyでは```numpy.sum(A*B)```ですがTorchでは

```
A:dot(B)
```

　一次元ベクトルの積ABは、numpyでは```A*B```ですがTorchでは

```
A:cmul(B)
```

　一次元ベクトルの定義はテーブル型```{}```を用いて

```
torch.Tensor({a11, a12, ..., a1n})
```

　また、行列の定義だと{}が増えて

```
torch.Tensor({{a11, a12, ..., a1n},{a21, a22, ..., a2n}})
```

　で2×n行列となります。

　この辺りは以下のマニュアルに詳しい記載があります。

　[Math Functions](https://github.com/torch/torch7/blob/master/doc/maths.md)

　それでは実行してみましょう。

```bash
th logic_gate.lua
```
```bash:出力
ANDゲート	
AND(0, 0):0	
AND(1, 0):0	
AND(0, 1):0	
AND(1, 1):1	
NANDゲート	
NAND(0, 0):1	
NAND(1, 0):1	
NAND(0, 1):1	
NAND(1, 1):0	
ORゲート	
OR(0, 0):0	
OR(1, 0):1	
OR(0, 1):1	
OR(1, 1):1	
XORゲート	
XOR(0, 0):0	
XOR(1, 0):1	
XOR(0, 1):1	
XOR(1, 1):0
```

　大丈夫ですね。

　今回は以上です。引き続き記事を書いていくので宜しくお願い致します。

　ありがとうございました。