62、深度生成模型:稀疏自编码器、变分自编码器与生成对抗网络

深度生成模型:稀疏自编码器、变分自编码器与生成对抗网络

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. 总结

本文介绍了三种不同类型的生成模型:稀疏自编码器、变分自编码器和生成对抗网络。
- 稀疏自编码器通过添加稀疏约束,使得编码层的神经元更加稀疏,从而提取出更有用的特征。
- 变分自编码器是一种概率生成模型,它的编码服从高斯分布,能够生成新的实例,并且支持语义插值。
- 生成对抗网络由生成器和判别器组成,通过两者的对抗训练,能够生成非常逼真的图像。

这些模型在不同的应用场景中都有各自的优势,在实际应用中可以根据具体需求选择合适的模型。例如,如果需要进行特征提取,可以选择稀疏自编码器;如果需要生成新的数据实例,可以考虑变分自编码器或生成对抗网络。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值