”ゼロからつくるDeep Learning"を読むことにした。

近い将来、機械学習を使ったレコメンドが必要になりそうでいま流行りのDeep Learningを勉強することにしました。ソースを読んでもあまり頭に入ってこないたちなのでTensorFlowやChainerなどのフレームワークを使う前に、急がば回れということでオライリー社の「ゼロからつくるDeep Learning」を購入し、昨日届きました。

O'Reilly Japan - ゼロから作るDeep Learning


できるだけ並列処理を意識したいのとHaskellの学習を兼ねて、サンプルコードをHaskellで書き直すことにしました。

環境は以下。

$ uname -a
Linux march 4.7.6-1-ARCH #1 SMP PREEMPT Fri Sep 30 19:28:42 CEST 2016 x86_64 GNU/Linux

$ gcc --version
gcc (GCC) 6.2.1 20160830

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.0.1


次に線形代数とかのライブラリがないと間違いなくきついのでNumpyの代替となるHaskellライブラリとして、hmatrixをまず使うことにしました。そこで以下にてインストール。

$ yaourt -S blas lapack
$ cabal install bmatrix

詳しいインストールの方法は以下を参照してください。(ウィンドウズとか)
hmatrix/INSTALL.md at master · albertoruiz/hmatrix · GitHub


hmatrixの使い方は以下を参照してください。
Numeric.LinearAlgebra


ではまず、pythonのサンプルコードより。

import numpy as np


def AND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.7
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

def OR(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.2
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

def NAND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([-0.5, -0.5])
    b = 0.7
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

deep-learning-from-scratch/ch02 at master · oreilly-japan/deep-learning-from-scratch · GitHub

から抜粋。

論理回路パーセプトロンアルゴリズムで書いたシンプルなコードです。
ただ、重みとバイアス以外すべて同じコードというところには何か悪意のようなものを感じたのは多分気のせいだと思うことにする。

パーセプトロンとは:

視覚と脳の機能をモデル化したものであり、パターン認識を行う。シンプルなネットワークでありながら学習能力を持つ。1960年代に爆発的なニューラルネットブームを巻き起こしたが、1969年に人工知能学者マービン・ミンスキーらによって線形分離可能なものしか学習できないことが指摘されたことによって下火となった。他の研究者によってさまざまな変種が考案されており、ニューロン階層を多層化し入出力が二値から実数になったボルツマンマシン(1985年)やバックプロパゲーション(1986年)などによって再び注目を集めた。2009年現在でも広く使われている機械学習アルゴリズムの基礎となっている。
(Wikipediaより抜粋)

だそうです。

上のpythonのコードからすこし悪意を取り除いてHaskellで書き直してみました。

import Numeric.LinearAlgebra

op::(Double, Double) -> Double -> Double -> Double -> Int 
op ws b x1 x2 = case (sumElements (x * w) + b) > 0 of
    True -> 1
    _    -> 0
 where x = vector [x1, x2]
       w = vector [fst ws, snd ws]

pAnd  x1 x2 = op (0.5, 0.5) (-0.7) x1 x2
pNand x1 x2 = op (-0.5, -0.5) 0.7 x1 x2
pOr   x1 x2 = op (0.5, 0.5) (-0.2) x1 x2

pXor  x1 x2 = pAnd (fromIntegral s1) (fromIntegral s2)
 where s1 = pNand x1 x2
       s2 = pXor x1 x2  


特に説明のしようがない簡素なコードですが、はやくちゃんとしたHaskellのコードをかけるように頑張っていきたいと思います。
ちょっとまずはひと記事ということでササッと書いたブログですが、もう少しまともなことを書けるようすこし考えます。