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

今回はニューラルネットワークの学習について説明をします。

学習って何・・?

ニューラルネットワークの学習には、「教師あり学習」「教師なし学習」「強化学習」がありますが、ここでは説明を簡単にするために教師あり学習のみを考えます。
教師あり学習とは、学習データに正解ラベル(答え)を付与した状態で学習させる手法です。学習データと正解ラベルを大量に使うことで、未知のデータに対しての分類や回帰の精度を高めます。

f:id:egao_papa:20210119230523p:plain

学習とは何か・・・について端的に言ってしまうと、重みバイアスをイイ感じに調整することを学習といいます。
ここでいうイイ感じとは「未知のデータに対しての分類や回帰の精度を高めるように」という意味です。

ニューラルネットワークでの1ノードでは以下の式で値が計算されると説明しましたが、このwとbを調整していくことになります。

y = Σx*W + b


機械がこれらのパラメータを調整するとき、「正解ラベル」と「ニューラルネットワークの予測値」の差を使います。

f:id:egao_papa:20210120223929p:plain

差を求める計算式のことを損失関数またはコスト関数とよびます。

コスト関数

コスト関数はネットワークの「悪さ」を評価する指標です。つまり、計算結果が大きければ大きいほど予測が外れていて、小さければ小さいほど予測が正しいと言えます。コスト関数は、解決したい問題によって使用する関数が異なります。
有名なところでは、回帰問題で使用するコスト関数は「最小二乗法」、分類問題で使用するコスト関数は「クロスエントロピー誤差」です。それぞれがどのように計算をされるかを以下で説明します。

最小二乗法

最小二乗法は以下の式で表されます。

yが正解ラベル、y^がニューラルネットワークの予測値です。

f:id:egao_papa:20210120233318p:plain

これはあまり難しく考える必要はなく、式に当てはめて計算をするだけです。

f:id:egao_papa:20210120234206p:plain

クロスエントロピー誤差

クロスエントロピー誤差は以下の式で表されます。

tkは正解ラベル、ykがニューラルネットワークの予測値です。

f:id:egao_papa:20210120234606p:plain

この計算は少し頭をひねる必要があります。

教師データの正解ラベルは離散的な値になっていますが、学習時にはone-hotベクトルと呼ばれる形に変形されます。
one-hotベクトルに変換する理由は確率的な表現をするためです。下図、犬のone-hotベクトル[1,0,0]は、「犬の確率100%、猫の確率0%、ペンギンの確率0%」という正解ラベルであると言い換えることが出来ます。

f:id:egao_papa:20210120235655p:plain

一方で、ちゃんと説明はしていませんでしたが、分類問題を解くニューラルネットワークは、一般に「予測確率」を出力します。
出力は[0.7,0.2,0.1]のような形となり、「犬の確率70%、猫の確率20%、ペンギンの確率10%」という予測がされたということを意味します。
クロスエントロピー関数では、[1,0,0]と[0.7,0.2,0.1]を用いて損失計算を行うことになります。

ニューラルネットワークの学習について、「学習とは何なのか」について説明をしました。
次の記事では、コスト関数を使ってどのように重みやバイアスを調整するか、について説明をします。

ニューラルネットワークと活性化関数

活性化関数のないニューラルネットワーク

ニューラルネットワークは現実世界のデータを学習し未知のデータに対して回帰や分類を行うものです。現実世界は複雑ですから、回帰や分類を行うための計算式もおのずと複雑になるのは想像に難くはありません。
ニューラルネットワークの計算式は目に見えるものではありませんが、活性化関数を使わないネットワークは割と簡易な式で表現することが出来ます。

その例を以下に示します。

f:id:egao_papa:20210116221546p:plain

f:id:egao_papa:20210116211138p:plain

f:id:egao_papa:20210116211315p:plain

yやzを順に計算していますが、中間層を飛ばし入力xと出力zを使ってこのネットワークの計算をすると、

z=Σw*x + b

と表すことが出来ます。
入力層と中間層の計算は、y=Σw*x + b。
中間層と出力層の計算は、z=Σw*y + b。

と計算できることから、1つの層で計算できることを無駄に層を増やして計算しているだけにすぎません。
活性化関数がないと線形変換を積み重ねるだけになり、層を増やしても無駄、且つ本来ニューラルネットワークを用いて解きたい複雑な問題を解くことが出来なくなってしまうのです。

f:id:egao_papa:20210117221036p:plain

活性化関数

活性化関数、活性化関数と言ってきましたが、実際何者なのでしょうか。
パーセプトロンでは、あるノードへの入力と重みを積和演算した結果が一定以上の数値であれば1を次の層に渡し、一定未満であれば0を次の層に渡す、というアルゴリズムでした。この、入力を0や1に変換する、関数を活性化関数と呼びます。

この関数をグラフで表すと、以下の通りになります。
f:id:egao_papa:20210117221255p:plain

グラフを見てわかる通り、活性化関数では非線形変換がなされているということが分かります。ニューラルネットワークでは層と層の間に活性化関数を入れることで、現実世界の複雑な計算を行うことが出来るようになります。

活性化関数の種類

ステップ関数

パーセプトロンで使われている活性化関数です。現在は活性化関数として使われていないので、説明は端折ります。

シグモイド関数

以下の式で計算される関数です。入力に対しての値域は[0,1]となっています。こちらも昔はよくつかわれていましたが、現在はあまり使われていません。
ただ、2値分類を行うために出力層の活性化関数としては利用されています。

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

双曲線正接関数(tanh)

シグモイドにちょっと似ていますが、値域が[-1,1]になっています。(ちなみにtanh(x) = 2*sigmoid(2x)-1と変形可能)
x=0付近が恒等関数になっていて学習に適していますが、実際には次のReLu関数が使われることが多いようです。

RNNやDCGANの生成器などで使われています。

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


ReLu

入力が負の時は学習が進みませんが、0より大きい時は恒等関数になっており、学習に適しています。しかも超簡単な計算なので高速に処理できます。迷ったときは大体これ?

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

ちなみにReLuは、

y = MAX(0,x) + a*MIN(0,x)

と一般化して表すことが可能で、第2項のaの取り方によって以下のような派生型ReLuが発明されています。

LeakyReLu(a=0.01)

X >= 0ではReLuと一緒です。x<0では(グラフ上ちょっとわかりにくいですが)、-0.01*xで少し左肩下がりになっています。
論文上あまり意味がなかったとか言われているみたいですが、DCGANと呼ばれるアルゴリズムの識別器なんかに使われています。

def lrelu(x):
	return np.where(x>0,x,0.01*x)


パラメトリックReLu(aを学習可能な任意の値とする)

aを学習可能なパラメータとして活性化関数としたものです。私自身は使われているところを見たことがありません。。。
紹介だけ。

def prelu(a,x):
	return np.where(x>0,x,a*x)


AVR(Absolute Value Rectification) (a = -1)

入力を絶対値として返す関数です。紹介だけ。

def AVR(x):
	return np.abs(x)


ELU(Exponential Linear Unit) (a = e^x - 1)

画像認識タスクにおいて、ReLu、Leaky Relu、PReluより性能がよくなったことが報告されています。
x=0付近で緩やかなカーブとなっていることが特徴です。

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


SoftMax

中間層で活性化関数として使用されることはありません。私は見たことありません。多クラス分類(マルチヌーイ出力)のための、出力層の活性化関数として使用されています。

def softmax(x):
	return np.exp(x) / np.sum(np.exp(x))


以上の通り、活性化関数1つをとっても様々なアルゴリズムが存在しています。
さて、活性化関数の中でいくつか、「学習に適している」と記載しているところがあります。ニューラルネットワークが学習するためには、活性化関数が微分可能であることが重要になります。
これについてはまた別の記事で説明をしようと思います。

ニューラルネットワークの基礎

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

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

  • 作者:斎藤 康毅
  • 発売日: 2016/09/24
  • メディア: 単行本(ソフトカバー)

今回はニューラルネットワークの基礎を説明していきます。

ニューラルネットワークとは

前回の記事でもふれたとおり、ニューラルネットワークパーセプトロンの集合体、多層パーセプトロンと同義です。
ニューラルネットワークは大きく3つの層に分かれており、下図の通り「入力層」「中間層(隠れ層)」「出力層」で構成されます。

f:id:egao_papa:20210115224220p:plain

このニューラルネットワークは複数の入力とそれに対する重みを積和演算し、次の層へ順に伝えていくということで、順伝播型ネットワークとも呼ばれます。
(順伝播と書くのも面倒なので、「ニューラルネットワーク」=「順伝播型ネットワーク」と読み替えてもらえればと思います。)

積和演算についてもう少し詳しく説明します。下図を見てください。

f:id:egao_papa:20210116221546p:plain

入力層、中間層の1層目の計算は、それぞれ以下の通りになります。
式から見てわかる通り、入力(xやy)と重み(w)をかけた結果を足し合わせ次の層に流しています。

f:id:egao_papa:20210116211138p:plain

f:id:egao_papa:20210116211315p:plain

XORをニューラルネットワークで表現する

さて、単純パーセプトロンではXORは表現できないのでした。
層を増やしたネットワークであれば、表現できるのでしょうか?それを見てみましょう。

XORを実現するニューラルネットワークは下図のようになります。
これを実際にプログラムに書き換えてみます。
f:id:egao_papa:20210116223916p:plain

まず、入力層です。

import numpy as np
x = np.array([[0,0],[0,1],[1,0],[1,1]])
#重みを定義
w1 = np.array([[-0.5,-0.5],[0.5,0.5]])
#バイアス
b11 = 0.7
b12 = -0.2

XORなので、x1、x2には0か1が入ってきます。ここではすべての組み合わせの配列xを定義しています。
入力x1,x2から中間層1つ目のノードへの重みはそれぞれ-0.5、2つ目のノードへの重みは0.5なので、w1の通り重みを定義します。
また、バイアスと呼ばれる入力を補正するための値b11、b12も定義します。

次にy1,y2の計算です。

#1層目の計算
y1 =np.sum(w1[0]*x,axis=1) + b11
y2 = np.sum(w1[1]*x,axis=1) + b12

y1、y2の計算では、簡単な行列計算を行っています。(ニューラルネットワークの理解に行列計算の知識が必要なのはこの辺りが理由です。)
np.sum(w1[0]*x,axis=1)では、w1[0] * x の結果を列方向に足します。蛇足ですが、axis=0とすると行方向に足すことになるので、np.sum(w1[0]*x,axis=1)の結果は(-1,-1)となります。

f:id:egao_papa:20210116231419p:plain

次に青い箱についてです。
ここは、「パーセプトロンの出力がある一定の値の場合1を次の層に流し、一定の値未満の場合は0を流す」というアルゴリズムを表現しています。(今回のプログラムでは「ある一定の値」=「0」と定義しています。)

この青い箱を活性化関数と呼び、
ニューラルネットワークにおいて非常に重要な要素となります。(なぜかは別の記事で説明します。)

この活性化関数部分をプログラムで書くと以下の通りです。

y1 = np.where(y1>0,1,0)
y2 = np.where(y2>0,1,0)

これで入力~中間層までの計算は終わりです。
それぞれの入力が中間層の処理でどうなっているかを見てみます。

左から[0,0],[0,1],[1,0],[1,1]を入力として与えたときの結果。
y1 = [1 1 1 0]
y2 = [0 1 1 1]

入力(x1,x2) = (0,0)を与えると中間層の出力(y1,y2)=(1,0)となり、(1,0)がそのまま出力層の入力となります。
終結果までのプログラムは以下の通りで、中間層での処理とやっていることは全く変わっていません。

#2層目の入力・重み・バイアス
y = np.concatenate([y1.reshape(4,1),y2.reshape(4,1)],axis=1)
w2 = np.array([0.5,0.5])
b2 = -0.7

#2層目の計算
#ANDの計算と同じ
z = np.sum(w2*y,axis=1) + b2
z = np.where(z>0,1,0)

zの出力は以下の通りになります。

z = [0 1 1 0]

無事、ニューラルネットワークでx = [[0,0],[0,1],[1,0],[1,1]]からz = [0 1 1 0]が計算できることを証明出来ました!
パーセプトロンの層を増やすことで、ネットワークの表現力が増し、より複雑な分類でも出来るようになります。
普遍性定理や万能近似定理などと呼ばれるのですが、難しいのでここでは割愛します。

入力と重みとバイアスと

色々とすっ飛ばして説明を続けてきましたが、ニューラルネットワークにおける入力と重みとバイアスについて少し補足します。

入力について

色々なサイトを見ると、入力ベクトルや次元という言葉が出てきます。
ベクトルとは、データを複数個おさめることができるように要素を1列に並べたもの、次元とは1つのベクトルを説明するための属性、を意味しています。
f:id:egao_papa:20210117001203p:plain

XORの説明で出てきたxは、(x1,x2)の2つの次元を持つベクトル、と言い換えることが出来ます。

ベクトルとして扱うことで、xのように4つのデータを一気に行列計算で処理することが出来たり、自然言語処理などでは単語ベクトルといった単語間の類似度をベクトルの内積で表現できたりなど色々なメリットがあります。

重みとバイアスについて

重みとバイアスは、出力に対してどの入力が重要か、をコントロールするためのパラメータです。
ニューラルネットワーク(機械学習)では一般に未知のデータを入力として回帰や予測を行うことになりますが、そのためにはニューラルネットワークの学習が必要となります。
学習は、データを入力したときに期待する出力がされるよう、重みやバイアスを調整することを意味しています。学習の結果、出力に寄与しない入力の重みは0になりますし、大きく寄与する入力の重みは大きくなります。小さいほうがよい、大きいほうがよい、は一概には言えませんが、ここでは重みとバイアスが学習によって決まるパラメータであることを理解いただければと思います。

パーセプトロンとは何か?

仕事がらAIを扱うことになり勉強をしていますが、本を読んだりするだけでは中々身につかないので、
AIもとい深層学習・機械学習に関してアウトプットをすることで学びを得ることを目的にブログを開設してみました。

なので、誤り等ありましたら、ご指摘いただけますと幸いです。

私自身、深い数学の知識や統計の知識をあまり持っていません。(たぶん統計検定2級くらいです)
なので、色々な本を開くたび数式アレルギーを起こしながら日々奮闘しています。
数式やプログラムを見ただけで、「うっ」となってしまう方々向けに、なるべく分かりやすく解説出来るように心がけていきたいと思います。<参考図書>

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

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

  • 作者:斎藤 康毅
  • 発売日: 2016/09/24
  • メディア: 単行本(ソフトカバー)

今回はニューラルネットワークのさわり部分(パーセプトロン)について説明します。

パーセプトロン

パーセプトロン概要

パーセプトロンは1957年頃に考案されたアルゴリズムで、ニューラルネットワークに深く関係しています。パーセプトロンニューラルネットワークの起源ともいえるアルゴリズムであり、パーセプトロンを幾重にも積み重ねたものがディープラーニングでは使用されています。

パーセプトロンアルゴリズムは、入力(x1,x2)と重み(w1,w2)の積和演算の結果が、一定の値を超えていたら「1」を、超えていなかったら「0」を出力する、という単純なアルゴリズムです。
(例として2つの入力を受け取っていますが、入力数に決まりはありません。)

f:id:egao_papa:20210113214428p:plain

パーセプトロンを数式で表すと以下のようになります。(θは「一定の値」)

f:id:egao_papa:20210113215216p:plain

ちなみに、例図のように入力と出力の2層からなるパーセプトロンを「単純パーセプトロン」と呼び、入力と中間と出力の3層からなるパーセプトロンを「多層パーセプトロン」と呼びます。
この「多層パーセプトロン」が他でもない、ニューラルネットワークと呼ばれるものです。

0と1の出力

0と1を出力出来ると何がうれしいのでしょうか。
それは分類問題が解決できることにあります。

つまり、入力データがあるクラスに属するか(1)、属さないか(0)を分類することが可能となります。

f:id:egao_papa:20210113221124p:plain

後述するように複雑な分類問題を解くことは出来ませんが、簡単な分類問題であれば機械で解決することが出来るようになったのです。

パーセプトロンの限界

しかし、パーセプトロンにも限界があります。
それは線形分離可能な問題しか解くことが出来ないということです。

f:id:egao_papa:20210113221902p:plain

この解説にはよくXORが使われます。XORを図表で表すと以下のようになります。

f:id:egao_papa:20210113223456p:plain

このように、少し複雑な問題になってくるとパーセプトロンでは対応できないことから研究は停滞し、一時日の目を見ることはなくなりましたが、ディープラーニングの実用化にあたり現在では目にする機会が多くなりました。

次回は「多層パーセプトロン」「入力」「重み」などについて触れていきます。