Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenDocCN
hands-on-ml-zh
提交
4880fa13
H
hands-on-ml-zh
项目概览
OpenDocCN
/
hands-on-ml-zh
通知
13
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
H
hands-on-ml-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
4880fa13
编写于
4月 19, 2018
作者:
W
wizardforcel
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
ch15 style
上级
de4026a2
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
23 addition
and
23 deletion
+23
-23
README.md
README.md
+1
-1
docs/15.自编码器.md
docs/15.自编码器.md
+22
-22
未找到文件。
README.md
浏览文件 @
4880fa13
...
...
@@ -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
)
|
...
...
docs/15.自编码器.md
浏览文件 @
4880fa13
...
...
@@ -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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录