生成对抗网络gan原理_生成对抗网络(GAN)的半监督学习
前言
如果您曾經聽說過或研究過深度學習,那么您可能就知道MNIST, SVHN, ImageNet, PascalVoc或者其他數據集。這些數據集都有一個共同點: 它們由成千上萬個有標簽的數據組成。 換句話說,這些集合由(x,y)對組成,其中(x)是原始數據,例如是一個圖像矩陣;而(y)則表示該數據點(x)表示的標簽。
以MNIST數據集為例, MNIST數據集包含60,000個圖像數據,每個數據表征0到10的數字圖像中的某一個。其數據表示形式一般為一個(輸入數據,數據標簽)對。 其中,MNIST的輸入數據是一個28x28灰度圖像,而數據標簽則是該圖像的內容(類別)。
圖1 MNIST數據集中的一個數據
這樣的有標簽的數據集通常用于訓練監督模型。監督學習一直是深度學習中大多數研究的中心,但是其訓練過程需要大量的含有標簽的數據。而現實生活中,給數據打標簽是一個非常昂貴而且容易出錯的工作。
考慮到這一點,為了利用打好標簽的一部分數據以及未曾擁有標簽的大部分數據,研究人員提出了半監督學習。半監督學習解決了有標簽數據較少時,模型訓練效果較差的問題。 它通過從沒有標簽的數據中提取有用的信息來彌補標簽損失帶來的不足,進一步提高了模型的整體性能。
半監督的分類器需要一小部分標記數據和大量未標記數據(來自同一域)。其目標是結合這些數據源來訓練模型,比如深度卷積神經網絡(DCNN),以學習這些數據中的類別信息。
在此領域中,我們學者提出一個GAN模型,該模型使用一個非常小的標簽訓練集對街景門牌號進行分類。實際上,該模型使用了大約1.3%的原始SVHN培訓標簽,即1000個(一千個)標簽示例。我們使用了OpenAI的《改進GAN訓練技術》一書中描述的一些技術。
如果您不熟悉圖像生成GAN,請參閱《生成對抗網絡簡介》。本文引用了該文章中描述的一些內容。
網絡
如圖2.,在構建用于生成圖像的GAN時,我們同時訓練了生成器和決策器。在訓練之后,我們可以放棄決策器,因為我們只用它來訓練生成器。
圖2.一個11類分類問題的半監督學習 GAN體系結構
對于半監督學習,我們需要將決策器轉換為多類分類器。這個新模型必須能夠在測試集上很好地推廣,即使我們沒有很多標記的例子來訓練。
此外,在這個例子中,生成器和決策器的角色發生了變化。在訓練結束時,我們實際上可以扔掉生成器。因為,在本例子的訓練過程中,發生器只用于幫助決策器。
換句話說,生成器充當不同的信息源,決策器從中獲得未經標記的原始訓練數據。正如我們看到的,這種未標記數據是提高鑒別器性能的關鍵。
此外,對于常規圖像生成GAN,決策器只有一個角色:計算輸入是真還是假的概率-----我們稱之為GAN問題。
然而,為了將決策器變成半監督分類器,除了GAN問題,決策器還必須學習原始數據集中每個類的概率。換句話說,對于每一個輸入圖像,識別器必須學習它變成1、2、3等等類別的概率。
回想一下,對于一個圖像生成GAN決策器,我們有一個單一的sigmoid單位輸出。這個值表示輸入圖像為真(值接近1)或假(值接近0)的概率。
換句話說,從決策器的角度來看,值接近于1意味著樣本很可能來自于訓練集,同樣的,值接近于0意味著樣本來自于生成器網絡的變化更大。
通過利用這個概率,決策器就能把信號送回發生器。這個信號允許發生器在訓練期間適應它的參數,使它有可能提高其能力創造真實的圖像。
我們必須將決策器(從以前的GAN)轉換為一個11類分類器。為此,我們可以將其sigmoid輸出轉換為softmax,其中包含11個類輸出。前10個類表示SVHN數據集的單個類概率(0到9),第11個類表示來自生成器的所有偽圖像。
注意,如果我們將第11類概率設置為0,那么前10個概率的和表示使用sigmoid函數計算的相同概率。
最后,我們需要設置損失,以這樣的方式,決策器可以做到:
- (i)幫助生成器學習產生真實的圖像。要做到這一點,我們必須指示決策器區分真樣本和假樣本。
- (ii)使用生成器的圖像,以及標記和未標記的訓練數據,以幫助分類數據集。
總之,決策器有三種不同的訓練數據來源。
帶有標簽的真實圖像。這些是像任何常規監督分類問題一樣的圖像標簽對。
沒有標簽的真實圖像。對于這些,分類器只知道這些圖像是真實的。
來自生成器的圖像。對于這些人,決策器學會把它們歸類為假的。
這些不同數據源的組合將使分類器能夠從更廣闊的視角學習。反過來,這使得模型能夠進行更精確的推理,而不是僅僅使用1000個標記的例子進行訓練。
生成器
生成器遵循DCGAN論文中描述的一般實現即可。該方法采用隨機向量z作為輸入。把它重塑成一個4D張量,然后把它輸入到一系列轉置卷積、批處理標準化(BN)和leaky ReLU操作中。
這個計算序列增加了輸入向量的空間維數,同時減少了它的通道數。結果,網絡通過雙曲正切函數輸出一個壓縮值在-1和1之間的32x32x3 RGB張量形狀。
def generator(z, output_dim, reuse=False, alpha=0.2, training=True, size_mult=128): with tf.variable_scope('generator', reuse=reuse): # First fully connected layer x1 = tf.layers.dense(z, 4 * 4 * size_mult * 4) # Reshape it to start the convolutional stack x1 = tf.reshape(x1, (-1, 4, 4, size_mult * 4)) x1 = tf.layers.batch_normalization(x1, training=training) x1 = tf.maximum(alpha * x1, x1) x2 = tf.layers.conv2d_transpose(x1, size_mult * 2, 5, strides=2, padding='same') x2 = tf.layers.batch_normalization(x2, training=training) x2 = tf.maximum(alpha * x2, x2) x3 = tf.layers.conv2d_transpose(x2, size_mult, 5, strides=2, padding='same') x3 = tf.layers.batch_normalization(x3, training=training) x3 = tf.maximum(alpha * x3, x3) # Output layer logits = tf.layers.conv2d_transpose(x3, output_dim, 5, strides=2, padding='same') out = tf.tanh(logits) return out決策器
決策器現在是一個多類的分類器。在這里,我們設置了一個同樣類似的DCGAN架構,其中我們使用帶有BN和ReLU的卷積堆棧。
我們使用strided卷積來減少特征向量的維數。注意,并不是所有的卷積都執行這種類型的計算。當我們想保持特征向量的維數不變時,我們使用長度為1的步長;否則,我們使用長度為2的步長。最后,為了穩定學習,我們廣泛使用BN(除了網絡的第一層)。
在所有的卷積中,2D卷積窗口(卷積核或過濾器)的寬度和高度被設置為3。另外,注意我們有一些帶有dropout的圖層。我們的決策器的(部分)行為與任何其他常規分類器相似,理解這一點很重要。正因為如此,它可能會遇到任何沒有經過良好設計的分類器都會遇到的問題。
當在一個非常有限的數據集上訓練一個大型分類器時,最可能遇到的缺點之一是過度擬合的問題。對于“過度訓練”的分類器,需要注意的一點是,它們通常在訓練錯誤(較小)和測試錯誤(較高)之間顯示出明顯的差異。
這表明該模型能夠很好地捕捉訓練數據集的結構。但是,由于它過于相信訓練數據,從而導致無法對未見的例子進行泛化。
為了防止這種情況發生,我們通常通過dropout來實現網絡層的正則化,哪怕是在網絡的第一層。
def discriminator(x, reuse=False, alpha=0.2, drop_rate=0., num_classes=10, size_mult=64): with tf.variable_scope('discriminator', reuse=reuse): x = tf.layers.dropout(x, rate=drop_rate/2.5) # Input layer is ?x32x32x3 x1 = tf.layers.conv2d(x, size_mult, 3, strides=2, padding='same') relu1 = tf.maximum(alpha * x1, x1) relu1 = tf.layers.dropout(relu1, rate=drop_rate) # [?x16x16x?] x2 = tf.layers.conv2d(relu1, size_mult, 3, strides=2, padding='same') bn2 = tf.layers.batch_normalization(x2, training=True) # [?x8x8x?] relu2 = tf.maximum(alpha * bn2, bn2) x3 = tf.layers.conv2d(relu2, size_mult, 3, strides=2, padding='same') # [?x4x4x?] bn3 = tf.layers.batch_normalization(x3, training=True) relu3 = tf.maximum(alpha * bn3, bn3) relu3 = tf.layers.dropout(relu3, rate=drop_rate) x4 = tf.layers.conv2d(relu3, 2 * size_mult, 3, strides=1, padding='same') # [?x4x4x?] bn4 = tf.layers.batch_normalization(x4, training=True) relu4 = tf.maximum(alpha * bn4, bn4) x5 = tf.layers.conv2d(relu4, 2 * size_mult, 3, strides=1, padding='same') # [?x4x4x?] bn5 = tf.layers.batch_normalization(x5, training=True) relu5 = tf.maximum(alpha * bn5, bn5) x6 = tf.layers.conv2d(relu5, 2 * size_mult, 3, strides=2, padding='same') # [?x2x2x?] bn6 = tf.layers.batch_normalization(x6, training=True) relu6 = tf.maximum(alpha * bn6, bn6) relu6 = tf.layers.dropout(relu6, rate=drop_rate)...最后,我們執行全局平均池(GAP),而不是在卷積堆棧的頂部應用一個完全連接的層。在GAP中,我們對特征向量的空間維度取平均值,從而壓縮張量維數到一個單一的值。
...# Flatten it by global average pooling# In global average pooling, for every feature map we take the average over all the spatial# domain and return a single value# In: [BATCH_SIZE,HEIGHT X WIDTH X CHANNELS] --> [BATCH_SIZE, CHANNELS]#輸入: [BATCH大小,X長 X寬 通道數] --> [BATCH_SIZE, 通道數]features = tf.reduce_mean(relu7, axis=[1,2])# Set class_logits to be the inputs to a softmax distribution over the different classes#將class_logits設置為softmax分布 在不同類別上的輸入class_logits = tf.layers.dense(features, num_classes)...例如,假設在經過一系列卷積后,我們得到一個形狀為[BATCH大小, 8,8, 通道數]的張量。為了實現GAP算法,我們取[8x8]張量切片上的平均值。這樣就得到了一個形狀為[BATCH大小, 1,1, 通道數]的張量,該張量可以被重塑為[BATCH大小, 通道數]。
在論文《Network In Network》中,描述了GAP層相對于傳統的全連接層的一些優點。其中包括:更高的魯棒性空間轉換和較少的過度擬合問題。在GAP層之后,我們應用一個完全連接的層來輸出最后的結果。它們的形狀為 [BATCH大小, 通道數]并對應于未縮放的最終類別的值。
為了得到分類概率,我們通過softmax函數來處理最后的結果。然而,我們仍然需要一種方法來表示輸入圖像的真實概率而不是假的。也就是說,我們仍然需要考慮GAN中的標準的二值分類問題。
...# Get the probability that the input is real rather than fakeout = tf.nn.softmax(class_logits) # class probabilities for the 10 real classes...我們知道最后的結果一般是softmax的概率值。然而,我們也需要一種方法來表示它們為sigmoid 輸出類型。我們知道輸入是實數的概率對應于所有實數對數的和。考慮到這一點,我們可以將這些值提供給LogSumExp函數,該函數將建模二進制分類值。在此之后,我們將LogSumExp的結果提輸入到一個sigmoid函數中。
我們可以使用Tensorflow的LogSumExp內置函數來避免數值問題。這個函數防止了在LogSumExp遇到非常極端的值(正數或負數)時可能發生的上/下溢流的問題。
...# This function is more numerically stable than log(sum(exp(input))).# It avoids overflows caused by taking the exp of large inputs and underflows# caused by taking the log of small inputs.gan_logits = tf.reduce_logsumexp(class_logits, 1)...模型損失
如前所述,我們可以將決策器損失分為兩部分:一個代表GAN問題,無監督損失;另一個計算個體真實類概率,監督損失。
對于無監督損失,決策器必須區分真實的訓練圖像和來自生成器的偽圖像。
對于常規的GAN,一半的時間決策器接收來自訓練集的未標記圖像,另一半時間接收來自生成器的虛的未標記圖像。
在這兩種情況下,我們處理的都是一個二元分類問題。由于我們希望真實圖像的概率值接近1,非真實圖像的概率值接近0,我們可以使用sigmoid型交叉熵函數來計算損失。
對于來自訓練集的圖像,我們通過分配1的標簽來最大化其真實的概率。對于來自生成器的偽造圖像,我們通過給它們0的標簽來最大化其偽造的可能性。
...# Here we compute `d_loss`, the loss for the discriminator.# This should combine two different losses:# 1. The loss for the GAN problem, where we minimize the cross-entropy for the binary# real-vs-fake classification problem.tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=gan_logits_on_data, labels=tf.ones_like(gan_logits_on_data) * (1 - smooth)))fake_data_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=gan_logits_on_samples, labels=tf.zeros_like(gan_logits_on_samples)))# This way, the unsupervisedunsupervised_loss = real_data_loss + fake_data_loss...對于監督損失,我們需要使用從決策器中得到的結果。由于這是一個多類分類問題,我們可以利用softmax交叉熵函數與我們現有的真實標簽。
注意,這一部分與任何其他分類模型相似。決策器損失是監督損失和非監督損失的總和。而且,因為我們假裝我們沒有大多數的標簽,我們需要忽略他們在監督損失。為此,我們將損失乘以mask變量,該變量指示可用的標簽集。
# 2. The loss for the SVHN digit classification problem, where we minimize the cross-entropy# for the multi-class softmax. For this one we use the labels. Don't forget to ignore# use `label_mask` to ignore the examples that we are pretending are unlabeled for the# semi-supervised learning problem.y = tf.squeeze(y)suppervised_loss = tf.nn.softmax_cross_entropy_with_logits(logits=class_logits_on_data, labels=tf.one_hot(y, num_classes, dtype=tf.float32))label_mask = tf.squeeze(tf.to_float(label_mask))# ignore the labels that we pretend does not exist for the losssuppervised_loss = tf.reduce_sum(tf.multiply(suppervised_loss, label_mask))# get the meansuppervised_loss = suppervised_loss / tf.maximum(1.0, tf.reduce_sum(label_mask))d_loss = unsupervised_loss + suppervised_loss正如在論文《 Improved Techniques for Training GANs》中所描述的,我們使用特征匹配的生成器損失。
如作者所述:
特征匹配的概念是對訓練數據上某組特征的平均值和生成樣本上這組特征的平均值之間的絕對平均誤差進行懲罰。
為了做到這一點,我們從兩個不同的來源獲取一些統計數據(動量),并迫使它們相似。
首先,當我們小批量的處理一個真實的訓練數據時,最后的結果需要對從決策器中提取的特征進行平均得到。
其次,我們用同樣的方法來計算由決策器得出的來自生成器生成的假圖像的結果的動量。
最后,用這兩組矩,生成器損失是他們之間的平均絕對差。換句話說,正如本文所強調的:
我們訓練生成器去匹配鑒別器中間層上特征的期望值
# Here we set `g_loss` to the "feature matching" loss invented by Tim Salimans at OpenAI.# This loss consists of minimizing the absolute difference between the expected features# on the data and the expected features on the generated samples.# This loss works better for semi-supervised learning than the tradition GAN losses.# Make the Generator output features that are on average similar to the features# that are found by applying the real data to the discriminatordata_moments = tf.reduce_mean(data_features, axis=0)sample_moments = tf.reduce_mean(sample_features, axis=0)g_loss = tf.reduce_mean(tf.abs(data_moments - sample_moments))pred_class = tf.cast(tf.argmax(class_logits_on_data, 1), tf.int32)eq = tf.equal(tf.squeeze(y), pred_class)correct = tf.reduce_sum(tf.to_float(eq))masked_correct = tf.reduce_sum(label_mask * tf.to_float(eq))雖然特征匹配損失在半監督學習的任務中表現得很好,但是由生成器生成的圖像并沒有上一篇文章中生成的那么好。
圖4. 樣本圖像由生成器網絡創建使用特征匹配損失。
在論文《Improved Techniques for Training GANs》中,OpenAI報告了其在MNIST、CIFAR-10和SVHN上半監督分類學習的最新結果。
我們的方案實現了訓練和測試的準確率分別接近93%和68%。這些結果比NIPS 2014年報告的大約64%的結果要好。
本筆記不打算演示交叉驗證技術的最佳實踐。它只使用了OpenAI原始論文中描述的一些技術。
總結
許多研究認為無監督學習是一般人工智能系統的缺失環節。要突破這些障礙,關鍵是嘗試使用較少標記的數據來解決已經存在的問題。在這個場景中,GANs為學習使用較少標記樣本的復雜任務提供了一個真正的替代方案。
然而,監督學習和半監督學習之間的性能差距仍然遠遠不是相等的。但我們當然可以預期,隨著新方法的出現,這種差距將會縮小。
原英文鏈接:https://towardsdatascience.com/semi-supervised-learning-with-gans-9f3cb128c5e
總結
以上是生活随笔為你收集整理的生成对抗网络gan原理_生成对抗网络(GAN)的半监督学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: threadlocal使用_多方位点评T
- 下一篇: python控制手机自动刷新闻_Pyth