提交 4880fa13 编写于 作者: W wizardforcel

ch15 style

上级 de4026a2
......@@ -64,7 +64,7 @@ OReilly Hands On Machine Learning with Scikit Learn and TensorFlow
| 十二、设备和服务器上的分布式TensorFlow | |
| 十三、卷积神经网络 | [@akonwang](https://github.com/wangxupeng) [@WilsonQu](https://github.com/WilsonQu) | [@飞龙](https://github.com/wizardforcel) |
| 十四、循环神经网络 | [@akonwang](https://github.com/wangxupeng) |
| 十五、自编码器 | [@akonwang](https://github.com/wangxupeng) |
| 十五、自编码器 | [@akonwang](https://github.com/wangxupeng) | [@飞龙](https://github.com/wizardforcel) |
| 十六、强化学习 | |
| 其它 | [@片刻](https://github.com/jiangzhonglian) |
......
......@@ -32,7 +32,7 @@
以下代码构建了一个简单的线性自编码器,以在 3D 数据集上执行 PCA,并将其投影到 2D:
```
```py
import tensorflow as tf
from tensorflow.contrib.layers import fully_connected
n_inputs = 3 # 3D inputs
......@@ -57,7 +57,7 @@ init = tf.global_variables_initializer()
现在让我们加载数据集,在训练集上训练模型,并使用它来对测试集进行编码(即将其投影到 2D):
```
```py
X_train, X_test = [...] # load the dataset
n_iterations = 1000
codings = hidden # the output of the hidden layer provides the codings
......@@ -84,7 +84,7 @@ with tf.Session() as sess:
您可以像常规深度 MLP 一样实现栈式自编码器。 特别是,我们在第 11 章中用于训练深度网络的技术也可以应用。例如,下面的代码使用 He 初始化,ELU 激活函数和 l2 正则化为 MNIST 构建一个栈式自编码器。 代码应该看起来很熟悉,除了没有标签(没有`y`):
```
```py
n_inputs = 28 * 28 # for MNIST
n_hidden1 = 300
n_hidden2 = 150 # codings
......@@ -117,7 +117,7 @@ init = tf.global_variables_initializer()
然后可以正常训练模型。 请注意,数字标签(`y_batch`)未使用:
```
```py
n_epochs = 5
batch_size = 150
with tf.Session() as sess:
......@@ -135,7 +135,7 @@ with tf.Session() as sess:
具体来说,如果自编码器总共具有`N`个层(不计入输入层),并且 $W_[L]$ 表示第`L`层的连接权重(例如,层1是第一隐藏层,则层`N / 2`是编码 层,而层`N`是输出层),则解码器层权重可以简单地定义为: $W_[N-L + 1]= W_[L]T$ (其中`L = 1,2,...,N2`)。
不幸的是,使用`fully_connected()`函数在 TensorFlow 中实现相关权重有点麻烦;手动定义层实际上更容易。 代码结尾明显更加冗长:
```
```py
activation = tf.nn.elu
regularizer = tf.contrib.layers.l2_regularizer(l2_reg)
initializer = tf.contrib.layers.variance_scaling_initializer()
......@@ -200,7 +200,7 @@ init = tf.global_variables_initializer()
TensorFlow 代码如下所示:
```
```py
[...] # Build the whole stacked autoencoder normally.
# In this example, the weights are not tied.
optimizer = tf.train.AdamOptimizer(learning_rate)
......@@ -232,7 +232,7 @@ with tf.name_scope("phase2"):
确保自编码器得到适当训练的一种方法是比较输入和输出。 它们必须非常相似,差异应该是不重要的细节。 我们来绘制两个随机数字及其重建:
```
```py
n_test_digits = 2
X_test = mnist.test.images[:n_test_digits]
......@@ -260,7 +260,7 @@ for digit_index in range(n_test_digits):
让我们看看另一种技术。 对于第一个隐藏层中的每个神经元,您可以创建一个图像,其中像素的强度对应于给定神经元的连接权重。 例如,以下代码绘制了第一个隐藏层中五个神经元学习的特征:
```
```py
with tf.Session() as sess:
[...] # train autoencoder
weights1_val = weights1.eval()
......@@ -310,7 +310,7 @@ TensorFlow 的实现没有什么特别之处:只需使用所有训练数据训
在 TensorFlow 中实现去噪自编码器并不难。 我们从高斯噪声开始。 这实际上就像训练一个常规的自编码器一样,除了给输入添加噪声外,重建损耗是根据原始输入计算的:
```
```py
X = tf.placeholder(tf.float32, shape=[None, n_inputs])
X_noisy = X + tf.random_normal(tf.shape(X))
[...]
......@@ -324,7 +324,7 @@ reconstruction_loss = tf.reduce_mean(tf.square(outputs - X)) # MSE
实施更普遍的 dropout 版本,而且这个版本并不困难:
```
```py
from tensorflow.contrib.layers import dropout
keep_prob = 0.7
......@@ -341,7 +341,7 @@ reconstruction_loss = tf.reduce_mean(tf.square(outputs - X)) # MSE
在训练期间,我们必须使用`feed_dict``is_training`设置为`True`(如第 11 章所述):
```
```py
sess.run(training_op, feed_dict={X: X_batch, is_training: True})
```
......@@ -367,11 +367,11 @@ sess.run(training_op, feed_dict={X: X_batch, is_training: True})
一旦我们已经计算了编码层中每个神经元的稀疏损失,我们就总结这些损失,并将结果添加到损失函数中。 为了控制稀疏损失和重构损失的相对重要性,我们可以用稀疏权重超参数乘以稀疏损失。 如果这个权重太高,模型会紧贴目标稀疏度,但它可能无法正确重建输入,导致模型无用。 相反,如果它太低,模型将大多忽略稀疏目标,它不会学习任何有趣的功能。
## TensorFlow实现
## TensorFlow 实现
我们现在拥有了使用 TensorFlow 实现稀疏自编码器所需的全部功能:
```
```py
def kl_divergence(p, q):
return p * tf.log(p / q) + (1 - p) * tf.log((1 - p) / (1 - q))
......@@ -392,13 +392,13 @@ training_op = optimizer.minimize(loss)
一个重要的细节是编码层的激活必须介于 0 和 1 之间(但不等于 0 或 1),否则 KL 散度将返回`NaN`(非数字)。 一个简单的解决方案是对编码层使用逻辑激活功能:
```
```py
hidden1 = tf.nn.sigmoid(tf.matmul(X, weights1) + biases1)
```
一个简单的技巧可以加速收敛:不是使用 MSE,我们可以选择一个具有较大梯度的重建损失。 交叉熵通常是一个不错的选择。 要使用它,我们必须对输入进行规范化处理,使它们的取值范围为 0 到 1,并在输出层中使用逻辑激活函数,以便输出也取值为 0 到 1。TensorFlow 的`sigmoid_cross_entropy_with_logits()`函数负责 有效地将 logistic(sigmoid)激活函数应用于输出并计算交叉熵:
```
```py
[...]
logits = tf.matmul(hidden1, weights2) + biases2)
outputs = tf.nn.sigmoid(logits)
......@@ -428,7 +428,7 @@ Diederik Kingma 和 Max Welling 于 2014 年推出了另一类重要的自编码
那么让我们看看损失函数。 它由两部分组成。 首先是通常的重建损失,推动自编码器重现其输入(我们可以使用交叉熵来解决这个问题,如前所述)。 第二种是潜在的损失,推动自编码器使编码看起来像是从简单的高斯分布中采样,为此我们使用目标分布(高斯分布)与编码实际分布之间的 KL 散度。 数学比以前复杂一点,特别是因为高斯噪声,它限制了可以传输到编码层的信息量(从而推动自编码器学习有用的特征)。 幸运的是,这些方程简化为下面的潜在损失代码:
```
```py
eps = 1e-10 # smoothing term to avoid computing log(0) which is NaN
latent_loss = 0.5 * tf.reduce_sum(
tf.square(hidden3_sigma) + tf.square(hidden3_mean)
......@@ -437,14 +437,14 @@ latent_loss = 0.5 * tf.reduce_sum(
一种常见的变体是训练编码器输出`γ= log(σ^2)`而不是`σ`。 只要我们需要`σ`,我们就可以计算`σ= exp(2/γ)`。 这使得编码器可以更轻松地捕获不同比例的`σ`,从而有助于加快收敛速度。 潜在损失结束会变得更简单一些:
```
```py
latent_loss = 0.5 * tf.reduce_sum(
tf.exp(hidden3_gamma) + tf.square(hidden3_mean) - 1 - hidden3_gamma)
```
以下代码使用`log(σ^2)`变体构建图 15-11(左)所示的变分自编码器:
```
```py
n_inputs = 28 * 28 # for MNIST
n_hidden1 = 500
n_hidden2 = 500
......@@ -487,7 +487,7 @@ init = tf.global_variables_initializer()
现在让我们使用这个变分自编码器来生成看起来像手写数字的图像。 我们所需要做的就是训练模型,然后从高斯分布中对随机编码进行采样并对它们进行解码。
```
```py
import numpy as np
n_digits = 60
n_epochs = 50
......@@ -506,7 +506,7 @@ with tf.Session() as sess:
现在我们可以看到由autoencoder生成的“手写”数字是什么样的(参见图15-12):
```
```py
for iteration in range(n_digits):
plt.subplot(n_digits, 10, iteration + 1)
plot_image(outputs_val[iteration])
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册