Flow-GAN: Combining Maximum Likelihood and Adversarial Learning in Generative Modelsを読んだのでメモ
はじめに
Flow-GAN: Combining Maximum Likelihood and Adversarial Learning in Generative Modelsを読んだのでメモ.簡単に言えばGANのgeneratorをflow-basedなモデルに置き換えて密度推定もできるようにしたというもの.
notation
データの分布をとし,パラメータを持つモデルによって表現される分布をとする.とのダイバージェンスを最小化することで最適なを見つけることが目標.
以下,この論文の基礎となる最尤推定とadversarial trainingについて.一般的な内容なのでさっくりと
Maximum likelihood estimation
データ分布とモデル分布のKLダイバージェンスを最小化することを考える.この場合の目的関数は以下のようになる.
がパラメータと独立しているため,上記の最適化問題は次のように書き換えられる.
この目的関数を使って学習することは,モデルの密度関数を陽に計算できるということを要求する.
Adversarial learning
KLダイバージェンスを含むダイバージェンスの一般化は次のように表現される.
はモデルのパラメータの集合.このの選び方でJensen-ShannonダイバージェンスのようなダイバージェンスやWasserstein距離のような指標が導かれる.
GANでは次のような目的関数が提案されている.
この目的関数ではモデル分布からのサンプリングが要求される.そのため,サンプリングしやすいモデルを使って以下のminmax問題を解くことで最適なモデルのパラメータを見つける.
結果として得られるモデルは容易にサンプリングを行えるがモデルの密度を陽に計算することはできない.
Flow Generative Adversarial Networks
ここからが本題.結局adversarial learningは綺麗なサンプルを生み出せるけど尤度の推定ができないところが問題で,最尤推定を基礎とする手法はサンプリングがしにくかったり表現力が乏しかったりする.そこでadversarial learningの恩恵を受けつつ尤度推定可能なFlow-GANを提案する.
Flow-GANは言ってしまえばGANのgeneratorをnormalizing flow modelにしたもの.Normalizing flowに関しての詳細は別のメモを参照.Normalizing flowのモデル分布は次のように計算できる.
はパラメータを持つ逆変換可能な関数で,事前分布に関数のヤコビアンの行列式をかけることで分布を陽に計算することができる.これは確率分布の変数変換の公式から導かれる関係.のヤコビアンの計算が用意で事前分布が扱いやすいものだったらデータ点の尤度を評価することができる.または逆変換が可能なためサンプリングも可能.
目的関数
重要なのはFlow-GANをどのような目的関数で学習させるか.この論文では単純に最尤推定とadversarial trainingを組み合わせた関数を考えたそう.つまり次の目的関数を最適化する.
ここではadversarial lossはWGANで提案されていた式を使ったとのこと.すなわちdiscriminatorは1-Lipschitzを満たす.
まとめ
実験ではNICEとRealNVPをgeneratorとしていたためいまいちパッとする結果にはなってないが今だったらglowがあるのでどんなもんかなあというところ.
MINEを使ってinfoGANを実装した
はじめに
Mutual information neural estimation(MINE)を使ってinfoGANを実装したのでメモ.MINEに関してのメモはこちら.
設定
オリジナルのinfoGANと同様にMNISTで離散変数1つ,連続変数2つでgeneratorを学習した.infoGANの特徴である相互情報量最大化の部分をMINEに置き換えた.MINEに関しては雰囲気を知りたかったのでだいぶ簡略化した実装にした. 具体的にはMINEのオリジナルの論文ではKLDが無限に大きくなってしまい勾配のバランスが崩れるため,adaptive gradient clippingを使っていたが,今回はKLDではなくDIM(DIMのメモはこちら)で使われていたJensen-Shannonダイバージェンスバージョンを使ってclippingの実装は省いた.また,statistics networkとgeneratorは別々に最適化するところを,これもDIMと同様同時に最適化するようにした.ただし,DIMではgeneratorとstatistics networkの一部を共有していたが完全に別々にした.
モデルはgeneratorとdiscriminator,3つの変数それぞれに対して相互情報量を計算するためのstatistics networkを用意.目的関数は以下のように定義した.
相互情報量は平均をとった.こうしないと相互情報量のロスに引っ張られて生成画像があんまり綺麗にならなかった.
モデルの構成はその辺に落ちてたinfoGANの実装のモデルを真似た.statistics networkに関してはとりあえず画像をベクトル化して潜在変数とくっつけたものを入力とするMLPとして実装した.後一応,discriminatorにはspectral normalizationを付けてる(なくても多分動くんじゃないかな).
離散変数はonehotベクトルで連続変数とノイズは-1~1の範囲の一様分布からサンプリングした.
実験結果
100エポック学習した結果.100エポックもいらなかった.
離散変数と連続変数の片方を-1から1で動かした場合.
離散変数と連続変数のもう一方を-1から1で動かした場合.
思った以上にうまく動いてびっくり.ただ,3と5の区別が微妙な感じなのと文字の太さはあんまり表現できてない.もう少しちゃんと実装すればもっとうまくいくのかどうか. とりあえず現状の実装だと相互情報量がサチってたからこれ以上は無理な気がする.
コード
適当に転がってたGANのコードを改変して作ったのでいろんなところがハードコードされているけどとりあえず動くはず. 以下メインファイル.
import torch import torch.optim as optim import torch.nn.functional as F import numpy as np import os import torchvision.utils as vutils from torchvision.datasets import MNIST from torchvision.transforms import ToTensor from torch.utils.data import DataLoader from model import generator, disciminator, disc_statistics, cont_statistics if torch.cuda.is_available(): device = "cuda" else: device = "cpu" BATCH_SIZE = 100 NUM_WORKERS = 8 RANGE = 1 G = generator().to(device) D = disciminator().to(device) S_disc = disc_statistics().to(device) S_cont1 = cont_statistics().to(device) S_cont2 = cont_statistics().to(device) optimG = optim.Adam(G.parameters(), lr=1e-3, betas=(0.5, 0.999)) optimD = optim.Adam(D.parameters(), lr=2e-4, betas=(0.5, 0.999)) optimS = optim.Adam([{"params":S_disc.parameters()}, {"params":S_cont1.parameters()}, {"params":S_cont2.parameters()}], lr=1e-3, betas=(0.5, 0.999)) train_data = MNIST("./data", train=True, download=True, transform=ToTensor()) loader = DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True, drop_last=True, num_workers=NUM_WORKERS) label = torch.zeros(BATCH_SIZE).to(device).float() real_label = 1 fake_label = 0 c = torch.linspace(-1, 1, 10).repeat(10).reshape(-1, 1) c1 = torch.cat([c, torch.zeros_like(c)], 1).float() * RANGE c2 = torch.cat([torch.zeros_like(c), c], 1).float() * RANGE idx = torch.from_numpy(np.arange(10).repeat(10)) one_hot = torch.zeros((100, 10)).float() one_hot[range(100), idx] = 1 fix_z = torch.Tensor(100, 62).uniform_(-1, 1) fix_noise1 = torch.cat([fix_z, c1, one_hot], 1)[...,None,None].to(device) fix_noise2 = torch.cat([fix_z, c2, one_hot], 1)[...,None,None].to(device) for epoch in range(100): for i, data in enumerate(loader): # discriminator optimD.zero_grad() ## real real, _ = data real = real.to(device) label.fill_(real_label) real_prob = D(real).squeeze() real_loss = F.binary_cross_entropy_with_logits(real_prob, label) real_loss.backward() ## fake label.fill_(fake_label) ### get noise idx = torch.randint(0, 10, (BATCH_SIZE,)).long() disc_c = torch.eye(10)[idx][...,None,None].float().to(device) cont_c = torch.zeros(BATCH_SIZE, 2, 1, 1).uniform_(-1, 1).float().to(device) * RANGE z = torch.zeros(BATCH_SIZE, 62, 1, 1).uniform_(-1, 1).float().to(device) noise = torch.cat([z, cont_c, disc_c], 1).to(device).float() ### generate fake = G(noise) fake_prob = D(fake.detach()).squeeze() fake_loss = F.binary_cross_entropy_with_logits(fake_prob, label) fake_loss.backward() loss_D = real_loss + fake_loss optimD.step() # generator optimG.zero_grad() optimS.zero_grad() label.fill_(real_label) ## adversarial loss inv_fake_prob = D(fake).squeeze() inv_fake_loss = F.binary_cross_entropy_with_logits(inv_fake_prob, label) ## MINE ### c ~ P(C) idx = torch.randint(0, 10, (100,)).long() disc_c_bar = torch.eye(10)[idx].float().to(device) cont_c_bar = torch.zeros(100, 2, 1, 1).uniform_(-1, 1).float().to(device) * RANGE ### discrete variable joint_disc = S_disc(torch.cat([fake.reshape(100, -1), disc_c.reshape(100, -1)], 1)) marginal_disc = S_disc(torch.cat([fake.reshape(100, -1), disc_c_bar.reshape(100, -1)], 1)) ### continuout variable joint_cont1 = S_cont1(torch.cat([fake.reshape(100, -1), cont_c[:,0].reshape(100, -1)], 1)) joint_cont2 = S_cont2(torch.cat([fake.reshape(100, -1), cont_c[:,1].reshape(100, -1)], 1)) marginal_cont1 = S_cont1(torch.cat([fake.reshape(100, -1), cont_c_bar[:,0].reshape(100, -1)], 1)) marginal_cont2 = S_cont2(torch.cat([fake.reshape(100, -1), cont_c_bar[:,1].reshape(100, -1)], 1)) ### calc mutual information mi_disc = F.softplus(-joint_disc).mean() + F.softplus(marginal_disc).mean() mi_cont1 = F.softplus(-joint_cont1).mean() + F.softplus(marginal_cont1).mean() mi_cont2 = F.softplus(-joint_cont2).mean() + F.softplus(marginal_cont2).mean() mi = (mi_disc + mi_cont1 + mi_cont2)/3 loss = mi + inv_fake_loss loss.backward() optimG.step() optimS.step() print("epoch [{}/{}], iter [{}/{}], D : {}, G : {}, S : {}".format( epoch, 100, i, len(loader), loss_D.item(), inv_fake_loss.item(), mi.item() )) with torch.no_grad(): fake1 = G(fix_noise1) fake2 = G(fix_noise2) if not os.path.exists("results_1"): os.mkdir("results_1") vutils.save_image(fake1.detach(), "results_1/{}epoch_fake1.png".format(epoch), normalize=True, nrow=10) vutils.save_image(fake2.detach(), "results_1/{}epoch_fake2.png".format(epoch), normalize=True, nrow=10)
以下モデルファイル.
import torch.nn as nn class generator(nn.Module): def __init__(self): super().__init__() self.main = nn.Sequential( nn.ConvTranspose2d(74, 1024, 1, 1, bias=False), nn.BatchNorm2d(1024), nn.ReLU(), nn.ConvTranspose2d(1024, 128, 7, 1, bias=False), nn.BatchNorm2d(128), nn.ReLU(), nn.ConvTranspose2d(128, 64, 4, 2, 1, bias=False), nn.BatchNorm2d(64), nn.ReLU(), nn.ConvTranspose2d(64, 1, 4, 2, 1, bias=False), nn.Sigmoid() ) for m in self.modules(): if isinstance(m, nn.ConvTranspose2d): nn.init.normal_(m.weight, 0, 0.02) elif isinstance(m, nn.BatchNorm2d): nn.init.normal_(m.weight, 1, 0.02) nn.init.constant_(m.bias, 0) def forward(self, x): return self.main(x) class disciminator(nn.Module): def __init__(self): super().__init__() self.main = nn.Sequential( nn.Conv2d(1, 64, 4, 2, 1, bias=False), nn.LeakyReLU(0.1), nn.Conv2d(64, 128, 4, 2, 1, bias=False), nn.BatchNorm2d(128), nn.LeakyReLU(0.1), nn.Conv2d(128, 1024, 7, bias=False), nn.BatchNorm2d(1024), nn.LeakyReLU(0.1), nn.Conv2d(1024, 1, 1, bias=False) ) for m in self.modules(): if isinstance(m, nn.Conv2d): nn.init.normal_(m.weight, 0, 0.02) nn.utils.spectral_norm(m, n_power_iterations=2) elif isinstance(m, nn.BatchNorm2d): nn.init.normal_(m.weight, 1, 0.02) nn.init.constant_(m.bias, 0) def forward(self, x): return self.main(x) class cont_statistics(nn.Module): def __init__(self): super().__init__() self.main = nn.Sequential( nn.Linear(28**2 + 1, 1024, bias=False), nn.BatchNorm1d(1024), nn.LeakyReLU(0.1), nn.Linear(1024, 1024, bias=False), nn.BatchNorm1d(1024), nn.LeakyReLU(0.1), nn.Linear(1024, 1, bias=False), ) for m in self.modules(): if isinstance(m, nn.Linear): nn.init.normal_(m.weight, 0, 0.02) elif isinstance(m, nn.BatchNorm1d): nn.init.normal_(m.weight, 1, 0.02) nn.init.constant_(m.bias, 0) def forward(self, x): return self.main(x) class disc_statistics(nn.Module): def __init__(self): super().__init__() self.main = nn.Sequential( nn.Linear(28**2 + 10, 1024, bias=False), nn.BatchNorm1d(1024), nn.LeakyReLU(0.1), nn.Linear(1024, 1024, bias=False), nn.BatchNorm1d(1024), nn.LeakyReLU(0.1), nn.Linear(1024, 1, bias=False), ) for m in self.modules(): if isinstance(m, nn.Linear): nn.init.normal_(m.weight, 0, 0.02) elif isinstance(m, nn.BatchNorm1d): nn.init.normal_(m.weight, 1, 0.02) nn.init.constant_(m.bias, 0) def forward(self, x): return self.main(x)
まとめ
MINEを論文通りに実装しようとするとちょっと面倒かなという印象で逃げてしまった.というかclippingの実装気になるからちゃんとした実装上がって欲しい.
実装は何も考えずにネットワークひとつ用意するだけなのでめちゃくちゃ簡単(厳密にやるともう少し複雑だけどこれでも十分動く).相互情報量の面だけみればmin-max gameのような不安定要素も入らないのでMINEとても良い.
Learning deep representations by mutual information estimation and maximizationを読んだのでメモ
はじめに
Learning deep representations by mutual information estimation and maximizationを読んだのでメモ.Abstractの最後の1文で"DIM opens new avenues for unsupervised learn- ing of representations and is an important step towards flexible formulations of representation-learning objectives catered towards specific end-goals."といっている非常に力強い論文.
気持ち
現状の表現学習はreconstruction lossを使った自己符号化器で行われるものが多いが,それは入力のデータに依存した目的関数になっているからよくないと論文では言っている.Introductionに書いてあるように"is it possible to learn representations with a training objective that is not defined in input space?"というのが論文の思い.
モチベーションとしては,reconstruction lossは相互情報量と以下の関係があるというところから,相互情報量に基づいた表現学習をしようというもの.
はエントロピーで下付きのはそれぞれencoder,decoderを表す.また,は入力と中間表現の確率変数を示す. 上記の式から分かるようにreconstruction lossを最小化することは相互情報量を大きくすることにつながる.すなわち,入力と中間表現が強い関連を持つようになる.同様にBiGANのようなadversarialな表現学習もを最小化するという文脈で同様に相互情報量を大きくしている.
Reconstructionを目的関数とした表現学習の問題点は,reconstruction lossを個々のピクセルごとに計算する事で,解像度が高くなると背景のような意味のないピクセルに誤差が引っ張られてしまい真に意味のある表現を獲得する妨げとなる.なので直接的に相互情報量を多くしたいというのが話の流れ.
Deep INFOMAX
提案手法であるDeep INFOMAX (DIM)について.DIMは3つのロスの組み合わせからなる.ここでは入出力間の相互情報量を最大化するようにencoderを学習する問題設定を考える.パラメータを持つニューラルネットをと定義する.ここで入力空間上の経験分布に従う学習サンプルの集合が与えられたと仮定する.ここでをpush-forward distributionとして定義する.Push-forward distributionはに従うサンプルをに通す事で得られる分布のこと.以下,marginal, joint, product of marginal push-forward distributionを定義する.
ただし,は上でのディラック測度.
Mutual information estimation and maximization
ここではMINEの枠組みに従って相互情報量を推定する.すなわち次のように相互情報量を求める.
ただし,でパラメータを持つニューラルネットを表す.MINEに関しては以前読んでメモした.この相互情報量を使ってencoder を次の目的関数に従って学習する.
ここにはMINEと重要な異なる点があり,ここではencoderとMINEが同じ目的関数で最適化される事とどちらもCNNによる計算が行われることから,両方のネットワークの初期レイヤーをのように組み合わせる. もう一つの違いは,相互情報量の推定をKLダイバージェンスではなくJensen-Shannonダイバージェンス (JSD)で行っている点. これらの違いにより最終的な目的関数は次のようになる.
は入力のサンプルで,はhigh-level representation,はに関係のないもう一方のサンプル,はsoftplus関数で.
このJSDに基づく推定器とKLに基づく推定器は似た振る舞いをするが,JSDベースの方が同時最適するのには適しているとのこと.というのも,相互情報量はunboundedであるから不安定になるのに対し,Jensen-Shannonは上界がになるため,MINEで行われていたclippingの必要がない.もう一つの理由が,KLのDonsker-Varadhan表現(MINEの論文またはメモを参照)におけるの期待値がバイアスの乗った勾配を導いてしまうのに対しJSDではunbiasな勾配を求めることができる.あとは単純に実験的にJSDが優れていたということらしい.ただ,JSDの場合の相互情報量の式の導出がいまいちわからなかった.
Local mutual information maximization
前節の目的関数は入出力間の相互情報量を最大化することだったが,タスクによってはあまり意味のない表現を獲得する可能性がある.というのも画像の分類問題などでは局所的に見れば意味のないピクセルが存在していて,そのような領域からくる情報は表現獲得の邪魔をする可能性がある.そこで画像分類問題のためにhigh-level representationと画像のlocal patch間の平均相互情報量を最大化することを考える.
Local mutual information maximization frameworkの概要は論文のFigure 3に書いてある.まず初めに画像を特徴マップにエンコードする (はパッチのこと).次にこの特徴マップを大局的な特徴ベクトルへとエンコードする.この特徴ベクトルをのようにlower-level feature mapと結合し, convolutional discriminatorによりペアスコアを算出する.
上の手順で作った特徴ベクトルをrealとし,fakeは異なる画像を使って次のように作る.
つまりlower-level feature mapを別な画像から作るということ.この場合には次の平均JSD相互情報量を最大化することで学習を行う.
Matching representations to a prior distribution
ここではpush-forward distributionをpriorにマッチするように学習する事を考える.priorに合わせるように学習すれば潜在表現をコントロールしやすくなって色々な場面で便利だろうという事.基本的な戦略としては次のmin-max gameによって学習する.
この学習方法はadversarial autoencodersやBiGANに似ているが,generatorがないということが大きな違い.
ここまでで,最初に定式化したglobal mutual information mazimizationとパッチを使うlocal mutual information maximization,最後のprior matchingの3つの目的関数を提案した.ただ,これは全部を同時に使うこともできて,これをここではdeep INFOMAX (DIM)として提案する.
はlocalとglobalの目的関数に関するdiscriminatorのパラメータではハイパーパラメータ.(実験ではにしたlocal-onlyとにしたglobal-only,の両方入りを使って比較してたが,local-onlyが一番うまく動いているよう.)
まとめ
設定によっては教師あり(提案手法も識別器は教師ありだけど)より良い精度が出ていて少し驚き. IntroductionからMotivation and Backgroundまでで語られてたコンセプトはなるほどという感じ.
Mutual Information Neural Estimationを読んだのでメモ
はじめに
Mutual Information Neural Estimationを読んだのでメモ.書き終わってちょっと殴り書きすぎたと反省.正直このメモ読んでもよくわからないと思う…
気持ち
相互情報量は二つの確率変数の依存関係を知る良い指標だが一般的に計算するのが難しく,離散変数または確率分布が既知の問題を除いて基本的に扱いにくい.また,ノンパラメトリックカーネル密度推定やガウス性を仮定した場合にも高次元になると計算が困難になる.そこでscalableでflexibleでback-prop可能でcompletely trainableな新たな手法を理論解析付きで提案するという話.
相互情報量
相互情報量は簡単に言えば二つの確率変数の依存関係を測る尺度で,相互情報量が0の時二つの確率変数は独立となり,のように因子分解された形でかける.相互情報量はいろんな書き方ができるが論文では次の表現を用いる.
は相互情報量エントロピーを示し,は条件付きエントロピーを表す.条件付きエントロピーはで表すことができる.これらの関係を使うと相互情報量は次のようなKLダイバージェンスの形で表現することができる.
この辺りは情報理論の初等的な教科書に書いてある内容.式からもわかるように相互情報量が大きければとのKLダイバージェンスが大きくなるということで確率変数の依存関係が強くなる.
Dual representations of the KL-divergence
以下で説明するDonsker-Varadhan representationと-divergence representationと呼ばれる二つのKL-divergenceの表現が提案手法の核となる理論らしい.
Theorem 1 (Donsker-Varahan representation)
KLダイバージェンスは次のような表現を持つ.
証明
関数が与えられた時,で定義されるギブス分布を考える.ただし,.すると次のような関係を考えることができる.
を次のようなgapとして定義する.
すると,は次のようなのKLダイバージェンスとして定義できる.
ただし,の関係を使った.KLダイバージェンスは負の値を取らないためとなりあらゆるにおいて次の不等式が成立する.
上の関係はの時に等式が成り立ち,その時よりの形をとる.ただし,は定数.この時のをoptimal functionsとして名付ける.よって,右辺の上界,すなわちがoptimal functionsである場合等号が成立するのでTheorem 1が成り立つ.
-divergence representation
KLダイバージェンスは次の下界が成り立つことも知られている.
一般のにおいてはDonsker-Varadhanの下界の方が負の項が対数表現になっているため上式の下界よりも大きくなることがわかる.
Mutual Information Neural Estimator
提案手法であるMINEの定式化をする.MINEではパラメータを持つDNNで表現された関数族によってを与える.このネットワークをstatistics networkと呼び,次のような相互情報量の下界を与えるものとする.
このをneural information measureと呼び次のように定義する.
この期待値はからのサンプリングなどを用いて計算され,勾配上昇法を使って最大化することで上界を求める.これは情報量の新しいクラスであって,ニューラルネットワークの表現力から任意の精度で相互情報量を近似することができる.
Difinition 3.1 (Mutual Information Neural Estimator)
をニューラルネットで表現される関数の集合とするとMINEは次のように定義される.
ただし,はi.i.dに得られた個のサンプルから計算される経験分布を表す.また,-divergence representationに従った下界を与えたものをMINE-として定義する.今までの議論からMINEとMINE-を比較すれば,MINEの方が良い近似を与えるが,mini-batchを使ったSGDで求められる勾配にはバイアスがのるとのこと.
Correctiong the bias from the stochastic gradients
MINEの勾配は次のように計算ができる.
右辺第2項の期待値はミニバッチから計算され,full batchの勾配にバイアスがのった推定結果を導く(この辺りがうまく理解できなかったがMINE-の方はunbiasな勾配を導けるらしい).ただし,分母を期待値の移動平均として置き換えることでそのバイアスは減らせるらしい.もっと言えばsmall learning rateを使えばバイアスを任意の大きさに抑えることができるとのこと.
Theoretical properties
ここでMINEのconsistencyとconvergenceを解析する.
Consistency
MINEはstatistics networkとデータ分布からのサンプルの選び方に依存する.
Definition 3.2 (Strong consistency)
次の関係性において全てのにおいてが成り立ち次の関係が成り立つstatistics networkを選択したとき,推定器はstrongly consistentとなる.
知識不足でconsistencyの意味がいまいちわからなかったが,consistencyの話はのサイズに関連したapproximation problemと経験測度(empirical measure)に関するestimation problemの二つの問題に分けられるらしい.
以下,面倒なnotationを避けるためとして定義し.をempirical versionとする.また,とする.
Lemma 1 (approximation)
とする.compact domainにおいて次の関係を満たすパラメータを持つニューラルネットの関数族が存在する.
証明
とすると,は次の式を満たす.
単純に左辺にを代入すれば求まる.これに対し,関数に関して,正のgapは次のようにかける.
最後の不等式はからとなることから示せる.
の定数とし,が定数によってboundされる場合を考える.ここで,ニューラルネットのuniversal approximation theoremを考えれば,次の関係を満たすfeedforward network functionを選択することができる.
がでのリプシッツ連続であることから,次の関係が得られる.
さらに三角不等式とから次の不等式が得られる.
一般の場合についても解説されていたが割愛.
Lemma 2 (estimation)
とする.compact domainにおけるパラメータのニューラルネットの族が与えられたとき,次の関係を満たすが存在する.
証明
まずはに三角不等式を使う.
導出はにそれぞれ代入してでまとめて三角不等式を使うだけ.compact domain上で定義された関数はboundされる.さらに関数は定数によってと一様にboundされる.が定数に対してのリプシッツ連続であるため次の関係が成り立つ.
がコンパクトで,feedforward network functionが連続であることから,関数との族はuniform law of large numbersを満たすらしい.が与えられたとき,次の関係を満たしとなるようなを選ぶことができる.
三角不等式とリプシッツ連続の性質を合わせることで以下の関係が導かれる.
よってlemma 2が成り立つ.
Sample complexity
提案している推定器のsample complexityを議論する.まず仮定として,相互情報量はneural information measureによって十分に近似可能であるとする.ここではLemma 2に手を加えてneural information measureの推定量が十分な精度と信頼度を達成するのにどれくらいのサンプル数が必要かを与える.
まず以下の仮定を置く.関数は-bounded()であり,パラメータに関して-リプシッツであるとする.domainがboundされていて,定数に関してが成り立つ.以下の定理は次元のパラメータ空間においてのsample complexityを持つことを示す.
Theorem 3
任意の値のaccuracyとconfidence parametersが与えられたとき,以下をの関係を満たす.
書くのに力尽きたので証明は割愛.
Maximizing mutual information to improve GANs
実験の一つとして行っていたGANの改善.GANの目的関数は以下のように記述される.
ここではinfoGANの枠組みを考えて,入力はノイズとコードを合わせたとする.ここではサンプルとコード間の相互情報量を最大化することでmode collapseが怒るのを防ぐアプローチを考える.するとgeneratorの目的関数は次のようになる.
Generatorはのパラメータに関して微分可能で,statistics networkは微分可能な関数であることからback-propと勾配上昇法を使うことで相互情報量を最大化することができる.相互情報量は任意の大きさにできてしまうためここではadaptive gradient clippingを使ってdiscriminatorとstatistics networkからくる勾配が同じ程度になるようにしたとのこと.ちなみにadaptive gradient clippingはmutual informationから計算される勾配を次のようにclippingすること.
ただし,はそれぞれdiscriminatorの勾配と相互情報量の勾配.実験結果を見る限りは通常のGANに比べてMode collapsを回避しているよう.
まとめ
証明等をかなり殴り書いたせいで結局論文の主張がこのメモから分かりにくくなってしまったけど,簡単に言えば相互情報量をニューラルネットを使ってとして推定可能で,その推定精度がサンプル数次第で任意精度を達成可能というところを証明した論文.実装ではGANのように生成モデル+相互情報量を推定するstatistics networkを用意して目的関数に相互情報量の最大化を組み込む感じ.手法自体はすごくシンプルでアルゴリズムテーブル1を見れば実装もなんとなく予想できる.
これかなり有用な手法な気がするので,とりあえず実装してどんなもんか確認したい.ただ実装が公開されてないのとclippingの実装がめんどくさそう.
一応MINEを使ってInfoGANを実装して遊んでみた内容もメモした.
Image Generation from Scene Graphsを読んだのでメモ
はじめに
Image Generation from Scene Graphsを読んだのでメモ.言語から画像を生成する研究.複雑な文章からでも安定して画像生成ができるとのこと.
概要
ここではシーングラフとノイズを入力として画像を生成するモデルの構築と学習を目標とする.モデルの特徴としてはシーングラフをgraph convolutionで処理するところで,graph convolutionで埋め込まれた各物体の特徴ベクトルを使って物体とその関係性を考慮したsegmentation maskとBB(bounding box)を生成する.後は得られたsegmentation maskとBBとノイズを合わせて,cascaded refinement network (CRN)で画像を生成するというのが処理の大まかな流れ.
Scene Graphs
モデルの入力となるのは画像のシーングラフで,シーングラフは画像中に何の物体がいて,画像中の物体間にどのような関係性があるかを記述したグラフ.具体的には物体のカテゴリと関係性のカテゴリが与えられた時,グラフはで記述され,は物体の集合で,有向エッジを表し,で形成される.
この論文の問題設定では物体とその関係性を示すカテゴリは言語として与えられるため,自然言語で使われる埋め込み処理によりdenseな特徴ベクトルを作る.
Graph Convolution Network
単語の埋め込みベクトルを持ったシーングラフをend-to-endで処理するために,ここではオリジナルのgraph convolution networkを使う.
入力のグラフが持つ特徴ベクトルをとした時,3つの関数を使って出力を作る.を出力する関数は関係性のベクトルが二つの物体からのみ決められるため単純で,として3つのベクトルを入力とする関数.逆に物体に関するベクトルを更新する場合は,ひとつの物体が複数の物体と関係性を持つための更新よりも複雑になる.もっと言えば,今回は有向グラフを考えているため,入ってくるエッジと出て行くエッジで意味合いが変わってくる.当然ある物体に関するベクトルはと関係性を持つ全ての物体のベクトルを使って更新されるべきである.そこで,から伸びる全てのエッジに対してを使ってcandidate vectorを計算する.それと同様にに入るエッジに対してを使ってcandidate vectorを計算する.
このように各方向のエッジに関するcandidate vectorの集合が得られたらに関する出力をとして計算する.ただし,は入力の集合をひとつのベクトルにするpooling関数.この論文では各関数は3つのベクトルを入力とするニューラルネットで構成したとのこと.また,pooling関数は入力のベクトルを平均する関数として定義したらしい.
Scene Layout
Graph convolution networkによってシーングラフからいい感じの情報を抽出した後はグラフで表現された情報を画像に起こす必要がある.ここでは画像生成の第1段階としてシーングラフをシーンレイアウトへと変換することを考える.シーンレイアウトはsegmentation maskとBBから作られ,maskとBBの推定にobject layout networkを使う.
Object layout networkは物体に関する埋め込みベクトルを入力とし,のsoft binary mask とBBの座標を出力する.要はGANのgeneratorの入力ノイズがgraph convolution networkで計算された物体の特徴ベクトルになったということ.細かいことを言えば,maskを出力するネットワークはtranspose convolutionで構成されたネットワークで最終層の活性化関数はsigmoid,BBを出力するネットワークは一般的な多層ニューラルネット.Object layout networkによって出力されたmaskはBBの領域にwarpされ,最終的に全ての物体に関するマスクを統合することでシーンレイアウトを作る.学習中はBBはground-truthを使ってシーンレイアウトをつくることに注意.
Cascaded Refinement Network
シーンレイアウトができたら後はそれをリアルな画像に起こすだけ.ここでは従来手法のCascaded Refinement Network (CRN)を使うとのこと.Cascadedと言うように,解像度を2倍にして行くmoduleを多段に積み上げていて,各moduleはシーンレイアウトと前のmoduleの出力を入力とする(ただし最初のmoduleは前段の出力の代わりにガウスノイズを入力とする).
Discriminator
ここまでで,シーングラフからの特徴抽出,シーンレイアウトの生成,画像の生成という3段構成で画像を生成したが,このプロセスをまとめて画像生成ネットワークとしてend-to-endで学習する.学習はGANの枠組みに沿って行われ,discriminatorとしての二つを用意する.は画像全体を入力とし,は物体領域を切り取って固定サイズにリサイズしたものを入力とする.要は画像全体のそれっぽさと物体のそれっぽさをそれぞれ学習するということ.ただし,は物体の分類問題も同時に解く.
Training
モデルが3段階構成でそれぞれGTを必要とするのでロスは結構複雑.まとめると次の6つのロスの重み付き和を最小化するように学習する.
・Box Loss Object layout networkのBBに関するロスで loss
・Mask Loss Object layout networkのmaskに関するロスでcross-entropy loss
・Pixel loss 画像の再構成に関するロスで,生成画像と真の画像と loss
・Image adversarial loss に関するmin-max game
・Object adversarial loss に関するmin-max game
・Auxiliarly classifier loss の物体の分類問題に関するロス.
まとめ
これ学習できるのすごいなという気持ち.複雑なモデルを思いついても実際に学習させきる力がないからそういう力も養っていきたい.
SEMI-SUPERVISED CLASSIFICATION WITH GRAPH CONVOLUTIONAL NETWORKSを読んだのでメモ
はじめに
SEMI-SUPERVISED CLASSIFICATION WITH GRAPH CONVOLUTIONAL NETWORKSを読んだのでメモ.
Fast approximate convolutions on graphs
ここでは次のような多層のgraph convolutional networks(GCN)を考える.
は無向グラフに自己ループを加えた隣接行列を表し,とは学習パラメータ.はReLUなどの活性化関数で,は層目の出力.
Spectral graph convolution
グラフフーリエ変換によるグラフ上でのフィルタリングは次のような入力信号とをパラメータとするフィルタの積によって表現される.
ここではnormalized graph Laplacianの固有ベクトルで,は固有値を対角成分とする対角行列.ここでは固有値の関数と見ることができる.ここでの問題として,固有ベクトル行列の行列積がとなり計算コストが高いことと,グラフラプラシアンの固有値分解の計算が巨大なグラフに対しては現実的でないことがあげられる.ここでは次のような次のチェビシェフ多項式による近似を使ってこの問題を回避する.
ただし,ではの最大固有値.また,はチェビシェフ係数.チェビシェフ多項式はとして再帰的に計算される.
畳み込みの話に戻れば,近似を使った畳み込みの計算は以下のように定義される.
ただし,.重要なのはチェビシェフ多項式の次数がフィルタサイズと対応している.ここまでは前回読んだ論文の内容.
Layer-wise linear model
この論文ではチェビシェフの多項式で近似されたモデルに対しの場合のみについて考える.この場合モデルはグラフラプラシアンに関して線形になっている.そのためモデルの表現力は大きく下がるが,そこはNNの多層構造によって補う.むしろとすることで,過学習を抑制する効果が期待できる.
以降,計算を簡単にするためとして扱う.この近似のもとではgraph convの計算式は以下のようになる.
これはという二つの学習パラメータを持つ.そこで,過学習を抑制するためのさらなるパラメータ数の制限として以下のような表現を用いる.
ここでは一つのパラメータのみを持つ.こんなんありかという感じだがまあ実験的にはいいんでしょう.グラフ上でのフィルタリング処理は元々はグラフ信号処理で研究されていたものなので,deep neural netに適用した際に勾配消失や爆発に関する問題を避けるような工夫はない.そこでさらなるテクニック(論文中でrenormalization trickと呼ばれていた)として,という変換を行う.ただし,.これにより勾配の消失,爆発を抑制できるらしい(よくわからない).
ここまでの定義を,入力信号 (は入力のチャネル数)に対して一般化すると次のようにかける.
は学習パラメータで,は出力.計算オーダーとしてはとなり,は疎な行列と密な行列の積として実装可能.
Semi-supervised node classification
今まで頑張って定義したGCNを使ってsemi-supervised learningをしようというもの.基本的には最終層にsoftmax関数をかけて得た出力と,正解ラベルを使って次のcross-entropyを最小化するよう学習する.
はラベルを持つ各ノードの集合.要はラベルがあるノードだけを使って分類問題を学習するという単純なもの.ただし,この論文ではSGDではなくbatch gradient descentで学習したとのこと.ただし,確率要素を加えるためdropoutを使ったらしい.dropout使うならデータをサンプリングしてSGDでやってもいい気はするけどどうなんでしょうという気持ち.
まとめ
Renormalizationのあたりがよくわからなかったが実験的にはrenormした方が精度が上がっていた.renormしないほうがresnetの残差学習の形になっていていい気がするんだけどよくわからん.でもこの論文の実験結果からもパラメータ2つより1つにした方が精度上がってたから,前の論文でチェビシェフ使った近似の方が精度良くなってたのはやっぱりパラメータ数が減ったからなのか.
後,ひとつ面白かったのはAppendixのBの実験で,2,3層くらいの浅いモデルが一番汎化して精度がよかったこと.データセットの問題かグラフデータの性質かモデルが悪いのかわからないけどGCNでdeepなモデルを学習するのはひとつの課題っぽい.
Convolutional Neural Networks on Graphs with Fast Localized Spectral Filteringを読んだのでメモ
はじめに
Convolutional Neural Networks on Graphs with Fast Localized Spectral Filteringを読んだのでメモ.
Convolution on Graph
この論文ではグラフフーリエ変換に基づく畳み込みを考える.
Graph Fourier transform
無向グラフで定義された信号を考える.は個の頂点集合,はエッジの集合,は重み付きの隣接行列を表す.を対角行列とすれば,非正規化ラプラシアンは,正規化ラプラシアンはとして表現される.グラフラプラシアンは実対称半正定値行列であるため直交固有ベクトルを持ち,非負の固有値を持つ.グラフラプラシアンの固有ベクトルはフーリエ基底として知られ,固有値分解からグラフラプラシアンはフーリエ基底をもちいてとして表現できる.グラフ上に定義された信号のフーリエ変換は,逆フーリエ変換はとして記述される.
Spectral filtering of graph signals
以前読んだ論文と変わりないのでさっくりと式だけ.Fourier domainで定義された信号に対するパラメータを持つフィルタによる畳み込みは次のように表現できる.
ただしフィルタは.
Polynomial parametrization for localized filters
グラフ上でのフィルタの学習はvertex domainでの局所性を考慮できないこととパラメータがとデータの次元によるという問題がある.そこでこの論文ではこの問題を解決するため次のような多項式展開したフィルタを使う.
パラメータは多項式の係数.頂点を中心とするフィルタの頂点の値はで与えられ,カーネルはクロネッカーのデルタによって表現される.ここで,グラフ上の2つの頂点を最短距離で結ぶパスのエッジの数がである時であることが知られている.結果としてラプラシアンの次の多項式で表現されるspectral fileterは近傍までの頂点を含んだ計算になっていることがわかる(つまりを畳み込みのカーネルサイズとした時にからより遠い頂点は畳み込みの計算に含まれないということ).さらにパラメータ数もになっていて従来のCNNと同様のオーダーになっている.
Recursive formulation for fast filtering
ここがこの論文の主な貢献部分.基本的にフィルタリングの処理はの計算コストがかかる.解決方法としては前節のようなから再帰的に計算可能な多項式関数としてを定義することが考えられる.疎な行列に対して回行列積を計算する時その演算回数のオーダーはになる.グラフ信号処理においてはグラフ上での畳み込みにおけるフィルタの多項式表現は昔から研究されていて,一般的な方法としてチェビシェフ多項式を使ってフィルタの近似をする方法がある.そこでここではチェビシェフ多項式を使ってフィルタを近似する.
次のチェビシェフ多項式はとして計算することが可能.この多項式はを測度とするヒルベルト空間を作ることが知られている(ちなみにこのあたりの初等的な教科書として金谷 健一先生の「これならわかる応用数学教室」などが自分のような数学弱者にも優しい).次のチェビシェフ多項式を使えばフィルタは次のように定義できる.
はチェビシェフ係数ではによって計算される次のチェビシェフ多項式.と定義すれば,チェビシェフ多項式の再帰関係からとして計算することができ,フィルタリング計算の演算回数はになる.
Learning filters
サンプルの番目の出力の特徴マップは次のように計算できる.
は入力の特徴マップでチェビシェフ係数が学習係数となっている.よって最終的な計算コストはになる.フィルタリング処理の入力と学習パラメータに関するbackprop中の微分計算は次のようになる.
ただし,は目的関数ではミニバッチ内のサンプル数.
Graph Coarsening
ここではグラフ上でのプーリングについて考える.グラフ上のプーリングは基本的に近傍の似た頂点同士を一つのクラスタにまとめる処理を指す.ただし,グラフのクラスタリングはNP-hardであることが知られていて一般的には何らかの近似を用いなければならない.Grapn Convの文脈ではマルチレベルなクラスタリングが可能でダウンサンプリングのスケールがコントロールできる必要がある.この論文ではGraclus multilevel clustering algorithmを転用したとのこと.このアルゴリズムはgreedy algorithmの一種で,クラスタが割り振られていないノードを適当に取り出して局所的なnormalized cut を最大化するような近傍のノードを選んでクラスタリングする.
Fast Pooling of Graph Signals
グラフ上でプーリングの処理は単純に行うと対応関係を保持する必要があって計算コストが非常にかさむ.そこでこの論文ではちょっとした工夫をして1Dプーリングと同程度の計算効率でgraph poolingを行う.具体的にはbalanced binary treeの構築と頂点の振り直しの二つの処理によって効率化する.
グラフ上でのプーリング処理が行われた場合,プーリング後のグラフの各ノードはプーリング前の2つ,もしくは1つのノードと結びつくことになる.そこで,全てのノードが二つの子ノードを持つように擬似ノード(fake node)を作る(これがbalanced binary tree).すると,全てのノードは(1)二つの真のノードを持つ(2)1つの真のノードと1つの擬似ノードを持つ(3)2つの擬似ノードを持つ3種類のノードに分けられる.ただし,全ての擬似ノードは(3)にあたる.擬似ノードはプーリング後に影響を及ぼさないような値,例えばReLUを活性化関数に使ってmaxpoolingをする場合は0などの値で初期化される.当然擬似ノードを導入するとその分次元が増えて計算コストは増えるが,実験的にGraclus algorithmを使った時には孤立ノードは少量しか出ないため特に問題はないとのこと.
で,このbalanced binary treeを作ることの何がいいかというと,こうして作られたグラフは二つのノードを一つにまとめることでプーリングされる,すなわち孤立ノードがないため綺麗に番号を並び替えることで1Dプーリングと同様の演算でプーリングを行うことが可能なため高速に演算することができる.Figure 2にこのプーリング処理の図解があるのでそこを見ればわかりやすい.ちなみに,今までの説明はスケールを2分の1にする際の処理だが,ダウンサンプリングのスケールを大きくしたい場合にはスケールに対応した数の子ノードを持つように擬似ノードを導入すればいい.
まとめ
実験で面白かったのは普通にフィルタの重みを用意するより多項式近似の形にした方が精度がよかったというところ(MNISTでの実験だからなんとも言えないが).普通のspectral filteringの方法で学習するとパラメータ多すぎて過学習気味になるってことなのかなんなのか.