Yotの日常

趣味の紅茶やエンジニアリングから投資、節約術まであれこれ書いていきます

深層学習をスクラッチで書いていく②〜活性化関数(隠れ層)を実装する〜

こんにちは。Yotです。

では、「深層学習をスクラッチで書いていく」の続きで、今回から実装に入ります。

最初は、記事のタイトル通り、活性化関数を実装していきます。言い忘れていましたが、実装はNumpy配列を使うことを前提にしています。今回の活性化関数の引数もNumpy配列です。

 

まず「活性化関数とは何か?」ですが、一言にまとめると「入力信号の総和を出力信号に変換する関数」になります。

分かりづらいので、噛み砕いて説明していきます。

深層学習は、生物の神経系を模した構造をしています。1つの神経細胞は、複数の神経細胞からの信号を受け取り、1つの信号を送るという働きをしています。

下の図ですと、右下の神経細胞が2つの神経細胞から信号を受け取っていますね。そして、その信号をさらに出力できる信号に変換して、下部の神経細胞へと伝えていきます。この時の受け取った信号を出力する信号に変換する部分が深層学習では活性化関数と呼ばれているものになります。この活性化関数、いくつか種類がありますので、次は簡単な解説を交えながら、実装を紹介していきます。

f:id:yot0201412:20190908110430p:plain

神経細胞

ステップ関数

一番、古典的な活性化関数です。入力の総和がある値を越えるまでは0を出力し、その値を越えると1を返します。生物の神経細胞を活性化の機能をそのまま数式にしたものですね。 実装は下記のようになります。

def step(x):
   return numpy.array(x > 0, dtype='int') 

f:id:yot0201412:20190908125337p:plain

Step関数

このStep関数は、そのほかの関数と比較し、値が不連続であるという特徴を持っています。不連続=滑らかでないという特徴が、学習する際の大きな問題になってきます。詳しくは、ここでは語りませんが、微分可能かどうかという部分が問題になります。

 

シグモイド関数

Step関数同様、値は0から1の間を取ります。Step関数を滑らかにしたものと思ってもらえれば、良いのではないでしょうか。ちなみにこちらの関数も極端な入力だと傾きがほとんどなくなってしまうという欠点があります。

 

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

f:id:yot0201412:20190908132346p:plain

Sigmoid関数


ReLU(Reactified Linear Unit)

こちらの活性化関数は、値が0より大きければ、そのまま入力値を、0以下の場合は0を返すというものです。一般的にSigmoid関数を用いるよりもReLU関数を用いた方が深層学習の精度は上がると言われています。深層学習は、生物の神経系を模したものですが、生物と同じ実装に近づけることが必ずしも正解ではないということの一例らしいです。

def relu(x):
    return np.maximum(0, x)

f:id:yot0201412:20190908133437p:plain

ReLU

 

eLU(Exponential Liner Units)

ReLUの派生形の一つで、入力が0以上の時、xを返すというところがReLUと同じです。

0より小さい場合はe^x -1という値を取ります。多くの場合、ReLUよりeLUの方が学習効率が良く、精度も上がるとのことです。原理は難しいです。。知りたい方は、論文とか読んでください!

def elu(x):
    return np.where( x >= 0, x , np.exp(x) -1)

 

f:id:yot0201412:20190908135124p:plain

eLU関数

まとめ

今回は、隠れ層で使われる活性化関数の実装をまとめてみました。今後の実装では、eLUを使っていきます。次回は、出力層で用いられる活性化関数を実装していきたいと思います。ありがとうございました。