"BOKU"のITな日常

還暦越えの文系システムエンジニアの”BOKU”は新しいことが大好きです。

SOFTMAX関数と損失関数について文系チックにざっくりと整理してみる/ディープラーニング

今回は「SOFTMAX関数」と「損失関数」について、できるだけ・・数学チックにならないように気をつけながら、ざっくりと整理してみます。

f:id:arakan_no_boku:20200109220616p:plain

 

SOFTMAX関数と損失関数とは何をするのか

 

位置づけとしては「出力層」にあたります。

以下のような簡単な図にしてみました。

f:id:arakan_no_boku:20200115230355p:plain

上記の「1層」「2層」「N層」にあたるのが、たとえば「Affin層」とか「活性化関数」とか「畳み込み層」とか「プーリング層」などというものになります。

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com

これらは、重み(ウェイト)やバイアスを入力データ(行列)を使って計算処理(内積計算)をしていくわけです。

ただ。

それだけで完結するわけではなくて、その計算結果をうけて、「正解」に近づくために、与えられた正解ラベルである確率が何パーセントなのか?を計算し、その計算結果が正解に対してどのくらいずれているのか?を判定して次の学習ステップにつなげる処理=出力層が必要になります。

今回は、その出力層を勉強しようとおもっています。

とりあえず、ごく一般的なモデルの場合に、出力層には

  • 与えられた正解ラベルである確率が何パーセントなのか?を計算=SoftMax関数。
  • 計算結果が正解に対してどのくらいずれているのか?を判定=損失関数

という、ざっくりした役割分担があります。

正解を予測して、ずれの大きさを計測して、その結果に基づいて重み等を更新してずれが最小になるようにする・・のが「学習」だと考えれば、まあ・・ここまでは、当然の役割分担であって、悩むところもない気がします。

 

SOFTMAX関数のしくみは?

 

SOFTMAX関数の役割としては。

上位の層の計算結果をうけとって、正解ラベル数分の「正解と判断できる確率としてとらえられる数字」を出力をすることです。

例えば。

正解ラベルが3つあって、以下の配列の0から2までが、正解ラベルA,B,Cに対応づいているとした場合

[ 0.2 0.3 0.5 ]

と出力されれば

  • 正解ラベルA: 0.2
  • 正解ラベルB: 0.3
  • 正解ラベルC: 0.5

と読み替えられるわけです。

これらの合計は1.0(つまり100%)になります。

だから、これを結果が正解ラベル1,2,3である確率と読み替えることができる・・とまあ、そういう考え方です。

ですので、この場合なら「正解ラベルC」が一番確率が高いので、正解とみなします。

考え方は簡単なのですけど。

実際にSOFTMAX関数の入力になる値には、プラス・マイナスが混在していますし、ほとんど0に近い位小さかったり、非常に大きかったり様々です。

単純に全部足し算してそれを分母にして割れば良しというわけにはいきません。

このへんを突っ込むと一気に文系チックでなくなってくる・・ので、さらっと流しますけど、SOFTMAX関数では以下のようにしてます。

例えば。

SOFTMAXに対する「入力A」「入力B」があったとすると

「eの入力A乗」を「(eの入力A乗)と(eの入力B乗)の総和」で割る・・みたいな感じで、入力Aに対する確率値を計算してます。

分母が全入力に対する総和で、分子がそれぞれの個別の数値。

なのですから、結果が上記のように合計で1(100%)になるのは当然です。

なお。

ここででてくる「e」は「ネイビア数」といって、ちょっと特別な数字です。

一応、簡単に説明している記事のリンクをのせておきますが、数学的にちゃんと理解しようとすると、なかなか手ごわい相手です。

mathwords.net

だから、単純に「そのまま合計して確率を求めるより、上記のような「e」を使った求め方が具合がいいから、やってる」的なことで、いったん、いいかな(笑)・・と思ってます。

話を戻します。

SOFTMAX関数を、pythonで超ざっくり実装するとしたら

output = exp_in / np.sum(exp_in)

みたいな感じです。

基本的に入力の行列と出力の行列の形は同じです。

だから。

SOFTMAXの入力にする前に、正解ラベル数にあわせて、行列の形を整えておく必要があります。

例えば、以下はSONYニューラルネットワークコンソールで定義した例です。

SOFTMAXの上に「Affine層」がくっついてます。

それで、Affine層の出力数を変えると自動的にSOFTMAXの出力数もそれと同じになるように変わります。

f:id:arakan_no_boku:20200111142903p:plain

こんなイメージですね。 

 

損失関数のしくみについて

 

損失関数は「計算結果が正解に対してどのくらいずれているのか?を判定」します。

そのずれの大きさは、当然ながら「数学的」な方法で計算します。

方法はいろいろあるみたいですが、基本的かつ代表的な2つのやり方が。

  • 2乗和誤差(mean squared error)
  • 交差エントロピー誤差(cross entropy error)

です。

 

2乗和誤差(mean squared error)

 

(SOFTMAXで出力された結果数値 - 教師ラベルデータ)の結果を二乗(マイナスの値があるから・・)してしたものの総和をとって、二分の一にする・・・という方法で率を計算する方法です。

例えば、前であげた例みたいに。

[ 0.2 0.3 0.5 ] 

 という結果があって、この正解が実は「2番目の正解ラベル2」だった場合だと、教師ラベルデータを以下のようにあらわします。

[ 0   1   0 ]

正解にあたるところが「1」、それ以外は「0」で表現してあります。

このような表し方を「one-hot表現」といいます。

そうしておいて「SOFTMAXで出力された結果数値 - 教師ラベルデータ」で計算するわけですから・・

そうすると、上記の例だと「(0.2 - 0)の2乗+(0.3 - 1)の2乗+(0.5 - 0)の2乗」を計算して、結果を2で割る感じですかね。

 

交差エントロピー誤差(cross entropy error)

 

ざっくりと言えば。

上記のように正解ラベルデータが

[ 0   1   0]

のような形(one-hot表現)で与えられていて、SOFTMAXの出力結果が

[ 0.2 0.3 0.5 ] 

だったとすると。

正解ラベルデータの値 × SOFTMAXの出力結果に対する自然対数

の総和をとるような形で計算します。

正解ラベルデータの値が0のところは、結局、結果も0になってしまいますから、正解ラベルデータ値が1の部分に対応する結果・・上記例なら「正解ラベル2の0.3」に対する自然対数・・のみが計算されることになります。

実際には1件だけデータを処理するわけではなく。

その時の学習単位(ミニバッチとかいいかす)件数分の総和をとってデータ件数で割って(平均をとる)マイナスにするみたいな計算式になるので、数式で見ると、複雑に見えますが、やっていることはそんなことです。

自然対数とは「e」(ネイビア数)を底とする対数(log)のことです。

ここで「ネイビア数とは?」とか「なぜ、自然対数を計算するんだ?」とか考え始めると文系の範囲を超えてくるので、一旦忘れます(笑)

「SOFTMAXの出力結果に対する自然対数」を計算することで、正解との誤差の大きさを示す「損失率」が得られる・・と数学の公式的にとらえておいて、おいおい、理解が進んできてから詳しく理解する・・でとりあえずやる。

こういうのも「アリ」かな・・ということで。

 

これらの意味合いと使い分けなど

 

文系SEにとって重要なのは、ここからです。

上記の2種類は計算方法が違うので、同じ結果入力と教師データでも、結果となる数字は違います。

でも共通していることは。

  • 正解に近いほど誤差として出力される結果は小さくなる。
  • 正解から遠いほど誤差として出力される結果は大きくなる。

ということです。

だから。

その結果をもとにして、遡って重み(ウェイト)やバイアスを修正して、その修正をうけて再度損失率を計算する・・という繰り返しで、乗除に精度が向上するわけです。

上記の2種類の方法の使い分けとしては。

  • 2乗和誤差は予測等の回帰問題
  • 交差エントロピー誤差は分類問題

が一般的です。

理由は。

  • 2乗和誤差は「すべてに対して教師データとの差を計算している」
  • 交差エントロピー誤差が「正解ラベルに対してピンポイントで計算している」

という違いがあると認識できれば・・まあ、当然です。

 

まとめ

 

今回はSOFTMAX関数と損失関数について、頭の整理をしてみました。

この辺になると、日本語で整理するのが逆に難しい領域になってきます。

数式になれた人達からは「数式見れば一発でわかることを、わざわざ日本語にする意味がわからん」・・的な指摘をもらったりもします。

でも。

自分もそうですけど。

言葉にして初めて腹にはまることだってあります。

それに、数式って毎日のように触れている時はいいんですけど、しばらく離れると、また読み解くのにエネルギーがいる状態に戻ってしまうことが多いです。

このへんが文系たるゆえんなんでしょうね。

ということで。

自分の備忘もかねて、無理やりでも、ざっくりでも、こうやって文章化しておくことに多少の意味はあるだろう。

そう思ってます。

ではでは。