ベイジアンニューラルネットワークと予測の不確実性について

# この記事について

ベイズ推定をニューラルネットワークに応用したものにベイジアンニューラルネットワークがあります。通常のニューラルネットワークとの違いや、その応用例についてイメージを掴むために概要を整理します。

## 処方箋
- ベイズとニューラルネットワークを組み合わせることで何が良いのかがよく分からない
- ベイジアンニューラルネットワークの世界観がよく分からない
- ベイジアンニューラルネットワークをどのように構築すればよいかが分からない

# はじめに

## モチベーション

ベイジアンニューラルネットワークでは、**モデルが予測値を出力した際に、その予測値に対してどの程度自信を持っているかを判断する情報も同時に得ることができる**ようになります。

一般にニューラルネットワークモデルを使った予測器は100%の精度を達成できません。これはどうしても予測結果に対して不確実な要素が含まれてしまうためです。また、ブラックボックスとも言われており、どのような判断で予測しているかもわからず、予測結果をどの程度信頼できるかどうかも分かりません。例え、予測結果が示す確率が高かったとしても、自信満々で間違っている可能性も否定できません。

ニューラルネットワークの予測結果を不確実なものにしてしまう要素は以下のように整理することができます。

- **偶然の不確実性(Aleatory uncertainty)**
    - 判定しようとしている入力データ自体があいまいなために発生する不確実性
    - ノイズが大きすぎるなど避けられない不確実性でいくらモデルを訓練しても改善できない
- **認識の不確実性(Epistemic uncertainty)**
    - 判定しようとしている入力データに対する予測能力が不足しているために発生する不確実性
    - その入力データに対する訓練不足が原因のため、再学習することで改善できる

最終的な予測結果の不確実性はこれらの不確実性の総和となります。通常のニューラルネットワークの場合、これらの不確実性を分解して測定することができません。一方で、ベイズの考え方でニューラルネットワークをとらえるベイジアンニューラルネットワークではこれらの**不確実性の種別を測定することができる**ようになります。主に、認識の不確実性を分離できることがメリットとなり、以下のような応用が期待されています。

- 訓練外データの検出(OOD：Out Of Distribution)
- 敵対的サンプルの検出
- 能動学習


# ベイジアンニューラルネットワーク

以上を踏まえて、ベイジアンニューラルネットワークの概要を記載します。

## 結論

最初に通常のニューラルネットワークと、ベイジアンニューラルネットワークの違いを図で示します。

![dnn_bnn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86216/ded495c2-51a6-e5c1-0b15-e70a3d475b1a.png)


左の図は通常のニューラルネットワークの模式図を、右の図はベイジアンニューラルネットワークの模式図を表しています。通常のニューラルネットワークでは各層の重みパラメータの値は学習によって収束した定数として扱われます。一方、ベイジアンニューラルネットワークでは、**重みパラメータをある確率分布に基づいて生成される確率変数**と考えます。いくら学習が終わったからといっても、通常は真の重みパラメータを導出できたとは考えません。もう一度学習を行うと別の重みパラメータが導出される可能性があると考えるのが普通です。このように何度も学習を繰り返すとそれぞれ違った重みパラメータが導出されますが、ベイジアンニューラルネットワークでは、これらの学習結果を確率変数とみなす（重みパラメータの推定値が従う確率分布があるという）アプローチを取ります。

このことのイメージを掴むのに最もわかりやすい例はDropoutによる学習かと思います。Dropoutを使った学習では、ドロップアウト率が同じでも、どのパラメータが無効化されるかはランダムなため、同じ教師データを使ったとしても学習するたびに少しずつ違った重みパラメータが導出されます。この学習を何回も繰り返すことで、複数の重みパラメータのセットを入手することができます。これらの得られた重みパラメータのセットを順番に並べていくと、ある一定の分布が見えてくるようになります。この分布は重みパラメータを確率変数と捉えた場合における重みパラメータの確率分布であると考えることができます。これが重みパラメータの確率分布のイメージです。


ベイジアンニューラルネットワークでは、推論時においてモデルに入力が与えられる度に、確率分布$P(w)$よりサンプリングされた値が重みパラメータに設定されて演算されていくイメージになります。これにより、同じ値xをモデルに入力しても毎回異なる値yが出力されるようになり、予測値yが一定の分布に広がるようになります（予測値も確率変数として扱えるようになります）。予測器は以下のような構成になります。$w_n$はn回目のサンプリング結果で、$P_r(w_n)$はn回目にサンプリングした重みパラメータの信頼度(出現確率)を表しています。最終的な予測値はこれらの和の加重平均となります。また、予測値の分散などの統計値も定義できるようになります。

$$ y = f(w_1,x)P_r(w_1)+f(w_2,x)P_r(w_2)+f(w_3,x)P_r(w_3) +  ... $$

## メリット

ベイジアンニューラルネットワークは、重みパラメータを確率変数とみなすことで重みパラメータの生成に関する確率分布を定義でき、予測値以外の統計値情報を出力できたり、重みパラメータ自体に情報量というものを定義できたりすることが可能となります。これにより、ニューラルネットワークの出力に対する不確実性を計測するさまざまな情報を手に入れることができるようになります。

この**パラメータがなんらかの確率分布$P_r(w)$から生成される確率変数と考える**部分が、ベイズ的な考え方に相当します。通常、この確率分布の事を**事後確率分布**（学習により推定する前は**事前確率分布**）とよびます。

## 実際の利用例

重みパラメータをある確率分布から生成される確率変数とみなすと言われても、実際にどのように学習したり推論したりすればよいのかイメージがつかないところですが、実はベイジアンニューラルネットワークの実現方法の一つとして非常に簡単な手法が提案されています。それは冒頭のイメージの部分に記載した**Dropoutを使って学習、推論する**という方法です。通常、学習時にしか利用しないDropoutを推論時にも適用して推論値を複数回取得することと、重みパラメータを確率変数とみなして（重みパラメータの事後確率分布から）サンプリングすることは等価であることが証明されています。この方法は**MC Dropout**と呼ばれています。

この方法は、冒頭にも記載した通り、ベイジアンニューラルネットワークのイメージを理解するための良い手法にもなっているかと思います。推論時にDropoutを使うことで、同じ入力データに対しても毎回異なる出力が得られることはイメージがつきやすいかと思います。この推論時のDropoutが重みパラメータの確率分布からのサンプリングをシミュレートしてることに相当し、得られた複数の予測値が予測結果の確率分布に相当することになります。この複数回取得した出力の平均が予測値の期待値、分散が不確実性を表す指標となります。

推論時にもDropoutを有効にするには、例えばkerasの場合は以下のようにtrainingパラメータにTrueを指定すると実現できます。

```python
x = keras.layers.Dropout(dropout_rate)(x, training=True)
```

## 不確実性の評価

ニューラルネットワークの予測結果の不確実性を測定する指標としては以下のようなものがあります。

|手法|測定対象|対象ネットワーク|
|:---|:------|:--------------|
|softmaxの最大値|予測全体の不確実性|通常のDNN|
|softmaxのエントロピー|予測全体の不確実性|通常のDNN|
|重みと予測値の相互情報量|認識の不確実性|MC Dropout|

softmaxの最大値は、最終出力層のsoftmaxの値の中から最大となる値を見て不確実性を判断する方法です。softmaxが示す最大の予測精度値が小さいということは、それだけ予測結果に自信がないことを表わすため、不確実性の一つの指標となります。ただし、これは不確実性を分離しない、予測全体の不確実性になります。

```math
\underset{C}{max} P_r(w_c|x)
```
```python
# pred: softmaxの結果
# 最大値が小さい = 高い確率で予測されるクラスが複数ある(不確実性が高い)
max_p = np.max(pred)
```

softmaxのエントロピーは、最終出力層のsoftmaxを確率分布とみなしてエントロピーを計算する手法となります。エントロピーは乱雑さ、不規則さを表す指標で、この値が大きければ大きいほど、その確率分布が不規則であることを表します。（確率分布が一様分布の時に最大となります。）これにより、エントロピーが高ければ高いほど不規則であり、不確実性が大きいと判断することができます。こちらについても予測全体の不確実性を測定する指標となります。

```math
-\sum_{i=0}^C P_i(w_c|x) \log P_i(w_c|x)
```

```python 
# pred: softmaxの結果
# 値が大きい = 各クラスが均等に予測されている（一様分布に近い)
entropy = np.sum(-pred*np.log(pred))
```

重みパラメータと予測値（の確率分布）の相互情報量は認識の不確実性を測定する指標となり、大きければ大きいほど不確実性が高いと考えることができます。

重みパラメータwと予測値yの相互情報量が大きいということは、重みパラメータwにとってyの情報価値が大きかったという事を意味します。(データxをモデルに入力した際に出力yが出力されるということはモデルを構成する重みパラメータwにとってみれば予想していない結果だった、という解釈ができます）。そのため、相互情報量は$y=f(w,x)$の結果に対する訓練不足を意味し、認識の不確実性を測る指標と考えることができます。この指標を近似計算する一つの方法として**softmaxの結果の分散**が提案されています。

```math
\frac{1}{C}\sum_{j=0}^C\frac{1}{T}\sum_{i=0}^T(P_{ij}-\hat{P}_i)^2
```

```python
preds = []
for i in range(sampling_num): # MCDropoutの試行回数
  # サンプリング毎のsoftmax出力 (modelはdropoutを有効にして推論)
  pred = model.predict(x)
  preds.append(pred)

# softmaxの結果の分散
# 値が大きい = 各試行毎にTop-1が異なっている
preds = np.array(preds)
preds_var = np.mean(np.var(preds,axis=0)) # predsの分散
```

## 不確実性評価による応用

予測全体の不確実性は通常のDNNでも一応測定することができます。ただし、予測全体の不確実性の中には偶発的不確実性の成分が入っているため、入力データのノイズなどに起因する不確実性に影響され、モデルの予測能力に起因する不確実性を考慮することが困難です。

ベイズニューラルネットワークでは、相互情報量を使って認識の不確実性を測定することが可能となります。この不確実性を使って、訓練外データの検出や、敵対的サンプルの検出に応用する方法が提案されています。

- 訓練外データ検出(OOD)
    - 認識の不確実性の大きさで判定することができる

- 敵対的サンプルの検出
    - 認識の不確実性の大きさと予測の不確実性の大きさの両方を監視することで検出
    - 敵対的サンプルの場合、予測を間違うように上手く細工されているため予測の不確実性は小さい（予測エントロピーは低くなる)
    - ただし、OOD同様、そのようなサンプルは訓練していないため、相互情報量が大きくなることで検出することができる

# 補足
## 事前知識

ベイジアンニューラルネットワークのメリットを理解するために必要最小限の知識について記載したいと思います。

### 確率変数と確率分布

$X=[x_0,x_1,x_2...]$という数列が得られたときに、これらの数列がある確率分布Prから生成されたものとみなすとき、Xを確率変数と呼びます。確率分布は確率密度関数ともいいます。正規分布などが一例です。

```math
P_r(x)
```

### 条件付き確率

確率変数X,Yがあり、一方の確率変数の値が確定した場合の、もう一方の確率変数が従う確率分布を条件付き確率と呼びます。記号|より右側にあるのが条件となります。通常、この確率分布は$P_r(x)$や、条件を反転した$P_r(y|x)$とは異なる分布となります。

```math
P_r(x|y)
```


### 情報量・エントロピー

情報xが発生する確率$P_r(x)$に対して、その情報xが持つ情報量(bit)は以下のように定義されます

```math
-\log P_r(x)
```

情報源$P_r(x)$のエントロピーは以下の式で定義されます。これはその情報源の不規則性を表し、値が大きいほど不規則で不確実性が高いことを意味します。どの情報xが出てくるか全く予想できないというのが一番エントロピーが高く、$P_r(x)$が一様分布に近づくほどエントロピーは高くなります。

$$ H[P_r(x)]=-\sum P_r(x)\log P_r(x) $$

### 相互情報量

XとYの相互情報量とは、**Xという情報を知ったことにより増えるYの情報量**というものになります。通信の世界では通信路容量の定義に使用されています。受信者Yがある通信路で受信したデータが本当に正しく受信できたかを確認するため、送信者Xが送信した送信データを何とか手に入れ、答え合わせをすることで修正された情報量、というのが相互情報量のイメージとなります。この量が大きいほど、YにとってXの情報価値が大きかったということを意味します。(ちなみに、この式でX,Yは入れ替えても成立します)

$$ M[X,Y] = H[P(Y)] - H[ P(Y[X)] $$


### カルバック・ライブラー・ダイバージェンス

カルバック・ライブラー・ダイバージェンス(KL情報量、KL距離)は二つの確率分布の類似度を表す指標として使われます。類似しているほど小さな値をとります。

$$KL[p||q]=\sum_i p_i \log \frac{p_i}{q_i} $$

KLダイバージェンスを使って相互情報量は以下のように書くことができます。

- XとYが独立に近いかどうか
$$ M[X,Y] = KL[P(X|Y)||P(X)P(Y)] $$

- Xが確定した場合のYの情報利得の大きさ
$$ M[X,Y] = KL[P(Y|X)||P(Y)] $$


# 参考文献
[Dropout as a Bayesian Approximation:Representing Model Uncertainty in Deep Learning](https://arxiv.org/pdf/1506.02142.pdf)
[Understanding Measures of Uncertainty for Adversarial Example Detection](https://arxiv.org/pdf/1803.08533.pdf)
[Predictive Uncertainty Estimation via Prior Networks](https://arxiv.org/pdf/1802.10501.pdf)