# 八、生成模型
生成模型已經成為計算機視覺中的重要應用。 與前幾章討論的應用根據圖像進行預測不同,生成模型可以為特定目標創建圖像。 在本章中,我們將了解:
* 生成模型的應用
* 風格遷移算法
* 訓練超分辨率圖像模型
* 生成模型的實現和訓練
* 當前模型的缺點
在本章的最后,您將能夠實現一些出色的應用來傳遞樣式,并理解與生成模型相關的可能性和困難。
# 生成模型的應用
讓我們從生成模型的可能應用開始本章。 應用是巨大的。 我們將看到其中一些應用,以了解動機和可能性。
# 藝術風格遷移
藝術風格遷移是將藝術風格遷移到任何圖像的過程。 例如,可以使用一幅圖像的藝術風格和另一幅圖??像的內容來創建圖像。 [Gatys 等人在此顯示了一個結合了幾種不同樣式的圖像示例](https://www.cv-foundation.org/openaccess/content_cvpr_2016/papers/Gatys_Image_Style_Transfer_CVPR_2016_paper.pdf)。 圖像 **A** 是應用了樣式的照片,其結果顯示在其他圖像中:

轉載自蓋蒂斯等。
此應用引起了公眾的注意,并且市場上有幾種提供此功能的移動應用。
# 預測視頻中的下一幀
可以使用生成模型從合成視頻集中預測未來的幀。 [在下面由 Lotter 等人提出的圖像中](https://arxiv.org/pdf/1511.06380.pdf),左側的圖像是前一幀的模型,而右側有兩種與基本事實比較的算法:

復制自 Lotter 等人
生成模型生成的框架將是現實的。
# 圖像超分辨率
**超分辨率**是從較小的圖像創建高分辨率圖像的過程。 傳統上,插值用于創建更大的圖像。 但是插值通過提供平滑效果而錯過了高頻細節。 經過訓練的生成模型針對此超分辨率的特定目的而創建的圖像具有出色的細節。 [以下是 Ledig 等人提出的此類模型的示例](https://arxiv.org/pdf/1609.04802.pdf)。 左側是通過 **4 倍縮放**生成的,看起來與右側的原件沒有區別:

轉自 Ledig 等人
超分辨率對于在高質量的顯示器或打印件上呈現低分辨率的圖像很有用。 另一個應用可能是重建高質量的壓縮圖像。
# 交互式圖像生成
生成模型可用于通過**交互作用**創建圖像。 用戶可以添加編輯內容,并且可以生成圖像,以反映編輯內容,[如 Zhu 等人建議的那樣](https://arxiv.org/pdf/1609.03552v2.pdf):

復制自 Zhu 等人
如圖所示,圖像是根據編輯的形狀和顏色生成的。 底部的綠色筆觸創建了草原,矩形創建了摩天大樓,依此類推。 圖像將被生成并通過用戶的進一步輸入進行微調。 生成的圖像還可以用于檢索可以利用的最相似的真實圖像。 提供交互式圖像生成是一種直觀搜索圖像的全新方法。
# 圖像到圖像的轉換
圖像可用于生成具有特定目標的其他圖像,因此此過程稱為**圖像到圖像的轉換**。 此處顯示了此類翻譯的一些示例,[以及由 Isola 等人提出的相應標準](https://arxiv.org/pdf/1611.07004.pdf):

復制自 Isola 等人
帶有標簽的圖像可以轉換為逼真的圖像以用于創意目的。 黑白圖像可以轉換為彩色圖像。 這樣的翻譯對于照片編輯應用,為舊電影著色,服裝設計等非常有用。
# 文本到圖像的生成
可以從文本描述中生成圖像,其步驟類似于圖像到圖像的翻譯。 [以下是一些由 Reed 等人展示的自然文本描述生成的示例](https://arxiv.org/pdf/1605.05396.pdf):

復制自 Reed 等人
當前,此模型僅適用于少數幾個對象。 從文本生成圖像還不夠實際,無法在應用中使用。
# 修復
修復是填充圖像中的間隙的過程,如下所示:

資料來源:https://www.flickr.com/photos/littleredelf/4756059924/
左側的圖像是正常圖像,右側的圖像是經過處理的圖像。 從圖像中可以看到,不需要的東西已從圖片中刪除。 修補對于從圖像中刪除不需要的對象以及填充掃描圖稿的空間很有用。
# 融合
融合是將圖像的一部分平滑地粘貼到另一個圖像上而沒有任何偽影的過程。 此處顯示的圖像表示一種圖像放置在另一圖像上的情況,給人留下不好的印象。 圖像 **b** 和 **c** 代表傳統的混合技術,例如**修正的泊松方法**和**多樣條方法**。
最終圖像或圖像 **d** 顯示了混合生成方法的結果,[該方法比 Wu 等人的其他方法提供了更好的結果](https://arxiv.org/pdf/1703.07195.pdf):

摘自 Wu 等人
混合對于照片編輯和電影行業中的特殊效果非常有用。
# 轉換屬性
可以使用生成模型來更改圖像的屬性。 蘭珀(Lample)等人在此顯示,可以修改人的人臉以反映不同的屬性,[例如性別,眼鏡,年齡等](https://research.fb.com/wp-content/uploads/2017/11/fader_networks__conditional_attribute_based_image_generation_by_disentangling_in_latent_space.pdf):

轉載于 Lample 等人。
更改屬性既可以用于創意應用,也可以用于娛樂,也可以用于生成更多具有變化的訓練數據。
# 創建訓練數據
生成模型可用于大規模生成訓練,甚至可用于完善為訓練而創建的合成圖像。 [這是使用 Wang 等人的生成模型為交通標志識別創建的合成圖像](https://arxiv.org/pdf/1707.03124.pdf):

轉載自 Wang 等人
使用這些圖像可以使分類更加準確。
# 創建新的動畫角色
生成模型可用于創建具有各種條件的新動畫角色,例如人臉表情,發型,服裝等,[如 Jin 等人所示](https://arxiv.org/pdf/1708.05509.pdf):

轉載自 Jin 等人
創建具有不同屬性的新角色可以徹底改變動畫產業。
# 照片的 3D 模型
我們可以使用生成模型從 2D 圖像創建 3D 模型,[如 Wu 等人所示](https://arxiv.org/pdf/1610.07584.pdf):

摘自 Wu 等人
從圖像創建 3D 模型對于機器人技術,增強現實和動畫行業很有用。 在以下各節中,我們將學習它們背后的算法。 在下一節中,我們將實現神經藝術風格的轉換。
# 神經藝術風格遷移
我們將要實現的第一個應用是**神經藝術風格轉換**。 在這里,我們將**梵高**藝術的風格遷移到圖像上。 圖像可以視為樣式和內容的組合。 藝術風格轉換技術將圖像轉換為看起來像具有特定繪畫風格的繪畫。 我們將看到如何編寫這個想法。 `loss`函數將比較生成的圖像與照片內容和繪畫風格。 因此,針對圖像像素而不是針對網絡權重執行優化。 通過將照片的內容與生成的圖像相比較,然后是繪畫風格和生成的圖像,可以計算出兩個值。
# 內容損失
由于像素不是一個好的選擇,我們將使用各個層的 CNN 特征,因為它們可以更好地表示內容。 如第 3 章,“圖像檢索”, 所示,初始層具有高頻,例如邊緣,拐角和紋理。 后面的層代表對象,因此更適合內容。 后者可以比像素更好地將對象與對象進行比較。 但是為此,我們需要先使用以下代碼導入所需的庫:
```py
import numpy as np
from PIL import Image
from scipy.optimize import fmin_l_bfgs_b
from scipy.misc import imsave
from vgg16_avg import VGG16_Avg
from keras import metrics
from keras.models import Model
from keras import backend as K
```
現在,讓我們使用以下命令加載所需的圖像:
```py
content_image = Image.open(work_dir + 'bird_orig.png')
```
我們將在此實例中使用以下圖片:

當我們使用 VGG 架構提取特征時,必須從所有圖像中減去所有`ImageNet`圖像的均值,如以下代碼所示:
```py
imagenet_mean = np.array([123.68, 116.779, 103.939], dtype=np.float32)
def subtract_imagenet_mean(image):
return (image - imagenet_mean)[:, :, :, ::-1]
```
請注意,通道是不同的。 `preprocess`函數拍攝生成的圖像并減去平均值,然后反轉通道。 `deprocess`函數由于進行了預處理步驟而使效果相反,如以下代碼所示:
```py
def add_imagenet_mean(image, s):
return np.clip(image.reshape(s)[:, :, :, ::-1] + imagenet_mean, 0, 255)
```
首先,我們將了解如何使用其他圖像中的內容創建圖像。 這是根據**隨機噪聲**創建圖像的過程。 此處使用的內容是某層中**激活**的總和。 我們將使隨機噪聲和圖像之間的內容損失最小化,這被稱為內容損失。 該損耗類似于逐像素損耗,但應用于層激活,因此將捕獲內容而沒有噪聲。 任何 CNN 架構都可以用來轉發內容圖像和隨機噪聲。 比較這兩個輸出的激活,進行激活并計算均方誤差。
凍結 CNN 權重時,將更新隨機圖像的像素。 在這種情況下,我們將凍結 VGG 網絡。 現在,可以加載 VGG 模型。 生成圖像對子采樣技術(例如**最大池化**)非常敏感。 無法從最大池化中取回像素值。 因此,**平均池化**比最大池化更平滑。 使用平均池化轉換 VGG 模型的特征用于加載模型,如下所示:
```py
vgg_model = VGG16_Avg(include_top=False)
```
請注意,即使合并類型已更改,此模型的權重也與原始模型相同。 ResNet 和 Inception 模型不適合此操作,因為它們無法提供各種抽象。 我們將從模型凍結的最后一個 VGG 模型的卷積層`block_conv1`中獲取激活。 這是 VGG 的第三層,具有廣闊的接收范圍。 這里給出了相同的代碼供您參考:
```py
content_layer = vgg_model.get_layer('block5_conv1').output
```
現在,使用截斷的 VGG 創建新模型,直到具有良好特征的層。 因此,該圖像現在可以加載,并且可以用于執行前向推斷,以獲得**實際激活的層**。 使用以下代碼創建 TensorFlow 變量以捕獲激活:
```py
content_model = Model(vgg_model.input, content_layer)
content_image_array = subtract_imagenet_mean(np.expand_dims(np.array(content_image), 0))
content_image_shape = content_image_array.shape
target = K.variable(content_model.predict(content_image_array))
```
讓我們定義一個評估器類,以計算圖像的損耗和梯度。 下列類在迭代的任意點返回損耗和梯度值:
```py
class ConvexOptimiser(object):
def __init__(self, cost_function, tensor_shape):
self.cost_function = cost_function
self.tensor_shape = tensor_shape
self.gradient_values = None def loss(self, point):
loss_value, self.gradient_values = self.cost_function([point.reshape(self.tensor_shape)])
return loss_value.astype(np.float64)
def gradients(self, point):
return self.gradient_values.flatten().astype(np.float64)
```
損失函數可以定義為特定卷積層的激活值之間的均方誤差。 損失將在生成的圖像和原始內容照片的層之間進行計算,如下所示:
```py
mse_loss = metrics.mean_squared_error(content_layer, target)
```
可以通過考慮模型的輸入來計算損耗的梯度,如下所示:
```py
grads = K.gradients(mse_loss, vgg_model.input)
```
函數的輸入是模型的輸入,輸出將是損耗和梯度值的數組,如下所示:
```py
cost_function = K.function([vgg_model.input], [mse_loss]+grads)
```
此函數是確定性的要優化的,因此不需要 **SGD**:
```py
optimiser = ConvexOptimiser(cost_function, content_image_shape)
```
可以使用簡單的優化程序來優化此函數,因為它是凸的,因此是確定性的。 我們還可以在迭代的每個步驟中保存圖像。 我們將以可訪問梯度的方式進行定義,就像我們使用 scikit-learn 的優化程序進行最終優化一樣。 注意,該損失函數是凸的,因此,簡單的優化器足以滿足計算要求。 可以使用以下代碼定義優化器:
```py
def optimise(optimiser, iterations, point, tensor_shape, file_name):
for i in range(iterations):
point, min_val, info = fmin_l_bfgs_b(optimiser.loss, point.flatten(),
fprime=optimiser.gradients, maxfun=20)
point = np.clip(point, -127, 127)
print('Loss:', min_val)
imsave(work_dir + 'gen_'+file_name+'_{i}.png', add_imagenet_mean(point.copy(), tensor_shape)[0])
return point
```
優化器采用`loss`函數,點和梯度,然后返回更新。 需要使用以下代碼生成隨機圖像,以使內容損失最小化:
```py
def generate_rand_img(shape):
return np.random.uniform(-2.5, 2.5, shape)/1 generated_image = generate_rand_img(content_image_shape)
```
這是創建的隨機圖像:

該優化可以運行 10 次迭代以查看結果,如下所示:
```py
iterations = 10 generated_image = optimise(optimiser, iterations, generated_image, content_image_shape, 'content')
```
如果一切順利,那么在迭代過程中,損失應如下圖所示:
```py
Current loss value: 73.2010421753
Current loss value: 22.7840042114
Current loss value: 12.6585302353
Current loss value: 8.53817081451
Current loss value: 6.64649534225
Current loss value: 5.56395864487
Current loss value: 4.83072710037
Current loss value: 4.32800722122
Current loss value: 3.94804215431
Current loss value: 3.66387653351
```
這是生成的圖像,現在,它看起來幾乎像只鳥。 可以運行優化以進行進一步的迭代以完成此操作:

優化器拍攝圖像并更新像素,以使內容相同。 雖然效果較差,但可以在一定程度上重現圖像內容。 通過迭代獲得的所有圖像都很好地說明了圖像的生成方式。 此過程不涉及批量。 在下一節中,我們將看到如何以繪畫風格創建圖像。
# 使用 Gram 矩陣的樣式損失
創建具有原始圖像內容的圖像后,我們將看到如何僅使用樣式創建圖像。 樣式可以認為是圖像顏色和紋理的混合。 為此,我們將定義樣式損失。 首先,我們將覆蓋圖像并將其轉換為數組,如以下代碼所示:
```py
style_image = Image.open(work_dir + 'starry_night.png')
style_image = style_image.resize(np.divide(style_image.size, 3.5).astype('int32'))
```
這是我們加載的樣式圖像:

現在,我們將使用以下代碼通過更改通道對該圖像進行預處理:
```py
style_image_array = subtract_imagenet_mean(np.expand_dims(style_image, 0)[:, :, :, :3])
style_image_shape = style_image_array.shape
```
為此,我們將考慮以下幾層,就像我們在以下代碼中所做的那樣:
```py
model = VGG16_Avg(include_top=False, input_shape=shp[1:])
outputs = {l.name: l.output for l in model.layers}
```
現在,我們將使用以下代碼將多層作為前四個塊的數組輸出:
```py
layers = [outputs['block{}_conv1'.format(o)] for o in range(1,3)]
```
現在創建一個新模型,該模型可以使用以下代碼輸出所有這些層并分配目標變量:
```py
layers_model = Model(model.input, layers)
targs = [K.variable(o) for o in layers_model.predict(style_arr)]
```
使用 **Gram 矩陣**計算樣式損失。 革蘭氏矩陣是矩陣及其轉置的乘積。 激活值可以簡單地轉置和相乘。 然后將此矩陣用于計算樣式和隨機圖像之間的誤差。 Gram 矩陣會丟失位置信息,但會保留紋理信息。 我們將使用以下代碼定義 Gram 矩陣:
```py
def grammian_matrix(matrix):
flattened_matrix = K.batch_flatten(K.permute_dimensions(matrix, (2, 0, 1)))
matrix_transpose_dot = K.dot(flattened_matrix, K.transpose(flattened_matrix))
element_count = matrix.get_shape().num_elements()
return matrix_transpose_dot / element_count
```
您可能現在已經知道,它是一對列之間的相關性的度量。 高度和寬度尺寸被展平。 這不包括任何本地信息,因為坐標信息被忽略。 樣式損失計算輸入圖像的 Gram 矩陣與目標之間的均方誤差,如以下代碼所示:
```py
def style_mse_loss(x, y):
return metrics.mse(grammian_matrix(x), grammian_matrix(y))
```
現在,我們使用以下代碼通過匯總各層的所有激活來計算損失:
```py
style_loss = sum(style_mse_loss(l1[0], l2[0]) for l1, l2 in zip(style_features, style_targets))
grads = K.gradients(style_loss, vgg_model.input)
style_fn = K.function([vgg_model.input], [style_loss]+grads)
optimiser = ConvexOptimiser(style_fn, style_image_shape)
```
然后,通過創建隨機圖像,以與以前相同的方式解決它。 但是這次,我們還將應用高斯過濾器,如以下代碼所示:
```py
generated_image = generate_rand_img(style_image_shape)
```
生成的隨機圖像如下所示:

優化可以運行 10 次迭代以查看結果,如下所示:
```py
generated_image = optimise(optimiser, iterations, generated_image, style_image_shape)
```
如果一切順利,求解器應打印類似于以下的損耗值:
```py
Current loss value: 5462.45556641
Current loss value: 189.738555908
Current loss value: 82.4192581177
Current loss value: 55.6530838013
Current loss value: 37.215713501
Current loss value: 24.4533748627
Current loss value: 15.5914745331
Current loss value: 10.9425945282
Current loss value: 7.66888141632
Current loss value: 5.84042310715
```
這是生成的圖像:

在這里,我們從隨機噪聲中創建了具有特定繪畫風格的圖像,而沒有任何位置信息。 在下一節中,我們將看到如何結合使用-內容損失和樣式損失。
# 風格遷移
現在,我們知道了如何重建圖像,以及如何構建捕獲原始圖像樣式的圖像。 顯而易見的想法可能是通過加權并添加兩個`loss`函數來將這兩種方法結合起來,如以下代碼所示:
```py
w,h = style.size
src = img_arr[:,:h,:w]
```
和以前一樣,我們將獲取一系列層輸出以計算樣式損失。 但是,我們仍然只需要一層輸出來計算內容損失。 我們如何知道要抓哪一層? 如前所述,層越低,內容重構將越精確。 在將內容重建與樣式相結合時,我們可以預期,對內容進行更寬松的重建將為樣式帶來更大的影響空間(例如:靈感)。 此外,即使沒有相同的細節,后面的層也可以確保圖像看起來像相同的主題。 以下代碼用于此過程:
```py
style_layers = [outputs['block{}_conv2'.format(o)] for o in range(1,6)]
content_name = 'block4_conv2'
content_layer = outputs[content_name]
```
現在,使用以下代碼使用所需的輸出層創建一個單獨的樣式模型:
```py
style_model = Model(model.input, style_layers)
style_targs = [K.variable(o) for o in style_model.predict(style_arr)]
```
我們還將使用以下代碼為具有內容層的內容創建另一個模型:
```py
content_model = Model(model.input, content_layer)
content_targ = K.variable(content_model.predict(src))
```
現在,兩種方法的合并就像合并它們各自的損失函數一樣簡單。 請注意,與我們之前的函數相反,此函數將產生三種不同類型的輸出:
* 一個用于原始圖像
* 一個用于模仿我們風格的圖片
* 一個用于訓練像素的隨機圖像
我們調整重建方式的一種方法是更改??內容損失系數,此處為 1/10。 如果增加分母,則樣式將對圖像產生較大影響,而如果太大,則非結構化樣式將掩蓋圖像的原始內容。 同樣,如果它太小,則圖像將沒有足夠的樣式。 我們將在此過程中使用以下代碼:
```py
style_wgts = [0.05,0.2,0.2,0.25,0.3]
```
`loss`函數同時包含樣式和內容層,如下所示:
```py
loss = sum(style_loss(l1[0], l2[0])*w
for l1,l2,w in zip(style_layers, style_targs, style_wgts))
loss += metrics.mse(content_layer, content_targ)/10
grads = K.gradients(loss, model.input)
transfer_fn = K.function([model.input], [loss]+grads) evaluator = Evaluator(transfer_fn, shp)
```
我們將使用以下代碼像以前一樣運行求解器 10 次迭代:
```py
iterations=10
x = rand_img(shp) x = solve_image(evaluator, iterations, x)
```
損耗值應按如下所示打印:
```py
Current loss value: 2557.953125
Current loss value: 732.533630371
Current loss value: 488.321166992
Current loss value: 385.827178955
Current loss value: 330.915924072
Current loss value: 293.238189697
Current loss value: 262.066864014
Current loss value: 239.34185791
Current loss value: 218.086700439
Current loss value: 203.045211792
```
這些結果是驚人的。 他們每個人都以藝術家的風格來完成原始圖像的復制工作。 生成的圖像如下所示:

現在,我們將結束樣式轉換部分。 此操作確實很慢,但可以處理任何圖像。 在下一節中,我們將看到如何使用類似的想法來創建超分辨率網絡。 有幾種方法可以改善這種情況,例如:
* 將高斯濾鏡添加到隨機圖像
* 為層添加不同的權重
* 可以使用不同的層和權重來滿足
* 初始化圖像而不是隨機圖像
* 顏色可以保存
* 掩碼可以用于指定所需的內容
* 任何草圖都可以轉換為繪畫
* 繪制草圖并創建圖像
通過訓練 CNN 輸出任何圖像,都可以將其轉換為藝術風格。
# 生成對抗網絡
**生成對抗網絡**(**GAN**)由 **Ian Goodfellow** 于 2014 年發明。這是一種無監督算法,其中兩個神經網絡被訓練為判別器和生成器。 , 同時。 該技術可以根據隨機噪聲生成圖像,判別器可以評估是否為原始圖像。 經過進一步訓練后,生成器網絡可以生成逼真的圖像。 生成器網絡通常是反卷積神經網絡,而判別器是卷積神經網絡。
理解這一點的一個很好的類比是,將生成器看作是偽造錢幣的人,而將判別器看作是確定錢幣是否為假幣的警察。 生成器會根據警察的反饋不斷提高偽鈔的質量,直到警察無法區分偽鈔和偽鈔。 現在,讓我們從實現開始。
# 原始 GAN
原始 GAN 稱為**原始 GAN** 。 在構建模型之前,讓我們定義一些對本章其余部分有用的層。 以下是`convolutional_layers`,其中添加了泄漏激活和正則化:
```py
def convolution_layer(input_layer,
filters,
kernel_size=[4, 4],
activation=tf.nn.leaky_relu):
layer = tf.layers.conv2d(
inputs=input_layer,
filters=filters,
kernel_size=kernel_size,
activation=activation,
kernel_regularizer=tf.nn.l2_loss,
bias_regularizer=tf.nn.l2_loss,
)
add_variable_summary(layer, 'convolution')
return layer
```
接下來,我們將使用以下代碼定義與帶有正則化的`convolution_layer`相反的`transpose_convolution_layer`:
```py
def transpose_convolution_layer(input_layer,
filters,
kernel_size=[4, 4],
activation=tf.nn.relu,
strides=2):
layer = tf.layers.conv2d_transpose(
inputs=input_layer,
filters=filters,
kernel_size=kernel_size,
activation=activation,
strides=strides,
kernel_regularizer=tf.nn.l2_loss,
bias_regularizer=tf.nn.l2_loss,
)
add_variable_summary(layer, 'convolution')
return layer
```
接下來,我們將使用以下代碼定義一個具有非線性激活的密集層:
```py
def dense_layer(input_layer,
units,
activation=tf.nn.relu):
layer = tf.layers.dense(
inputs=input_layer,
units=units,
activation=activation
)
add_variable_summary(layer, 'dense')
return layer
```
現在,我們將定義一個生成器,該生成器將噪聲作為輸入并變為圖像。 生成器由幾個全連接層組成,然后是轉置卷積層以對噪聲進行上采樣。 最后,提出了卷積層以使噪聲成為單個通道。 每層之間都有批量歸一化層,以使梯度平滑流動。 我們將使用以下代碼定義生成器:
```py
def get_generator(input_noise, is_training=True):
generator = dense_layer(input_noise, 1024)
generator = tf.layers.batch_normalization(generator, training=is_training)
generator = dense_layer(generator, 7 * 7 * 256)
generator = tf.layers.batch_normalization(generator, training=is_training)
generator = tf.reshape(generator, [-1, 7, 7, 256])
generator = transpose_convolution_layer(generator, 64)
generator = tf.layers.batch_normalization(generator, training=is_training)
generator = transpose_convolution_layer(generator, 32)
generator = tf.layers.batch_normalization(generator, training=is_training)
generator = convolution_layer(generator, 3)
generator = convolution_layer(generator, 1, activation=tf.nn.tanh)
return generator
```
現在,我們將定義 GAN 的**判別器**部分,該部分可拍攝圖像并嘗試區分假冒商品和真實形象。 判別器是一個規則的卷積網絡,上面有幾個`convolutional_layers`,其后是致密層。 批歸一化層位于層之間。 我們將使用以下代碼來定義鑒別符:
```py
def get_discriminator(image, is_training=True):
x_input_reshape = tf.reshape(image, [-1, 28, 28, 1],
name='input_reshape')
discriminator = convolution_layer(x_input_reshape, 64)
discriminator = convolution_layer(discriminator, 128)
discriminator = tf.layers.flatten(discriminator)
discriminator = dense_layer(discriminator, 1024)
discriminator = tf.layers.batch_normalization(discriminator, training=is_training)
discriminator = dense_layer(discriminator, 2)
return discriminator
```
創建判別器后,我們將使用以下代碼創建一個噪聲向量,該噪聲向量將作為生成器的輸入:
```py
input_noise = tf.random_normal([batch_size, input_dimension])
```
可以使用 TensorFlow 中的`tf.contrib.gan`模塊創建 GAN 模型。 它采用了生成器和判別器方法及其相應的輸入,如下所示:
```py
gan = tf.contrib.gan.gan_model(
get_generator,
get_discriminator,
real_images,
input_noise)
```
現在,可以使用以下代碼從`gan_train`方法開始訓練,該方法將`gan_train_ops`方法帶給生成器和判別器以損失,并對優化器進行優化,并使用以下代碼:
```py
tf.contrib.gan.gan_train(
tf.contrib.gan.gan_train_ops(
gan,
tf.contrib.gan.gan_loss(gan),
tf.train.AdamOptimizer(0.001),
tf.train.AdamOptimizer(0.0001)))
```
通過運行此命令,將創建可從隨機向量輸出圖像的 GAN 模型。 生成的圖像不受限制,可以來自任何標簽。 在下一節中,我們將使用條件 GAN 生成所需的輸出。
# 條件 GAN
有條件的 GAN 生成帶有所需標簽的圖像。 例如,我們可以要求模型生成數字 8,而模型將生成數字 8。為此,需要標簽以及使用模型訓練的噪聲,如下所示:
```py
gan = tf.contrib.gan.gan_model(
get_generator,
get_discriminator,
real_images,
(input_noise, labels))
```
其余的訓練與原始 GAN 相似。 接下來,我們將使用 GAN 壓縮圖像。
# 對抗損失
對抗性損失是來自生成器的損失。 該損失可以與偽圖像和真實圖像之間的逐像素損失相結合,以形成組合的對抗性損失。 GAN 模型必須隨`real_images`一起提供給生成器和判別器,如下所示:
```py
gan = tf.contrib.gan.gan_model(
get_autoencoder,
get_discriminator,
real_images,
real_images)
```
生成器是一個自編碼器。 可以在第 3 章,“圖像檢索”中找到該實現。 此后,我們將使用以下代碼定義損失:
```py
loss = tf.contrib.gan.gan_loss(
gan, gradient_penalty=1.0)
l1_pixel_loss = tf.norm(gan.real_data - gan.generated_data, ord=1)
loss = tf.contrib.gan.losses.combine_adversarial_loss(
loss, gan, l1_pixel_loss, weight_factor=1)
```
GAN 損失的梯度是不利的。 然后,計算逐像素損失并將其添加到損失的損失中。 訓練此模型將創建一個功能強大的自編碼器,可用于圖像壓縮。
# 圖片轉換
正如我們在應用部分中所了解的,可以將一個圖像轉換為另一個圖像。 輸入圖像被提供給判別器,而目標圖像被提供給生成器,同時創建 GAN 模型,如下所示:
```py
gan = tf.contrib.gan.gan_model(
get_generator,
get_discriminator,
real_images,
input_images)
```
除像素級損失外,最小二乘損失也用于訓練模型。 可以使用以下代碼進行計算:
```py
loss = tf.contrib.gan.gan_loss(
gan,
tf.contrib.gan.losses.least_squares_generator_loss,
tf.contrib.gan.losses.least_squares_discriminator_loss)
l1_loss = tf.norm(gan.real_data - gan.generated_data, ord=1)
gan_loss = tf.contrib.gan.losses.combine_adversarial_loss(
loss, gan, l1_loss, weight_factor=1)
```
使用此技術,可以將一個圖像轉換為另一個圖像。
# InfoGAN
InfoGAN 無需任何明確的監督訓練即可生成所需標簽的圖像。 `infogan_model`接受非結構化和結構化的輸入,如以下代碼所示:
```py
info_gan = tf.contrib.gan.infogan_model(
get_generator,
get_discriminator,
real_images,
unstructured_input,
structured_input)
loss = tf.contrib.gan.gan_loss(
info_gan,
gradient_penalty_weight=1,
gradient_penalty_epsilon=1e-10,
mutual_information_penalty_weight=1)
```
由于訓練不穩定,因此將損失定義為罰款。 增加罰分可以在訓練過程中提供更大的穩定性。
# GAN 的缺點
GAN 生成的圖像具有一些缺點,例如計數,透視圖和全局結構。 當前正在廣泛研究以改進模型。
# 視覺對話模型
**視覺對話模型**(**VDM**)可以基于圖像進行聊天。 VDM 應用了計算機視覺,**自然語言處理**(**NLP**)和聊天機器人的技術。 它發現了主要的應用,例如向盲人解釋圖像,向醫生解釋醫學掃描,虛擬伴侶等。 接下來,我們將看到解決這一難題的算法。
# VDM 算法
[**Lu 等人**](https://research.fb.com/wp-content/uploads/2017/11/camera_ready_nips2017.pdf)提出了此處討論的算法。 Lu 等人提出了基于 GAN 的 VDM。 生成器生成答案,判別器對這些答案進行排名。 以下是該過程的示意圖:

基于 GAN 技術的 VDM 架構[摘自 Lu 等人]
聊天歷史,當前問題和圖像將作為輸入提供給生成器。 接下來,我們將看到生成器如何工作。
# 生成器
生成器具有編碼器和解碼器。 編碼器將圖像,問題和歷史記錄作為輸入。 編碼器首先關注 **LSTM** 的歷史記錄,并關注圖像的輸出。 流程如下所示:

轉載自 Lu 等人
整個歷史記錄都可用,并且 **LSTM** 記錄了聊天的歷史記錄。 輸出伴隨有產生嵌入的圖像。 編碼器生成的嵌入被解碼器用來創建答案。 解碼器由 RNN 制成。 編碼器和解碼器一起形成生成器,生成可能的答案。 接下來,我們將了解判別器的工作原理。
# 判別器
判別器從生成器獲取生成的序列并對其進行排序。 排名是通過對 n 對損失學習的嵌入完成的。 n 對損失類似于三元組損失,不同之處在于使用幾對正負對進行比較。 這是該模型產生的一些結果。

轉載自 Lu 等人
結果是合理的,并且比簡單的判別器產生的結果更好。
# 總結
在本章中,我們了解了生成模型和大量應用。 我們實現它們是為了在保留內容的同時將樣式從一種轉換為另一種。 我們看到了 GAN 背后的直覺和經過訓練的模型可以做到這一點。 最后,我們了解了視覺對話系統。
在下一章中,我們將學習用于視頻分析的深度學習方法。 我們將看到如何通過攝像機,文件等訪問視頻內容。 我們將通過在幀級別和整個視頻上應用分類來實現視頻分類。 稍后,我們將看到如何跟蹤視頻中的對象。
- TensorFlow 1.x 深度學習秘籍
- 零、前言
- 一、TensorFlow 簡介
- 二、回歸
- 三、神經網絡:感知器
- 四、卷積神經網絡
- 五、高級卷積神經網絡
- 六、循環神經網絡
- 七、無監督學習
- 八、自編碼器
- 九、強化學習
- 十、移動計算
- 十一、生成模型和 CapsNet
- 十二、分布式 TensorFlow 和云深度學習
- 十三、AutoML 和學習如何學習(元學習)
- 十四、TensorFlow 處理單元
- 使用 TensorFlow 構建機器學習項目中文版
- 一、探索和轉換數據
- 二、聚類
- 三、線性回歸
- 四、邏輯回歸
- 五、簡單的前饋神經網絡
- 六、卷積神經網絡
- 七、循環神經網絡和 LSTM
- 八、深度神經網絡
- 九、大規模運行模型 -- GPU 和服務
- 十、庫安裝和其他提示
- TensorFlow 深度學習中文第二版
- 一、人工神經網絡
- 二、TensorFlow v1.6 的新功能是什么?
- 三、實現前饋神經網絡
- 四、CNN 實戰
- 五、使用 TensorFlow 實現自編碼器
- 六、RNN 和梯度消失或爆炸問題
- 七、TensorFlow GPU 配置
- 八、TFLearn
- 九、使用協同過濾的電影推薦
- 十、OpenAI Gym
- TensorFlow 深度學習實戰指南中文版
- 一、入門
- 二、深度神經網絡
- 三、卷積神經網絡
- 四、循環神經網絡介紹
- 五、總結
- 精通 TensorFlow 1.x
- 一、TensorFlow 101
- 二、TensorFlow 的高級庫
- 三、Keras 101
- 四、TensorFlow 中的經典機器學習
- 五、TensorFlow 和 Keras 中的神經網絡和 MLP
- 六、TensorFlow 和 Keras 中的 RNN
- 七、TensorFlow 和 Keras 中的用于時間序列數據的 RNN
- 八、TensorFlow 和 Keras 中的用于文本數據的 RNN
- 九、TensorFlow 和 Keras 中的 CNN
- 十、TensorFlow 和 Keras 中的自編碼器
- 十一、TF 服務:生產中的 TensorFlow 模型
- 十二、遷移學習和預訓練模型
- 十三、深度強化學習
- 十四、生成對抗網絡
- 十五、TensorFlow 集群的分布式模型
- 十六、移動和嵌入式平臺上的 TensorFlow 模型
- 十七、R 中的 TensorFlow 和 Keras
- 十八、調試 TensorFlow 模型
- 十九、張量處理單元
- TensorFlow 機器學習秘籍中文第二版
- 一、TensorFlow 入門
- 二、TensorFlow 的方式
- 三、線性回歸
- 四、支持向量機
- 五、最近鄰方法
- 六、神經網絡
- 七、自然語言處理
- 八、卷積神經網絡
- 九、循環神經網絡
- 十、將 TensorFlow 投入生產
- 十一、更多 TensorFlow
- 與 TensorFlow 的初次接觸
- 前言
- 1.?TensorFlow 基礎知識
- 2. TensorFlow 中的線性回歸
- 3. TensorFlow 中的聚類
- 4. TensorFlow 中的單層神經網絡
- 5. TensorFlow 中的多層神經網絡
- 6. 并行
- 后記
- TensorFlow 學習指南
- 一、基礎
- 二、線性模型
- 三、學習
- 四、分布式
- TensorFlow Rager 教程
- 一、如何使用 TensorFlow Eager 構建簡單的神經網絡
- 二、在 Eager 模式中使用指標
- 三、如何保存和恢復訓練模型
- 四、文本序列到 TFRecords
- 五、如何將原始圖片數據轉換為 TFRecords
- 六、如何使用 TensorFlow Eager 從 TFRecords 批量讀取數據
- 七、使用 TensorFlow Eager 構建用于情感識別的卷積神經網絡(CNN)
- 八、用于 TensorFlow Eager 序列分類的動態循壞神經網絡
- 九、用于 TensorFlow Eager 時間序列回歸的遞歸神經網絡
- TensorFlow 高效編程
- 圖嵌入綜述:問題,技術與應用
- 一、引言
- 三、圖嵌入的問題設定
- 四、圖嵌入技術
- 基于邊重構的優化問題
- 應用
- 基于深度學習的推薦系統:綜述和新視角
- 引言
- 基于深度學習的推薦:最先進的技術
- 基于卷積神經網絡的推薦
- 關于卷積神經網絡我們理解了什么
- 第1章概論
- 第2章多層網絡
- 2.1.4生成對抗網絡
- 2.2.1最近ConvNets演變中的關鍵架構
- 2.2.2走向ConvNet不變性
- 2.3時空卷積網絡
- 第3章了解ConvNets構建塊
- 3.2整改
- 3.3規范化
- 3.4匯集
- 第四章現狀
- 4.2打開問題
- 參考
- 機器學習超級復習筆記
- Python 遷移學習實用指南
- 零、前言
- 一、機器學習基礎
- 二、深度學習基礎
- 三、了解深度學習架構
- 四、遷移學習基礎
- 五、釋放遷移學習的力量
- 六、圖像識別與分類
- 七、文本文件分類
- 八、音頻事件識別與分類
- 九、DeepDream
- 十、自動圖像字幕生成器
- 十一、圖像著色
- 面向計算機視覺的深度學習
- 零、前言
- 一、入門
- 二、圖像分類
- 三、圖像檢索
- 四、對象檢測
- 五、語義分割
- 六、相似性學習
- 七、圖像字幕
- 八、生成模型
- 九、視頻分類
- 十、部署
- 深度學習快速參考
- 零、前言
- 一、深度學習的基礎
- 二、使用深度學習解決回歸問題
- 三、使用 TensorBoard 監控網絡訓練
- 四、使用深度學習解決二分類問題
- 五、使用 Keras 解決多分類問題
- 六、超參數優化
- 七、從頭開始訓練 CNN
- 八、將預訓練的 CNN 用于遷移學習
- 九、從頭開始訓練 RNN
- 十、使用詞嵌入從頭開始訓練 LSTM
- 十一、訓練 Seq2Seq 模型
- 十二、深度強化學習
- 十三、生成對抗網絡
- TensorFlow 2.0 快速入門指南
- 零、前言
- 第 1 部分:TensorFlow 2.00 Alpha 簡介
- 一、TensorFlow 2 簡介
- 二、Keras:TensorFlow 2 的高級 API
- 三、TensorFlow 2 和 ANN 技術
- 第 2 部分:TensorFlow 2.00 Alpha 中的監督和無監督學習
- 四、TensorFlow 2 和監督機器學習
- 五、TensorFlow 2 和無監督學習
- 第 3 部分:TensorFlow 2.00 Alpha 的神經網絡應用
- 六、使用 TensorFlow 2 識別圖像
- 七、TensorFlow 2 和神經風格遷移
- 八、TensorFlow 2 和循環神經網絡
- 九、TensorFlow 估計器和 TensorFlow HUB
- 十、從 tf1.12 轉換為 tf2
- TensorFlow 入門
- 零、前言
- 一、TensorFlow 基本概念
- 二、TensorFlow 數學運算
- 三、機器學習入門
- 四、神經網絡簡介
- 五、深度學習
- 六、TensorFlow GPU 編程和服務
- TensorFlow 卷積神經網絡實用指南
- 零、前言
- 一、TensorFlow 的設置和介紹
- 二、深度學習和卷積神經網絡
- 三、TensorFlow 中的圖像分類
- 四、目標檢測與分割
- 五、VGG,Inception,ResNet 和 MobileNets
- 六、自編碼器,變分自編碼器和生成對抗網絡
- 七、遷移學習
- 八、機器學習最佳實踐和故障排除
- 九、大規模訓練
- 十、參考文獻