经典论文复现 | InfoGAN:一种无监督生成方法
過去幾年發(fā)表于各大 AI 頂會(huì)論文提出的 400 多種算法中,公開算法代碼的僅占 6%,其中三分之一的論文作者分享了測試數(shù)據(jù),約 54% 的分享包含“偽代碼”。這是今年 AAAI 會(huì)議上一個(gè)嚴(yán)峻的報(bào)告。?人工智能這個(gè)蓬勃發(fā)展的領(lǐng)域正面臨著實(shí)驗(yàn)重現(xiàn)的危機(jī),就像實(shí)驗(yàn)重現(xiàn)問題過去十年來一直困擾著心理學(xué)、醫(yī)學(xué)以及其他領(lǐng)域一樣。最根本的問題是研究人員通常不共享他們的源代碼。?
可驗(yàn)證的知識是科學(xué)的基礎(chǔ),它事關(guān)理解。隨著人工智能領(lǐng)域的發(fā)展,打破不可復(fù)現(xiàn)性將是必要的。為此,PaperWeekly 聯(lián)手百度 PaddlePaddle 共同發(fā)起了本次論文有獎(jiǎng)復(fù)現(xiàn),我們希望和來自學(xué)界、工業(yè)界的研究者一起接力,為 AI 行業(yè)帶來良性循環(huán)。
作者丨黃濤?
學(xué)校丨中山大學(xué)數(shù)學(xué)學(xué)院18級本科生
研究方向丨圖像識別、VQA、生成模型和自編碼器
論文復(fù)現(xiàn)代碼:?
http://aistudio.baidu.com/#/projectdetail/23600
GAN
生成對抗網(wǎng)絡(luò)(Generative Adversarial Nets)是一類新興的生成模型,由兩部分組成:一部分是判別模型(discriminator)D(·),用來判別輸入數(shù)據(jù)是真實(shí)數(shù)據(jù)還是生成出來的數(shù)據(jù);另一部分是是生成模型(generator)G(·),由輸入的噪聲生成目標(biāo)數(shù)據(jù)。GAN 的優(yōu)化問題可以表示為:
其中 Pdata 是生成樣本,noise 是隨機(jī)噪聲。而對于帶標(biāo)簽的數(shù)據(jù),通常用潛碼(latent code)c 來表示這一標(biāo)簽,作為生成模型的一個(gè)輸入,這樣我們有:
然而當(dāng)我們遇到存在潛在的類別差別而沒有標(biāo)簽數(shù)據(jù),要使 GAN 能夠在這類數(shù)據(jù)上擁有更好表現(xiàn),我們就需要一類能夠無監(jiān)督地辨別出這類潛在標(biāo)簽的數(shù)據(jù),InfoGAN 就給出了一個(gè)較好的解決方案。
互信息(Mutual Information)
互信息是兩個(gè)隨機(jī)變量依賴程度的量度,可以表示為:
要去直接優(yōu)化 I(c;G(z,c)) 是極其困難的,因?yàn)檫@意味著我們要能夠計(jì)算后驗(yàn)概率(posterior probability)P(c|x),但是我們可以用一個(gè)輔助分布(auxiliary distribution)Q(c|x),來近似這一后驗(yàn)概率。這樣我們能夠給出互信息的一個(gè)下界(lower bounding):
InfoGAN
在 InfoGAN 中,為了能夠增加潛碼和生成數(shù)據(jù)間的依賴程度,我們可以增大潛碼和生成數(shù)據(jù)間的互信息,使生成數(shù)據(jù)變得與潛碼更相關(guān):
▲?圖1.?InfoGAN的整體結(jié)構(gòu)圖
由上面的,對于一個(gè)極大化互信息的問題轉(zhuǎn)化為一個(gè)極大化互信息下界的問題,我們接下來就可以定義:
在論文的附錄中,作者證明了:
于是:
故 LI (G, Q) 是互信息的一個(gè)下界。作者指出,用蒙特卡羅模擬(Monte Carlo simulation)去逼近 LI (G, Q) 是較為方便的,這樣我們的優(yōu)化問題就可以表示為:
實(shí)現(xiàn)
在實(shí)現(xiàn)中,D(x)、G(z, c) 和 Q(x) 分別用一個(gè) CNN (Convolutional Neural Networks)、CNN、DCNN (DeConv Neural Networks) 來實(shí)現(xiàn)。同時(shí),潛碼 c 也包含兩部分:一部分是類別,服從 Cat(K = N,p = 1/N),其中 N 為類別數(shù)量;另一部分是連續(xù)的與生成數(shù)據(jù)有關(guān)的參數(shù),服從 Unif(?1,1) 的分布。?
在此應(yīng)指出,Q(c|x) 可以表示為一個(gè)神經(jīng)網(wǎng)絡(luò) Q(x) 的輸出。對于輸入隨機(jī)變量 z 和類別潛碼 c,實(shí)際的 LI(G, Q) 可以表示為:
其中 · 表示內(nèi)積(inner product),c 是一個(gè)選擇計(jì)算哪個(gè) log 的參數(shù),例如 ci = 1 而 cj = 0(?j = 1,2,···,i ? 1,i + 1,···,n),那么 z 這時(shí)候計(jì)算出的 LI(G,Q) 就等于 log(Q(z,c)i)。這里我們可以消去 H(c),因?yàn)?c 的分布是固定的,即優(yōu)化目標(biāo)與 H(c) 無關(guān):
而對于參數(shù)潛碼,我們假設(shè)它符合正態(tài)分布,神經(jīng)網(wǎng)絡(luò) Q(x) 則輸出其預(yù)測出的該潛碼的均值和標(biāo)準(zhǔn)差, 我們知道,對于均值 μ,標(biāo)準(zhǔn)差 σ 的隨機(jī)變量,其概率密度函數(shù)為:
要計(jì)算參數(shù)潛碼 c 的,就是要計(jì)算 log p(c),即:
設(shè) Q(x) 輸出的參數(shù)潛碼 c 的均值 μ,標(biāo)準(zhǔn)差 σ 分別為 Q(x)μ 和 Q(x)σ,那么對于參數(shù)潛碼 c:
同樣的,我們可以消去 H(c),因?yàn)?c 的分布是固定的,那么:
實(shí)驗(yàn)
首先,通過和普通的 GAN 比較 LI ,作者證明了 InfoGAN 確實(shí)能夠優(yōu)化這一互信息的下界 2。?
作者在 MNIST 手寫數(shù)字?jǐn)?shù)據(jù)集(3)、3D 面部數(shù)據(jù)集(4)、3D 椅子數(shù)據(jù)集(5)、SVHN 街景房號數(shù)據(jù)集(6)以及 CelebA 人臉數(shù)據(jù)集(7)上進(jìn)行了模型的相關(guān)測試。?
▲?圖2. MNIST手寫字符數(shù)據(jù)集上的結(jié)果
▲?圖3. 3D面部數(shù)據(jù)集上的結(jié)果
▲?圖4. 3D椅子數(shù)據(jù)集上的結(jié)果
▲?圖5. SVHN街景房號數(shù)據(jù)集上的結(jié)果
▲?圖6. CelebA人臉數(shù)據(jù)集上的結(jié)果
作者展示了這些數(shù)據(jù)集上學(xué)習(xí)到的類別潛碼(從上至下變化)和參數(shù)潛碼(從左至右變化,由 -2 到 2),我們可以看出,InfoGAN 不僅能夠很好地學(xué)習(xí)數(shù)據(jù)之間的類型差別,也能夠很好地學(xué)習(xí)到數(shù)據(jù)本身的一些易于區(qū)分的特點(diǎn),而且生成模型對這些特點(diǎn)的泛化能力還是很好的。
再論InfoGAN的LI
讀完論文,我們發(fā)現(xiàn),對于類別潛碼,這個(gè) LI 本質(zhì)上是 x 與 G(z, c) 之間的 KL 散度:
也就是說:
而 min DKL(c||Q(G(z, c))) 意味著減小 c 與 Q(G(z, c)) 的差別。
▲?圖7. 普通GAN和InfoGAN的LI在訓(xùn)練過程中的比較
如果我們不考慮 Q(x)σ 的影響,LI 的優(yōu)化過程:
而也意味著減小 c 與 Q(G(z, c))μ 的差。
再縱觀整個(gè)模型,我們會(huì)發(fā)現(xiàn)這一對 LI 優(yōu)化的過程,實(shí)質(zhì)上是以 G 為編碼器(Encoder), Q 為解碼器(Decoder),生成的圖像作為我們要編碼的碼(code),訓(xùn)練一個(gè)自編碼器(Autoencoder),也就是說,作者口中的信息論優(yōu)化問題,本質(zhì)上是無監(jiān)督訓(xùn)練問題。
關(guān)于PaddlePaddle
在 PaddlePaddle 中,一個(gè)極為重要的概念即是 fluid.Program(),在官方文檔里常見的 exe.run(program= fluid.default_startup_program())的 fluid.default_startup_program() 就是其中一個(gè)例子。
在這一使用中可以了解到,我們要用 exe.run() 中的 program 參數(shù)運(yùn)行指定的 fluid.Program(),而官方文檔指出,當(dāng)該參數(shù)未指定時(shí),會(huì)運(yùn)行 fluid.default_main_program(),而 fluid.default_main_program() 代表的是未指定 fluid.Program() 的所有操作。
注意,這里說的是“所有”,由于 PaddlePaddle 沒有計(jì)算依賴檢測機(jī)制,即使在計(jì)算 fetch_list 中的值的時(shí)候不會(huì)用到操作也會(huì)被計(jì)算,這一點(diǎn)與 TensorFlow 極其不同,作者本人在使用過程中踩了很大的坑,還望各位注意。在執(zhí)行多種任務(wù)的時(shí)候不要一股腦全部寫在 fluid.default_main_program() 之中, 這樣極其浪費(fèi)資源,也容易造成一些問題。
一個(gè)新的 fluid.Program() 被創(chuàng)建之后,可以在 fluid.program_guard() 中指定該 fluid.Program() 中的操作與變量:
#創(chuàng)建Infer_program
Infer_program?=?fluid.Program()
#在這里面定義Infer_program中的操作與變量
with?fluid.program_guard(main_program?=?Infer_program):
????#從外部通過feed傳入的變量,一般是輸入、標(biāo)簽等
????X?=?fluid.layers.data(name='X',?shape=[X_dim],?dtype='float32')
????#全鏈接層
????output?=?fluid.layers.fc(input?=?X,?size?=?128)?
PaddlePaddle?中還需要注意的一點(diǎn)是,fluid.Variable 的命名空間是全局的,也就是說在同一或者不同 fluid. Program() 間,同名(fluid.Variable 的 name 屬性相同)的 fluid.Variable 所指向的變量是相同的,所以同一名稱在同一或者不同 fluid.Program () 中可以被使用多次,而不用擔(dān)心 TensorFlow 中會(huì)出現(xiàn)的 reuse 問題。?
要對一個(gè)操作的中的權(quán)值的名稱進(jìn)行定義(權(quán)值命名為 W1,偏置命名為 b1):
output?=?fluid.layers.fc(input?=?X,?
?????????????????????????size?=?10,?
?????????????????????????param_attr?=?fluid.ParamAttr(name="W1"),?
?????????????????????????bias_attr?=?fluid.ParamAttr(name="b1"))
要在之后使用這些 fluid.Variable,例如在 Optimizer 中使用:
#可以直接用名稱指代對應(yīng)的fluid.Variable
parameter_list?=?["W1",?"b1"]
#構(gòu)建optimizer
optimizer?=?fluid.optimizer.AdamOptimizer()
#指定optimizer優(yōu)化的目標(biāo)和對象
optimizer.minimize(loss,?parameter_list=parameter_list)
在構(gòu)建完基本的運(yùn)算操作后,便可以開始初始化操作了:
#初始化fluid.Executor(指定執(zhí)行程序位置)
exe?=?fluid.Executor(fluid.CPUPlace())
#執(zhí)行fluid.default_startup_program(),在fluid.program_guard()中
#若沒有指定初始化program,則默認(rèn)為此program
exe.run(program=fluid.default_startup_program())
初始化完成后,可以開始訓(xùn)練啦:
#在從外部傳入數(shù)據(jù)的時(shí)候要注意,傳入數(shù)據(jù)的數(shù)據(jù)類型必須與fluid.layers.data
#中定義的類型一致,否則會(huì)報(bào)錯(cuò)
#如果傳入數(shù)據(jù)是list類型,建議轉(zhuǎn)換為np.array,否則可能回報(bào)錯(cuò):
#fedding的數(shù)據(jù)中包含lod信息,請您轉(zhuǎn)換成lodtensor
#(渣翻譯,?原因是list被默認(rèn)為含有變長數(shù)據(jù))
feeding?=?{"X"?:?np.array(Z_noise).astype('float32')}
#傳入feeding中的數(shù)據(jù),執(zhí)行program程序,從計(jì)算結(jié)果中獲取loss
#(默認(rèn)會(huì)被轉(zhuǎn)換成np.array,可在函數(shù)參數(shù)中設(shè)置)
loss_curr?=?exe.run(feed?=?feeding,?program?=?program,?fetch_list?=?[loss])
GAN實(shí)現(xiàn)
生成對抗網(wǎng)絡(luò)(Generative Adversarial Nets)是一類新興的生成模型,由兩部分組成:一部分是判別模型(discriminator)D(·),用來判別輸入數(shù)據(jù)是真實(shí)數(shù)據(jù)還是生成出來的數(shù)據(jù);另一部分是是生成模型(generator)G(·),由輸入的噪聲生成目標(biāo)數(shù)據(jù)。GAN 的優(yōu)化問題可以表示為:
其中 Pdata 是生成樣本,noise 是隨機(jī)噪聲。我們用一個(gè)雙層的 MLP 來演示:
#判別模型
def?discriminator(x):
????#使用fluid.unique_name.guard()添加模型內(nèi)參數(shù)名稱的前綴
????with?fluid.unique_name.guard('D_'):
????????D_h1?=?fluid.layers.fc(input?=?x,?size?=?256,?act?=?"relu")
????????D_logit?=?fluid.layers.fc(input?=?D_h1,?size?=?1,?act?=?"sigmoid")
????return?D_logit
#生成模型
def?generator(inputs):
????with?fluid.unique_name.guard('G_'):
????????D_h1?=?fluid.layers.fc(input?=?inputs,?size?=?256,?act?=?"relu")
????????D_logit?=?fluid.layers.fc(input?=?D_h1,?size?=?784,?act?=?"sigmoid")
????return?D_logit
通常,一個(gè) GAN 的訓(xùn)練由兩部分組成,第一部分是對 D(·) 進(jìn)行訓(xùn)練,極大化目標(biāo)函數(shù):
第二部分是對 G(·) 進(jìn)行訓(xùn)練,極小化目標(biāo)函數(shù):
以下是兩部分優(yōu)化的定義:
#參考Todd的LSGAN的實(shí)現(xiàn),使用函數(shù)獲取模型所有變量
def?get_params(program,?prefix):
????all_params?=?program.global_block().all_parameters()
????return?[t.name?for?t?in?all_params?if?t.name.startswith(prefix)]
#G優(yōu)化程序
G_program?=?fluid.Program()
with?fluid.program_guard(main_program?=?G_program):
????#定義輸入數(shù)據(jù)
????Z?=?fluid.layers.data(name='Z',?shape=[Z_dim],?dtype='float32')
????#執(zhí)行相關(guān)模型的計(jì)算
????G_sample?=?generator(Z)
????D_fake?=?discriminator(G_sample)?
????#計(jì)算損失函數(shù)
????G_loss?=?0.0?-?fluid.layers.reduce_mean(fluid.layers.log(D_fake?+?1e-8))
????#定義optimizer優(yōu)化的變量的范圍
????theta_G?=?get_params(G_program,?"G")
????G_optimizer?=?fluid.optimizer.AdamOptimizer()
????G_optimizer.minimize(G_loss,?parameter_list=theta_G)
#D優(yōu)化程序
D_program?=?fluid.Program()
with?fluid.program_guard(main_program?=?D_program):
????Z?=?fluid.layers.data(name='Z',?shape=[Z_dim],?dtype='float32')
????X?=?fluid.layers.data(name='X',?shape=[784],?dtype='float32')
????#在使用數(shù)據(jù)集時(shí),要注意相應(yīng)接口傳入數(shù)據(jù)的值的范圍
????#paddle.dataset.mnist中的數(shù)據(jù),范圍在[-1,?1]
????#要將其轉(zhuǎn)換到sigmoid函數(shù)的值域內(nèi)
????X?=?X?*?0.5?+?0.5
????G_sample?=?generator(Z)
????D_real?=?discriminator(X)
????D_fake?=?discriminator(G_sample)??
????D_loss?=?0.0?-?fluid.layers.reduce_mean(fluid.layers.log(D_real?+?1e-8)?
????+?fluid.layers.log(1.0?-?D_fake?+?1e-8))
????theta_D?=?get_params(G_program,?"D")
????D_optimizer?=?fluid.optimizer.AdamOptimizer()
????D_optimizer.minimize(D_loss,?parameter_list=theta_D)
在定義好這些之后,是時(shí)候開訓(xùn)練了:
#定義傳入的數(shù)據(jù)
feeding_withx=?{"X"?:?np.array(X_mb).astype('float32'),?
????"Z"?:?np.array(Z_noise).astype('float32')}
feeding?=?{"Z"?:?np.array(Z_noise).astype('float32')}
#執(zhí)行訓(xùn)練操作并獲取當(dāng)前損失函數(shù)的值
D_loss_curr?=?exe.run(feed?=?feeding_withx,?program?=?D_program,?
??????????????????????fetch_list?=?[D_loss])
G_loss_curr?=?exe.run(feed?=?feeding,?program?=?G_program,?
??????????????????????fetch_list?=?[G_loss])
若欲測試模型效果,可再定義一個(gè) Inference:
#Inference
Infer_program?=?fluid.Program()
with?fluid.program_guard(main_program?=?Infer_program):???
????Z?=?fluid.layers.data(name='Z',?shape=[Z_dim],?dtype='float32')
????G_sample?=?generator(Z)
然后再這樣獲取 samples:
feeding?=?{"Z"?:?np.array(Z_noise).astype('float32')}
samples?=?exe.run(feed?=?feeding,?program?=?Infer_program,?
??????????????????fetch_list?=?[G_sample])
后記
本文先前于今年 8 月完成,共享于 PaddlePaddle 論文復(fù)現(xiàn)群內(nèi),在 10 月 LSGAN 的復(fù)現(xiàn)公開之 后,參考該復(fù)現(xiàn)更改了模型參數(shù)命名和參數(shù)列表的實(shí)現(xiàn)方法,在此感謝 Todd 同學(xué)的復(fù)現(xiàn)對本文的幫助。
點(diǎn)擊標(biāo)題查看更多論文解讀:?
在全景視頻中預(yù)測頭部運(yùn)動(dòng):一種深度強(qiáng)化學(xué)習(xí)方法
網(wǎng)絡(luò)表示學(xué)習(xí)綜述:一文理解Network Embedding
神經(jīng)網(wǎng)絡(luò)架構(gòu)搜索(NAS)綜述
從傅里葉分析角度解讀深度學(xué)習(xí)的泛化能力
深度解讀DeepMind新作:史上最強(qiáng)GAN圖像生成器
ACL2018高分論文:混合高斯隱向量文法
自然語言處理中的語言模型預(yù)訓(xùn)練方法
EMNLP 2018論文解讀 | 對話生成 & 文本風(fēng)格轉(zhuǎn)化
#投 稿 通 道#
?讓你的論文被更多人看到?
如何才能讓更多的優(yōu)質(zhì)內(nèi)容以更短路徑到達(dá)讀者群體,縮短讀者尋找優(yōu)質(zhì)內(nèi)容的成本呢??答案就是:你不認(rèn)識的人。
總有一些你不認(rèn)識的人,知道你想知道的東西。PaperWeekly 或許可以成為一座橋梁,促使不同背景、不同方向的學(xué)者和學(xué)術(shù)靈感相互碰撞,迸發(fā)出更多的可能性。?
PaperWeekly 鼓勵(lì)高校實(shí)驗(yàn)室或個(gè)人,在我們的平臺上分享各類優(yōu)質(zhì)內(nèi)容,可以是最新論文解讀,也可以是學(xué)習(xí)心得或技術(shù)干貨。我們的目的只有一個(gè),讓知識真正流動(dòng)起來。
??來稿標(biāo)準(zhǔn):
? 稿件確系個(gè)人原創(chuàng)作品,來稿需注明作者個(gè)人信息(姓名+學(xué)校/工作單位+學(xué)歷/職位+研究方向)?
? 如果文章并非首發(fā),請?jiān)谕陡鍟r(shí)提醒并附上所有已發(fā)布鏈接?
? PaperWeekly 默認(rèn)每篇文章都是首發(fā),均會(huì)添加“原創(chuàng)”標(biāo)志
? 投稿郵箱:
? 投稿郵箱:hr@paperweekly.site?
? 所有文章配圖,請單獨(dú)在附件中發(fā)送?
? 請留下即時(shí)聯(lián)系方式(微信或手機(jī)),以便我們在編輯發(fā)布時(shí)和作者溝通
?
現(xiàn)在,在「知乎」也能找到我們了
進(jìn)入知乎首頁搜索「PaperWeekly」
點(diǎn)擊「關(guān)注」訂閱我們的專欄吧
關(guān)于PaperWeekly
PaperWeekly 是一個(gè)推薦、解讀、討論、報(bào)道人工智能前沿論文成果的學(xué)術(shù)平臺。如果你研究或從事 AI 領(lǐng)域,歡迎在公眾號后臺點(diǎn)擊「交流群」,小助手將把你帶入 PaperWeekly 的交流群里。
▽ 點(diǎn)擊 |?閱讀原文?| 收藏復(fù)現(xiàn)代碼
總結(jié)
以上是生活随笔為你收集整理的经典论文复现 | InfoGAN:一种无监督生成方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 线下讲座 | 机器翻译大牛Kevin K
- 下一篇: 直播预告 | 全国高校人工智能人才与科技