深度生成模型:稀疏自编码器、变分自编码器与生成对抗网络
1. 稀疏自编码器
稀疏自编码器是一种通过在代价函数中添加约束项,来减少编码层中活跃神经元数量的自编码器。这种约束有助于提取有用的特征,使每个神经元代表一个有意义的特征。
1.1 简单实现方法
- 使用 sigmoid 激活函数将编码值约束在 0 到 1 之间。
- 使用较大的编码层(例如 300 个单元)。
- 对编码层的激活值添加 ℓ1 正则化。
以下是简单实现的代码:
import tensorflow as tf
sparse_l1_encoder = tf.keras.Sequential([
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(100, activation="relu"),
tf.keras.layers.Dense(300, activation="sigmoid"),
tf.keras.layers.ActivityRegularization(l1=1e-4)
])
sparse_l1_decoder = tf.keras.Sequential([
tf.keras.layers.Dense(100, activation="relu"),
tf.keras.layers.Dense(28 * 28),
tf.keras.layers.Reshape([28, 28])
])
sparse_l1_ae = tf.keras.Sequential([sparse_l1_encoder, sparse_l1_decoder])
1.2 基于 KL 散度的实现方法
这种方法通过测量编码层的实际稀疏性,并在其与目标稀疏性不同时对模型进行惩罚。具体步骤如下:
1. 计算每个训练批次中编码层每个神经元的平均激活值。
2. 使用 Kullback–Leibler(KL)散度计算稀疏性损失,并将其添加到代价函数中。
3. 为了控制稀疏性损失和重建损失的相对重要性,可以使用稀疏性权重超参数。
以下是基于 KL 散度的实现代码:
import tensorflow as tf
kl_divergence = tf.keras.losses.kullback_leibler_divergence
class KLDivergenceRegularizer(tf.keras.regularizers.Regularizer):
def __init__(self, weight, target):
self.weight = weight
self.target = target
def __call__(self, inputs):
mean_activities = tf.reduce_mean(inputs, axis=0)
return self.weight * (
kl_divergence(self.target, mean_activities) +
kl_divergence(1. - self.target, 1. - mean_activities))
kld_reg = KLDivergenceRegularizer(weight=5e-3, target=0.1)
sparse_kl_encoder = tf.keras.Sequential([
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(100, activation="relu"),
tf.keras.layers.Dense(300, activation="sigmoid",
activity_regularizer=kld_reg)
])
sparse_kl_decoder = tf.keras.Sequential([
tf.keras.layers.Dense(100, activation="relu"),
tf.keras.layers.Dense(28 * 28),
tf.keras.layers.Reshape([28, 28])
])
sparse_kl_ae = tf.keras.Sequential([sparse_kl_encoder, sparse_kl_decoder])
1.3 稀疏自编码器工作流程
graph LR
A[输入数据] --> B[编码器]
B --> C[编码层(稀疏约束)]
C --> D[解码器]
D --> E[输出重建数据]
2. 变分自编码器
变分自编码器(VAEs)是一种概率生成模型,具有以下特点:
- 概率性:即使在训练后,其输出也部分由随机因素决定。
- 生成性:可以生成看起来像是从训练集中采样的新实例。
2.1 工作原理
变分自编码器的编码器不是直接生成编码,而是生成均值编码 μ 和标准差 σ,然后从具有均值 μ 和标准差 σ 的高斯分布中随机采样得到实际编码,最后由解码器对采样的编码进行解码。
2.2 代价函数
变分自编码器的代价函数由两部分组成:
- 重建损失:促使自编码器重现输入数据,通常使用均方误差(MSE)。
- 潜在损失:促使自编码器的编码看起来像是从简单的高斯分布中采样得到的,即目标分布(高斯分布)和实际编码分布之间的 KL 散度。
潜在损失的计算公式如下:
- 原始公式:
[
\mathcal{L} = -\frac{1}{2} \sum_{i = 1}^{n} (1 + \log \sigma_i^2 - \sigma_i^2 - \mu_i^2)
]
- 使用 γ = log(σ²) 的简化公式:
[
\mathcal{L} = -\frac{1}{2} \sum_{i = 1}^{n} (1 + \gamma_i - \exp(\gamma_i) - \mu_i^2)
]
2.3 代码实现
以下是构建变分自编码器的代码:
import tensorflow as tf
class Sampling(tf.keras.layers.Layer):
def call(self, inputs):
mean, log_var = inputs
return tf.random.normal(tf.shape(log_var)) * tf.exp(log_var / 2) + mean
codings_size = 10
inputs = tf.keras.layers.Input(shape=[28, 28])
Z = tf.keras.layers.Flatten()(inputs)
Z = tf.keras.layers.Dense(150, activation="relu")(Z)
Z = tf.keras.layers.Dense(100, activation="relu")(Z)
codings_mean = tf.keras.layers.Dense(codings_size)(Z) # μ
codings_log_var = tf.keras.layers.Dense(codings_size)(Z) # γ
codings = Sampling()([codings_mean, codings_log_var])
variational_encoder = tf.keras.Model(
inputs=[inputs], outputs=[codings_mean, codings_log_var, codings])
decoder_inputs = tf.keras.layers.Input(shape=[codings_size])
x = tf.keras.layers.Dense(100, activation="relu")(decoder_inputs)
x = tf.keras.layers.Dense(150, activation="relu")(x)
x = tf.keras.layers.Dense(28 * 28)(x)
outputs = tf.keras.layers.Reshape([28, 28])(x)
variational_decoder = tf.keras.Model(inputs=[decoder_inputs], outputs=[outputs])
_, _, codings = variational_encoder(inputs)
reconstructions = variational_decoder(codings)
variational_ae = tf.keras.Model(inputs=[inputs], outputs=[reconstructions])
latent_loss = -0.5 * tf.reduce_sum(
1 + codings_log_var - tf.exp(codings_log_var) - tf.square(codings_mean),
axis=-1)
variational_ae.add_loss(tf.reduce_mean(latent_loss) / 784.)
variational_ae.compile(loss="mse", optimizer="nadam")
history = variational_ae.fit(X_train, X_train, epochs=25, batch_size=128,
validation_data=(X_valid, X_valid))
2.4 变分自编码器工作流程
graph LR
A[输入数据] --> B[编码器]
B --> C[生成 μ 和 σ]
C --> D[从高斯分布采样编码]
D --> E[解码器]
E --> F[输出重建数据]
3. 生成时尚 MNIST 图像
使用训练好的变分自编码器生成时尚物品图像的步骤如下:
1. 从高斯分布中随机采样编码。
2. 使用解码器对采样的编码进行解码。
以下是生成图像的代码:
import tensorflow as tf
codings = tf.random.normal(shape=[3 * 7, codings_size])
images = variational_decoder(codings).numpy()
变分自编码器还支持语义插值,即通过在潜在空间中沿着任意直线采样编码并解码,可以得到从一种物品逐渐过渡到另一种物品的图像序列。
import numpy as np
codings = np.zeros([7, codings_size])
codings[:, 3] = np.linspace(-0.8, 0.8, 7) # axis 3 looks best in this case
images = variational_decoder(codings).numpy()
4. 生成对抗网络
生成对抗网络(GANs)由 Ian Goodfellow 等人在 2014 年提出,它由两个相互对抗的神经网络组成:生成器和判别器。
4.1 网络结构
- 生成器 :接收随机分布(通常是高斯分布)作为输入,输出数据(通常是图像)。可以将随机输入看作是待生成图像的潜在表示(即编码),其功能类似于变分自编码器中的解码器。
- 判别器 :接收来自生成器的假图像或训练集中的真实图像作为输入,判断输入图像是假的还是真实的。
4.2 训练过程
GAN 的训练过程分为两个阶段,每个训练迭代都会交替进行这两个阶段:
1.
训练判别器
:从训练集中采样一批真实图像,同时使用生成器生成相同数量的假图像。将真假图像合并成一个批次,为假图像设置标签 0,为真实图像设置标签 1,然后使用二元交叉熵损失来训练判别器。在这个阶段,只优化判别器的权重。
2.
训练生成器
:使用生成器生成一批假图像,将判别器的标签全部设置为 1(即希望判别器将这些假图像误判为真实图像)。在这个阶段,判别器的权重被冻结,只优化生成器的权重。
4.3 代码实现
以下是构建一个简单 GAN 用于 Fashion MNIST 的代码:
import tensorflow as tf
codings_size = 30
Dense = tf.keras.layers.Dense
generator = tf.keras.Sequential([
Dense(100, activation="relu", kernel_initializer="he_normal"),
Dense(150, activation="relu", kernel_initializer="he_normal"),
Dense(28 * 28, activation="sigmoid"),
tf.keras.layers.Reshape([28, 28])
])
discriminator = tf.keras.Sequential([
tf.keras.layers.Flatten(),
Dense(150, activation="relu", kernel_initializer="he_normal"),
Dense(100, activation="relu", kernel_initializer="he_normal"),
Dense(1, activation="sigmoid")
])
gan = tf.keras.Sequential([generator, discriminator])
discriminator.compile(loss="binary_crossentropy", optimizer="rmsprop")
discriminator.trainable = False
gan.compile(loss="binary_crossentropy", optimizer="rmsprop")
batch_size = 32
dataset = tf.data.Dataset.from_tensor_slices(X_train).shuffle(buffer_size=1000)
dataset = dataset.batch(batch_size, drop_remainder=True).prefetch(1)
def train_gan(gan, dataset, batch_size, codings_size, n_epochs):
generator, discriminator = gan.layers
for epoch in range(n_epochs):
for X_batch in dataset:
# phase 1 - training the discriminator
noise = tf.random.normal(shape=[batch_size, codings_size])
generated_images = generator(noise)
X_fake_and_real = tf.concat([generated_images, X_batch], axis=0)
y1 = tf.constant([[0.]] * batch_size + [[1.]] * batch_size)
discriminator.train_on_batch(X_fake_and_real, y1)
# phase 2 - training the generator
noise = tf.random.normal(shape=[batch_size, codings_size])
y2 = tf.constant([[1.]] * batch_size)
gan.train_on_batch(noise, y2)
train_gan(gan, dataset, batch_size, codings_size, n_epochs=50)
4.4 生成对抗网络工作流程
graph LR
A[随机噪声] --> B[生成器]
B --> C[生成假图像]
C --> D[判别器]
E[真实图像] --> D
D --> F[判断真假]
G[训练信号] --> B
G --> D
4.5 训练过程对比
| 网络类型 | 训练方式 | 输出特点 | 应用场景 |
|---|---|---|---|
| 稀疏自编码器 | 通过添加稀疏约束到代价函数来训练 | 提取有用特征,编码层神经元稀疏激活 | 特征提取 |
| 变分自编码器 | 最小化重建损失和潜在损失 | 生成符合高斯分布编码,可生成新实例 | 数据生成、语义插值 |
| 生成对抗网络 | 生成器和判别器对抗训练 | 生成逼真图像 | 图像生成 |
5. 总结
本文介绍了三种不同类型的生成模型:稀疏自编码器、变分自编码器和生成对抗网络。
- 稀疏自编码器通过添加稀疏约束,使得编码层的神经元更加稀疏,从而提取出更有用的特征。
- 变分自编码器是一种概率生成模型,它的编码服从高斯分布,能够生成新的实例,并且支持语义插值。
- 生成对抗网络由生成器和判别器组成,通过两者的对抗训练,能够生成非常逼真的图像。
这些模型在不同的应用场景中都有各自的优势,在实际应用中可以根据具体需求选择合适的模型。例如,如果需要进行特征提取,可以选择稀疏自编码器;如果需要生成新的数据实例,可以考虑变分自编码器或生成对抗网络。
超级会员免费看
92

被折叠的 条评论
为什么被折叠?



