cda

全國校區

您的位置:首頁 > 精彩閱讀 > 如何在Keras中開發最大化生成對抗網絡(InfoGAN)的信息?

如何在Keras中開發最大化生成對抗網絡(InfoGAN)的信息?

2019-11-13

如何在<wordsbank_match class='wbmatch' location='/map/Keras/' style='cursor:pointer;'>Keras</wordsbank_match>中開發最大化生成對抗網絡(InfoGAN)的信息?

作者 | CDA數據分析師

生成對抗網絡(GAN)是一種用于訓練深度卷積模型以生成合成圖像的體系結構。

盡管非常有效,但默認GAN無法控制生成的圖像類型。信息最大化GAN(簡稱InfoGAN)是GAN架構的擴展,它引入了架構自動學習的控制變量,并允許控制生成的圖像,例如在生成圖像樣式的情況下,厚度和類型手寫的數字。

在本教程中,您將了解如何從頭開始實現信息最大化生成對抗網絡模型。

完成本教程后,您將了解:

  • InfoGAN的動機是希望解開和控制生成的圖像中的屬性。
  • InfoGAN涉及添加控制變量以生成預測控制變量的輔助模型,通過互信息損失函數進行訓練。
  • 如何從頭開發和訓練InfoGAN模型,并使用控制變量來控制模型生成的數字。

讓我們開始吧。


教程概述

本教程分為四個部分; 他們是:

  1. 什么是最大化GAN的信息
  2. 如何實現InfoGAN丟失功能
  3. 如何為MNIST開發InfoGAN
  4. 如何使用訓練有素的InfoGAN模型使用控制代碼

什么是最大化GAN的信息

Generative Adversarial Network(簡稱GAN)是一種用于訓練生成模型的體系結構,例如用于生成合成圖像的模型。

它涉及同時訓練生成器模型以生成具有鑒別器模型的圖像,該模型學習將圖像分類為真實的(來自訓練數據集)或假的(生成的)。這兩個模型在零和游戲中競爭,使得訓練過程的收斂涉及在生成器生成令人信服的圖像的技能與能夠檢測它們的鑒別器之間找到平衡。

生成器模型將來自潛在空間的隨機點作為輸入,通常為50到100個隨機高斯變量。生成器通過訓練對潛在空間中的點應用獨特的含義,并將點映射到特定的輸出合成圖像。這意味著雖然潛在空間由生成器模型構成,但是無法控制生成的圖像。

GAN公式使用簡單的因子連續輸入噪聲向量z,而對發生器可以使用該噪聲的方式沒有限制。結果,發生器可能以高度糾纏的方式使用噪聲,導致z的各個維度不對應于數據的語義特征

可以探索潛在空間并比較生成的圖像,以試圖理解生成器模型已經學習的映射。或者,可以例如通過類標簽來調節生成過程,以便可以按需創建特定類型的圖像。這是條件生成對抗網絡的基礎,簡稱CGAN或cGAN。

另一種方法是提供控制變量作為發電機的輸入,以及潛在空間中的點(噪聲)。可以訓練發生器以使用控制變量來影響所生成圖像的特定屬性。這是信息最大化生成對抗網絡(簡稱InfoGAN)所采用的方法。

InfoGAN,生成對抗網絡的信息理論擴展,能夠以完全無監督的方式學習解纏結的表示。

在訓練過程中由發生器學習的結構化映射有些隨機。雖然生成器模型學習在潛在空間中空間分離生成圖像的屬性,但是沒有控制。這些屬性糾纏在一起。InfoGAN的動機是希望解開生成圖像的屬性。

例如,在面部的情況下,可以解開和控制生成面部的特性,例如面部的形狀,頭發顏色,發型等。

例如,對于面部的數據集,有用的解開的表示可以為以下屬性中的每一個分配一組單獨的維度:面部表情,眼睛顏色,發型,眼鏡的存在或不存在,以及相應人的身份。

控制變量與噪聲一起提供作為發電機的輸入,并且通過互信息丟失功能訓練模型。

......我們對生成對抗性網絡目標進行了簡單的修改,鼓勵它學習可解釋和有意義的表達。我們通過最大化GAN噪聲變量的固定小子集與觀測值之間的互信息來實現這一點,結果證明是相對簡單的。

相互信息是指在給定另一個變量的情況下獲得的關于一個變量的信息量。在這種情況下,我們感興趣的是有關使用噪聲和控制變量生成的圖像的控制變量的信息。

在信息論中,X和Y之間的互信息I(X; Y)測量從隨機變量Y的知識中學習的關于另一個隨機變量X 的“ 信息量 ”。

相互信息(MI)被計算為圖像的條件熵(由發生器(G)從噪聲(z)和控制變量(c)創建),給定控制變量(c)從邊際熵減去控制變量(c); 例如:

  • MI =熵(c) - 熵(c | G(z,c))

在實踐中,計算真實的互信息通常是難以處理的,盡管本文采用了簡化,稱為變分信息最大化,并且控制代碼的熵保持不變。

通過使用稱為Q或輔助模型的新模型來實現通過互信息訓練發電機。新模型與用于解釋輸入圖像的鑒別器模型共享所有相同的權重,但與預測圖像是真實還是假的鑒別器模型不同,輔助模型預測用于生成圖像的控制代碼。

兩種模型都用于更新生成器模型,首先是為了提高生成愚弄鑒別器模型的圖像的可能性,其次是改善用于生成圖像的控制代碼和輔助模型對控制代碼的預測之間的互信息。

結果是生成器模型通過互信息丟失而正規化,使得控制代碼捕獲所生成圖像的顯著特性,并且反過來可以用于控制圖像生成過程。

每當我們有興趣學習從給定輸入X到保留關于原始輸入的信息的更高級別表示Y的參數化映射時,可以利用互信息。[...]表明,最大化互信息的任務基本上等同于訓練自動編碼器以最小化重建誤差。

如何在<wordsbank_match class='wbmatch' location='/map/Keras/' style='cursor:pointer;'>Keras</wordsbank_match>中開發最大化生成對抗網絡(InfoGAN)的信息?

如何實現InfoGAN丟失功能

一旦熟悉模型的輸入和輸出,InfoGAN就可以相當直接地實現。

唯一的絆腳石可能是互信息丟失功能,特別是如果你沒有像大多數開發人員那樣強大的數學背景。

InfoGan使用兩種主要類型的控制變量:分類和連續,連續變量可能具有不同的數據分布,這會影響相互損失的計算方式。可以基于變量類型計算所有控制變量的相互損失并將其相加,這是OpenAI為TensorFlow發布的InfoGAN實現中使用的方法。

Keras中,將控制變量簡化為分類和高斯或均勻連續變量可能更容易,并且對于每個控制變量類型在輔助模型上具有單獨的輸出。這樣可以使用不同的損失函數,大大簡化了實現。

有關本節中建議的更多背景信息,請參閱更多閱讀部分中的文章和帖子。

分類控制變量

分類變量可用于控制所生成圖像的類型或類別。

這被實現為一個熱編碼矢量。也就是說,如果類具有10個值,則控制代碼將是一個類,例如6,并且輸入到生成器模型的分類控制向量將是所有零值的10個元素向量,其中對于類6具有一個值,例如,[0,0,0,0,0,0,1,0,0]。

訓練模型時,我們不需要選擇分類控制變量; 相反,它們是隨機生成的,例如,每個樣本以均勻的概率選擇每個樣本。

...關于潛碼c~Cat(K = 10,p = 0.1)的統一分類分布

在輔助模型中,分類變量的輸出層也將是一個熱編碼矢量以匹配輸入控制代碼,并且使用softmax激活函數。

對于分類潛在代碼ci,我們使用softmax非線性的自然選擇來表示Q(ci | x)。

回想一下,互信息被計算為來自控制變量的條件熵和從提供給輸入變量的控制變量的熵中減去的輔助模型的輸出。我們可以直接實現這一點,但這不是必需的。

控制變量的熵是一個常數,并且是一個接近于零的非常小的數; 因此,我們可以從計算中刪除它。條件熵可以直接計算為控制變量輸入和輔助模型的輸出之間的交叉熵。因此,可以使用分類交叉熵損失函數,就像我們對任何多類分類問題一樣。

超參數lambda用于縮放互信息丟失函數并設置為1,因此可以忽略。

即使InfoGAN引入了額外的超參數λ,它也很容易調整,簡單地設置為1就足以支持離散的潛碼。

如何在<wordsbank_match class='wbmatch' location='/map/Keras/' style='cursor:pointer;'>Keras</wordsbank_match>中開發最大化生成對抗網絡(InfoGAN)的信息?

連續控制變量

連續控制變量可用于控制圖像的樣式。

連續變量從均勻分布中采樣,例如在-1和1之間,并作為輸入提供給發電機模型。

...可以捕捉連續性變化的連續代碼:c2,c3~Unif(-1,1)

輔助模型可以用高斯分布實現連續控制變量的預測,其中輸出層被配置為具有一個節點,平均值和一個用于高斯標準偏差的節點,例如每個連續控制需要兩個輸出變量。

對于連續潛在代碼cj,根據什么是真正的后驗P(cj | x),有更多選項。在我們的實驗中,我們發現簡單地將Q(cj | x)視為因式高斯是足夠的。

輸出均值的節點可以使用線性激活函數,而輸出標準偏差的節點必須產生正值,因此可以使用諸如sigmoid的激活函數來創建0到1之間的值。

對于連續潛碼,我們通過對角高斯分布對近似后驗進行參數化,識別網絡輸出其均值和標準差,其中標準偏差通過網絡輸出的指數變換進行參數化以確保積極性。

必須將損失函數計算為高斯控制碼的互信息,這意味著它們必須在計算損失之前從平均值和標準差重建。計算高斯分布變量的熵和條件熵可以直接實現,但不是必需的。相反,可以使用均方誤差損失。

或者,可以將輸出分布簡化為每個控制變量的均勻分布,可以使用具有線性激活的輔助模型中的每個變量的單個輸出節點,并且模型可以使用均方誤差損失函數

如何為MNIST開發InfoGAN

在本節中,我們將仔細研究生成器(g),鑒別器(d)和輔助模型(q)以及如何在Keras中實現它們。

我們將為MNIST數據集開發InfoGAN實現,如InfoGAN論文中所做的那樣。

本文探討了兩個版本; 第一個僅使用分類控制代碼,并允許模型將一個分類變量映射到大約一個數字(盡管沒有按分類變量排序數字)。

如何在<wordsbank_match class='wbmatch' location='/map/Keras/' style='cursor:pointer;'>Keras</wordsbank_match>中開發最大化生成對抗網絡(InfoGAN)的信息?

本文還探討了InfoGAN架構的一個版本,其中包含一個熱編碼分類變量(c1)和兩個連續控制變量(c2和c3)。

發現第一個連續變量用于控制數字的旋轉,第二個連續變量用于控制數字的粗細。

如何在<wordsbank_match class='wbmatch' location='/map/Keras/' style='cursor:pointer;'>Keras</wordsbank_match>中開發最大化生成對抗網絡(InfoGAN)的信息?

我們將重點關注使用具有10個值的分類控制變量的簡單情況,并鼓勵模型學習讓該變量控制生成的數字。您可能希望通過更改分類控制變量的基數或添加連續控制變量來擴展此示例。

用于MNIST數據集訓練的GAN模型的配置作為本文的附錄提供,轉載如下。我們將使用列出的配置作為開發我們自己的生成器(g),鑒別器(d)和輔助(q)模型的起點。

如何在<wordsbank_match class='wbmatch' location='/map/Keras/' style='cursor:pointer;'>Keras</wordsbank_match>中開發最大化生成對抗網絡(InfoGAN)的信息?

讓我們從將生成器模型開發為深度卷積神經網絡(例如DCGAN)開始。

該模型可以將噪聲向量(z)和控制向量(c)作為單獨的輸入,并在將它們用作生成圖像的基礎之前將它們連接起來。或者,可以預先將矢量連接起來并提供給模型中的單個輸入層。方法是等價的,在這種情況下我們將使用后者來保持模型簡單。

下面的define_generator()函數定義生成器模型,并將輸入向量的大小作為參數。

完全連接的層采用輸入向量并產生足夠數量的激活,以創建512個7×7特征映射,從中重新激活激活。然后,它們以1×1步幅通過正常卷積層,然后兩個隨后的上采樣將卷積層轉換為2×2步幅優先至14×14特征映射,然后轉換為所需的1通道28×28特征映射輸出,其中像素值為通過tanh激活函數的范圍[-1,-1]。

良好的發生器配置啟發式如下,包括隨機高斯權重初始化,隱藏層中的ReLU激活以及批量歸一化的使用。

# define the standalone generator model

def define_generator(gen_input_size):

# weight initialization

init = RandomNormal(stddev=0.02)

# image generator input

in_lat = Input(shape=(gen_input_size,))

# foundation for 7x7 image

n_nodes = 512 * 7 * 7

gen = Dense(n_nodes, kernel_initializer=init)(in_lat)

gen = Activation('relu')(gen)

gen = BatchNormalization()(gen)

gen = Reshape((7, 7, 512))(gen)

# normal

gen = Conv2D(128, (4,4), padding='same', kernel_initializer=init)(gen)

gen = Activation('relu')(gen)

gen = BatchNormalization()(gen)

# upsample to 14x14

gen = Conv2DTranspose(64, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(gen)

gen = Activation('relu')(gen)

gen = BatchNormalization()(gen)

# upsample to 28x28

gen = Conv2DTranspose(1, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(gen)

# tanh output

out_layer = Activation('tanh')(gen)

# define model

model = Model(in_lat, out_layer)

return model

接下來,我們可以定義鑒別器和輔助模型。

根據普通GAN,鑒別器模型以獨立方式訓練在真實和偽造圖像上。發電機和輔助模型都不直接配合; 相反,它們適合作為復合模型的一部分。

鑒別器和輔助模型共享相同的輸入和特征提取層,但它們的輸出層不同。因此,同時定義它們是有意義的。

同樣,有許多方法可以實現這種架構,但是將鑒別器和輔助模型定義為單獨的模型首先允許我們稍后通過功能API直接將它們組合成更大的GAN模型。

下面的define_discriminator()函數定義了鑒別器和輔助模型,并將分類變量的基數(例如數值,例如10)作為輸入。輸入圖像的形狀也被參數化為函數參數,并設置為MNIST圖像大小的默認值。

特征提取層涉及兩個下采樣層,而不是池化層作為最佳實踐。此外,遵循DCGAN模型的最佳實踐,我們使用LeakyReLU激活和批量標準化。

鑒別器模型(d)具有單個輸出節點,并通過S形激活函數預測輸入圖像的實際概率。該模型被編譯,因為它將以獨立的方式使用,通過具有最佳實踐學習速率和動量的隨機梯度下降的Adam版本來優化二元交叉熵函數。

輔助模型(q)對分類變量中的每個值具有一個節點輸出,并使用softmax激活函數。如InfoGAN論文中所使用的那樣,在特征提取層和輸出層之間添加完全連接的層。該模型未編譯,因為它不是獨立使用或以獨立方式使用。

# define the standalone discriminator model

def define_discriminator(n_cat, in_shape=(28,28,1)):

# weight initialization

init = RandomNormal(stddev=0.02)

# image input

in_image = Input(shape=in_shape)

# downsample to 14x14

d = Conv2D(64, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(in_image)

d = LeakyReLU(alpha=0.1)(d)

# downsample to 7x7

d = Conv2D(128, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(d)

d = LeakyReLU(alpha=0.1)(d)

d = BatchNormalization()(d)

# normal

d = Conv2D(256, (4,4), padding='same', kernel_initializer=init)(d)

d = LeakyReLU(alpha=0.1)(d)

d = BatchNormalization()(d)

# flatten feature maps

d = Flatten()(d)

# real/fake output

out_classifier = Dense(1, activation='sigmoid')(d)

# define d model

d_model = Model(in_image, out_classifier)

# compile d model

d_model.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0002, beta_1=0.5))

# create q model layers

q = Dense(128)(d)

q = BatchNormalization()(q)

q = LeakyReLU(alpha=0.1)(q)

# q model output

out_codes = Dense(n_cat, activation='softmax')(q)

# define q model

q_model = Model(in_image, out_codes)

return d_model, q_model

接下來,我們可以定義復合GAN模型。

該模型使用所有子模型,并且是訓練發電機模型權重的基礎。

下面的define_gan()函數實現了這個并定義并返回模型,將三個子模型作為輸入。

如上所述,鑒別器以獨立方式訓練,因此鑒別器的所有權重被設置為不可訓練(僅在此上下文中)。生成器模型的輸出連接到鑒別器模型的輸入,并連接到輔助模型的輸入。

這將創建一個新的復合模型,該模型將[noise + control]向量作為輸入,然后通過生成器生成圖像。然后,圖像通過鑒別器模型以產生分類,并通過輔助模型產生控制變量的預測。

該模型有兩個輸出層,需要使用不同的損失函數進行訓練。二進制交叉熵損失用于鑒別器輸出,正如我們在編譯獨立使用的鑒別器時所做的那樣,并且互信息丟失用于輔助模型,在這種情況下,輔助模型可以直接實現為分類交叉熵并實現期望的結果。

# define the combined discriminator, generator and q network model

def define_gan(g_model, d_model, q_model):

# make weights in the discriminator (some shared with the q model) as not trainable

d_model.trainable = False

# connect g outputs to d inputs

d_output = d_model(g_model.output)

# connect g outputs to q inputs

q_output = q_model(g_model.output)

# define composite model

model = Model(g_model.input, [d_output, q_output])

# compile model

opt = Adam(lr=0.0002, beta_1=0.5)

model.compile(loss=['binary_crossentropy', 'categorical_crossentropy'], optimizer=opt)

return model

為了使GAN模型架構更清晰,我們可以創建模型和復合模型圖。

下面列出了完整的示例。

# create and plot the infogan model for mnist

from keras.optimizers import Adam

from keras.models import Model

from keras.layers import Input

from keras.layers import Dense

from keras.layers import Reshape

from keras.layers import Flatten

from keras.layers import Conv2D

from keras.layers import Conv2DTranspose

from keras.layers import LeakyReLU

from keras.layers import BatchNormalization

from keras.layers import Activation

from keras.initializers import RandomNormal

from keras.utils.vis_utils import plot_model

# define the standalone discriminator model

def define_discriminator(n_cat, in_shape=(28,28,1)):

# weight initialization

init = RandomNormal(stddev=0.02)

# image input

in_image = Input(shape=in_shape)

# downsample to 14x14

d = Conv2D(64, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(in_image)

d = LeakyReLU(alpha=0.1)(d)

# downsample to 7x7

d = Conv2D(128, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(d)

d = LeakyReLU(alpha=0.1)(d)

d = BatchNormalization()(d)

# normal

d = Conv2D(256, (4,4), padding='same', kernel_initializer=init)(d)

d = LeakyReLU(alpha=0.1)(d)

d = BatchNormalization()(d)

# flatten feature maps

d = Flatten()(d)

# real/fake output

out_classifier = Dense(1, activation='sigmoid')(d)

# define d model

d_model = Model(in_image, out_classifier)

# compile d model

d_model.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0002, beta_1=0.5))

# create q model layers

q = Dense(128)(d)

q = BatchNormalization()(q)

q = LeakyReLU(alpha=0.1)(q)

# q model output

out_codes = Dense(n_cat, activation='softmax')(q)

# define q model

q_model = Model(in_image, out_codes)

return d_model, q_model

# define the standalone generator model

def define_generator(gen_input_size):

# weight initialization

init = RandomNormal(stddev=0.02)

# image generator input

in_lat = Input(shape=(gen_input_size,))

# foundation for 7x7 image

n_nodes = 512 * 7 * 7

gen = Dense(n_nodes, kernel_initializer=init)(in_lat)

gen = Activation('relu')(gen)

gen = BatchNormalization()(gen)

gen = Reshape((7, 7, 512))(gen)

# normal

gen = Conv2D(128, (4,4), padding='same', kernel_initializer=init)(gen)

gen = Activation('relu')(gen)

gen = BatchNormalization()(gen)

# upsample to 14x14

gen = Conv2DTranspose(64, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(gen)

gen = Activation('relu')(gen)

gen = BatchNormalization()(gen)

# upsample to 28x28

gen = Conv2DTranspose(1, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(gen)

# tanh output

out_layer = Activation('tanh')(gen)

# define model

model = Model(in_lat, out_layer)

return model

# define the combined discriminator, generator and q network model

def define_gan(g_model, d_model, q_model):

# make weights in the discriminator (some shared with the q model) as not trainable

d_model.trainable = False

# connect g outputs to d inputs

d_output = d_model(g_model.output)

# connect g outputs to q inputs

q_output = q_model(g_model.output)

# define composite model

model = Model(g_model.input, [d_output, q_output])

# compile model

opt = Adam(lr=0.0002, beta_1=0.5)

model.compile(loss=['binary_crossentropy', 'categorical_crossentropy'], optimizer=opt)

return model

# number of values for the categorical control code

n_cat = 10

# size of the latent space

latent_dim = 62

# create the discriminator

d_model, q_model = define_discriminator(n_cat)

# create the generator

gen_input_size = latent_dim + n_cat

g_model = define_generator(gen_input_size)

# create the gan

gan_model = define_gan(g_model, d_model, q_model)

# plot the model

plot_model(gan_model, to_file='gan_plot.png', show_shapes=True, show_layer_names=True)

運行該示例將創建所有三個模型,然后創建復合GAN模型并保存模型體系結構的圖。

注意:創建此圖假設已安裝pydot和graphviz庫。如果這是一個問題,您可以注釋掉import語句和對plot_model()函數的調用。

該圖顯示了生成器模型的所有細節以及鑒別器和輔助模型的壓縮描述。重要的是,請注意鑒別器輸出的形狀作為預測圖像是真實還是假的單個節點,以及輔助模型預測分類控制代碼的10個節點。

回想一下,該復合模型將僅用于更新生成器和輔助模型的模型權重,并且鑒別器模型中的所有權重將保持不可約,即僅在更新獨立鑒別器模型時更新。

如何在<wordsbank_match class='wbmatch' location='/map/Keras/' style='cursor:pointer;'>Keras</wordsbank_match>中開發最大化生成對抗網絡(InfoGAN)的信息?

接下來,我們將為發電機開發輸入。

每個輸入都是由噪聲和控制代碼組成的矢量。具體地,高斯隨機數的矢量和一個熱編碼的隨機選擇的分類值。

下面的generatelatentpoints()函數實現了這一點,將潛在空間的大小,分類值的數量以及要生成的樣本數作為參數作為輸入。該函數返回輸入連接向量作為生成器模型的輸入,以及獨立控制代碼。通過復合GAN模型更新發電機和輔助模型時,將需要獨立控制代碼,專門用于計算輔助模型的互信息損失。

# generate points in latent space as input for the generator

def generate_latent_points(latent_dim, n_cat, n_samples):

# generate points in the latent space

z_latent = randn(latent_dim * n_samples)

# reshape into a batch of inputs for the network

z_latent = z_latent.reshape(n_samples, latent_dim)

# generate categorical codes

cat_codes = randint(0, n_cat, n_samples)

# one hot encode

cat_codes = to_categorical(cat_codes, num_classes=n_cat)

# concatenate latent points and control codes

z_input = hstack((z_latent, cat_codes))

return [z_input, cat_codes]

接下來,我們可以生成真實和虛假的例子。

可以通過為灰度圖像添加附加維度來加載MNIST數據集,將其轉換為3D輸入,并將到范圍[-1,1]以匹配來自生成器模型的輸出。這是在下面的loadreal

完 謝謝觀看

分享
收藏

OK
3d彩经网免费预测