Elsaの技術日記(徒然なるままに)

主に自分で作ったアプリとかの報告・日記を記載

MENU

Deep Learning勉強 1

前回宣言しました通り、Deep Learning勉強中!!

勉強方法はこちらの本を読みながら基礎を抑えているとことです!!

ゼロから作るDeep Learning ?Pythonで学ぶディープラーニングの理論と実装

新品価格
¥3,740から
(2020/11/3 12:29時点)


まだ途中(半分ぐらい??😅)ですが、備忘録も踏まえてまとめておこうと思います!!👍

今回まとめるのは、
 ・パーセプトロン
 ・ニューラルネットワーク
 ・ニューラルネットワークでの学習
の3つです。


パーセプトロン

<パーセプトロンとは>
複数の入力信号から1つの信号を出力することをパーセプトロンと言います。
図で表すとこんな感じになっております。
f:id:Elsammit:20201103123918p:plain

こちらの図の〇がニューロンと呼ばれており、ニューロンから別のニューロンに送られる際に重み付け(図だとw1、w2)が行われます。
このため、ニューロンyに入力される値は、

w1 ×x1 + w2×x2

となります。
こちらのyに閾値を設けておくと、0/1の判定が行えるようになります。
※こちらの閾値を設けて判定結果が1になることをニューロンが発火する、と言う。

では、パーセプトロンで単純なAND、OR回路をpythonで作成していきます。

#AND回路

def AND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.7   
    y = 0
    if np.sum(x*w) + b > 0:
        y = 1
    else:
        y = 0
    return y
#OR回路

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

やっていることは単純で、

w1 ×x1 + w2×x2 + b

の結果がAND回路、OR回路の結果となるように重み(w1、w2)やバイアス(b)を変更させるのみです。
w1 ×x1 + w2×x2の計算方法は、numpyを用いて、

np.sum(x*w)

としております。
※numpy便利すぎ🤣

これで簡単な(線形)回路は実現できるのですが、XORなどの非線形の場合にはどうすればよいのでしょうか??🤔
こちらは、パーセプトロンを組み合わせることにより実現ができます!!
XORを例にしますと、XORはAND、OR、NANDのパーセプトロンを組み合わせればOK!!

ニューラルネットワーク

ニューラルネットワークとは、こちらの図のように左から入力層⇒中間層⇒出力層の構成のことです。
f:id:Elsammit:20201103131246p:plain

こちらのニューラルネットワークを実装するとこんな感じになります。

import numpy as np
import matplotlib.pylab as plt 

#活性化関数.
def sigmoid(x):
    return np.round(1 / (1 + np.exp(-x)), decimals=1)

x = np.array([1.0,2.0])   # 入力値.

w1 = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])       # 入力層⇒第1層への重み
w2 = np.array([[0.1, 0.2], [0.3,0.4], [0.5,0.6]])  # 第1層⇒第2層への重み
w3 = np.array([[0.1,0.5],[0.6,0.8]])                  # 第2層⇒出力層への重み

b1 = np.array([-0.3, -0.5, -0.8])   # 入力層バイアス
b2 = np.array([0.2, 0.6])              # 第1層バイアス
b3 = np.array([-0.3,-0.2])            # 第2層バイアス

#第1層結果.
y1 = np.dot(x,w1) + b1
print(sigmoid(y1))


#第2層結果
y1 = np.array(y1) + b1
y2 = np.dot(y1, w2) + b2
print(sigmoid(y2))

#出力層結果
y3 = np.dot(y2, w3) + b3
print(y3)

活性化関数とは、先ほどパーセプトロンにて記載した閾値を実現するための関数になります。
今回は活性化関数としてシグモイド関数を用いました。
シグモイド関数についてはこちらをご参考に下さい。
https://www.atmarkit.co.jp/ait/articles/2003/04/news021.html

それで実施していることは、
入力層⇒第1層にて、1×2行列 かける 2×3行列で1×3行の行列が生成されます
すなわち、各パーセプトロンにて、

w1 ×x1 + w2×x2 + b

が実行していることになります。
こちらの結果を活性化関数に代入した結果を次の層に入力します。

ここで、行列計算はnumpyのdotを用いることで実現できます。

第1層⇒第2層も同様の処理を行います。
最後に第2層⇒出力層についても活性化関数に代入するまでは同じなのですが、
出力層には恒等関数、ソフトマックス関数を用います。
今回は恒等関数を用いました。
ソフトマックス関数についてはこちらを参考ください。
https://www.atmarkit.co.jp/ait/articles/2004/08/news016.html

ニューラルネットワークでの学習

ニューラルネットワークを学習する上で損失関数は重要になります。
この損失関数から得られる値が最小になるようにパラメータ設定を行うことで精度を上げることが可能になります。
こちらの損失関数に与えるパラメータを算出するにあたり、微分値を用いて微小な変化を得ます。
こちらの微小変化により、損失関数の微小変化から最小となるパラメータが算出できるようになるわけです。

先ほどのニューラルネットワークでの図でもそうですが、一般的に入力層が2以上になることが多くなります。
2つ以上の異なる入力値から出力を得る関数となるため、微分偏微分が多くなります。

この2以上に与えられる入力値の偏微分をベクトルとしてまとめたものを勾配と呼びます。
この勾配は対象としている(偏微分している)関数の最小値への方向(最小までの大きさ)を示す特性があります。
こちらの特性を利用してパラメータを算出する方法が勾配法と呼びます。
勾配法を式で示すと、
f:id:Elsammit:20201103135744p:plain
となります。
ηは学習率と呼び、こちらのパラメータをあらかじめ設定しておき勾配法を行うことになります。

では、こちらの関数の場合を例に勾配法で損失関数が最小となるパラメータを算出します。

y = x1 * x1 + x2*x2

コードはこちらになります。

#対象関数
def function3(x):
    return x[0]**2 + x[1]**2

#勾配算出
def numerical_gradient(f ,x):
    h = 1e-4
    grad = np.zeros_like(x)
    for idx in range(x.size):
        tmp_val = x[idx]
        x[idx] = tmp_val + h
        fxh1 = f(x)

        x[idx] = tmp_val - h
        fxh2 = f(x)
        grad[idx] = (fxh1 - fxh2)/(2*h)
        x[idx] = tmp_val
    return grad

#勾配法を実施(学習率0.01、ステップ回数100)
def gradient_descent(f, init_x, lr=0.01, step_num=100):
    x = init_x

    for i in range(step_num):
        grad = numerical_gradient(f, x)
        x -= lr * grad
        print(x)
    return x

init_x = np.array([3.0, 4.0])
Ret = gradient_descent(function3, init_x, lr=0.1, step_num=100)
print(Ret)

こちらを実行すると結果は、

[6.11110793e-10 8.14814391e-10]

となり、ほぼほぼ0に近似することが可能になります。


最後に学習アルゴリズムの流れをまとめると、
①訓練(学習を行う)ために使用するデータを用意する。
 訓練データの中からランダムに一部分のデータを選び出すことをミニバッチと呼びます。
②ミニバッチの損失関数を減らすためにパラメータの勾配を求める
③勾配方向・微笑量を元にパラメータの更新を行う
④①~③を繰り返す
となります。
この①~④の流れが勾配法によってパラメータを更新する方法になる、わけです!!

■最後に

ちょっと書きすぎました😅
まだ本を読んだ内容をまとめただけなので、自分で色々と手を動かしながら理解を深めていきたいと思います!!😆
このブログも後で1つ1つ分解して、詳細書いていこうかな??
とりあえず今回は概要ということでw