"機械学習","信号解析","ディープラーニング"の勉強

HELLO CYBERNETICS

深層学習、機械学習、強化学習、信号処理、制御工学などをテーマに扱っていきます

機械学習で抑えておくべき損失関数(分類編)

 

 

f:id:s0sem0y:20170620132218p:plain

 

 

 

 

はじめに

機械学習における教師あり学習では、入力xに対してパラメータwを用いて関数f(w,x)を構築し、正解データtに対して損失L(t,f(w,x))を定義し、これを最小化する手続きを取ります。

 

損失L(t,f(w,x))を、色々なxtの組(x_i,t_i)に対して計算し、その総和が最小化されるようにwを決めることを学習と呼びます。これにより未知のデータx_?を入力した時に、それに対する正解をf(w,x_?)が出力してくれることを期待するのです。

 

学習がLの最小化という目標に従っている以上、このLをどのような形にするのかが重要になるのは言うまでもありません。

 

ニューラルネットワーク

ニューラルネットワークでは通常

 

  • 回帰

    \displaystyle L(t,f(w,x))=\sum_i(t_i-f(w,x_i))^2

    正解tと関数の出力f(w,x)が近くなるようにする。

  • 分類

    \displaystyle L(t,f(w,x))=-\sum_i t_i\log(f(w,x_i))

    正解t_iと出力f(w,x_i)をそれぞれ確率分布と見なして、確率分布を近づける。

 

という損失が用いられます。

 

損失関数を考えるモチベーション

 

上記の損失関数は「ベストである」という保証はどこにもありません。ただ、手元のデータを表すには、最尤推定という枠組みにおいて上記の形を取るというだけの話です(従って、特別な工夫なしでは必ず過学習すると思っていい)。

 

ニューラルネットには過学習を防ぐ様々な工夫が存在します。ドロップアウトや正則化などが代表的な例です。

 

s0sem0y.hatenablog.com

 

 

一方で従来の機械学習では損失関数の形に様々な工夫を施すことで、上手いf(w,x)を構築してきました。

 

実用的な場面に置いては、データ量や計算コストが膨大なディープラーニングより、工夫された機械学習を用いた場合が良いケースもあります(というよりそれで済むならそうしたほうが良い)。

 

従って、ディープラーニングをやる人でも従来の機械学習の手法について知見は有していなければならないと思っています。

 

今回は分類に用いられる損失関数について一度まとめておこうと思います。

 

分類の損失関数

分類では正解データが離散的であり、関数f(w,x)が正解データtを出力することを目的としています。この際、回帰との大きな違いは、出力値が正解データに近いか否かを、値の差を見るなどの単純な方法では測ることができないという点です。このことは分類問題を考える上では明確に意識して置かなければなりません。

 

そのことを知るために、2クラス分類における重要な基本的損失関数を先に見ておきます。

 

以下、正解データtとし、学習させたい関数はf(w,x)とし、データ点xは1つだけとします。(実際にはデータ点を大量に扱うが、1つ1つ計算して和を取るだけ)

 

0−1損失関数

分類における損失関数の基本

2クラス分類における正解データt-11のいずれかです。通常、それぞれ負例と正例などと呼びます。この符号は、両者を区別する便宜的なものであり、数値に明確な意味があるわけではないことは意識しておいてください(故に単純に値を見ることに意味が見出だせない)。

 

この際の損失関数は

 

L(t,f(w,x))= 0 if t = sign(f(w,x)) else 1

 

と定められます。sign(u)とはuの符号が「負」なら「−1」を「正」なら「1」を返す関数としておきます。この式の意味するところは、「正解ラベルtと出力f(w,x)の符号が一致しているならば損失は0(すなわち分類が成功)であり、符号が一致していなければ損失は1」ということです。

 

ここで見ているのはあくまで「符号」であることに注意してください。

 

f(w,x)が「10000000」を出力して正例だと分類しても、「0.00000001」と出力して正例だと分類しても構わないということです。分類を誤る場合においても、どのような大きさの値を出力しようが与えられる損失は「1」であることに変わりはありません。

  

0-1損失の問題点と代理損失

この0-1損失関数の問題は、既に気づかれていると思いますが、分類がギリギリ成功するケースと余裕を持って成功するケース、あるいは同様に失敗するケースに関して区別をできない点です。

 

しかし、注意して欲しいのは、だからといって分類がギリギリのものと、余裕をもって分類できるものに明確に損失の差を与えるのは必ずしも得策ではないということです。

 

仮に分類が成功したとしても、境界ギリギリだった場合に強く損失を与える方法を考えた場合には、「既に分類に成功しているようなデータを更に確実にすること」ばかりに学習が集中してしまう場合があるためです。本来の目的は正しく分類をすることです。

 

学習を行うにおいて本質的な問題点がまだあります。勾配法を今後応用する場合は、損失関数の微分が必要になりますが、この損失関数は微分値が常に0になるという状態であり最適化に適していません。

 

これらを解決するために、通常の学習では「代理損失」というものが使われます。

 

色々な損失関数

分類の損失を考える上で重要な「正解と出力の積」

2クラス分類の損失関数を見ていくうえでは、正解tと出力f(w,x)の積tfが出てきます。この値は非常に以下に示すように良い性質を持っています。

 

正解tが「1」であり、出力fが正 → tfが正
正解tが「1」であり、出力fが負 → tfが負
正解tが「-1」であり、出力fが正 → tfが負
正解tが「-1」であり、出力fが負 → tfが正


となります。まとめればtfは「分類成功時に正となり、失敗時に負になる値」となります。

 

ロジスティック損失

 

L(t,f(w,x))=\log(1+\exp(-tf(w,x)))

 

ロジスティック回帰で用いられる損失関数です。\expの中身は先に述べたとおり正解と出力の積であり、分類に成功すれば「正」であり、失敗すれば「負」の値をとります。これは分類に成功しても、境界面ギリギリである場合には小さな損失を与えます。損失が0になることはありません。

 

指数損失

 

L(t,f(w,x))=\exp(-tf(w,x))

 

損失が0になることはありません。分類が失敗しているケースに置いて非常に厳しい(非常に大きな値の)損失を与えます。

 

 

ヒンジ損失

 

L(t,f(w,x))=\max(1-tf(w,x),0)

 

サポートベクターマシンで用いられる損失関数です。これは分類に成功したとしても境界面付近である場合には損失を与えますが、一定以上離れた場合には損失を0にする働きがあります。

 

 
平滑化ヒンジ損失

 

\displaystyle L(t,f(w,x))= 0 if tf \geq 1, \frac{1}{2}-tf elif tf \leq 0, else \frac{1}{2}(1-tf)^2

 

ヒンジ損失における0\leq tf \leq1の領域を二次関数に変えて繋げたものです。

 

 

損失関数の図示

以下の図では、横軸を正解tと出力f(w,x)の積tfとし、縦軸をL(w,x)とします。

 

もう一度確認です。

 

正解tは-1か1のみを取ります。

fは実数値を出力します。その値の符号が分類結果となります。

従ってtfが正であれば分類に成功しており、負であれば分類に失敗しています。

正解tが「1」であり、出力fが正 → tfが正
正解tが「1」であり、出力fが負 → tfが負
正解tが「-1」であり、出力fが正 → tfが負
正解tが「-1」であり、出力fが負 → tfが正

 

 fは大きな値である場合も小さな値である場合も分類結果は符号のみによって決められます。しかし、出力の大きさに関しては、10000と0.1では、「確実に正例」と「恐らく正例」くらいの差異があると考え損失の与え方を変えるのが通常の代理損失の設計方法です。

 

0-1損失で図の見方を確認

 

L(t,f(w,x))= 0 if t = sign(f(w,x)) else 1

f:id:s0sem0y:20170620130236p:plain

tf \geq 0の領域は、分類に成功していることを意味しているので、損失を一切与えません。一方でtf \leq 0の領域では分類に失敗しているため、1という損失を与えます。

 

結果としてこの損失の値は、分類させたデータ点のうち、何個分類に失敗したのかを表しています。分類失敗の数が0になるのを目指して学習を行っていることになります。

 

 

ロジスティック損失

 

L(t,f(w,x))=\log(1+\exp(-tf(w,x)))

 

f:id:s0sem0y:20170620130526p:plain

 

tf \geq 0の領域は、分類に成功していることを意味しているのですが、tfが0に近いうちは損失を与えるようにします。一方でtf \leq 0の領域では分類に失敗しているため、損失を与えます。更に、負の値が大きい場合には、激しく間違えていると考えて大きな損失を与えるようにします。

 

この損失関数は0になることは無いので、学習が進んだ末に分類が完全に成功したとしても損失は無くなりません。その場合の損失の大きさというのは、どれくらい確実に分類が上手くいっているのかの指標になります。

 

ロジスティック回帰で用いられる損失関数です。(名前は回帰だが、これは分類に使われる手法である)

 

 

 

指数損失

 

L(t,f(w,x))=\exp(-tf(w,x))

 

f:id:s0sem0y:20170620130850p:plain

ロジスティック損失と考え方は似ていますが、分類の間違いに対して非常に厳しい損失を与えます。正直あまり利用している例を知らないです。

 

直感的には、間違いに対する損失を強くしておけば学習が速く進みそうな気分にはなりますが、仮に外れ値が紛れ込んでいた場合(つまりデータの一部自体がおかしい場合)に、そのデータの損失に大きく引きずられることとなります。

 

ヒンジ損失

 

L(t,f(w,x))=\max(1-tf(w,x),0)

 

f:id:s0sem0y:20170620131324p:plain

tf \leq 0(分類が間違っている領域)では、出力の絶対値に対して直線的に増加する損失を与えるようにします。ポイントは、tf=1の点から損失を与え始めることです。この点を分類が確実に上手くいっていると言える境目とみなしていることになります(従ってそれ以降は損失は与えません)。

 

全てのデータ点を分類できるようになり、それが割と確実に分類できている(tf \geq 1)データばかりになれば損失は0となります(が通常は機械学習では分類精度100%を過学習と疑うべき)。

 

サポートベクターマシンに用いられる損失関数です。

 

サポートベクターマシンについては以下

 

s0sem0y.hatenablog.com

 

 

平滑化ヒンジ損失

 

\displaystyle L(t,f(w,x))= 0 if tf \geq 1, \frac{1}{2}-tf elif tf \leq 0, else \frac{1}{2}(1-tf)^2

 

f:id:s0sem0y:20170620131939p:plain

 

ヒンジ損失と基本的に考え方は同じです。0\leq tf \leq 1の領域を二次関数にして、接続を滑らかにしたものです。数値的には、分類が成功しているがその確実性が低いと思われる場合への損失が、ヒンジ損失に比べると寛容です。

 

 

 

比較

f:id:s0sem0y:20170620132218p:plain

基本的なのは「0-1損失」の間違えたら損失を与えるというものです。これは直接的に間違えた数を数えていることになります。他の損失は概ね、間違いの度合いが強いほど損失も強くし、正解していても、境界付近で怪しい場合には小さな損失を与えるようになっています。

 

通常0-1損失はあまり使われません。(最も単純なパーセプトロンでは学習性能自体を評価するために使われていました)

 

多くの場合は代理損失を立てて問題を考えていくことになります。

 

また、これらの損失関数は機械学習のモデルとある程度セットで用いられることが多いようです。

 

ヒンジ損失はサポートベクターマシンで用いられています。またロジスティック損失は、後の多層パーセプトロンやロジスティック回帰モデルで用いられています。

 

ロジスティック損失においては、今回のような単に分類結果を-1,1で割り振るというところから始まるのではなく、出力値を「あるクラスに属する確率」だと考えられるようにモデル化するところから始め、その最尤推定を考えた際に自然とロジスティック損失が尤度関数として導かれます。

 

 

 

最後に

モデルf(w,x)の方の話

ニューラルネットの多クラス分類では交差エントロピーが用いられますが、ロジスティック損失と同様に最尤推定という形で導かれます。このようにモデルの出力を確率だと考えて、その確率が高いクラスに分類するという形で分類問題のモデルを考えるものを識別モデルと呼びます。

 

一方で、サポートベクターマシンのようにとにかく分類をできるような関数f(w,x)を考える場合、これを識別関数と呼びます。

 

今回は紹介していませんが、他に生成モデルというものもあり、データがあるクラスから生成される確率と、あるクラス自体の確率の積から、分類の確率を求める(ベイズの定理を用いる)モデルもあります。

 

s0sem0y.hatenablog.com

 

 

 

実際に使う場合の話

確率分布から開始する識別モデルや生成モデルになるほど、損失関数を設計していくという概念は薄くなっていきます(なぜならモデルを立てて、それを上手く推定するということを考えると、自然と損失関数に相当する何かが出てくるため)。そして、そのモデルの意味が明確な状態で設計されていくため、パラメータの意味するところも人間にとって把握しやすいかもしれません。

 

一方で分類だけが目的の場合は、損失関数からスタートして識別関数をパパっと考えてしまったほうがコストも精度も良いということは多々あります。また、機械学習の発展の上では、とりあえず損失関数からスタートしてみて、分類が上手くいく手法が出来上がり、後から調べたら●●という確率モデルと同等であったという後付である場合の方が多いです(ニューラルネットだって本来は識別関数である。後から確率を出力する識別モデルと考えることができると分かった。実は生成モデルにもできる)。

 

ですから、識別関数や識別モデル、生成モデルの考え方の違いを明確に理解しつつ、実際に使うときには目的に応じて、簡単な方法(識別関数)から試したほうが良いかもしれません(簡単な方法といえど、結果的に生成モデルと同等の働きであることもある。それを明示していないだけ)。(もちろん目的が、データの生成をすることならば、生成モデルを考えなければならない)

 

学習の評価は「正解・不正解」だけでない

今回は2クラス分類という基本的なところからはじめました。実際に多クラスへ拡張する場合は、複数の2クラス分類器を組み合わせるなどの方法が取られます。

 

その際には、単に正解・不正解だけでなく、どんな間違え方をしているのか(どのクラスをどのクラスと間違ってしまったかなど)も重要な指標になってきます。

 

s0sem0y.hatenablog.com

 

 

回帰における損失関数

回帰では、ダイレクトに正解と出力との距離を測ることで損失を決定します。(従って直感的にはこちらのほうが分かりやすい。一方で、モデルは出力を細かく連続的に変える必要がある点で、評価は難しい)

 

 

s0sem0y.hatenablog.com