Deep Learningの表現学習を情報量という観点で見てみる。
所属組織のしがらみがあるので公開情報に限定し自分の考察などは基本記述しない
まとめ
相互情報量使うといろいろおもしろ表現学習できるし汎化誤差にも関係ありそうだし、相互情報量大事だよ!
おまけで相互情報量を計算するサンプルコード載せたよ!
相互情報量とは?
2つの確率変数XとYの情報がどれだけかぶっていないかを表す指標で以下で定義される
I\left(X;Y\right)\equiv D_{{\rm KL}}\left(p\left(x,y\right)||p\left(x\right)p\left(y\right)\right)=\iint p\left(x,y\right)\log\frac{p\left(x,y\right)}{p\left(x\right)p\left(y\right)}dxdy
ここで$D_{\rm{KL}}$はKL Divergenceを表しているので、相互情報量はx,yを同時にみたときと独立に見たときのギャップになっている。
KL divergenceの説明
KL divervenceは確率分布間の距離のようなもので、以下で定義される
D_{{\rm KL}}\left(p\left(x\right)||q\left(x\right)\right)\equiv\int p\left(x\right)\log\frac{p\left(x\right)}{q\left(x\right)}dx
定義からわかるように以下の性質を満たす
- $p\left(x\right)=q\left(x\right)\rightarrow D_{{\rm KL}}\left(p\left(x\right)||q\left(x\right)\right)=0$ : 同じ場所だと距離0
- $D_{{\rm KL}}\left(p\left(x\right)||q\left(x\right)\right)\geq0$: 距離は必ず正
距離のようなものと書いたのは距離の公理である以下を満たさないためだ
- $D_{{\rm KL}}\left(p\left(x\right)||q\left(x\right)\right)\neq D_{{\rm KL}}\left(q\left(x\right)||p\left(x\right)\right)$ : 対称性
- $D_{{\rm KL}}\left(p\left(x\right)||q\left(x\right)\right)+D_{{\rm KL}}\left(q\left(x\right)||r\left(x\right)\right)\geq D_{{\rm KL}}\left(p\left(x\right)||r\left(x\right)\right)$ : 三角不等式
Deep Learningにおける相互情報量
情報量という観点でDeep Learningが何を行っているかを考える。各Layerのノードを高次元の確率変数だとみなし入力$X$と各Layer$T$と出力 $\hat{Y}$ の間でそれぞれ相互情報量を観測した。論文中ではencoderとdecoderと書いてあるが、これは教師ありのDeep Learningで適当な隠れ層までをencoderとしている(教師なしでも同様の議論)。前提
- 各layerはマルコフ性を仮定している(ResNetの中のようなskip connectionはダメ、ResNetのブロックを1つのlayerだと思えば多分大丈夫)
- SGDを使ってる
この図からわかるのは、学習の初期ではX→T→Y全てで相互情報量が大きくなる(これは誤差を下げるため)、学習の終盤ではX→T→YでX→Tの間の相互情報量が小さくなる(入力をできるだけ忘れることで学習データの覚えこみを防いでいる)。
論文の主張ではDeep Learningにはfitting phaseとcompression phaseが存在していてcompression phaseが汎化性能の改善に貢献している。
注:compress phaseが汎化性能を高めているかについて否定する論文がICLR2018に採択されていてopen review上で元の論文の作者と熱いレスバトルを繰り広げていて完全に正しい主張かは未だわからない。[^informatin bottleneck res]
Disentangledな表現学習と転移性能
相互情報量による縛りを用いるとdisentangle表現と呼ばれる面白い表現学習ができる1。
disentangle表現とは、通常の分散表現とは異なり、1つの意味が1つの隠れ変数の次元で表されている表現である。 以下の動画を見るとわかりやすい2
図:VAE likeな潜在変数モデル(x→z→x)で学習を行い、特定のz次元のzを-3~3に変化させて生成画像を生成した結果を表示
上:β-VAEと呼ばれるdisentangle学習をしたもの
下:普通のVAE(分散表現)
横軸:変化させるzの次元の違い
Disentangle表現としては以下の特徴が言われている。
- transfer learning(特にzero shot)に向いている
- ラベルを使わずに意味の抽出ができる
- 潜在変数が解釈可能である(保証はないが論文の例では情報圧縮で得られる特徴は人間の理解と一致している(celebAでいうと笑顔や年齢など))
以下もdisentangleで意味が抽出された例2
ではこのようなdisentangle表現はどうやって実現されるのかをβ-VAEを例に見ていく。
β-VAEのlossは
-E_{q\left(z|x\right)}\left[\log p\left(x|z\right)\right]+\beta\left|D_{{\rm KL}}\left(q\left(z|x\right)||p\left(z\right)\right)-C\right|
ここでβ,Cは定数(C=0,β=1を取るとVAEと等価になる)。通常VAEは$\log p(x)$の変分下限として導出されるがβ-VAEはβ≠1なのでもはや変分下限ではない。β-VAEはinformation bottleneckから導出することができる。
データxを使ってタスクyを解くときのコンパクトな表現zを考える。
I ( \mathbf { x } ; \mathbf { y } ) = I ( \mathbf { z } ; \mathbf { y } )\\
\min I ( x ; z )=C
つまりx→z→yを考えたときにxとyが持つ情報を保ちながらxとzの情報を小さくしろという式になる。
これは制約付き最適化問題なのでラグランジュ未定乗数法でとく。すると結果としてβ-VAEのloss関数を導出することができる(βが未定定数になる)。直感的にはデータを再構成する上で重要な情報を極限まで削るとそのデータに含まれた本質的な情報をが抜き取れる(β-VAEの例でいうとkl divergence lossを通してq(z|x)がN(0,1)のgaussianに制約され情報が削られる)。最近の研究でinformation bottlenckの制約が間接的に潜在変数zのtotal correlationを小さくすることでdisentangleが実現されることがわかってきた。
相互情報量の汎化誤差
母集団からサンプルした標本集団で学習を行ったときの母集団に対する誤差を汎化誤差という。仮設集団Hにおいて、有意水準δでm個のデータセットで学習すると 以下のように汎化誤差εに上限がつく
\varepsilon ^ { 2 } \leq \frac { \log | H | + \log \frac { 1 } { \delta } } { 2 m }
DeepLearningにおいては以下のboundが成り立つ?? (この証明は自分は追ってないし、論文としても2018/12/11時点でpublishされてるわけではないので正しさは???)
\varepsilon ^ { 2 } \leq \frac { 2 ^ { I \left( X ; Z _ { \varepsilon } \right) } + \log \frac { 1 } { \delta } } { 2 m }
これが正しければ$I(z;x)$を小さくすれば汎化誤差の上限を抑えることができる。Deep Learningが層が深いほど汎化誤差が下がることに対する説明になる。なぜなら普通のDeep Learningは層が深なるほど入力層との相互情報量が下がることが示せるからである(これはlayerのマルコフ性からくる)。
おまけ
相互情報量をDeep Learningで簡単に計算する方法Mine3が提案された。MineはKL DivergenceのDonsker-Varahan表現を用いる。
D _ { K L } ( \mathbb { P } | | \mathbb { Q } ) = \sup _ { T . \Omega \rightarrow \mathbb { R } } \mathbb { E } _ { \mathbb { P } } [ T ] - \log \left( \mathbb { E } _ { \mathbb { Q } } \left[ e ^ { T } \right] \right)
Ω:測度空間, T:任意関数
証明
d \mathbb { G } = \frac { 1 } { Z } e ^ { T } d \mathbb { Q }\\
Z = \mathbb { E } _ { \mathbb { Q } } \left[ e ^ { T } \right]
Tは任意の関数
すると以下の関係1が成り立つ
\begin{aligned} \mathbb { E } _ { \mathbb { P } } [ T ] - \log Z & = \mathbb { E } _ { \mathbb { P } } \left[ \log e ^ { T } \right] - \log \left( e ^ { T } \frac { d \mathbb { Q } } { d \mathbb { G } } \right) \\ & = \mathbb { E } _ { \mathbb { P } } \left[ \log e ^ { T } - \log e ^ { T } - \log \frac { d \mathbb { Q } } { d \mathbb { G } } \right] \\ & = \mathbb { E } _ { \mathbb { P } } \left[ \log \frac { d \mathbb { G } } { d \mathbb { Q } } \right]
\end{aligned}
以下が証明したいこと
D _ { K L } ( \mathbb { P } | | \mathbb { Q } ) = \Delta + \mathbb { E } _ { \mathbb { P } } [ T ] - \log \left( \mathbb { E } _ { \mathbb { Q } } \left[ e ^ { T } \right] \right) \geq \mathbb { E } _ { \mathbb { p } } [ T ] - \log \left( \mathbb { E } _ { \mathbb { Q } } \left[ e ^ { T } \right] \right)
Δは等式が成り立つように次のように定義
\Delta \equiv D _ { K L } ( \mathbb { P } | | \mathbb { Q } ) - \left( \mathbb { E } _ { \mathbb { P } } [ T ] - \log \left( \mathbb { E } _ { \mathbb { Q } } \left[ e ^ { T } \right] \right) \right)
Δ≧0を示すことができれば証明完了
\Delta = \mathbb { E } _ { \mathbb { P } } \left[ \log \frac { d \mathbb { P } } { d \mathbb { Q } } - \log \frac { d \mathbb { G } } { d \mathbb { Q } } \right] = \mathbb { E } _ { \mathbb { P } } \left[ \log \frac { d \mathbb { P } } { d \mathbb { C } } \right] = D _ { K L } ( \mathbb { P } | | \mathbb { G } )
関係式1を使うとKL divergenceに変形できるので必ず≧0よって証明完了!
これを相互情報量版にすると以下を計算すれば相互情報量が計算できる。
実際はTをDeep Learningで学習することで相互情報量を計算する
I _ { \Theta } ( X , Z ) = \sup _ { \theta \in \Theta } \mathbb { E } _ { P ( X , Z ) } \left[ T _ { \theta } \right] - \log \left( \mathbb { E } _ { P ( X ) P ( Z ) } \left[ e ^ { T _ { \theta } } \right] \right)
簡単なサンプルコードを作った[^mine github]
import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
from tqdm import tqdm
import holoviews as hv
import bokeh
hv.extension('bokeh')
# データ生成
var = 0.2
def func(x):
return x
def gen_x():
return np.sign(np.random.normal(0.,1.,[data_size,1]))
def gen_y(x):
return func(x)+np.random.normal(0.,np.sqrt(var),[data_size,1])
# Mineの計算
H=10
n_epoch = 500
data_size = 20000
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(1, H)
self.fc2 = nn.Linear(1, H)
self.fc3 = nn.Linear(H, 1)
def forward(self, x, y):
h1 = F.relu(self.fc1(x)+self.fc2(y))
h2 = self.fc3(h1)
return h2
model = Net()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
plot_loss = []
for epoch in tqdm(range(n_epoch)):
x_sample=gen_x()
y_sample=gen_y(x_sample)
y_shuffle=np.random.permutation(y_sample)
x_sample = Variable(torch.from_numpy(x_sample).type(torch.FloatTensor), requires_grad = True)
y_sample = Variable(torch.from_numpy(y_sample).type(torch.FloatTensor), requires_grad = True)
y_shuffle = Variable(torch.from_numpy(y_shuffle).type(torch.FloatTensor), requires_grad = True)
pred_xy = model(x_sample, y_sample)
pred_x_y = model(x_sample, y_shuffle)
ret = torch.mean(pred_xy) - torch.log(torch.mean(torch.exp(pred_x_y)))
loss = - ret # maximize
plot_loss.append(loss.data.numpy())
model.zero_grad()
loss.backward()
optimizer.step()
# 普通の情報量の計算
data_size = 1000000
x=gen_x()
y=gen_y(x)
p_y_x=np.exp(-(y-x)**2/(2*var))
p_y_x_minus=np.exp(-(y+1)**2/(2*var))
p_y_x_plus=np.exp(-(y-1)**2/(2*var))
mi=np.average(np.log(p_y_x/(0.5*p_y_x_minus+0.5*p_y_x_plus)))
mi
# 普通の相互情報量の計算とMineの答えがあってるかチェック
plot_x = np.arange(len(plot_loss))
plot_y = np.array(plot_loss).reshape(-1,)
hv.Curve((plot_x, -plot_y)) * hv.Curve((plot_x, mi))
結果
青:Mineによる計算、オレンジ:普通の方法での相互情報量の計算
横軸:epoch, 縦軸:相互情報量
参考文献
[^informatin bottleneck res]: ICLR2018のopen reiview
[^ ib日本語解説]: 日本語解説 https://www.slideshare.net/DeepLearningJP2016/dlopening-the-black-box-of-deep-neural-networks-via-information-81269767
[^mine github]: github: mineのpytroch実装