# Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版（七）（4）

Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版（七）（3）https://developer.aliyun.com/article/1482451

## 去噪自编码器

dropout_encoder = tf.keras.Sequential([
tf.keras.layers.Flatten(),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(100, activation="relu"),
tf.keras.layers.Dense(30, activation="relu")
])
dropout_decoder = tf.keras.Sequential([
tf.keras.layers.Dense(100, activation="relu"),
tf.keras.layers.Dense(28 * 28),
tf.keras.layers.Reshape([28, 28])
])
dropout_ae = tf.keras.Sequential([dropout_encoder, dropout_decoder])


## 稀疏自编码器

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])


###### 方程 17-1. Kullback–Leibler 散度

D KL ( P ∥ Q ) = ∑ i P ( i ) log P(i) Q(i)

###### 方程 17-2. 目标稀疏度p和实际稀疏度q之间的 KL 散度

D KL ( p ∥ q ) = p log p q + ( 1 - p ) log 1-p 1-q

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])


## 变分自编码器

2013 年，Diederik Kingma 和 Max Welling⁠⁶引入了一个重要类别的自编码器，并迅速成为最受欢迎的变体之一：变分自编码器（VAEs）。

VAEs 在这些特定方面与我们迄今讨论过的所有自编码器都有很大不同：

• 它们是概率自编码器，这意味着它们的输出在训练后部分地由机会决定（与去噪自编码器相反，在训练期间仅使用随机性）。
• 最重要的是，它们是生成自编码器，这意味着它们可以生成看起来像是从训练集中采样的新实例。

###### 方程 17-3。变分自编码器的潜在损失

L=-12∑i=1n1+log(σi2)-σi2-μi2

###### 方程 17-4。变分自编码器的潜在损失，使用γ = log(σ²)重写

L=-12∑i=1n1+γi-exp(γi)-μi2

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.compile(loss="mse", optimizer="nadam")
history = variational_ae.fit(X_train, X_train, epochs=25, batch_size=128,
validation_data=(X_valid, X_valid))


## 生成时尚 MNIST 图像

codings = tf.random.normal(shape=[3 * 7, codings_size])
images = variational_decoder(codings).numpy()


###### 图 17-12. 由变分自编码器生成的时尚 MNIST 图像

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()


## 生成对抗网络

###### 图 17-14. 生成对抗网络

• 在第一阶段，我们训练鉴别器。从训练集中抽取一批真实图像，并通过生成器生成相同数量的假图像来完成。标签设置为 0 表示假图像，1 表示真实图像，并且鉴别器在这个带标签的批次上进行一步训练，使用二元交叉熵损失。重要的是，在这个阶段只有鉴别器的权重被优化。
• 在第二阶段，我们训练生成器。我们首先使用它生成另一批假图像，然后再次使用鉴别器来判断图像是假的还是真实的。这次我们不在批次中添加真实图像，所有标签都设置为 1（真实）：换句话说，我们希望生成器生成鉴别器会（错误地）认为是真实的图像！在这一步骤中，鉴别器的权重被冻结，因此反向传播只影响生成器的权重。
###### 注意

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")

###### 注意

trainable属性只有在编译模型时才会被 Keras 考虑，因此在运行此代码后，如果我们调用其fit()方法或train_on_batch()方法（我们将使用），则discriminator是可训练的，而在调用这些方法时gan模型是不可训练的。

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)


• 在第一阶段，我们向生成器提供高斯噪声以生成假图像，并通过连接相同数量的真实图像来完成这一批次。目标y1设置为 0 表示假图像，1 表示真实图像。然后我们对这一批次训练鉴别器。请记住，在这个阶段鉴别器是可训练的，但我们不会触及生成器。
• 在第二阶段，我们向 GAN 提供一些高斯噪声。其生成器将开始生成假图像，然后鉴别器将尝试猜测这些图像是假还是真实的。在这个阶段，我们试图改进生成器，这意味着我们希望鉴别器失败：这就是为什么目标y2都设置为 1，尽管图像是假的。在这个阶段，鉴别器是可训练的，因此gan模型中唯一会改进的部分是生成器。

codings = tf.random.normal(shape=[batch_size, codings_size])
generated_images = generator.predict(codings)


### 深度卷积 GAN

• 用步进卷积（在鉴别器中）和转置卷积（在生成器中）替换任何池化层。
• 在生成器和鉴别器中使用批量归一化，除了生成器的输出层和鉴别器的输入层。
• 删除更深层次架构的全连接隐藏层。
• 在生成器的所有层中使用 ReLU 激活，除了输出层应使用 tanh。
• 在鉴别器的所有层中使用泄漏 ReLU 激活。

codings_size = 100
generator = tf.keras.Sequential([
tf.keras.layers.Dense(7 * 7 * 128),
tf.keras.layers.Reshape([7, 7, 128]),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Conv2DTranspose(64, kernel_size=5, strides=2,
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Conv2DTranspose(1, kernel_size=5, strides=2,
])
discriminator = tf.keras.Sequential([
activation=tf.keras.layers.LeakyReLU(0.2)),
tf.keras.layers.Dropout(0.4),
activation=tf.keras.layers.LeakyReLU(0.2)),
tf.keras.layers.Dropout(0.4),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(1, activation="sigmoid")
])
gan = tf.keras.Sequential([generator, discriminator])


X_train_dcgan = X_train.reshape(-1, 28, 28, 1) * 2. - 1. # reshape and rescale


## 扩散模型

###### 方程 17-5. 前向扩散过程的概率分布 q

q(xt|xt-1)=N(1-βtxt-1,βtI)

###### 方程 17-6. 前向扩散过程的快捷方式

q(xt|x0)=Nα¯tx0,(1-α¯t)I

###### 方程 17-7。前向扩散过程的方差计划方程

βt=1-α¯tα¯t-1，其中 α¯t=f(t)f(0) 和 f(t)=cos(t/T+s1+s·π2)2

• s是一个微小值，防止β[t]在t = 0 附近太小。在论文中，作者使用了s = 0.008。
• β[t]被剪切为不大于 0.999，以避免在t = T附近的不稳定性。

###### 图 17-21。噪声方差计划β[t]，以及剩余信号方差α̅[t]

def variance_schedule(T, s=0.008, max_beta=0.999):
t = np.arange(T + 1)
f = np.cos((t / T + s) / (1 + s) * np.pi / 2) ** 2
alpha = np.clip(f[1:] / f[:-1], 1 - max_beta, 1)
alpha = np.append(1, alpha).astype(np.float32)  # add α₀ = 1
beta = 1 - alpha
alpha_cumprod = np.cumprod(alpha)
return alpha, alpha_cumprod, beta  # αₜ , α̅ₜ , βₜ for t = 0 to T
T = 4000
alpha, alpha_cumprod, beta = variance_schedule(T)


def prepare_batch(X):
X = tf.cast(X[..., tf.newaxis], tf.float32) * 2 - 1  # scale from –1 to +1
X_shape = tf.shape(X)
t = tf.random.uniform([X_shape[0]], minval=1, maxval=T + 1, dtype=tf.int32)
alpha_cm = tf.gather(alpha_cumprod, t)
alpha_cm = tf.reshape(alpha_cm, [X_shape[0]] + [1] * (len(X_shape) - 1))
noise = tf.random.normal(X_shape)
return {
"X_noisy": alpha_cm ** 0.5 * X + (1 - alpha_cm) ** 0.5 * noise,
"time": t,
}, noise


• 为简单起见，我们将使用 Fashion MNIST，因此函数必须首先添加一个通道轴。将像素值从-1 缩放到 1 也会有所帮助，这样它更接近均值为 0，方差为 1 的最终高斯分布。
• 接下来，该函数创建t，一个包含每个图像批次中随机时间步长的向量，介于 1 和T之间。
• 然后它使用tf.gather()来获取向量t中每个时间步长的alpha_cumprod的值。这给我们了向量alpha_cm，其中包含每个图像的一个α̅[t]值。
• 下一行将alpha_cm从[批次大小]重塑为[批次大小, 1, 1, 1]。这是为了确保alpha_cm可以与批次X进行广播。
• 然后我们生成一些均值为 0，方差为 1 的高斯噪声。
• 最后，我们使用方程 17-6 将扩散过程应用于图像。请注意，x ** 0.5等于x的平方根。该函数返回一个包含输入和目标的元组。输入表示为一个 Python dict，其中包含嘈杂图像和用于生成每个图像的时间步。目标是用于生成每个图像的高斯噪声。
###### 注意

def prepare_dataset(X, batch_size=32, shuffle=False):
ds = tf.data.Dataset.from_tensor_slices(X)
if shuffle:
ds = ds.shuffle(buffer_size=10_000)
return ds.batch(batch_size).map(prepare_batch).prefetch(1)
train_set = prepare_dataset(X_train, batch_size=32, shuffle=True)
valid_set = prepare_dataset(X_valid, batch_size=32)


def build_diffusion_model():
X_noisy = tf.keras.layers.Input(shape=[28, 28, 1], name="X_noisy")
time_input = tf.keras.layers.Input(shape=[], dtype=tf.int32, name="time")
[...]  # build the model based on the noisy images and the time steps
outputs = [...]  # predict the noise (same shape as the input images)
return tf.keras.Model(inputs=[X_noisy, time_input], outputs=[outputs])


DDPM 的作者使用了一个修改过的U-Net 架构，它与我们在第十四章中讨论的 FCN 架构有许多相似之处，用于语义分割：它是一个卷积神经网络，逐渐对输入图像进行下采样，然后再逐渐对其进行上采样，跳跃连接从每个下采样部分的每个级别跨越到相应的上采样部分的级别。为了考虑时间步长，他们使用了与Transformer架构中的位置编码相同的技术对其进行编码（参见第十六章）。在 U-Net 架构的每个级别上，他们通过Dense层传递这些时间编码，并将它们馈送到 U-Net 中。最后，他们还在各个级别使用了多头注意力层。查看本章的笔记本以获取基本实现，或者https://homl.info/ddpmcode以获取官方实现：它基于已弃用的 TF 1.x，但非常易读。

model = build_diffusion_model()
history = model.fit(train_set, validation_data=valid_set, epochs=100)


###### 方程 17-8。在扩散过程中向后走一步

xt-1=1αtxt-βt1-α¯tϵθ(xt,t)+βtz

def generate(model, batch_size=32):
X = tf.random.normal([batch_size, 28, 28, 1])
for t in range(T, 0, -1):
noise = (tf.random.normal if t > 1 else tf.zeros)(tf.shape(X))
X_noise = model({"X_noisy": X, "time": tf.constant([t] * batch_size)})
X = (
1 / alpha[t] ** 0.5
* (X - beta[t] / (1 - alpha_cumprod[t]) ** 0.5 * X_noise)
+ (1 - alpha[t]) ** 0.5 * noise
)
return X
X_gen = generate(model)  # generated images


## 练习

1. 自编码器主要用于哪些任务？
2. 假设你想要训练一个分类器，你有大量未标记的训练数据，但只有几千个标记实例。自编码器如何帮助？你会如何继续？
3. 如果自编码器完美地重建输入，它一定是一个好的自编码器吗？你如何评估自编码器的性能？
4. 什么是欠完备和过完备自编码器？过度欠完备自编码器的主要风险是什么？过度完备自编码器的主要风险又是什么？
5. 如何在堆叠自编码器中绑定权重？这样做的目的是什么？
6. 什么是生成模型？你能说出一种生成自编码器吗？
7. 什么是 GAN？你能说出几个 GAN 可以发挥作用的任务吗？
8. 训练 GAN 时的主要困难是什么？
9. 扩散模型擅长什么？它们的主要限制是什么？
10. 尝试使用去噪自编码器预训练图像分类器。您可以使用 MNIST（最简单的选项），或者如果您想要更大的挑战，可以使用更复杂的图像数据集，比如CIFAR10。无论您使用的数据集是什么，都要遵循以下步骤：
1. 将数据集分割成训练集和测试集。在完整的训练集上训练一个深度去噪自编码器。
2. 检查图像是否被相当好地重建。可视化激活编码层中每个神经元的图像。
3. 构建一个分类 DNN，重用自编码器的较低层。仅使用训练集中的 500 张图像进行训练。它在有无预训练的情况下表现更好吗？
1. 在您选择的图像数据集上训练一个变分自编码器，并使用它生成图像。或者，您可以尝试找到一个您感兴趣的无标签数据集，看看是否可以生成新样本。
2. 训练一个 DCGAN 来处理您选择的图像数据集，并使用它生成图像。添加经验重放，看看这是否有帮助。将其转换为条件 GAN，您可以控制生成的类别。
3. 浏览 KerasCV 出色的稳定扩散教程，并生成一幅漂亮的图画，展示一只读书的蝾螈。如果您在 Twitter 上发布您最好的图画，请在@ aureliengeron 处标记我。我很想看看您的创作！

¹ William G. Chase 和 Herbert A. Simon，“国际象棋中的感知”，认知心理学 4，第 1 期（1973 年）：55-81。

² Yoshua Bengio 等，“深度网络的贪婪逐层训练”，第 19 届神经信息处理系统国际会议论文集（2006）：153-160。

³ Jonathan Masci 等，“用于分层特征提取的堆叠卷积自编码器”，第 21 届国际人工神经网络会议论文集 1（2011）：52-59。

⁴ Pascal Vincent 等，“使用去噪自编码器提取和组合稳健特征”，第 25 届国际机器学习会议论文集（2008）：1096-1103。

⁵ Pascal Vincent 等，“堆叠去噪自编码器：使用局部去噪标准在深度网络中学习有用的表示”，机器学习研究杂志 11（2010）：3371-3408。

⁶ Diederik Kingma 和 Max Welling，“自编码变分贝叶斯”，arXiv 预印本 arXiv:1312.6114（2013）。

⁷ 变分自编码器实际上更通用；编码不限于高斯分布。

⁸ 要了解更多数学细节，请查看有关变分自编码器的原始论文，或查看 Carl Doersch 的优秀教程（2016）。

⁹ Ian Goodfellow 等，“生成对抗网络”，第 27 届神经信息处理系统国际会议论文集 2（2014）：2672-2680。

¹⁰ 要了解主要 GAN 损失的良好比较，请查看 Hwalsuk Lee 的这个GitHub 项目

¹¹ Mario Lucic 等，“GAN 是否平等？大规模研究”，第 32 届神经信息处理系统国际会议论文集（2018）：698-707。

¹² Alec Radford 等，“使用深度卷积生成对抗网络进行无监督表示学习”，arXiv 预印本 arXiv:1511.06434（2015）。

¹³ 在作者的亲切授权下再现。

¹⁴ Mehdi Mirza 和 Simon Osindero，“有条件生成对抗网络”，arXiv 预印本 arXiv:1411.1784（2014）。

¹⁵ Tero Karras 等，“用于改善质量、稳定性和变化的 GAN 的渐进增长”，国际学习表示会议论文集（2018）。

¹⁶ 变量的动态范围是其可能取的最高值和最低值之间的比率。

¹⁷ Tero Karras 等人，“基于风格的生成对抗网络架构”，arXiv 预印本 arXiv:1812.04948（2018）。

¹⁸ 在作者的亲切授权下复制。

¹⁹ Jascha Sohl-Dickstein 等人，“使用非平衡热力学进行深度无监督学习”，arXiv 预印本 arXiv:1503.03585（2015）。

²⁰ Jonathan Ho 等人，“去噪扩散概率模型”（2020）。

²¹ Alex Nichol 和 Prafulla Dhariwal，“改进的去噪扩散概率模型”（2021）。

²² Olaf Ronneberger 等人，“U-Net：用于生物医学图像分割的卷积网络”，arXiv 预印本 arXiv:1505.04597（2015）。

²³ Robin Rombach，Andreas Blattmann 等人，“使用潜在扩散模型进行高分辨率图像合成”，arXiv 预印本 arXiv:2112.10752（2021）。

|
5天前
|

【5月更文挑战第9天】Sklearn是Python热门机器学习库，提供丰富算法和预处理工具。本文深入讲解基础概念、核心理论、常见问题及解决策略。内容涵盖模型选择与训练、预处理、交叉验证、分类回归、模型评估、数据集划分、正则化、编码分类变量、特征选择与降维、集成学习、超参数调优、模型评估、保存加载及模型解释。学习Sklearn是迈入机器学习领域的关键。
26 3
|
5天前
|

Python深度学习基于Tensorflow（5）机器学习基础
Python深度学习基于Tensorflow（5）机器学习基础
18 2
|
5天前
|

18 0
|
5天前
|

【Python 机器学习专栏】使用 TensorFlow 构建深度学习模型
【4月更文挑战第30天】本文介绍了如何使用 TensorFlow 构建深度学习模型。TensorFlow 是谷歌的开源深度学习框架，具备强大计算能力和灵活编程接口。构建模型涉及数据准备、模型定义、选择损失函数和优化器、训练、评估及模型保存部署。文中以全连接神经网络为例，展示了从数据预处理到模型训练和评估的完整流程。此外，还提到了 TensorFlow 的自动微分、模型可视化和分布式训练等高级特性。通过本文，读者可掌握 TensorFlow 基本用法，为构建高效深度学习模型打下基础。
35 0
|
5天前
|

TensorFlow 2keras开发深度学习模型实例：多层感知器（MLP），卷积神经网络（CNN）和递归神经网络（RNN）
TensorFlow 2keras开发深度学习模型实例：多层感知器（MLP），卷积神经网络（CNN）和递归神经网络（RNN）
11 0
|
5天前
|

TensorFlow、Keras 和 Python 构建神经网络分析鸢尾花iris数据集|代码数据分享
TensorFlow、Keras 和 Python 构建神经网络分析鸢尾花iris数据集|代码数据分享
33 0
|
5天前
|

TensorFlow分布式训练：加速深度学习模型训练
【4月更文挑战第17天】TensorFlow分布式训练加速深度学习模型训练，通过数据并行和模型并行利用多机器资源，减少训练时间。优化策略包括配置计算资源、优化数据划分和减少通信开销。实际应用需关注调试监控、系统稳定性和容错性，以应对分布式训练挑战。
39 0
|
5天前
|

Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版（九）（2）
Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版（九）
157 0
|
5天前
|

TensorFlow Lite，ML Kit 和 Flutter 移动深度学习：6~11（5）
TensorFlow Lite，ML Kit 和 Flutter 移动深度学习：6~11（5）
76 0
|
2天前
|

【5月更文挑战第18天】本文介绍了TensorFlow深度学习入门，包括TensorFlow的概述和一个简单的CNN手写数字识别例子。TensorFlow是由谷歌开发的开源机器学习框架，以其灵活性、可扩展性和高效性著称。文中展示了如何安装TensorFlow，加载MNIST数据集，构建并编译CNN模型，以及训练和评估模型。此外，还提供了预测及可视化结果的代码示例。
18 6