相互情報量からみるDeep Learning
Deep Learningの表現学習を情報量という観点で見てみる。
所属組織のしがらみがあるので公開情報に限定し自分の考察などは基本記述しない
まとめ
相互情報量使うといろいろおもしろ表現学習できるし汎化誤差にも関係ありそうだし、相互情報量大事だよ!
おまけで相互情報量を計算するサンプルコード載せたよ!
相互情報量とは?
2つの確率変数XとYの情報がどれだけかぶっていないかを表す指標で以下で定義される
ここで
KL divergenceの説明
KL divervenceは確率分布間の距離のようなもので、以下で定義される
定義からわかるように以下の性質を満たす
-
: 同じ場所だと距離0p\left(x\right)=q\left(x\right)\rightarrow D_{{\rm KL}}\left(p\left(x\right)||q\left(x\right)\right)=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のノードを高次元の確率変数だとみなし入力
前提
- 各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上で元の論文の作者と熱いレスバトルを繰り広げていて完全に正しい主張かは未だわからない。[1]
Disentangledな表現学習と転移性能
相互情報量による縛りを用いるとdisentangle表現と呼ばれる面白い表現学習ができる[2]。
disentangle表現とは、通常の分散表現とは異なり、1つの意味が1つの隠れ変数の次元で表されている表現である。 以下の動画を見るとわかりやすい[3]
図:VAE likeな潜在変数モデル(x→z→x)で学習を行い、特定のz次元のzを-3~3に変化させて生成画像を生成した結果を表示
上:β-VAEと呼ばれるdisentangle学習をしたもの
下:普通のVAE(分散表現)
横軸:変化させるzの次元の違い
Disentangle表現としては以下の特徴が言われている。
- transfer learning(特にzero shot)に向いている
- ラベルを使わずに意味の抽出ができる
- 潜在変数が解釈可能である(保証はないが論文の例では情報圧縮で得られる特徴は人間の理解と一致している(celebAでいうと笑顔や年齢など))
以下もdisentangleで意味が抽出された例[^disentangle_video]
ではこのようなdisentangle表現はどうやって実現されるのかをβ-VAEを例に見ていく。
β-VAEのlossは
ここでβ,Cは定数(C=0,β=1を取るとVAEと等価になる)。通常VAEは
データxを使ってタスクyを解くときのコンパクトな表現zを考える。
つまり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個のデータセットで学習すると 以下のように汎化誤差εに上限がつく
DeepLearningにおいては以下のboundが成り立つ?? (この証明は自分は追ってないし、論文としても2018/12/11時点でpublishされてるわけではないので正しさは???)
これが正しければ
おまけ
相互情報量をDeep Learningで簡単に計算する方法Mine[4]が提案された。MineはKL DivergenceのDonsker-Varahan表現を用いる。
Ω:測度空間, T:任意関数
証明
Boltzmann分布をGを考える
Tは任意の関数
すると以下の関係1が成り立つ
以下が証明したいこと
Δは等式が成り立つように次のように定義
Δ≧0を示すことができれば証明完了
関係式1を使うとKL divergenceに変形できるので必ず≧0よって証明完了!
これを相互情報量版にすると以下を計算すれば相互情報量が計算できる。
実際はTをDeep Learningで学習することで相互情報量を計算する
簡単なサンプルコードを作った[5]]
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, 縦軸:相互情報量
参考文献
Discussion