参考书目:Deep Learning with Python
参考视频:Deep Learning with Python 61 Generative Deep Learning-6 神經網路風格遷移-1 (recorded on_哔哩哔哩_bilibili
8.1 使用LSTM生成文本
8.1.1 LSTM介绍
LSTM在之前的处理文本序列(第六章)已经介绍过,作者在这章仍旧使用LSTM层,想起输入从文本语料中提取的N个字符组的字符串,训练模型来生成第N+1个字符。上述为字符级的神经语言模型。
8.1.2 采样策略介绍
贪婪采样:始终选择可能性最大的下一个字符。
随机采样 :在采样过程中引入随机性,即从下一个制度的概率分布中采样。
8.1.3 利用LSTM进行文本生成
针对于文本处理部分在此不再赘述,下面针对于训练语言模型并从中采样进行代码展示。
def sample(preds, temperature=1.0):
preds = np.asarray(preds).astype('float64')
preds = np.log(preds) / temperature
exp_preds = np.exp(preds)
preds = exp_preds / np.sum(exp_preds)
probas = np.random.multinomial(1, preds, 1)
return np.argmax(probas)
上述代码是对模型得到的原始概率分布进行重新加权,并从中抽取一个字符索引。
import random
import sys
for epoch in range(1, 60):
print('epoch', epoch)
# Fit the model for 1 epoch on the available training data
model.fit(x, y,
batch_size=128,
epochs=1)
# Select a text seed at random
start_index = random.randint(0, len(text) - maxlen - 1)
generated_text = text[start_index: start_index + maxlen]
print('--- Generating with seed: "' + generated_text + '"')
for temperature in [0.2, 0.5, 1.0, 1.2]:
print('------ temperature:', temperature)
sys.stdout.write(generated_text)
# We generate 400 characters
for i in range(400):
sampled = np.zeros((1, maxlen, len(chars)))
for t, char in enumerate(generated_text):
sampled[0, t, char_indices[char]] = 1.
preds = model.predict(sampled, verbose=0)[0]
next_index = sample(preds, temperature)
next_char = chars[next_index]
generated_text += next_char
generated_text = generated_text[1:]
sys.stdout.write(next_char)
sys.stdout.flush()
print()
观察所输出的文本,发现不同的温度设置所输出的文本不同。较小的温度值会得到重复较多的文本,但局部结构是非常真实的。而当温度值设置较高时,随机性较大,可能产生一些不存在的单词。
8.2 实现DeepDream
DeepDream和卷积神经网络过滤器可视化技术(第五章)几乎相同,均为反向运行一个卷积神经网络。区别如下:
1.使用DeepDream,是将所有层的激活最大化,而不是将某一层的激活最大化。
2.输入并非从空白的、略带噪声的输入开始,而是从现有的图像开始。
3.输入图像是在不同的尺度上进行处理的。
8.3 实现神经风格迁移
神经风格迁移实际上指的是将两幅图像进行融合,一幅为主图,另一幅为背景图。
风格损失:在风格参考图像与生成图像之间,在不同的层激活内保存相似的内部相互关系。
神经风格迁移可以用卷积神经网络VGG19来实现。过程如下:
(1)创建一个网络,能过同时计算风格参考图像、目标图像和生成图像的VGG19层激活。
(2)使用者三张图像上的层激活来定义之前所述的损失函数,为了实现风格迁移,需要将这个损失函数最小化。
a.内容损失
def content_loss(base, combination):
return K.sum(K.square(combination - base))
b.风格损失
def gram_matrix(x):
features = K.batch_flatten(K.permute_dimensions(x, (2, 0, 1)))
gram = K.dot(features, K.transpose(features))
return gram
def style_loss(style, combination):
S = gram_matrix(style)
C = gram_matrix(combination)
channels = 3
size = img_height * img_width
return K.sum(K.square(S - C)) / (4. * (channels ** 2) * (size ** 2))
c.总变差损失:对生成的组合图像的像素进行操作,促使生成图像具有空间连续性,避免结果过渡像素化。
def total_variation_loss(x):
a = K.square(
x[:, :img_height - 1, :img_width - 1, :] - x[:, 1:, :img_width - 1, :])
b = K.square(
x[:, :img_height - 1, :img_width - 1, :] - x[:, :img_height - 1, 1:, :])
return K.sum(K.pow(a + b, 1.25))
d.定义需要最小化的最终损失
import tensorflow as tf
tf.compat.v1.disable_eager_execution()
# Dict mapping layer names to activation tensors
outputs_dict = dict([(layer.name, layer.output) for layer in model.layers])
# Name of layer used for content loss
content_layer = 'block5_conv2'
# Name of layers used for style loss
style_layers = ['block1_conv1',
'block2_conv1',
'block3_conv1',
'block4_conv1',
'block5_conv1']
# Weights in the weighted average of the loss components
total_variation_weight = 1e-4
style_weight = 1.
content_weight = 0.025
# Define the loss by adding all components to a `loss` variable
loss = K.variable(0.)
layer_features = outputs_dict[content_layer]
target_image_features = layer_features[0, :, :, :]
combination_features = layer_features[2, :, :, :]
loss = loss + content_weight * content_loss(target_image_features,
combination_features)
for layer_name in style_layers:
layer_features = outputs_dict[layer_name]
style_reference_features = layer_features[1, :, :, :]
combination_features = layer_features[2, :, :, :]
sl = style_loss(style_reference_features, combination_features)
loss += (style_weight / len(style_layers)) * sl
loss += total_variation_weight * total_variation_loss(combination_image)
(3)设置梯度下降过程来将这个损失函数最小化。
文章中使用Scipy的L-BGFS进行提付上升过程的操作,在每一次迭代时均保留当前所产出的结果。
8.4 变分自编码器(VAE,variational autoencoder)生成图像
图像生成的要点:找到一个低维的表示潜在空间(latent space),其中任一点都可以被映射为一张逼真的图像。
实现映射的模块:生成器(GAN)或者解码器(VAE)。
8.5 了解生成式对抗网络(GAN,generative adversarial network)
由以下两部分组成:
生成器网络:以一个随机向量作为输入,并将其解码为一张合成图像。
判别器网络或对手:以一张图像作为输入,并预测该图像是来自训练集还是由生成器网络创建。
训练生成器网络的目的是使其能够欺骗判别网络,因此随着训练的进行,它能够逐渐生成越来越逼真的图像,以至于判别器网络无法区分二者。于此同时,判别器也在不断适应生成器逐渐提高的能力,为生成图像的真实性设置了很高的标准。