提交 54918377 编写于 作者: W wizardforcel

2020-08-02 17:17:19

上级 70063c62
# TensorFlow 核心
TensorFlow 核心是较低级别的库,其上构建了更高级别的 TensorFlow 模块。在深入学习高级 TensorFlow 之前,学习低级库的概念非常重要。在本节中,我们将快速回顾所有这些核心概念。
\ No newline at end of file
# 二分类
二分类是指仅有两个不同类的问题。正如我们在上一章中所做的那样,我们将使用 SciKit Learn 库中的便捷函数`make_classification()`生成数据集:
```py
X, y = skds.make_classification(n_samples=200,
n_features=2,
n_informative=2,
n_redundant=0,
n_repeated=0,
n_classes=2,
n_clusters_per_class=1)
if (y.ndim == 1):
y = y.reshape(-1,1)
```
`make_classification()`的论据是不言自明的; `n_samples`是要生成的数据点数,`n_features`是要生成的特征数,`n_classes`是类的数量,即 2:
* `n_samples`是要生成的数据点数。我们将其保持在 200 以保持数据集较小。
* `n_features`是要生成的特征数量;我们只使用两个特征,因此我们可以将它作为一个简单的问题来理解 TensorFlow 命令。
* `n_classes`是类的数量,它是 2,因为它是二分类问题。
让我们使用以下代码绘制数据:
```py
plt.scatter(X[:,0],X[:,1],marker='o',c=y)
plt.show()
```
我们得到以下绘图;您可能会得到一个不同的图,因为每次运行数据生成函数时都会随机生成数据:
![](img/707586af-1084-493a-86a8-f827a115cfa5.png)
然后我们使用 NumPy `eye`函数将`y`转换为单热编码目标:
```py
print(y[0:5])
y=np.eye(num_outputs)[y]
print(y[0:5])
```
单热编码目标如下所示:
```py
[1 0 0 1 0]
[[ 0\. 1.]
[ 1\. 0.]
[ 1\. 0.]
[ 0\. 1.]
[ 1\. 0.]]
```
将数据划分为训练和测试类别:
```py
X_train, X_test, y_train, y_test = skms.train_test_split(
X, y, test_size=.4, random_state=42)
```
在分类中,我们使用 sigmoid 函数来量化模型的值,使得输出值位于范围[0,1]之间。以下等式表示由`φ(z)`表示的 S 形函数,其中`z`是等式`w × x + b`。损失函数现在变为由`J(θ)`表示的值,其中`θ`表示参数。
![](img/af47d49d-2bb6-4e48-b6d3-4d7cd65ff6d5.png)
![](img/e5b82a11-b867-4a43-9f3d-09d6cb44099b.png)
![](img/717945b1-b35a-43d9-a469-44f33de91e8a.png)
我们使用以下代码实现新模型和损失函数:
```py
num_outputs = y_train.shape[1]
num_inputs = X_train.shape[1]
learning_rate = 0.001
# input images
x = tf.placeholder(dtype=tf.float32, shape=[None, num_inputs], name="x")
# output labels
y = tf.placeholder(dtype=tf.float32, shape=[None, num_outputs], name="y")
# model paramteres
w = tf.Variable(tf.zeros([num_inputs,num_outputs]), name="w")
b = tf.Variable(tf.zeros([num_outputs]), name="b")
model = tf.nn.sigmoid(tf.matmul(x, w) + b)
loss = tf.reduce_mean(-tf.reduce_sum(
(y * tf.log(model)) + ((1 - y) * tf.log(1 - model)), axis=1))
optimizer = tf.train.GradientDescentOptimizer(
learning_rate=learning_rate).minimize(loss)
```
最后,我们运行我们的分类模型:
```py
num_epochs = 1
with tf.Session() as tfs:
tf.global_variables_initializer().run()
for epoch in range(num_epochs):
tfs.run(optimizer, feed_dict={x: X_train, y: y_train})
y_pred = tfs.run(tf.argmax(model, 1), feed_dict={x: X_test})
y_orig = tfs.run(tf.argmax(y, 1), feed_dict={y: y_test})
preds_check = tf.equal(y_pred, y_orig)
accuracy_op = tf.reduce_mean(tf.cast(preds_check, tf.float32))
accuracy_score = tfs.run(accuracy_op)
print("epoch {0:04d} accuracy={1:.8f}".format(
epoch, accuracy_score))
plt.figure(figsize=(14, 4))
plt.subplot(1, 2, 1)
plt.scatter(X_test[:, 0], X_test[:, 1], marker='o', c=y_orig)
plt.title('Original')
plt.subplot(1, 2, 2)
plt.scatter(X_test[:, 0], X_test[:, 1], marker='o', c=y_pred)
plt.title('Predicted')
plt.show()
```
我们获得了大约 96%的相当好的准确率,原始和预测的数据图如下所示:
![](img/abc7eea6-1cdf-486e-9f34-0b571ef90b67.png)
很简约!!现在让我们让我们的问题变得复杂,并尝试预测两个以上的类。
\ No newline at end of file
# 多类分类
多类分类的一个流行示例是标记手写数字的图像。此示例中的类或标签为{0,1,2,3,4,5,6,7,8,9}。在以下示例中,我们将使用 MNIST。让我们像前面章节中所做的那样加载 MNIST 图像,代码如下:
```py
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets(os.path.join(
datasetslib.datasets_root, 'mnist'), one_hot=True)
```
如果已按照前一章的说明下载了 MNIST 数据集,那么我们将获得以下输出:
```py
Extracting /Users/armando/datasets/mnist/train-images-idx3-ubyte.gz
Extracting /Users/armando/datasets/mnist/train-labels-idx1-ubyte.gz
Extracting /Users/armando/datasets/mnist/t10k-images-idx3-ubyte.gz
Extracting /Users/armando/datasets/mnist/t10k-labels-idx1-ubyte.gz
```
现在让我们设置一些参数,如下面的代码所示:
```py
num_outputs = 10 # 0-9 digits
num_inputs = 784 # total pixels
learning_rate = 0.001
num_epochs = 1
batch_size = 100
num_batches = int(mnist.train.num_examples/batch_size)
```
上面代码中的参数如下:
* `num_outputs`:由于我们必须预测图像代表十位数中的哪一位,因此我们将输出数设置为 10.数字由打开或设置为 1 的输出表示。
* `num_inputs`:我们知道我们的输入数字是 28 x 28 像素,因此每个像素都是模型的输入。因此,我们总共有 784 个输入。
* `learning_rate`:此参数表示梯度下降优化器算法的学习率。我们将学习率任意设定为 0.001。
* `num_epochs`:我们将仅针对一次迭代运行我们的第一个示例,因此我们将周期数设置为 1。
* `batch_size`:在现实世界中,我们可能拥有庞大的数据集并加载整个数据集以便训练模型可能是不可能的。因此,我们将输入数据分成随机选择的批次。我们将`batch_size`设置为 100 个图像,可以使用 TensorFlow 的内置算法一次选择。
* `num_batches`:此参数设置应从总数据集中选择批次的次数;我们将其设置为等于数据集中的项目数除以批量中的项目数。
我们鼓励您尝试使用这些参数的不同值。
现在让我们使用以下代码定义输入,输出,参数,模型和损失函数:
```py
# input images
x = tf.placeholder(dtype=tf.float32, shape=[None, num_inputs], name="x")
# output labels
y = tf.placeholder(dtype=tf.float32, shape=[None, num_outputs], name="y")
# model paramteres
w = tf.Variable(tf.zeros([784, 10]), name="w")
b = tf.Variable(tf.zeros([10]), name="b")
model = tf.nn.softmax(tf.matmul(x, w) + b)
loss = tf.reduce_mean(-tf.reduce_sum(y * tf.log(model), axis=1))
optimizer = tf.train.GradientDescentOptimizer(
learning_rate=learning_rate).minimize(loss)
```
代码类似于二分类示例,但有一个显着差异:我们使用`softmax`而不是`sigmoid`函数。 Softmax 用于多类分类,而 sigmoid 用于二元类分类。 Softmax 函数是 sigmoid 函数的推广,它将任意实数值的 n 维向量 z 转换为实数值的 n 维向量 _σ(z)_,范围`(0, 1]`和为 1。
现在让我们运行模型并打印精度:
```py
with tf.Session() as tfs:
tf.global_variables_initializer().run()
for epoch in range(num_epochs):
for batch in range(num_batches):
batch_x, batch_y = mnist.train.next_batch(batch_size)
tfs.run(optimizer, feed_dict={x: batch_x, y: batch_y})
predictions_check = tf.equal(tf.argmax(model, 1), tf.argmax(y, 1))
accuracy_function = tf.reduce_mean(
tf.cast(predictions_check, tf.float32))
feed_dict = {x: mnist.test.images, y: mnist.test.labels}
accuracy_score = tfs.run(accuracy_function, feed_dict)
print("epoch {0:04d} accuracy={1:.8f}".format(
epoch, accuracy_score))
```
我们得到以下准确率:
```py
epoch 0000 accuracy=0.76109999
```
让我们尝试在多次迭代中训练我们的模型,以便在每次迭代中学习不同的批次。我们建立了两个支持函数来帮助我们:
```py
def mnist_batch_func(batch_size=100):
batch_x, batch_y = mnist.train.next_batch(batch_size)
return [batch_x, batch_y]
```
上述函数将批量中的示例数作为输入,并使用`mnist.train.next_batch()`函数返回一批特征(`batch_x`)和目标(`batch_y`):
```py
def tensorflow_classification(num_epochs, num_batches, batch_size,
batch_func, optimizer, test_x, test_y):
accuracy_epochs = np.empty(shape=[num_epochs], dtype=np.float32)
with tf.Session() as tfs:
tf.global_variables_initializer().run()
for epoch in range(num_epochs):
for batch in range(num_batches):
batch_x, batch_y = batch_func(batch_size)
feed_dict = {x: batch_x, y: batch_y}
tfs.run(optimizer, feed_dict)
predictions_check = tf.equal(
tf.argmax(model, 1), tf.argmax(y, 1))
accuracy_function = tf.reduce_mean(
tf.cast(predictions_check, tf.float32))
feed_dict = {x: test_x, y: test_y}
accuracy_score = tfs.run(accuracy_function, feed_dict)
accuracy_epochs[epoch] = accuracy_score
print("epoch {0:04d} accuracy={1:.8f}".format(
epoch, accuracy_score))
plt.figure(figsize=(14, 8))
plt.axis([0, num_epochs, np.min(
accuracy_epochs), np.max(accuracy_epochs)])
plt.plot(accuracy_epochs, label='Accuracy Score')
plt.title('Accuracy over Iterations')
plt.xlabel('# Epoch')
plt.ylabel('Accuracy Score')
plt.legend()
plt.show()
```
上述函数获取参数并执行训练迭代,打印每次迭代的准确率分数并打印准确率分数。它还可以保存`accuracy_epochs`数组中每个周期的准确率分数。之后,它绘制了每个周期的准确性。让我们使用我们之前设置的参数运行此函数 30 个周期,使用以下代码:
```py
num_epochs=30
tensorflow_classification(num_epochs=num_epochs,
num_batches=num_batches,
batch_size=batch_size,
batch_func=mnist_batch_func,
optimizer=optimizer,
test_x=mnist.test.images,test_y=mnist.test.labels)
```
我们得到以下准确率和图表:
```py
epoch 0000 accuracy=0.76020002
epoch 0001 accuracy=0.79420000
epoch 0002 accuracy=0.81230003
epoch 0003 accuracy=0.82309997
epoch 0004 accuracy=0.83230001
epoch 0005 accuracy=0.83770001
--- epoch 6 to 24 removed for brevity ---
epoch 0025 accuracy=0.87930000
epoch 0026 accuracy=0.87970001
epoch 0027 accuracy=0.88059998
epoch 0028 accuracy=0.88120002
epoch 0029 accuracy=0.88180000
```
![](img/19db0579-c2c6-4d7a-a4ef-a2417fc5fd2f.png)
从图中我们可以看出,初始迭代中的准确率会急剧提高,然后准确率的提高速度会降低。稍后,我们将看到如何在 TensorFlow 中使用神经网络的全部功能,并将此分类精度提高到更大的值。
\ No newline at end of file
# 总结
在本章中,我们学习了如何在 TensorFlow 中应用经典机器学习算法,而不使用神经网络。在本章的第一部分,我们了解了回归模型。我们解释了如何训练具有一个或多个特征的线性回归模型。我们使用 TensorFlow 编写线性回归代码。我们还讨论了正则化基本上是增加一个惩罚项,以便模型在训练阶段学习参数时不会过拟合训练数据。我们使用 TensorFlow 实现了 Lasso,Ridge 和 ElasticNet 正则化。 TensorFlow 有一些内置的正则化方法,我们将在下一章中学习。
在本章的后续章节中,我们了解了有监督机器学习中的分类问题。我们讨论了两类和多类分类的模型函数,平滑函数和损失函数。我们在本章中使用了逻辑回归,因为这是实现分类的最简单方法。对于二分类,我们使用 sigmoid 函数,对于多类分类,我们使用 softmax 函数来平滑线性模型的值,以产生输出在特定类中的概率。
我们在 TensorFlow 中实现了模型和损失函数的逻辑,并训练模型进行二分类和多类分类。虽然我们在本章中使用了经典的机器学习方法,并使用 TensorFlow 实现了它们,但是当我们实现神经网络和深度神经网络来解决机器学习问题时,TensorFlow 的全部功能得以释放。我们将在本书的神经网络相关章节中研究这些高级方法。
建议您阅读以下书籍以了解有关回归和分类的更多详细信息:
Sebastian Raschka,Python 机器学习,第 2 版,Packt Publishing,2017
Trevor Hastie,Robert Tibshirani,Jerome Friedman,统计学习的要素,第二版,施普林格,2013
\ No newline at end of file
# 使用 TensorFlow 和 Keras 的神经网络和 MLP
神经网络是一种受大脑结构和功能启发的建模技术。正如大脑包含数百万个被称为神经元的微小互连单元一样,今天的神经网络由数百万个分层排列的微小互连计算单元组成。由于神经网络的计算单元仅存在于数字世界中,与大脑的物理神经元相反,它们也被称为人工神经元。类似地,神经网络(NN)也称为人工神经网络(ANN)。
在本章中,我们将进一步扩展以下主题:
* 感知机(人工神经元)
* 前馈神经网络
* **MultiLayer Perceptron****MLP** )用于图像分类
* 基于 TensorFlow 的 MLP 用于 MNIST 图像分类
* 基于 Keras 的 MLP 用于 MNIST 分类
* 基于 TFLearn 的 MLP 用于 MNIST 分类
* MLP 用于时间序列回归
\ No newline at end of file
# 感知机
让我们了解神经网络的最基本构建块,**感知机,**也称为**人工神经元**。感知机的概念起源于 Frank Rosenblatt 于 1962 年的作品。
您可能希望阅读以下工作来探索神经网络的起源:
Frank Rosenblatt,神经动力学原理:感知器和脑机制理论,斯巴达书籍,1962 年
在最简化的视图中,感知机被建模在生物神经元之后,使得它接收一个或多个输入并将它们组合以产生输出。
如下图所示,感知机采用三个输入并将它们相加以生成输出`y`
![](img/a19eccda-749c-4dab-9020-41120070fd53.png)
这种感知机太简单了,不具备任何实际用途。因此,通过添加权重,偏差和激活函数的概念来增强它。将权重添加到每个输入以获得加权和。如果加权和`Σw[i]x[i]`小于阈值,则输出为 0,否则输出为 1:
![](img/ad008099-c40e-4e5f-bc65-721e82255fa8.png)
阈值称为**偏差**。让我们将偏差移到等式的左边,用`b`表示它,`Σw·x`代表`w``x`的向量点积。感知机的等式现在变为如下:
![](img/144a0cb4-f3e8-440c-9778-28e0f4c8b603.png)
感知机现在看起来像下图:
![](img/6c2085db-a65d-495c-96b9-4524ba54eacf.png) Simple perceptron with weights and bias
到目前为止,神经元是一个线性函数。为了使这个神经元产生非线性决策边界,通过称为 **a** **ctiva** 或传递函数的非线性函数运行求和输出。有许多流行的激活函数可用:
* `ReLU`**整流线性单元**,将值平滑到范围`(0, x)`
![](img/7538f31f-444e-4922-9d11-7ae37e375e4f.png)
* `sigmoid`**Sigmoid** 将值平滑到`(0, 1)`
![](img/5433180b-4099-4c59-ad7d-9ca67d6deff1.png)
* `tanh`**双曲正切**将值平滑到`(-1, 1)`
![](img/bf847fab-b08c-41e5-af41-19d2bb877240.png)
使用激活函数,感知机的等式变为:
![](img/d16676a1-31ee-43ba-9f94-25cc90573568.png)
其中`φ(·)`是激活函数。
神经元看起来像下图:
![](img/4ec4a553-192d-42a2-bf66-e6790103a7c6.png)
\ No newline at end of file
# 多层感知机
当我们将人工神经元连接在一起时,基于明确定义的结构,我们将其称为神经网络。这是一个神经元最简单的神经网络:
![](img/ba2849d1-c6bf-42c2-a9d3-d50f9d49de08.png)Neural network with one neuron
我们连接神经元,使得一层的输出成为下一层的输入,直到最后一层的输出成为最终输出。这种神经网络被称为**前馈神经网络(FFNN)**。由于这些 FFNN 由连接在一起的神经元层组成,因此它们被称为 **MultiLayer** **感知机(MLP)****深度神经网络(DNN)**
作为示例,下图中描绘的 MLP 具有三个特征作为输入:两个隐藏层,每个神经元包含五个神经元,一个输出 y。神经元完全连接到下一层的神经元。这些层也称为致密层或仿射层,并且这种模型也称为顺序模型。
![](img/2f715ec1-4960-4c19-b0c0-150dadcdadd0.png)
让我们重温一下我们之前探索过的一些示例数据集,并在 TensorFlow 中构建简单的神经网络(MLP 或 DNN)。
您可以按照 Jupyter 笔记本`ch-05_MLP`中的代码进行操作。
\ No newline at end of file
# 用于图像分类的 MLP
让我们使用不同的库(例如 TensorFlow,Keras 和 TFLearn)构建用于图像分类的 MLP 网络。 我们将在本节中使用示例的 MNIST 数据集。
MNIST 数据集包含从 0 到 9 的手写数字的 28x28 像素图像,以及它们的标签,训练集为 60K,测试集为 10K。 MNIST 数据集是使用最广泛的数据集,包括 TensorFlow 示例和教程。
[MNIST 数据集和相关文档可从此链接获得](http://yann.lecun.com/exdb/mnist/)
让我们从纯 TensorFlow 方法开始。
\ No newline at end of file
# 用于 MNIST 分类的基于 Keras 的 MLP
现在让我们与 Keras 建立相同的 MLP 网络,Keras 是 TensorFlow 的高级库。我们保留所有参数与本章中用于 TensorFlow 示例的参数相同,例如,隐藏层的激活函数保留为 ReLU 函数。
1. 从 Keras 导入所需的模块:
```py
import keras
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
```
1. 定义超参数(我们假设数据集已经加载到`X_train``Y_train``X_test``Y_test`变量):
```py
num_layers = 2
num_neurons = []
for i in range(num_layers):
num_neurons.append(256)
learning_rate = 0.01
n_epochs = 50
batch_size = 100
```
1. 创建顺序模型:
```py
model = Sequential()
```
1. 添加第一个隐藏层。只有在第一个隐藏层中,我们必须指定输入张量的形状:
```py
model.add(Dense(units=num_neurons[0], activation='relu',
input_shape=(num_inputs,)))
```
1. 添加第二层:
```py
model.add(Dense(units=num_neurons[1], activation='relu'))
```
1. 使用 softmax 激活函数添加输出层:
```py
model.add(Dense(units=num_outputs, activation='softmax'))
```
1. 打印模型详细信息:
```py
model.summary()
```
我们得到以下输出:
```py
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_1 (Dense) (None, 256) 200960
_________________________________________________________________
dense_2 (Dense) (None, 256) 65792
_________________________________________________________________
dense_3 (Dense) (None, 10) 2570
=================================================================
Total params: 269,322
Trainable params: 269,322
Non-trainable params: 0
_________________________________________________________________
```
1. 使用 SGD 优化器编译模型:
```py
model.compile(loss='categorical_crossentropy',
optimizer=SGD(lr=learning_rate),
metrics=['accuracy'])
```
1. 训练模型:
```py
model.fit(X_train, Y_train,
batch_size=batch_size,
epochs=n_epochs)
```
在训练模型时,我们可以观察每次训练迭代的损失和准确性:
```py
Epoch 1/50
55000/55000 [========================] - 4s - loss: 1.1055 - acc: 0.7413
Epoch 2/50
55000/55000 [========================] - 3s - loss: 0.4396 - acc: 0.8833
Epoch 3/50
55000/55000 [========================] - 3s - loss: 0.3523 - acc: 0.9010
Epoch 4/50
55000/55000 [========================] - 3s - loss: 0.3129 - acc: 0.9112
Epoch 5/50
55000/55000 [========================] - 3s - loss: 0.2871 - acc: 0.9181
--- Epoch 6 to 45 output removed for brevity ---
Epoch 46/50
55000/55000 [========================] - 4s - loss: 0.0689 - acc: 0.9814
Epoch 47/50
55000/55000 [========================] - 4s - loss: 0.0672 - acc: 0.9819
Epoch 48/50
55000/55000 [========================] - 4s - loss: 0.0658 - acc: 0.9822
Epoch 49/50
55000/55000 [========================] - 4s - loss: 0.0643 - acc: 0.9829
Epoch 50/50
55000/55000 [========================] - 4s - loss: 0.0627 - acc: 0.9829
```
1. 评估模型并打印损失和准确性:
```py
score = model.evaluate(X_test, Y_test)
print('\n Test loss:', score[0])
print('Test accuracy:', score[1])
```
我们得到以下输出:
```py
Test loss: 0.089410082236
Test accuracy: 0.9727
```
笔记本`ch-05_MLP`中提供了使用 Keras 进行 MNIST 分类的 MLP 的完整代码。
\ No newline at end of file
# 用于 MNIST 分类的基于 TFLearn 的 MLP
现在让我们看看如何使用 TFLearn 实现相同的 MLP,TFLearn 是 TensorFlow 的另一个高级库:
1. 导入 TFLearn 库:
```py
import tflearn
```
1. 定义超参数(我们假设数据集已经加载到`X_train``Y_train``X_test``Y_test`变量):
```py
num_layers = 2
num_neurons = []
for i in range(num_layers):
num_neurons.append(256)
learning_rate = 0.01
n_epochs = 50
batch_size = 100
```
1. 构建输入层,两个隐藏层和输出层(与 TensorFlow 和 Keras 部分中的示例相同)
```py
# Build deep neural network
input_layer = tflearn.input_data(shape=[None, num_inputs])
dense1 = tflearn.fully_connected(input_layer, num_neurons[0],
activation='relu')
dense2 = tflearn.fully_connected(dense1, num_neurons[1],
activation='relu')
softmax = tflearn.fully_connected(dense2, num_outputs,
activation='softmax')
```
1. 使用最后一步中构建的 DNN(在变量`softmax`中)定义优化器函数,神经网络和 MLP 模型(在 TFLearn 中称为 DNN):
```py
optimizer = tflearn.SGD(learning_rate=learning_rate)
net = tflearn.regression(softmax, optimizer=optimizer,
metric=tflearn.metrics.Accuracy(),
loss='categorical_crossentropy')
model = tflearn.DNN(net)
```
1. 训练模型:
```py
model.fit(X_train, Y_train, n_epoch=n_epochs,
batch_size=batch_size,
show_metric=True, run_id="dense_model")
```
训练结束后,我们得到以下输出:
```py
Training Step: 27499 | total loss: 0.11236 | time: 5.853s
| SGD | epoch: 050 | loss: 0.11236 - acc: 0.9687 -- iter: 54900/55000
Training Step: 27500 | total loss: 0.11836 | time: 5.863s
| SGD | epoch: 050 | loss: 0.11836 - acc: 0.9658 -- iter: 55000/55000
--
```
1. 评估模型并打印准确率分数:
```py
score = model.evaluate(X_test, Y_test)
print('Test accuracy:', score[0])
```
我们得到以下输出:
```py
Test accuracy: 0.9637
```
与使用 TFLearn 相比,我们获得了相当的精确度。
在笔记本 `ch-05_MLP` 中提供了使用 TFLearn 进行 MNIST 分类的 MLP 的完整代码。
\ No newline at end of file
# 代码预热 - Hello TensorFlow
作为学习任何新编程语言,库或平台的习惯传统,让我们在深入探讨之前,编写简单的 Hello TensorFlow 代码作为热身练习。
我们假设您已经安装了 TensorFlow。 如果还没有,请参阅[ TensorFlow 安装指南](https://www.tensorflow.org/install/),了解安装 TensorFlow 的详细说明。
打开 Jupyter Notebook 中的文件`ch-01_TensorFlow_101.ipynb`,在学习文本时关注并运行代码。
1. 使用以下代码导入 TensorFlow 库:
```py
import tensorflow as tf
```
1. 获取 TensorFlow 会话。 TensorFlow 提供两种会话:`Session()``InteractiveSession()`。我们将使用以下代码创建交互式会话:
```py
tfs = tf.InteractiveSession()
```
`Session()``InteractiveSession()`之间的唯一区别是用`InteractiveSession()`创建的会话成为默认会话。因此,我们不需要指定会话上下文以便稍后执行与会话相关的命令。例如,假设我们有一个会话对象`tfs`和一个常量对象`hello`。如果`tfs`是一个`InteractiveSession()`对象,那么我们可以使用代码`hello.eval()`来评估`hello`。如果`tfs``Session()`对象,那么我们必须使用`tfs.hello.eval()``with`块。最常见的做法是使用`with`块,这将在本章后面介绍。
1. 定义 TensorFlow 常量,`hello`
```py
hello = tf.constant("Hello TensorFlow !!")
```
1. 在 TensorFlow 会话中执行常量并打印输出:
```py
print(tfs.run(hello))
```
1. 您将获得以下输出:
```py
'Hello TensorFlow !!'
```
现在您已经使用 TensorFlow 编写并执行了前两行代码,让我们来看看 TensorFlow 的基本组成部分。
\ No newline at end of file
# 使用 TensorFlow,Keras 和 TFLearn 的 MLP 摘要
在前面的部分中,我们学习了如何使用 TensorFLow 及其高级库构建简单的 MLP 架构。纯 TensorFlow 的准确率约为 0.93-0.94,Keras 的准确率为 0.96-0.98,TFLearn 的准确率为 0.96-0.97。尽管我们的代码的所有示例都使用下面的 TensorFlow,但相同体系结构和参数的准确性差异可归因于这样的事实:尽管我们初始化了一些重要的超参数,但高级库和 TensorFlow 却抽象了许多其他超级 - 我们没有从默认值修改的参数。
我们观察到,与 Keras 和 TFLearn 相比,TensorFlow 中的代码非常详细和冗长。高级库使我们更容易构建和训练神经网络模型。
\ No newline at end of file
# 用于时间序列回归的 MLP
我们已经看到了图像数据分类的例子;现在让我们看一下时间序列数据的回归。我们将建立并使用 MLP 作为一个较小的单变量时间序列数据集,称为国际航空公司乘客数据集。该数据集包含多年来的乘客总数。该数据集可从此链接获得:
* <https://www.kaggle.com/andreazzini/international-airline-passengers/data>
* <https://datamarket.com/data/set/22u3/international-airline-passengers-monthly-totals-in-thousands-jan-49-dec-60>
让我们从准备数据集开始。
1. 首先,使用以下代码加载数据集:
```py
filename = os.path.join(datasetslib.datasets_root,
'ts-data',
'international-airline-passengers-cleaned.csv')
dataframe = pd.read_csv(filename,usecols=[1],header=0)
dataset = dataframe.values
dataset = dataset.astype('float32')
```
1. 利用`datasetslib`的效用函数,我们将数据集分成测试和训练集。对于时间序列数据集,我们有一个单独的函数,不会改变观察结果,因为对于时间序列回归,我们需要维持观察的顺序。我们使用 67%的数据进行训练,33%的数据用于测试。您可能希望尝试使用不同比例的示例。
```py
train,test=dsu.train_test_split(dataset,train_size=0.67)
```
1. 对于时间序列回归,我们转换数据集以构建监督数据集。在此示例中,我们使用两个时间步长的滞后。我们将`n_x`设置为 2,`mvts_to_xy()`函数返回输入和输出(`X``Y`)训练和测试集,使得 X 在两列和 Y 中具有时间{t-1,t}的值在一列中具有时间{t + 1}的值。我们的学习算法假设通过找到时间{t-1,t,t + 1}的值之间的关系,可以学习时间 t + 1 的值。
```py
# reshape into X=t-1,t and Y=t+1
n_x=2
n_y=1
X_train, Y_train, X_test, Y_test = tsd.mvts_to_xy(train,
test,n_x=n_x,n_y=n_y)
```
有关将时间序列数据集转换为监督学习问题的更多信息,[请访问此链接](http://machinelearningmastery.com/convert-time-series-supervised-learning-problem-python/)
现在我们在我们的训练数据集上构建和训练模型:
1. 我导入所需的 Keras 模块:
```py
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
```
1. 设置构建模型所需的超参数:
```py
num_layers = 2
num_neurons = [8,8]
n_epochs = 50
batch_size = 2
```
请注意,我们使用批量大小为 2,因为数据集非常小。我们使用两层 MLP,每层只有八个神经元,因为我们的示例问题的规模很小。
1. 构建,编译和训练模型:
```py
model = Sequential()
model.add(Dense(num_neurons[0], activation='relu',
input_shape=(n_x,)))
model.add(Dense(num_neurons[1], activation='relu'))
model.add(Dense(units=1))
model.summary()
model.compile(loss='mse', optimizer='adam')
model.fit(X_train, Y_train,
batch_size=batch_size,
epochs=n_epochs)
```
请注意,我们使用 Adam 优化器而不是 SGD。 您可能想要尝试 TensorFlow 和 Keras 中可用的不同优化器。
1. 评估模型并打印均方误差(MSE)和均方根误差(RMSE):
```py
score = model.evaluate(X_test, Y_test)
print('\nTest mse:', score)
print('Test rmse:', math.sqrt(score))
```
我们得到以下输出:
```py
Test mse: 5619.24934188
Test rmse: 74.96165247566114
```
1. 使用我们的模型预测值并绘制它们,用于测试和训练数据集:
```py
# make predictions
Y_train_pred = model.predict(X_train)
Y_test_pred = model.predict(X_test)
# shift train predictions for plotting
Y_train_pred_plot = np.empty_like(dataset)
Y_train_pred_plot[:, :] = np.nan
Y_train_pred_plot[n_x-1:len(Y_train_pred)+n_x-1, :] = Y_train_pred
# shift test predictions for plotting
Y_test_pred_plot = np.empty_like(dataset)
Y_test_pred_plot[:, :] = np.nan
Y_test_pred_plot[len(Y_train_pred)+(n_x*2)-1:len(dataset)-1, :] = \
Y_test_pred
# plot baseline and predictions
plt.plot(dataset,label='Original Data')
plt.plot(Y_train_pred_plot,label='Y_train_pred')
plt.plot(Y_test_pred_plot,label='Y_test_pred')
plt.legend()
plt.show()
```
我们得到以下关于原始和预测时间序列值的图:
![](img/3d26fd19-43da-4196-8f1f-4c19ed3040fe.png)
如你所见,这是一个非常好的估计。然而,在现实生活中,数据本质上是多变量和复杂的。因此,我们将在后面的章节中看到时间序列数据的循环神经网络架构。
\ No newline at end of file
# 总结
在本章中,我们了解了多层感知机。我们解释了如何为分类和回归问题构建和训练 MLP 模型。我们使用纯 TensorFlow,Keras 和 TFLearn 构建了 MLP 模型。对于分类,我们使用图像数据,对于回归,我们使用时间序列数据。
构建和训练 MLP 网络模型的技术对于任何其他类型的数据(例如数字或文本)是相同的。然而,对于图像数据集,CNN 架构已被证明是最佳架构,对于序列数据集,例如时间序列和文本,RNN 模型已被证明是最佳架构。
虽然我们在本章中仅使用简单的数据集示例来演示 MLP 体系结构,但在后面的章节中,我们将介绍具有一些大型和高级数据集的 CNN 和 RNN 体系结构。
\ No newline at end of file
# 使用 TensorFlow 和 Keras 的 RNN
在涉及有序数据序列的问题中,例如**时间序列预测****自然语言处理**,上下文对于预测输出非常有价值。可以通过摄取整个序列而不仅仅是最后一个数据点来确定这些问题的上下文。因此,先前的输出成为当前输入的一部分,并且当重复时,最后的输出结果是所有先前输入的结果以及最后一个输入。 **循环神经网络****RNN** )架构是用于处理涉及序列的机器学习问题的解决方案。
**循环神经网络****RNN** )是一种用于处理顺序数据的专用神经网络架构。顺序数据可以是一段时间内的观察序列,如时间序列数据,或字符序列,单词和句子,如文本数据。
标准神经网络的一个假设是,输入数据的排列方式是一个输入不依赖于另一个输入。然而,对于时间序列数据和文本数据,该假设不成立,因为序列中稍后出现的值通常受到之前出现的值的影响。
为了实现这一目标,RNN 通过以下方式扩展了标准神经网络:
* 通过在计算图中添加循环或循环,RNN 增加了将一个层的输出用作相同或前一层的输入的特性。
* RNN 添加存储器单元以存储可在当前计算中使用的先前输入和输出。
在本章中,我们将介绍以下有关 RNN 的主题:
* 简单的循环神经网络
* RNN 变种
* 长期短期内存网络
* 门控循环单元网络
* RNN 的 TensorFlow
* 适用于 RNN 的 Keras
* 用于 MNIST 数据的 Keras 中的 RNN
接下来的两章将介绍在 TensorFlow 和 Keras 中为时间序列和文本(NLP)数据构建 RNN 模型的实际示例。
\ No newline at end of file
# 简单循环神经网络
这是一个带循环的简单神经网络:
![](img/fe89a986-6079-4b70-b184-39f9b4b5e8bb.png)RNN Network
在该图中,神经网络`N`接受输入`x[t]`以产生输出`y[t]`。由于循环,在下一步`t+1`,输入`y[t]`和输入`x[t+1]`产生输出`y[t+1]`。在数学上,我们将其表示为以下等式:
![](img/e6eb9d40-90e7-4850-bc5b-dc5fd44fa73f.png)
当我们展开循环时,RNN 架构在时间步`t1`看起来如下:
![](img/af2b19d9-701b-402e-8fbc-383fe1b045ba.png)
随着时间步长的发展,这个循环在时间步骤 5 展开如下:
![](img/3166287c-3e95-4248-9324-c17d7e4054b7.png)
在每个时间步骤,使用相同的学习函数`φ(·)`和相同的参数,`w``b`
输出`y`并不总是在每个时间步产生。相反,在每个时间步产生输出`h`,并且对该输出`h`应用另一个激活函数以产生输出`y`。 RNN 的等式现在看起来像这样:
![](img/1109a666-62de-4eac-928c-0888b0db98fa.png)
![](img/eb66e53f-2c5e-4d4d-96b1-0d6dfd768ba6.png)
其中,
* `w(hx)`是连接到隐藏层的`x`输入的权重向量
* `w(hh)`是来自前一时间步的`h`的值的权重向量
* `w(yh)`是连接隐藏层和输出层的层的权重向量
* 用于`h[t]`的函数通常是非线性函数,例如 tanh 或 ReLU
在 RNN 中,在每个时间步使用相同的参数`w(hx), w(hh), w(yh), b(h), b(y)`。这一事实大大减少了我们需要学习的基于序列模型的参数数量。
由此, RNN 在时间步`t5`如下展开,假设输出`y`仅在时间步`t5`产生:
![](img/e3ba641c-7ad9-439e-87d6-f465c428d146.png)
简单的 RNN 由 Elman 在 1990 年引入,因此它也被称为 Elman 网络。然而,简单的 RNN 无法满足我们今天的处理需求,因此我们将在下一节中了解 RNN 的变体。
阅读 Elman 的原始研究论文,了解 RNN 架构的起源:
```
J. L. Elman, Finding Structure in Time, Cogn. Sci., vol. 14, no. 2, pp. 179–211, 1990.
```
\ No newline at end of file
# RNN 变种
RNN 架构已经以多种方式扩展,以适应某些问题中的额外需求,并克服简单 RNN 模型的缺点。我们列出了下面的 RNN 架构的一些主要扩展。
* **双向** **RNN****BRNN** )用于输出依赖于序列的前一个和后一个元素的情况。 BRNN 通过堆叠两个 RNN(称为前向和后向层)来实现,输出是前向和后向层 RNN 的隐藏状态的结果。在前向层中,存储器状态 h 从时间步长`t`流向时间步长`t + 1`,并且在后向层中,存储器状态从时间步长`t`流出。到时间步`t-1`。两个层在时间步`t`时采用相同的输入`x[t]`,但它们在时间步`t`共同产生输出。
* **深双向 RNN****DBRNN** )通过添加多个层进一步扩展 BRNN。 BRNN 在时间维度上隐藏了层或单元。但是,通过堆叠 BRNN,我们可以在 DBRNN 中获得分层表示。其中一个显着差异是,在 BRNN 中,我们对同一层中的每个单元使用相同的参数,但在 DBRNN 中,我们对每个堆叠层使用不同的参数。
* **长短期记忆****LSTM** )网络通过使用涉及多个非线性函数而不是一个简单非线性函数的架构来扩展 RNN 隐藏状态。 LSTM 由称为 **单元** 的黑盒组成,取三个输入:时间`t-1`的工作记忆(`h[t-1]`),当前输入(`x[t]`)和时间`t-1`的长期记忆(`c[t-1]`),并产生两个输出:更新的工作记忆(`h[t]`)和长期记忆(`c[t]`)。单元使用称为门的功能来决定从内存中选择性地保存和擦除的内容。我们在下面的部分中详细描述了 LSTM。
阅读以下关于 LSTM 的研究论文,以获得有关 LSTM 起源的更多信息:
```
S. Hochreiter and J. Schmidhuber, Long Short-Term Memory, Neural Comput., vol. 9, no. 8, pp. 1735–1780, 1997.http://www.bioinf.jku.at/publications/older/2604.pdf
```
* **门控递归单元****GRU** )网络是 LSTM 的简化变体。 结合遗忘和输入的功能,在更简单的更新门中进行门控。它还将隐藏状态和单元状态组合成一个单一状态。因此,与 LSTM 相比,GRU 在计算上更便宜。 我们在下面的部分中详细描述了 GRU。
阅读以下研究论文以探索 GRU 的更多细节:
```
K. Cho, B. van Merrienboer, C. Gulcehre, D. Bahdanau, F. Bougares, H. Schwenk, and Y. Bengio, Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation, 2014.https://arxiv.org/abs/1406.1078
J. Chung, C. Gulcehre, K. Cho, and Y. Bengio, Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling, pp. 1–9, 2014. https://arxiv.org/abs/1412.3555
```
* **seq2seq** 模型将编码器 - 解码器架构与 RNN 架构相结合。在 seq2seq 架构中,模型训练数据序列,例如文本数据或时间序列数据,然后该模型用于生成输出序列。例如,在英文文本上训练模型,然后从模型生成西班牙文本。 seq2seq 模型由编码器和解码器模型组成,它们都使用 RNN 架构构建。可以堆叠 seq2seq 模型以构建分层多层模型。
\ No newline at end of file
# LSTM 网络
当 RNN 在很长的数据序列上进行训练时,梯度往往变得非常大或非常小,它们会消失到几乎为零。 **长短期记忆****LSTM** )网络通过添加用于控制对过去信息的访问的门,来解决消失/爆炸梯度问题。 LSTM 概念最初由 Hochreiter 和 Schmidhuber 在 1997 年引入。
阅读以下关于LSTM的研究论文,以获得有关LSTM起源的更多信息:
```
S. Hochreiter and J. Schmidhuber, Long Short-Term Memory, Neural Comput., vol. 9, no. 8, pp. 1735–1780, 1997. http://www.bioinf.jku.at/publications/older/2604.pdf
```
在 RNN 中,使用重复使用的学习函数`φ`的单个神经网络层,而在 LSTM 中,使用由四个主要函数组成的重复模块。构建 LSTM 网络的模块称为**单元**。 LSTM 单元通过选择性地学习或擦除信息,有助于在长序列通过时更有效地训练模型。组成单元的功能也称为门,因为它们充当传入和传出单元的信息的网守。
LSTM 模型有两种内存:
* 用 _**h**_(隐藏状态)表示的工作记忆
* 用 _**c**_(单元状态)表示的长期记忆。
单元状态或长期记忆仅在两个线性相互作用下从一个单元流向另一个单元。 LSTM 将信息添加到长期记忆中,或通过门从长期记忆中删除信息。
下图描绘了 LSTM 单元:
![](img/5cd7f05b-1514-45d1-948f-b023de11377d.png)The LSTM Cell
通过 LSTM 单元中的门的内部流动如下:
1. **遗忘门(或记忆门)`f()`**`h[t-1]``x[t]`按照以下等式作为输入流向`f()`门:
![](img/925e0a35-3fef-4e56-a3b9-852ee9704a88.png)
遗忘门的功能是决定忘记哪些信息以及要记住哪些信息。这里使用`sigmoid`激活函数,因此输出 1 表示信息被转移到单元内的下一步骤,输出 0 表示信息被选择性地丢弃。
2. **输入门(或保存门)`i()`**`h[t-1]``x[t]`按照以下等式作为输入流向`i()`门:
![](img/9b60f5ae-c253-4d41-8896-c3a94db45567.png)
输入门的功能是决定是保存还是丢弃输入。输入功能还允许单元了解要保留或丢弃的候选存储器的哪个部分。
3. **候选长期记忆**:候选长期记忆由`h[t-1]``x[t]`使用激活函数计算,主要是`tanh`,按照下式:
![](img/338bafaf-9c59-40d7-9aa4-29b96248c40b.png)
4. 接下来,组合前面的三个计算以得到更新长期记忆,由`c[t]`表示,如下式所示:
![](img/f244e66e-0b70-49e7-b1c3-dade32143d29.png)
5. **输出门(或聚焦/关注门)`o()`**`h[t-1]``x[t]`按照以下等式作为输入流向`o()`门:
![](img/b32dd2e9-bafa-41ae-ab11-0dfbd95f3a02.png)
输出门的功能是决定多少信息可用于更新工作内存。
6. 接下来,工作记忆`h[t]`从长期记忆`c[t]`和焦点/注意力向量更新,如下式所示:
![](img/9e296cf4-d44b-4d7c-b6a5-aa4f7afce542.png)
其中`φ(·)`是激活函数,通常是`tanh`
\ No newline at end of file
# GRU 网络
LSTM 网络的计算成本很高,因此,研究人员发现了一种几乎同样有效的 RNN 配置,称为**门控递归单元****GRU** )架构。
在 GRU 中,不使用工作和长期记忆,只使用一种记忆,用 _**h**_(隐藏状态)表示。 GRU 单元通过**复位****更新**门,将信息添加到此状态存储器,或从该状态存储器中删除信息。
下图描绘了 GRU 单元(说明如下图):
![](img/cb5734c0-dc19-4d5d-bf98-eb448f083dd2.png)The GRU Cell
GRU 单元中通过门的内部流量如下:
1. **更新门`u()`**:输入`h[t-1]``x[t]`按照以下公式流向`u()`门:
![](img/772bddac-9209-47d8-a1c4-eb66fe59fe1f.png)
2. **复位门`r()`**:输入`h[t-1]``x[t]`按照以下公式流向`r()`门:
![](img/a0f59f6c-94df-4742-bd5f-5ac3d81540cf.png)
1. **候选状态记忆**:候选长期记忆是根据`r()`门,`h[t-1]``x[t]`的输出计算出来的,按照下列公式:
![](img/7ce40c11-c131-493c-8ccf-7759863540c0.png)
2. 接下来,组合前面的三个计算以得到更新的状态存储器,由`h[t]`,表示,如下式所示:
![](img/519ccb8b-513c-4b1a-a1d7-9f48d6c2577b.png)
阅读以下研究论文以探索 GRU 的更多细节:
```
K. Cho, B. van Merrienboer, C. Gulcehre, D. Bahdanau, F. Bougares, H. Schwenk, and Y. Bengio, Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation, 2014. https://arxiv.org/abs/1406.1078
J. Chung, C. Gulcehre, K. Cho, and Y. Bengio, Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling, pp. 1–9, 2014. https://arxiv.org/abs/1412.3555
```
\ No newline at end of file
# TensorFlow RNN
在低级 TensorFlow 库中创建 RNN 模型的基本工作流程与 MLP 几乎相同:
* 首先创建形状的输入和输出占位符(无,#TimeSteps,#Features)或(批量大小,#TimeSteps,#Features)
* 从输入占位符中,创建一个长度为#TimeSteps 的列表,其中包含形状的张量(无,#特征)或(批量大小,#特征)
*`tf.rnn.rnn_cell`模块创建所需 RNN 类型的单元
* 使用先前创建的单元和输入张量列表来创建静态或动态 RNN
* 创建输出权重和偏差变量,并定义损失和优化器函数
* 对于所需的周期数,使用损失和优化器函数训练模型
这个基本工作流程将在下一章的示例代码中演示。让我们看看可用于支持先前工作流程的各种类。
\ No newline at end of file
# TensorFlow RNN 单元类
`tf.nn.rnn_cell`模块包含以下用于在 TensorFlow 中创建不同类型单元的类:
| **类** | **描述** |
| --- | --- |
| BasicRNNCell | 提供 RNN 单元的实现 |
| BasicLSTMCell | 提供 LSTM RNN 单元的实现,基于 <http://arxiv.org/abs/1409.2329> |
| LSTMCell | 提供 LSTM RNN 单元,基于 <http://deeplearning.cs.cmu.edu/pdfs/Hochreiter97_lstm.pdf>[https:// research.google.com/pubs/archive/43905.pdf](https://research.google.com/pubs/archive/43905.pdf) |
| GRUCell | 提供 GRU RNN 单元,基于 <http://arxiv.org/abs/1406.1078> |
| MultiRNNCell | 提供由连续连接的多个简单单元组成的 RNN 单元 |
`tf.contrib.rnn` 模块提供以下额外的类用于在 TensorFlow 中创建不同类型的单元:
| **类** | **描述** |
| --- | --- |
| LSTMBlockCell | 提供块 LSTM RNN 单元,基于 <http://arxiv.org/abs/1409.2329> |
| LSTMBlockFusedCell | 提供块融合 LSTM RNN 单元,基于 <http://arxiv.org/abs/1409.2329> |
| GLSTMCell | 根据 <https://arxiv.org/abs/1703.10722> 提供组 LSTM 单元 |
| GridLSTMCell | 提供网格 LSTM RNN 单元,基于 <http://arxiv.org/abs/1507.01526> |
| GRUBlockCell | 提供块 GRU RNN 单元,基于 <http://arxiv.org/abs/1406.1078> |
| BidirectionalGridLSTMCell | 仅在频率上而不是在时间上提供双向网格 LSTM |
| NASCell | 提供神经架构搜索 RNN 单元,基于 <https://arxiv.org/abs/1611.01578> |
| UGRNNCell | 提供更新门 RNN 信元,基于 <https://arxiv.org/abs/1611.09913> |
\ No newline at end of file
# 张量
**张量**是 TensorFlow 中计算的基本元素和基本数据结构。可能是您需要学习使用 TensorFlow 的唯一数据结构。张量是由维度,形状和类型标识的 n 维数据集合。
**Rank** 是张量的维数,**形状**是表示每个维度的大小的列表。张量可以具有任意数量的尺寸。您可能已经熟悉零维集合(标量),一维集合(向量),二维集合(矩阵)的数量,以及多维集合。
标量值是等级 0 的张量,因此具有[1]的形状。向量或一维数组是秩 1 的张量,并且具有[列]或[行]的形状。矩阵或二维数组是秩 2 的张量,并且具有[行,列]的形状。三维数组将是秩 3 的张量,并且以相同的方式,n 维数组将是秩`n`的张量。
请参阅以下资源以了解有关张量及其数学基础的更多信息:
* [维基百科上的张量页面](https://en.wikipedia.org/wiki/Tensor)
* [来自美国国家航空航天局的张量导言](https://www.grc.nasa.gov/www/k-12/Numbers/Math/documents/Tensors_TM2002211716.pdf)
张量可以在其所有维度中存储一种类型的数据,并且其元素的数据类型被称为张量的数据类型。
您还可以在[这里](https://www.tensorflow.org/api_docs/python/tf/DType)查看最新版本的 TensorFlow 库中定义的数据类型。
在编写本书时,TensorFlow 定义了以下数据类型:
| **TensorFlow Python API 数据类型** | **描述** |
| --- | --- |
| `tf.float16` | 16 位半精度浮点数 |
| `tf.float32` | 32 位单精度浮点 |
| `tf.float64` | 64 位双精度浮点 |
| `tf.bfloat16` | 16 位截断浮点 |
| `tf.complex64` | 64 位单精度复合体 |
| `tf.complex128` | 128 位双精度复合体 |
| `tf.int8` | 8 位有符号整数 |
| `tf.uint8` | 8 位无符号整数 |
| `tf.uint16` | 16 位无符号整数 |
| `tf.int16` | 16 位有符号整数 |
| `tf.int32` | 32 位有符号整数 |
| `tf.int64` | 64 位有符号整数 |
| `tf.bool` | 布尔 |
| `tf.string` | 串 |
| `tf.qint8` | 量化的 8 位有符号整数 |
| `tf.quint8` | 量化的 8 位无符号整数 |
| `tf.qint16` | 量化的 16 位有符号整数 |
| `tf.quint16` | 量化的 16 位无符号整数 |
| `tf.qint32` | 量化的 32 位有符号整数 |
| `tf.resource` | 处理可变资源 |
我们建议您避免使用 Python 本地数据类型。 使用 TensorFlow 数据类型来定义张量,而不是 Python 本地数据类型。
可以通过以下方式创建张量:
* 通过定义常量,操作和变量,并将值传递给它们的构造函数。
* 通过定义占位符并将值传递给`session.run()`
* 通过`tf.convert_to_tensor()`函数转换 Python 对象,如标量值,列表和 NumPy 数组。
让我们来看看创建张量的不同方法。
\ No newline at end of file
# TensorFlow RNN 模型构建类
TensorFlow 提供了从 RNN 单元对象创建 RNN 模型的类。静态 RNN 类在编译时为时间步骤添加展开的单元,而动态 RNN 类在运行时添加展开的单元用于时间步长。
* `tf.nn.static_rnn`
* `tf.nn.static_state_saving_rnn`
* `tf.nn.static_bidirectional_rnn`
* `tf.nn.dynamic_rnn`
* `tf.nn.bidirectional_dynamic_rnn`
* `tf.nn.raw_rnn`
* `tf.contrib.rnn.stack_bidirectional_dynamic_rnn`
\ No newline at end of file
# TensorFlow RNN 单元包装器类
TensorFlow 还提供包装其他单元类的类:
* `tf.contrib.rnn.LSTMBlockWrapper`
* `tf.contrib.rnn.DropoutWrapper`
* `tf.contrib.rnn.EmbeddingWrapper`
* `tf.contrib.rnn.InputProjectionWrapper`
* `tf.contrib.rnn.OutputProjectionWrapper`
* `tf.contrib.rnn.DeviceWrapper`
* `tf.contrib.rnn.ResidualWrapper`
有关 TensorFlow 中 RNN 的最新文档,[请访问此链接](https://www.tensorflow.org/api_guides/python/contrib.rnn)
\ No newline at end of file
# 适用于 RNN 的 Keras
与 TensorFlow 相比,在 Keras 中创建 RNN 要容易得多。正如您在第 3 章中学到的,Keras 提供了用于创建循环网络的函数式和顺序 API。要构建 RNN 模型,您必须从`kera.layers.recurrent`模块添加层。 Keras 在`keras.layers.recurrent`模块中提供以下类型的循环层:
* SimpleRNN
* LSTM
* GRU
**有状态模型**
Keras 复现层还支持 RNN 模型,可在批次之间保存状态。您可以通过将`stateful`参数作为`True`传递来创建有状态 RNN,LSTM 或 GRU 模型。对于有状态模型,为输入指定的批量大小必须是固定值。在有状态模型中,从训练批次中学到的隐藏状态将重新用于下一批。如果您想在训练期间的某个时刻重置内存,可以通过调用`model.reset_states()``layer.reset_states()`函数使用额外的代码来完成。
我们将在下一章中看到使用 Keras 构建 RNN 的示例。
[有关 Keras Recurrent Layers 的最新文档可在此链接中找到](https://keras.io/layers/recurrent/)
\ No newline at end of file
# RNN 的应用领域
RNN 更频繁使用的一些应用领域如下:
* **自然语言模型**:RNN 模型已用于 n 自然语言处理(NLP),用于自然语言理解和自然语言生成任务。在 NLP 中,RNN 模型被给予一系列单词并且它预测另一个单词序列。因此,训练的模型可用于生成单词序列,称为文本生成的字段。例如,生成故事和剧本。 NLP 的另一个领域是语言翻译,其中给定一种语言的一系列单词,该模型预测另一种语言的单词序列。
* **语音和语音识别**:RNN 模型非常适用于构建模拟音频数据的模型。在语音识别中,RNN 模型被给予音频数据并且它预测一系列语音片段。它可用于训练模型以识别语音命令,甚至用于与基于语音的聊天机器人的对话。
* **图像/视频描述或字幕生成**:RNN 模型可与 CNN 结合使用,以生成图像和视频中找到的元素的描述。这些描述也可用于生成图像和视频的标题。
* **TimeSeries 数据**:最重要的是,RNN 对 TimeSeries 数据非常有用。大多数传感器和系统生成时间顺序很重要的数据。 RNN 模型非常适合于查找模式和预测此类数据。
通过此链接了解有关 RNN 的更多信息:
<http://karpathy.github.io/2015/05/21/rnn-effectiveness/>
<http://colah.github.io/posts/2015-08-Understanding-LSTMs/>
<http://www.wildml.com/2015/09/recurrent-neural-networks-tutorial-part-1-introduction-to-rnns/>
<https://r2rt.com/written-memories-understanding-deriving-and-extending-the-lstm.html>
\ No newline at end of file
# 用于 MNIST 数据的 Keras 中的 RNN
虽然 RNN 主要用于序列数据,但它也可用于图像数据。我们知道图像具有最小的两个维度 - 高度和宽度。现在将其中一个维度视为时间步长,将其他维度视为特征。对于 MNIST,图像大小为 28 x 28 像素,因此我们可以将 MNIST 图像视为具有 28 个时间步长,每个时间步长具有 28 个特征。
我们将在下一章中提供时间序列和文本数据的示例,但让我们为 Keras 中的 MNIST 构建和训练 RNN,以快速浏览构建和训练 RNN 模型的过程。
您可以按照 Jupyter 笔记本中的代码`ch-06_RNN_MNIST_Keras`
导入所需的模块:
```py
import keras
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.layers.recurrent import SimpleRNN
from keras.optimizers import RMSprop
from keras.optimizers import SGD
```
获取 MNIST 数据并将数据从 1-D 中的 784 像素转换为 2-D 中的 28 x 28 像素:
```py
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets(os.path.join(datasetslib.datasets_root,
'mnist'),
one_hot=True)
X_train = mnist.train.images
X_test = mnist.test.images
Y_train = mnist.train.labels
Y_test = mnist.test.labels
n_classes = 10
n_classes = 10
X_train = X_train.reshape(-1,28,28)
X_test = X_test.reshape(-1,28,28)
```
在 Keras 构建 SimpleRNN 模型:
```py
# create and fit the SimpleRNN model
model = Sequential()
model.add(SimpleRNN(units=16, activation='relu', input_shape=(28,28)))
model.add(Dense(n_classes))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
optimizer=RMSprop(lr=0.01),
metrics=['accuracy'])
model.summary()
```
该模型如下:
```py
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
simple_rnn_1 (SimpleRNN) (None, 16) 720
_________________________________________________________________
dense_1 (Dense) (None, 10) 170
_________________________________________________________________
activation_1 (Activation) (None, 10) 0
=================================================================
Total params: 890
Trainable params: 890
Non-trainable params: 0
_________________________________________________________________
```
训练模型并打印测试数据集的准确性:
```py
model.fit(X_train, Y_train,
batch_size=100, epochs=20)
score = model.evaluate(X_test, Y_test)
print('\nTest loss:', score[0])
print('Test accuracy:', score[1])
```
我们得到以下结果:
```py
Test loss: 0.520945608187
Test accuracy: 0.8379
```
\ No newline at end of file
# 总结
在本章中,我们了解了循环神经网络(RNN)。我们了解了 RNN 的各种变体,并详细描述了其中的两个:长短期记忆(LSTM)网络和门控循环单元(GRU)网络。我们还描述了可用于在 TensorFlow 和 Keras 中构建 RNN 单元,模型和层的类。我们构建了一个简单的 RNN 网络,用于对 MNIST 数据集的数字进行分类。
在下一章中,我们将学习如何构建和训练时间序列数据的 RNN 模型。
\ No newline at end of file
# 使用 TensorFlow 和 Keras 的时间序列数据的 RNN
时间序列数据是一系列值,以不同的时间间隔记录或测量。作为序列,RNN 架构是从这些数据训练模型的最佳方法。在本章中,我们将使用示例时间序列数据集来展示如何使用 TensorFlow 和 Keras 构建 RNN 模型。
我们将在本章中介绍以下主题:
* 航空公司乘客时间序列数据集:
* 描述和下载数据集
* 可视化数据集
* 在 TensorFlow 中预处理 RNN 的数据集
* TensorFlow 中的 RNN 用于时间序列数据:
* TensorFlow 中的 SimpleRNN
* TensorFlow 中的 LSTM
* GRU 在 TensorFlow 中
* 在 Keras 中预处理 RNN 的数据集
* Keras 的 RNN 用于时间序列数据:
* Keras 的 SimpleRNN
* Keras 的 LSTM
* 格拉斯在 Keras
让我们从了解样本数据集开始。
您可以按照 Jupyter 笔记本中的代码`ch-07a_RNN_TimeSeries_TensorFlow`
\ No newline at end of file
# 航空公司乘客数据集
为了简洁起见,我们选择了一个名为国际航空公司乘客(航空通票)的非常小的数据集。该数据包含从 1949 年 1 月到 1960 年 12 月的每月总乘客数量。数据集中的数字是指数千的数量。该数据集最初由 Box 和 Jenkins 在 1976 年的工作中使用。它作为 **TimeSeries 数据集库****TSDL** )的一部分与 Rob Hyndman 教授的各种其他时间序列数据集一起收集。在澳大利亚莫纳什大学。后来,TSDL 被转移到 [DataMarket](http://datamarket.com)
[您可以从此链接下载数据集](https://datamarket.com/data/set/22u3/international-airline-passengers-monthly-totals-in-thousands-jan-49-dec-60)
\ No newline at end of file
# 加载 airpass 数据集
我们将数据集保存为数据集根目录(〜/ datasets)中`ts-data`文件夹中的 CSV 文件,并使用以下命令将数据加载到 pandas 数据框中:
```py
filepath = os.path.join(datasetslib.datasets_root,
'ts-data',
'international-airline-passengers-cleaned.csv'
)
dataframe = pd.read_csv(filepath,usecols=[1],header=0)
dataset = dataframe.values
dataset = dataset.astype(np.float32)
```
从 NumPy 数组中的数据框中提取值并转换为`np.float32`
```py
dataset = dataframe.values
dataset = dataset.astype(np.float32)
```
\ No newline at end of file
# 可视化 airpass 数据集
让我们看一下数据集的外观:
```py
plt.plot(dataset,label='Original Data')
plt.legend()
plt.show()
```
`airpass`数据集的图如下所示:
![](img/305f4a94-92a4-4164-9ec2-473cc7225413.png)Airline Passengers Dataset
\ No newline at end of file
# 常量
使用具有以下签名的`tf.constant()`函数创建常量值张量:
```py
tf.constant(
value,
dtype=None,
shape=None,
name='Const',
verify_shape=False
)
```
让我们看看本书中 Jupyter 笔记本中提供的示例代码:
```py
c1=tf.constant(5,name='x')
c2=tf.constant(6.0,name='y')
c3=tf.constant(7.0,tf.float32,name='z')
```
让我们详细研究一下代码:
* 第一行定义一个常数张量`c1`,给它值 5,并将其命名为 x。
* 第二行定义一个常数张量`c2`,存储值为 6.0,并将其命名为 y。
* 当我们打印这些张量时,我们看到`c1``c2`的数据类型由 TensorFlow 自动推导出来。
* 要专门定义数据类型,我们可以使用`dtype`参数或将数据类型作为第二个参数。在前面的代码示例中,我们将`tf.float32`的数据类型定义为`tf.float32`
让我们打印常量`c1``c2``c3`
```py
print('c1 (x): ',c1)
print('c2 (y): ',c2)
print('c3 (z): ',c3)
```
当我们打印这些常量时,我​​们得到以下输出:
```py
c1 (x): Tensor("x:0", shape=(), dtype=int32)
c2 (y): Tensor("y:0", shape=(), dtype=float32)
c3 (z): Tensor("z:0", shape=(), dtype=float32)
```
为了打印这些常量的值,我们必须使用`tfs.run()`命令在 TensorFlow 会话中执行它们:
```py
print('run([c1,c2,c3]) : ',tfs.run([c1,c2,c3]))
```
我们看到以下输出:
```py
run([c1,c2,c3]) : [5, 6.0, 7.0]
```
\ No newline at end of file
# 使用 TensorFlow RNN 模型预处理数据集
为了使其为学习模型做好准备,通过应用 MinMax 缩放来正则化数据集,该缩放使数据集值介于 0 和 1 之间。您可以尝试根据数据的性质对数据应用不同的缩放方法。
```py
# normalize the dataset
scaler = skpp.MinMaxScaler(feature_range=(0, 1))
normalized_dataset = scaler.fit_transform(dataset)
```
我们使用自己开发的实用函数将数据集拆分为训练和测试数据集。必须拆分数据而不对数据集进行混洗,因为改组数据集会破坏序列。维护数据序列对于训练时间序列模型非常重要。
```py
train,test=tsu.train_test_split(normalized_dataset,train_size=0.67)
```
然后我们将训练和测试数据集转换为有监督的机器学习集。让我们试着理解监督学习集的含义。假设我们有一系列数据:1,2,3,4,5。我们想要了解生成数据集的概率分布。为了做到这一点,我们可以假设时间步长`t`的值是从时间步长`t-1``tk`的值的结果,其中`k`是窗口大小。为简化起见,假设窗口大小为 1.因此,时间步长`t`的值(称为输入特征)是时间步长值`t-1`的结果,被称为目标。让我们重复一遍所有时间步骤,我们得到下表:
| 输入值或特征 | 输出值或目标 |
| --- | --- |
| 1 | 2 |
| 2 | 3 |
| 3 | 4 |
| 4 | 5 |
我们展示的示例只有一个变量值,它将转换为特征和目标。当目标值取决于一个变量时,它被称为单变量时间序列。同样的逻辑可以应用于多变量时间序列,其中目标取决于多个变量。我们使用`x`来表示输入特征,使用`y`来表示输出目标。
考虑到这一背景,为了将`airpass`数据转换为监督机器学习数据,我们设置了以下超参数:
1. 设置用于学习或预测下一个时间步的过去时间步数:
```py
n_x=1
```
1. 设置学习或预测的未来时间步长的数量:
```py
n_y=1
```
1. 设置用于学习的`x`变量的数量;由于当前示例是单变量的,因此设置为 1:
```py
n_x_vars = 1
```
1. 设置要预测的`y`变量的数量;由于当前示例是单变量的,因此设置为 1:
```py
n_y_vars = 1
```
1. 最后,我们通过应用本节开头所述的逻辑将训练和测试数据集转换为`X``Y`集:
```py
X_train, Y_train, X_test, Y_test = tsu.mvts_to_xy(train,
test,n_x=n_x,n_y=n_y)
```
现在数据已经过预处理并可以输入到我们的模型中,让我们使用 TensorFlow 准备一个 SimpleRNN 模型。
\ No newline at end of file
# TensorFlow 中的简单 RNN
在 TensorFlow 中定义和训练简单 RNN 的工作流程如下:
1. 定义模型的超参数:
```py
state_size = 4
n_epochs = 100
n_timesteps = n_x
learning_rate = 0.1
```
这里新的超参数是`state_size``state_size`表示 RNN 单元的权重向量的数量。
1. 为模型定义`X``Y`参数的占位符。`X`占位符的形状为 `(batch_size, number_of_input_timesteps, number_of_inputs)``Y`占位符的形状为`(batch_size, number_of_output_timesteps, number_of_outputs)`。对于`batch_size`,我们使用`None`,以便我们以后可以输入任意大小的批次。
```py
X_p = tf.placeholder(tf.float32, [None, n_timesteps, n_x_vars],
name='X_p')
Y_p = tf.placeholder(tf.float32, [None, n_timesteps, n_y_vars],
name='Y_p')
```
1. 将输入占位符`X_p`转换为长度等于时间步数的张量列表,在此示例中为`n_x`或 1:
```py
# make a list of tensors of length n_timesteps
rnn_inputs = tf.unstack(X_p,axis=1)
```
1. 使用`tf.nn.rnn_cell.BasicRNNCell`创建一个简单的 RNN 单元:
```py
cell = tf.nn.rnn_cell.BasicRNNCell(state_size)
```
1. TensorFlow 提供`static_rnn``dynamic_rnn`便利方法(以及其他方法)分别创建静态和动态 RNN。创建静态 RNN:
```py
rnn_outputs, final_state = tf.nn.static_rnn(cell,
rnn_inputs,
dtype=tf.float32
)
```
静态 RNN 在编译时创建单元,即展开循环。动态 RNN 创建单元,即在运行时展开循环 。在本章中,我们仅展示了 `static_rnn` 的示例,但是一旦获得静态 RNN 的专业知识,就应该探索 `dynamic_rnn`
`static_rnn`方法采用以下参数:
* `cell`:我们之前定义的基本 RNN 单元对象。它可能是另一种单元,我们将在本章中进一步看到。
* `rnn_inputs`:形状`(batch_size, number_of_inputs)`的张量列表。
* `dtype`:初始状态和预期输出的数据类型。
1. 定义预测层的权重和偏差参数:
```py
W = tf.get_variable('W', [state_size, n_y_vars])
b = tf.get_variable('b', [n_y_vars],
initializer=tf.constant_initializer(0.0))
```
1. 将预测层定义为密集线性层:
```py
predictions = [tf.matmul(rnn_output, W) + b \
for rnn_output in rnn_outputs]
```
1. 输出 Y 是 Tensors 的形状;将其转换为张量列表:
```py
y_as_list = tf.unstack(Y_p, num=n_timesteps, axis=1)
```
1. 将损失函数定义为预测标签和实际标签之间的均方误差:
```py
mse = tf.losses.mean_squared_error
losses = [mse(labels=label, predictions=prediction)
for prediction, label in zip(predictions, y_as_list)
]
```
1. 将总损失定义为所有预测时间步长的平均损失:
```py
total_loss = tf.reduce_mean(losses)
```
1. 定义优化器以最小化`total_loss`
```py
optimizer = tf.train.AdagradOptimizer(learning_rate).minimize(total_loss)
```
1. 现在我们已经定义了模型,损耗和优化器函数,让我们训练模型并计算训练损失:
```py
with tf.Session() as tfs:
tfs.run(tf.global_variables_initializer())
epoch_loss = 0.0
for epoch in range(n_epochs):
feed_dict={X_p: X_train.reshape(-1, n_timesteps,
n_x_vars),
Y_p: Y_train.reshape(-1, n_timesteps,
n_x_vars)
}
epoch_loss,y_train_pred,_=tfs.run([total_loss,predictions,
optimizer], feed_dict=feed_dict)
print("train mse = {}".format(epoch_loss))
```
我们得到以下值:
```py
train mse = 0.0019413739209994674
```
1. 让我们在测试数据上测试模型:
```py
feed_dict={X_p: X_test.reshape(-1, n_timesteps,n_x_vars),
Y_p: Y_test.reshape(-1, n_timesteps,n_y_vars)
}
test_loss, y_test_pred = tfs.run([total_loss,predictions],
feed_dict=feed_dict
)
print('test mse = {}'.format(test_loss))
print('test rmse = {}'.format(math.sqrt(test_loss)))
```
我们在测试数据上得到以下 mse 和 rmse(均方根误差):
```py
test mse = 0.008790395222604275
test rmse = 0.09375710758446143
```
这非常令人印象深刻。
这是一个非常简单的例子,只用一个变量值预测一个时间步。在现实生活中,输出受到多个特征的影响,并且需要预测不止一个时间步。后一类问题被称为多变量多时间步进预测问题。这些问题是使用递归神经网络进行更好预测的积极研究领域。
现在让我们重新调整预测和原始值并绘制原始值(请在笔记本中查找代码)。
我们得到以下绘图:
![](img/b83815e7-8ee4-469a-a23a-8a71b9c46b30.png)
令人印象深刻的是,在我们的简单示例中,预测数据几乎与原始数据相匹配。对这种准确预测的一种可能解释是,单个时间步的预测基于来自最后一个时间步的单个变量的预测,因此它们总是在先前值的附近。
尽管如此,前面示例的目的是展示在 TensorFlow 中创建 RNN 的方法。现在让我们使用 RNN 变体重新创建相同的示例。
\ No newline at end of file
# TensorFlow 中的 LSTM
由于爆炸和消失梯度的问题,简单的 RNN 架构并不总是有效,因此使用了改进的 RNN 架构,例如 LSTM 网络。 TensorFlow 提供 API 来创建 LSTM RNN 架构。
在上一节中展示的示例中,要将 Simple RNN 更改为 LSTM 网络,我们所要做的就是更改单元类型,如下所示:
```py
cell = tf.nn.rnn_cell.LSTMCell(state_size)
```
其余代码保持不变,因为 TensorFlow 会为您在 LSTM 单元内创建门。
笔记本 `ch-07a_RNN_TimeSeries_TensorFlow` 中提供了 LSTM 模型的完整代码。
然而,对于 LSTM,我们必须运行 600 个周期的代码才能使结果更接近基本 RNN。原因是 LSTM 需要学习更多参数,因此需要更多的训练迭代。对于我们的简单示例,它似乎有点过分,但对于较大的数据集,与简单的 RNN 相比,LSTM 显示出更好的结果。
具有 LSTM 架构的模型的输出如下:
```py
train mse = 0.0020806745160371065
test mse = 0.01499235536903143
test rmse = 0.12244327408653947
```
![](img/5dd03142-e42f-4e1c-bf60-19e31475b853.png)
\ No newline at end of file
# TensorFlow 中的 GRU
要将最后一节中的 LSTM 示例更改为 GRU 网络, 按如下方式更改单元类型,TensorFlow 将为您处理其余部分:
```py
cell = tf.nn.rnn_cell.GRUCell(state_size)
```
笔记本 `ch-07a_RNN_TimeSeries_TensorFlow`中提供了 GRU 模型的完整代码。
对于小`airpass`数据集,GRU 在相同数量的周期中表现出更好的表现。在实践中,GRU 和 LSTM 表现出相当的表现。就执行速度而言,与 LSTM 相比,GRU 模型训练和预测更快。
GRU 模型的完整代码在 Jupyter 笔记本中提供。GRU 模型的结果如下:
```py
train mse = 0.0019633215852081776
test mse = 0.014307591132819653
test rmse = 0.11961434334066987
```
![](img/2d9ac55a-7f30-406b-934d-3cba2d9c6a91.png)
我们鼓励您探索 TensorFlow 中可用的其他选项来创建循环神经网络。现在让我们在 TensorFlow 的一个高级库中尝试相同的示例。
对于下一节,您可以按照 Jupyter 笔记本中的代码`ch-07b_RNN_TimeSeries_Keras`
\ No newline at end of file
# 使用 Keras RNN 模型预处理数据集
与使用 lower = level TensorFlow 类和方法构建相比,在 Keras 中构建 RNN 网络要简单得多。对于 Keras,我们预先处理数据,如前面部分所述,以获得受监督的机器学习时间序列数据集:`X_train, Y_train, X_test, Y_test`
从这里开始,预处理有所不同。对于 Keras,输入必须是`(samples, time steps, features)`形状。当我们将数据转换为监督机器学习格式时,在重塑数据时,我们可以将时间步长设置为 1,从而将所有输入时间步长作为特征,或者我们可以设置时间步长为实际的时间步数,从而为每个时间步长提供特征集。换句话说,我们之前获得的`X_train``X_test`数据集可以重新整形为以下方法之一:
方法 1:`n`时间步长与`1`特征:
```py
X_train.reshape(X_train.shape[0], X_train.shape[1],1)
```
方法 2:`1`时间步长`n`特征:
```py
X_train.reshape(X_train.shape[0], 1, X_train.shape[1])
```
在本章中,我们将对特征大小为 1 的数据集进行整形,因为我们只使用一个变量作为输入:
```py
# reshape input to be [samples, time steps, features]
X_train = X_train.reshape(X_train.shape[0], X_train.shape[1],1)
X_test = X_test.reshape(X_test.shape[0], X_train.shape[1], 1)
```
\ No newline at end of file
# 使用 Keras 的简单 RNN
通过添加具有内部神经元数量和输入张量形状的 SimpleRNN 层,可以在 Keras 中轻松构建 RNN 模型,不包括样本维数。以下代码创建,编译和拟合 SimpleRNN:
```py
# create and fit the SimpleRNN model
model = Sequential()
model.add(SimpleRNN(units=4, input_shape=(X_train.shape[1],
X_train.shape[2])))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(X_train, Y_train, epochs=20, batch_size=1)
```
由于我们的数据集很小,我们使用`batch_size`为 1 并训练 20 次迭代,但对于较大的数据集,您需要调整这些和其他超参数的值。
该模型的结构如下:
```py
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
simple_rnn_1 (SimpleRNN) (None, 4) 24
_________________________________________________________________
dense_1 (Dense) (None, 1) 5
=================================================================
Total params: 29
Trainable params: 29
Non-trainable params: 0
```
训练的结果如下:
```py
Epoch 1/20
95/95 [==============================] - 0s - loss: 0.0161
Epoch 2/20
95/95 [==============================] - 0s - loss: 0.0074
Epoch 3/20
95/95 [==============================] - 0s - loss: 0.0063
Epoch 4/20
95/95 [==============================] - 0s - loss: 0.0051
-- epoch 5 to 14 removed for the sake of brevity --
Epoch 14/20
95/95 [==============================] - 0s - loss: 0.0021
Epoch 15/20
95/95 [==============================] - 0s - loss: 0.0020
Epoch 16/20
95/95 [==============================] - 0s - loss: 0.0020
Epoch 17/20
95/95 [==============================] - 0s - loss: 0.0020
Epoch 18/20
95/95 [==============================] - 0s - loss: 0.0020
Epoch 19/20
95/95 [==============================] - 0s - loss: 0.0020
Epoch 20/20
95/95 [==============================] - 0s - loss: 0.0020
```
损失从 0.0161 开始,平稳在 0.0020。让我们做出预测并重新调整预测和原件。我们使用 Keras 提供的函数来计算均方根误差:
```py
from keras.losses import mean_squared_error as k_mse
from keras.backend import sqrt as k_sqrt
import keras.backend as K
# make predictions
y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)
# invert predictions
y_train_pred = scaler.inverse_transform(y_train_pred)
y_test_pred = scaler.inverse_transform(y_test_pred)
#invert originals
y_train_orig = scaler.inverse_transform(Y_train)
y_test_orig = scaler.inverse_transform(Y_test)
# calculate root mean squared error
trainScore = k_sqrt(k_mse(y_train_orig[:,0],
y_train_pred[:,0])
).eval(session=K.get_session())
print('Train Score: {0:.2f} RMSE'.format(trainScore))
testScore = k_sqrt(k_mse(y_test_orig[:,0],
y_test_pred[:,0])
).eval(session=K.get_session())
print('Test Score: {0:.2f} RMSE'.format(testScore))
```
我们得到以下结果:
```py
Train Score: 23.27 RMSE
Test Score: 54.13 RMSE
```
![](img/93bcf886-fc39-4e77-8fa0-d72af7ac310b.png)
我们可以看到,这不像我们在 TensorFlow 部分得到的那样完美;但是,这种差异是因为超参数值。我们留给您尝试不同的超参数值来调整此 Keras 模型以获得更好的结果。
\ No newline at end of file
# 使用 Keras 的 LSTM
创建 LSTM 模型只需添加 LSTM 层而不是 SimpleRNN 层,如下所示:
```py
model.add(LSTM(units=4, input_shape=(X_train.shape[1], X_train.shape[2])))
```
模型结构如下所示:
```py
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
lstm_1 (LSTM) (None, 4) 96
_________________________________________________________________
dense_1 (Dense) (None, 1) 5
=================================================================
Total params: 101
Trainable params: 101
Non-trainable params: 0
_________________________________________________________________
```
笔记本 `ch-07b_RNN_TimeSeries_Keras` 中提供了 LSTM 模型的完整代码。
由于 LSTM 模型具有更多需要训练的参数,对于相同数量的迭代(20 个周期),我们得到更高的误差分数。我们留给您探索周期和其他超参数的各种值,以获得更好的结果:
```py
Train Score: 32.21 RMSE
Test Score: 84.68 RMSE
```
![](img/b64ddef8-5b68-44b8-842e-779177ef1557.png)
\ No newline at end of file
# 使用 Keras 的 GRU
使用 TensorFlow 和 Keras 的一个优点是它们可以轻松创建模型。与 LSTM 一样,创建 GRU 模型只需添加 GRU 层而不是 LSTM 或 SimpleRNN 层,如下所示:
```py
model.add(GRU(units=4, input_shape=(X_train.shape[1], X_train.shape[2])))
```
模型结构如下:
```py
Layer (type) Output Shape Param #
=================================================================
gru_1 (GRU) (None, 4) 72
_________________________________________________________________
dense_1 (Dense) (None, 1) 5
=================================================================
Total params: 77
Trainable params: 77
Non-trainable params: 0
```
笔记本 `ch-07b_RNN_TimeSeries_Keras`中提供了 GRU 模型的完整代码。
正如预期的那样,GRU 模型显示出与 LSTM 几乎相同的表现,我们让您尝试使用不同的超参数值来优化此模型:
```py
Train Score: 31.49 RMSE
Test Score: 92.75 RMSE
```
![](img/f5e8871e-1511-408f-ab58-0b3e3b79644d.png)
\ No newline at end of file
# 总结
时间序列数据是基于序列的数据,因此 RNN 模型是从时间序列数据中学习的相关架构。在本章中,您学习了如何使用 TensorFlow(一个低级库)和 Keras(一个高级库)创建不同类型的 RNN 模型。我们只介绍了 SimpleRNN,LSTM 和 GRU,但您应该探索可以使用 TensorFlow 和 Keras 创建的许多其他 RNN 变体。
在下一章中,我们将使用当前章节和前几章中构建的基础为各种**自然语言处理****NLP** )任务创建文本数据的 RNN 模型。
\ No newline at end of file
# 使用 TensorFlow 和 Keras 的文本数据的 RNN
文本数据可以被视为一系列字符,单词,句子或段落。 **循环神经网络****RNN** )已被证明是非常有用的序列神经网络结构。为了将神经网络模型应用于**自然语言处理****NLP** )任务,文本被视为单词序列。事实证明,这对于 NLP 任务非常成功,例如:
* 问题回答
* 会话智能体或聊天机器人
* 文件分类
* 情绪分析
* 图像标题或描述文本生成
* 命名实体识别
* 语音识别和标记
NLP 与 TensorFlow 深度学习技术是一个广阔的领域,很难在一章中捕捉到。因此,我们尝试使用 Tensorflow 和 Keras 为您提供该领域中最流行和最重要的示例。一旦掌握了本章的内容,不要忘记探索和试验 NLP 的其他领域。
在本章中,我们将了解以下主题:
* 词向量表示
* 为 word2vec 模型准备数据
* TensorFlow 和 Keras 中的 skip-gram 模型
* 使用 t-SNE 可视化单词嵌入
* TensorFlow 和 Keras 中使用 LSTM 模型的文本生成示例
\ No newline at end of file
# 操作
TensorFlow 为我们提供了许多可以应用于 Tensors 的操作。通过传递值并将输出分配给另一个张量来定义操作。例如,在提供的 Jupyter Notebook 文件中,我们定义了两个操作,`op1``op2`
```py
op1 = tf.add(c2,c3)
op2 = tf.multiply(c2,c3)
```
当我们打印`op1``op2`时,我们发现它们被定义为张量:
```py
print('op1 : ', op1)
print('op2 : ', op2)
```
输出如下:
```py
op1 : Tensor("Add:0", shape=(), dtype=float32)
op2 : Tensor("Mul:0", shape=(), dtype=float32)
```
要打印这些操作的值,我们必须在 TensorFlow 会话中运行它们:
```py
print('run(op1) : ', tfs.run(op1))
print('run(op2) : ', tfs.run(op2))
```
输出如下:
```py
run(op1) : 13.0
run(op2) : 42.0
```
下表列出了一些内置操作:
| **操作类型** | **操作** |
| --- | --- |
| 算术运算 | `tf.add``tf.subtract``tf.multiply``tf.scalar_mul``tf.div``tf.divide``tf.truediv``tf.floordiv``tf.realdiv``tf.truncatediv``tf.floor_div``tf.truncatemod``tf.floormod``tf.mod``tf.cross` |
| 基本的数学运算 | `tf.add_n``tf.abs``tf.negative``tf.sign``tf.reciprocal``tf.square``tf.round``tf.sqrt``tf.rsqrt``tf.pow``tf.exp``tf.expm1``tf.log``tf.log1p``tf.ceil``tf.floor``tf.maximum``tf.minimum``tf.cos``tf.sin``tf.lbeta``tf.tan``tf.acos``tf.asin``tf.atan``tf.lgamma``tf.digamma``tf.erf``tf.erfc``tf.igamma``tf.squared_difference``tf.igammac``tf.zeta``tf.polygamma``tf.betainc``tf.rint` |
| 矩阵数学运算 | `tf.diag``tf.diag_part``tf.trace``tf.transpose``tf.eye``tf.matrix_diag``tf.matrix_diag_part``tf.matrix_band_part``tf.matrix_set_diag``tf.matrix_transpose``tf.matmul``tf.norm``tf.matrix_determinant` ],`tf.matrix_inverse``tf.cholesky``tf.cholesky_solve``tf.matrix_solve``tf.matrix_triangular_solve``tf.matrix_solve_ls``tf.qr, tf.self_adjoint_eig``tf.self_adjoint_eigvals``tf.svd` |
| 张量数学运算 | `tf.tensordot` |
| 复数运算 | `tf.complex``tf.conj``tf.imag``tf.real` |
| 字符串操作 | `tf.string_to_hash_bucket_fast``tf.string_to_hash_bucket_strong``tf.as_string``tf.encode_base64``tf.decode_base64``tf.reduce_join``tf.string_join``tf.string_split``tf.substr``tf.string_to_hash_bucket` |
\ No newline at end of file
# 词向量表示
为了从文本数据中学习神经网络模型的参数,首先,我们必须将文本或自然语言数据转换为可由神经网络摄取的格式。神经网络通常以数字向量的形式摄取文本。将原始文本数据转换为数字向量的算法称为字嵌入算法。
一种流行的字嵌入方法是我们在 MNIST 图像分类中看到的**单热编码**。假设我们的文本数据集由 60,000 个字典单词组成。然后,每个单词可以由具有 60,000 个元素的单热编码向量表示,其中除了表示具有值 1 的该单词的一个元素之外,所有其他元素具有零值。
然而,单热编码方法有其缺点。首先,对于具有大量单词的词汇,单热词向量的维数变得非常大。其次,人们无法找到与单热编码向量的单词相似性。例如,假设猫和小猫的向量分别为`[1 0 0 0 0 0]``[0 0 0 0 0 1]`。这些向量没有相似之处。
还有其他基于语料库的方法,用于将基于文本的语料库转换为数字向量,例如:
* 术语频率 - 反向文档频率(TF-IDF)
* 潜在语义分析(LSA)
* 主题建模
最近,用数值向量表示单词的焦点已转移到基于分布假设的方法,这意味着具有相似语义含义的单词倾向于出现在类似的上下文中。
两种最广泛使用的方法称为 word2vec 和 GloVe。我们将在本章中使用 word2vec 进行练习。正如我们在前一段中所了解到的,单热编码给出了语料库字典中单词总数大小的维数。使用 word2vec 创建的单词向量的维度要低得多。
word2vec 系列模型使用两种架构构建:
* **连续词汇**:训练模型以学习给定上下文词的中心词的概率分布。因此,给定一组上下文单词,模型以您在高中语言课程中所做的填空方式预测中心单词。 CBOW 体系结构最适用于具有较小词汇表的数据集。
* **Skip-gram** :训练模型以学习给定中心词的上下文词的概率分布。因此,给定一个中心词,模型以您在高中语言课程中完成的句子方式预测语境词。
例如,让我们考虑一下这句话:
```
Vets2data.org is a non-profit for educating the US Military Veterans Community on Artificial Intelligence and Data Science.
```
在 CBOW 架构中,给出单词`Military``Community`,模型学习单词`Veterans`的概率,并在 skip-gram 架构中,给出单词 `Veterans`,模型学习单词`Military``Community`的概率。
word2vec 模型以无监督的方式从文本语料库中学习单词向量。文本语料库分为成对的上下文单词和目标单词。虽然这些对是真正的对,但是伪对是用随机配对的上下文词和上下文词生成的,因此在数据中产生噪声。训练分类器以学习用于区分真对和假对的参数。该分类器的参数成为 word2vec 模型或单词向量。
关于 word2vec 理论背后的数学和理论的更多信息可以从以下论文中学到:
```
Mikolov, T., I. Sutskever, K. Chen, G. Corrado, and J. Dean. Distributed Representations of Words and Phrases and Their Compositionality. _Advances in Neural Information Processing Systems_, 2013, pp. 3111–3119.
Mikolov, T., K. Chen, G. Corrado, and J. Dean. Efficient Estimation of Word Representations in Vector Space. _arXiv_, 2013, pp. 1–12.
Rong, X. word2vec Parameter Learning Explained. _arXiv:1411.2738_, 2014, pp. 1–19.
Baroni, M., G. Dinu, and G. Kruszewski. Don’t Count, Predict! A Systematic Comparison of Context-Counting vs. Context-Predicting Semantic Vectors. 2014.
```
您应该使用 GloVe 和 word2vec 练习并应用适用于您的文本数据的方法。
有关 GLoVe 算法的更多信息可以从以下文章中学习:
```
Pennington, J., R. Socher, and C. Manning. GloVe: Global Vectors for Word Representation. 2014.
```
让我们通过在 TensorFlow 和 Keras 中创建单词向量来理解 word2vec 模型。
您可以按照 Jupyter 笔记本中的下几节的代码`ch-08a_Embeddings_in_TensorFlow_and_Keras`
# 为 word2vec 模型准备数据
我们将使用流行的 PTB 和 text8 数据集进行演示。
**Penn Treebank****PTB** )数据集是在 UPenn 进行的[ Penn Treebank 项目](https://catalog.ldc.upenn.edu/ldc99t42)的副产品。 PTB 项目团队在华尔街日报三年的故事中提取了大约一百万字,并以 Treebank II 风格对其进行了注释。 PTB 数据集有两种形式: 基本示例,大小约为 35 MB, 高级示例,大小约为 235 MB。我们将使用由 929K 字组成的简单数据集进行训练,73K 字用于验证,82K 字用于测试。建议您浏览高级数据集。有关 PTB 数据集的更多详细信息,[请访问此链接](http://www.fit.vutbr.cz/~imikolov/rnnlm/simple-examples.tgz)
[可以从此链接下载 PTB 数据集](http://www.fit.vutbr.cz/~imikolov/rnnlm/rnn-rt07-example.tar.gz)
**text8** 数据集是一个较短的清理版本的大型维基百科数据转储,大小约为 1 GB。有关如何创建 text8 数据集的过程,[请参见此链接](http://mattmahoney.net/dc/textdata.html)
[text8 数据集可以从此链接下载](http://mattmahoney.net/dc/text8.zip)
使用我们的自定义库`datasetslib`中的`load_data`代码加载数据集:
`load_data()`函数执行以下操作:
1. 如果数据集的 URL 在本地不可用,它将从数据集的 URL 下载数据存档。
2. 由于`PTB`数据有三个文件,它首先从训练文件中读取文本,而对于`text8`,它从归档中读取第一个文件。
3. 它将训练文件中的单词转换为词汇表,并为每个词汇单词分配一个唯一的数字,word-id,将其存储在集合`word2id`中,并准备反向词典,这样我们就可以从 ID 中查找单词,并将其存储在集合`id2word`中。
1. 它使用集合`word2id`将文本文件转换为 ID 序列。
2. 因此,在`load_data`的末尾,我们在训练数据集中有一系列数字,在集合`id2word`中有一个 ID 到字的映射。
让我们看一下从 text8 和 PTB 数据集加载的数据:
\ No newline at end of file
# 加载和准备 PTB 数据集
首先导入模块并加载数据如下::
```py
from datasetslib.ptb import PTBSimple
ptb = PTBSimple()
# downloads data, converts words to ids, converts files to a list of ids
ptb.load_data()
print('Train :',ptb.part['train'][0:5])
print('Test: ',ptb.part['test'][0:5])
print('Valid: ',ptb.part['valid'][0:5])
print('Vocabulary Length = ',ptb.vocab_len)
```
每个数据集的前五个元素以及词汇长度打印如下:
```py
Train : [9970, 9971, 9972, 9974, 9975]
Test: [102, 14, 24, 32, 752]
Valid: [1132, 93, 358, 5, 329]
Vocabulary Length = 10000
```
我们将上下文窗口设置为两个单词并获得 CBOW 对:
```py
ptb.skip_window=2
ptb.reset_index_in_epoch()
# in CBOW input is the context word and output is the target word
y_batch, x_batch = ptb.next_batch_cbow()
print('The CBOW pairs : context,target')
for i in range(5 * ptb.skip_window):
print('(', [ptb.id2word[x_i] for x_i in x_batch[i]],
',', y_batch[i], ptb.id2word[y_batch[i]], ')')
```
输出是:
```py
The CBOW pairs : context,target
( ['aer', 'banknote', 'calloway', 'centrust'] , 9972 berlitz )
( ['banknote', 'berlitz', 'centrust', 'cluett'] , 9974 calloway )
( ['berlitz', 'calloway', 'cluett', 'fromstein'] , 9975 centrust )
( ['calloway', 'centrust', 'fromstein', 'gitano'] , 9976 cluett )
( ['centrust', 'cluett', 'gitano', 'guterman'] , 9980 fromstein )
( ['cluett', 'fromstein', 'guterman', 'hydro-quebec'] , 9981 gitano )
( ['fromstein', 'gitano', 'hydro-quebec', 'ipo'] , 9982 guterman )
( ['gitano', 'guterman', 'ipo', 'kia'] , 9983 hydro-quebec )
( ['guterman', 'hydro-quebec', 'kia', 'memotec'] , 9984 ipo )
( ['hydro-quebec', 'ipo', 'memotec', 'mlx'] , 9986 kia )
```
现在让我们看看 skip-gram 对:
```py
ptb.skip_window=2
ptb.reset_index_in_epoch()
# in skip-gram input is the target word and output is the context word
x_batch, y_batch = ptb.next_batch()
print('The skip-gram pairs : target,context')
for i in range(5 * ptb.skip_window):
print('(',x_batch[i], ptb.id2word[x_batch[i]],
',', y_batch[i], ptb.id2word[y_batch[i]],')')
```
输出为:
```py
The skip-gram pairs : target,context
( 9972 berlitz , 9970 aer )
( 9972 berlitz , 9971 banknote )
( 9972 berlitz , 9974 calloway )
( 9972 berlitz , 9975 centrust )
( 9974 calloway , 9971 banknote )
( 9974 calloway , 9972 berlitz )
( 9974 calloway , 9975 centrust )
( 9974 calloway , 9976 cluett )
( 9975 centrust , 9972 berlitz )
( 9975 centrust , 9974 calloway )
```
\ No newline at end of file
# 加载和准备 text8 数据集
现在我们使用 text8 数据集执行相同的加载和预处理步骤:
```py
from datasetslib.text8 import Text8
text8 = Text8()
text8.load_data()
# downloads data, converts words to ids, converts files to a list of ids
print('Train:', text8.part['train'][0:5])
print('Vocabulary Length = ',text8.vocab_len)
```
我们发现词汇长度大约是 254,000 字:
```py
Train: [5233, 3083, 11, 5, 194]
Vocabulary Length = 253854
```
一些教程通过查找最常用的单词或将词汇量大小截断为 10,000 个单词来操纵此数据。 但是,我们使用了 text8 数据集的第一个文件中的完整数据集和完整词汇表。
准备 CBOW 对:
```py
text8.skip_window=2
text8.reset_index_in_epoch()
# in CBOW input is the context word and output is the target word
y_batch, x_batch = text8.next_batch_cbow()
print('The CBOW pairs : context,target')
for i in range(5 * text8.skip_window):
print('(', [text8.id2word[x_i] for x_i in x_batch[i]],
',', y_batch[i], text8.id2word[y_batch[i]], ')')
```
输出是:
```py
The CBOW pairs : context,target
( ['anarchism', 'originated', 'a', 'term'] , 11 as )
( ['originated', 'as', 'term', 'of'] , 5 a )
( ['as', 'a', 'of', 'abuse'] , 194 term )
( ['a', 'term', 'abuse', 'first'] , 1 of )
( ['term', 'of', 'first', 'used'] , 3133 abuse )
( ['of', 'abuse', 'used', 'against'] , 45 first )
( ['abuse', 'first', 'against', 'early'] , 58 used )
( ['first', 'used', 'early', 'working'] , 155 against )
( ['used', 'against', 'working', 'class'] , 127 early )
( ['against', 'early', 'class', 'radicals'] , 741 working )
```
准备 skip-gram 对:
```py
text8.skip_window=2
text8.reset_index_in_epoch()
# in skip-gram input is the target word and output is the context word
x_batch, y_batch = text8.next_batch()
print('The skip-gram pairs : target,context')
for i in range(5 * text8.skip_window):
print('(',x_batch[i], text8.id2word[x_batch[i]],
',', y_batch[i], text8.id2word[y_batch[i]],')')
```
输出为:
```py
The skip-gram pairs : target,context
( 11 as , 5233 anarchism )
( 11 as , 3083 originated )
( 11 as , 5 a )
( 11 as , 194 term )
( 5 a , 3083 originated )
( 5 a , 11 as )
( 5 a , 194 term )
( 5 a , 1 of )
( 194 term , 11 as )
( 194 term , 5 a )
```
\ No newline at end of file
# 准备小验证集
为了演示该示例,我们创建了一个包含 8 个单词的小型验证集,每个单词是从单词中随机选择的,其中 word-id 在 0 到 10 x 8 之间。
```py
valid_size = 8
x_valid = np.random.choice(valid_size * 10, valid_size, replace=False)
print(x_valid)
```
作为示例,我们将以下内容作为验证集:
```py
valid: [64 58 59 4 69 53 31 77]
```
我们将使用此验证集通过打印五个最接近的单词来演示嵌入一词的结果。
\ No newline at end of file
# 使用 TensorFlow 的 skip-gram 模型
现在我们已经准备好了训练和验证数据,让我们在 TensorFlow 中创建一个 skip-gram 模型。
我们首先定义超参数:
```py
batch_size = 128
embedding_size = 128
skip_window = 2
n_negative_samples = 64
ptb.skip_window=2
learning_rate = 1.0
```
* `batch_size`是要在单个批次中输入算法的目标和上下文单词对的数量
* `embedding_size`是每个单词的单词向量或嵌入的维度
* `ptb.skip_window`是在两个方向上的目标词的上下文中要考虑的词的数量
* `n_negative_samples`是由 NCE 损失函数生成的负样本数,本章将进一步说明
在一些教程中,包括 TensorFlow 文档中的一个教程,还使用了一个参数`num_skips`。在这样的教程中,作者选择了`num_skips`(目标,上下文)对。例如,如果`skip_window`是 2,那么对的总数将是 4,如果`num_skips`被设置为 2,则只有两对将被随机选择用于训练。但是,我们考虑了所有的对以便保持训练练习简单。
定义训练数据的输入和输出占位符以及验证数据的张量:
```py
inputs = tf.placeholder(dtype=tf.int32, shape=[batch_size])
outputs = tf.placeholder(dtype=tf.int32, shape=[batch_size,1])
inputs_valid = tf.constant(x_valid, dtype=tf.int32)
```
定义一个嵌入矩阵,其行数等于词汇长度,列等于嵌入维度。该矩阵中的每一行将表示词汇表中一个单词的单词向量。使用在-1.0 到 1.0 之间均匀采样的值填充此嵌入矩阵。
```py
# define embeddings matrix with vocab_len rows and embedding_size columns
# each row represents vectore representation or embedding of a word
# in the vocbulary
embed_dist = tf.random_uniform(shape=[ptb.vocab_len, embedding_size],
minval=-1.0,maxval=1.0)
embed_matrix = tf.Variable(embed_dist,name='embed_matrix')
```
使用此矩阵,定义使用`tf.nn.embedding_lookup()`实现的嵌入查找表。 `tf.nn.embedding_lookup()`有两个参数:嵌入矩阵和输入占位符。 lookup 函数返回`inputs`占位符中单词的单词向量。
```py
# define the embedding lookup table
# provides the embeddings of the word ids in the input tensor
embed_ltable = tf.nn.embedding_lookup(embed_matrix, inputs)
```
`embed_ltable`也可以解释为输入层顶部的嵌入层。接下来,将嵌入层的输出馈送到 softmax 或噪声对比估计(NCE)层。 NCE 基于一个非常简单的想法,即训练基于逻辑回归的二分类器,以便从真实和嘈杂数据的混合中学习参数。
TensorFlow documentation describes the NCE in further detail: [https://www.tensorflow.org/tutorials/word2vec.](https://www.tensorflow.org/tutorials/word2vec#scaling_up_with_noise-contrastive_training)
总之,基于 softmax 损失的模型在计算上是昂贵的,因为在整个词汇表中计算概率分布并对其进行归一化。基于 NCE 损耗的模型将其减少为二分类问题,即从噪声样本中识别真实样本。
NCE 的基本数学细节可以在以下 NIPS 论文中找到:_学习词嵌入有效地与噪声对比估计_,作者 Andriy Mnih 和 Koray Kavukcuoglu。[该论文可从此链接获得](http://papers.nips.cc/paper/5165-learning-word-embeddings-efficiently-with-noise-contrastive-estimation.pdf)
`tf.nn.nce_loss()`函数在评估计算损耗时自动生成负样本:参数`num_sampled`设置为等于负样本数(`n_negative_samples`)。此参数指定要绘制的负样本数。
```py
# define noise-contrastive estimation (NCE) loss layer
nce_dist = tf.truncated_normal(shape=[ptb.vocab_len, embedding_size],
stddev=1.0 /
tf.sqrt(embedding_size * 1.0)
)
nce_w = tf.Variable(nce_dist)
nce_b = tf.Variable(tf.zeros(shape=[ptb.vocab_len]))
loss = tf.reduce_mean(tf.nn.nce_loss(weights=nce_w,
biases=nce_b,
inputs=embed_ltable,
labels=outputs,
num_sampled=n_negative_samples,
num_classes=ptb.vocab_len
)
)
```
接下来,计算验证集中的样本与嵌入矩阵之间的余弦相似度:
1. 为了计算相似性得分,首先,计算嵌入矩阵中每个单词向量的 L2 范数。
```py
# Compute the cosine similarity between validation set samples
# and all embeddings.
norm = tf.sqrt(tf.reduce_sum(tf.square(embed_matrix), 1,
keep_dims=True))
normalized_embeddings = embed_matrix / norm
```
1. 在验证集中查找样本的嵌入或单词向量:
```py
embed_valid = tf.nn.embedding_lookup(normalized_embeddings,
inputs_valid)
```
1. 通过将验证集的嵌入与嵌入矩阵相乘来计算相似性得分。
```py
similarity = tf.matmul(
embed_valid, normalized_embeddings, transpose_b=True)
```
这给出了具有(`valid_size``vocab_len`)形状的张量。张量中的每一行指的是验证词和词汇单词之间的相似性得分。
接下来,定义 SGD 优化器,学习率为 0.9,历时 50 个周期。
```py
n_epochs = 10
learning_rate = 0.9
n_batches = ptb.n_batches(batch_size)
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
.minimize(loss)
```
对于每个周期:
1. 逐批运行整个数据集上的优化器。
```py
ptb.reset_index_in_epoch()
for step in range(n_batches):
x_batch, y_batch = ptb.next_batch()
y_batch = dsu.to2d(y_batch,unit_axis=1)
feed_dict = {inputs: x_batch, outputs: y_batch}
_, batch_loss = tfs.run([optimizer, loss], feed_dict=feed_dict)
epoch_loss += batch_loss
```
1. 计算并打印周期的平均损失。
```py
epoch_loss = epoch_loss / n_batches
print('\n','Average loss after epoch ', epoch, ': ', epoch_loss)
```
1. 在周期结束时,计算相似性得分。
```py
similarity_scores = tfs.run(similarity)
```
1. 对于验证集中的每个单词,打印具有最高相似性得分的五个单词。
```py
top_k = 5
for i in range(valid_size):
similar_words = (-similarity_scores[i,:])
.argsort()[1:top_k + 1]
similar_str = 'Similar to {0:}:'
.format(ptb.id2word[x_valid[i]])
for k in range(top_k):
similar_str = '{0:} {1:},'.format(similar_str,
ptb.id2word[similar_words[k]])
print(similar_str)
```
最后,在完成所有周期之后,计算可在学习过程中进一步利用的嵌入向量:
```py
final_embeddings = tfs.run(normalized_embeddings)
```
完整的训练代码如下:
```py
n_epochs = 10
learning_rate = 0.9
n_batches = ptb.n_batches_wv()
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
with tf.Session() as tfs:
tf.global_variables_initializer().run()
for epoch in range(n_epochs):
epoch_loss = 0
ptb.reset_index()
for step in range(n_batches):
x_batch, y_batch = ptb.next_batch_sg()
y_batch = nputil.to2d(y_batch, unit_axis=1)
feed_dict = {inputs: x_batch, outputs: y_batch}
_, batch_loss = tfs.run([optimizer, loss], feed_dict=feed_dict)
epoch_loss += batch_loss
epoch_loss = epoch_loss / n_batches
print('\nAverage loss after epoch ', epoch, ': ', epoch_loss)
# print closest words to validation set at end of every epoch
similarity_scores = tfs.run(similarity)
top_k = 5
for i in range(valid_size):
similar_words = (-similarity_scores[i, :]
).argsort()[1:top_k + 1]
similar_str = 'Similar to {0:}:'.format(
ptb.id2word[x_valid[i]])
for k in range(top_k):
similar_str = '{0:} {1:},'.format(
similar_str, ptb.id2word[similar_words[k]])
print(similar_str)
final_embeddings = tfs.run(normalized_embeddings)
```
这是我们分别在第 1 和第 10 周期之后得到的输出:
```py
Average loss after epoch 0 : 115.644006802
Similar to we: types, downturn, internal, by, introduce,
Similar to been: said, funds, mcgraw-hill, street, have,
Similar to also: will, she, next, computer, 's,
Similar to of: was, and, milk, dollars, $,
Similar to last: be, october, acknowledging, requested, computer,
Similar to u.s.: plant, increase, many, down, recent,
Similar to an: commerce, you, some, american, a,
Similar to trading: increased, describes, state, companies, in,
Average loss after epoch 9 : 5.56538496033
Similar to we: types, downturn, introduce, internal, claims,
Similar to been: exxon, said, problem, mcgraw-hill, street,
Similar to also: will, she, ssangyong, audit, screens,
Similar to of: seasonal, dollars, motor, none, deaths,
Similar to last: acknowledging, allow, incorporated, joint, requested,
Similar to u.s.: undersecretary, typically, maxwell, recent, increase,
Similar to an: banking, officials, imbalances, americans, manager,
Similar to trading: describes, increased, owners, committee, else,
```
最后,我们运行 5000 个周期的模型并获得以下结果:
```py
Average loss after epoch 4999 : 2.74216903135
Similar to we: matter, noted, here, classified, orders,
Similar to been: good, precedent, medium-sized, gradual, useful,
Similar to also: introduce, england, index, able, then,
Similar to of: indicator, cleveland, theory, the, load,
Similar to last: dec., office, chrysler, march, receiving,
Similar to u.s.: label, fannie, pressures, squeezed, reflection,
Similar to an: knowing, outlawed, milestones, doubled, base,
Similar to trading: associates, downturn, money, portfolios, go,
```
尝试进一步运行,最多 50,000 个周期,以获得更好的结果。
同样,我们在 50 个周期之后使用 text8 模型得到以下结果:
```py
Average loss after epoch 49 : 5.74381046423
Similar to four: five, three, six, seven, eight,
Similar to all: many, both, some, various, these,
Similar to between: with, through, thus, among, within,
Similar to a: another, the, any, each, tpvgames,
Similar to that: which, however, although, but, when,
Similar to zero: five, three, six, eight, four,
Similar to is: was, are, has, being, busan,
Similar to no: any, only, the, another, trinomial,
```
\ No newline at end of file
# 使用 t-SNE 可视化单词嵌入
让我们可视化我们在上一节中生成的单词嵌入。 t-SNE 是在二维空间中显示高维数据的最流行的方法。我们将使用 scikit-learn 库中的方法,并重用 TensorFlow 文档中给出的代码,来绘制我们刚学过的词嵌入的图形。
[TensorFlow 文档中的原始代码可从此链接获得](https://github.com/tensorflow/tensorflow/blob/r1.3/tensorflow/examples/tutorials/word2vec/word2vec_basic.py)
以下是我们如何实现该程序:
1. 创建`tsne`模型:
```py
tsne = TSNE(perplexity=30, n_components=2,
init='pca', n_iter=5000, method='exact')
```
1. 将要显示的嵌入数限制为 500,否则,图形变得非常难以理解:
```py
n_embeddings = 500
```
1. 通过调用`tsne`模型上的`fit_transform()`方法并将`final_embeddings`的第一个`n_embeddings`作为输入来创建低维表示。
```py
low_dim_embeddings = tsne.fit_transform(
final_embeddings[:n_embeddings, :])
```
1. 找到我们为图表选择的单词向量的文本表示:
```py
labels = [ptb.id2word[i] for i in range(n_embeddings)]
```
1. 最后,绘制嵌入图:
```py
plot_with_labels(low_dim_embeddings, labels)
```
我们得到以下绘图:
![](img/16116250-d5d1-4e33-943a-f9c465a7edbf.png)t-SNE visualization of embeddings for PTB data set
同样,从 text8 模型中,我们得到以下图:
![](img/652fb621-e9a3-48bb-8270-ee1073f69df3.png)t-SNE visualization of embeddings for text8 data set
\ No newline at end of file
# keras 的 skip-gram 模型
使用 Keras 的嵌入模型的流程与 TensorFlow 保持一致。
* 在 Keras 函数式或顺序模型中创建网络体系结构
* 将目标和上下文单词的真假对提供给网络
* 查找目标和上下文单词的单词向量
* 执行单词向量的点积以获得相似性得分
* 将相似性得分通过 sigmoid 层以将输出作为真或假对
现在让我们使用 Keras 函数式 API 实现这些步骤:
1. 导入所需的库:
```py
from keras.models import Model
from keras.layers.embeddings import Embedding
from keras.preprocessing import sequence
from keras.preprocessing.sequence import skipgrams
from keras.layers import Input, Dense, Reshape, Dot, merge
import keras
```
重置图,以便清除以前在 Jupyter Notebook 中运行的任何后续效果:
```py
# reset the jupyter buffers
tf.reset_default_graph()
keras.backend.clear_session()
```
1. 创建一个验证集,我们将用它来打印我们的模型在训练结束时找到的相似单词:
```py
valid_size = 8
x_valid = np.random.choice(valid_size * 10, valid_size, replace=False)
print('valid: ',x_valid)
```
1. 定义所需的超参数:
```py
batch_size = 1024
embedding_size = 512
n_negative_samples = 64
ptb.skip_window=2
```
1. 使用`keras.preprocessing.sequence`中的`make_sampling_table()`函数创建一个大小等于词汇长度的样本表。接下来,使用`keras.preprocessing.sequence`中的函数`skipgrams()`生成上下文和目标词对以及表示它们是真对还是假对的标签。
```py
sample_table = sequence.make_sampling_table(ptb.vocab_len)
pairs, labels= sequence.skipgrams(ptb.part['train'],
ptb.vocab_len,window_size=ptb.skip_window,
sampling_table=sample_table)
```
1. 让我们打印一些使用以下代码生成的伪造和真实对:
```py
print('The skip-gram pairs : target,context')
for i in range(5 * ptb.skip_window):
print(['{} {}'.format(id,ptb.id2word[id]) \
for id in pairs[i]],':',labels[i])
```
对配对如下:
```py
The skip-gram pairs : target,context
['547 trying', '5 to'] : 1
['4845 bargain', '2 <eos>'] : 1
['1705 election', '198 during'] : 1
['4704 flows', '8117 gun'] : 0
['13 is', '37 company'] : 1
['625 above', '132 three'] : 1
['5768 pessimistic', '1934 immediate'] : 0
['637 china', '2 <eos>'] : 1
['258 five', '1345 pence'] : 1
['1956 chrysler', '8928 exercises'] : 0
```
1. 从上面生成的对中拆分目标和上下文单词,以便将它们输入模型。将目标和上下文单词转换为二维数组。
```py
x,y=zip(*pairs)
x=np.array(x,dtype=np.int32)
x=dsu.to2d(x,unit_axis=1)
y=np.array(y,dtype=np.int32)
y=dsu.to2d(y,unit_axis=1)
labels=np.array(labels,dtype=np.int32)
labels=dsu.to2d(labels,unit_axis=1)
```
1. 定义网络的体系结构。正如我们所讨论的,必须将目标和上下文单词输入网络,并且需要从嵌入层中查找它们的向量。因此,首先我们分别为目标和上下文单词定义输入,嵌入和重塑层:
```py
# build the target word model
target_in = Input(shape=(1,),name='target_in')
target = Embedding(ptb.vocab_len,embedding_size,input_length=1,
name='target_em')(target_in)
target = Reshape((embedding_size,1),name='target_re')(target)
# build the context word model
context_in = Input((1,),name='context_in')
context = Embedding(ptb.vocab_len,embedding_size,input_length=1,
name='context_em')(context_in)
context = Reshape((embedding_size,1),name='context_re')(context)
```
1. 接下来,构建这两个模型的点积,将其输入 sigmoid 层以生成输出标签:
```py
# merge the models with the dot product to check for
# similarity and add sigmoid layer
output = Dot(axes=1,name='output_dot')([target,context])
output = Reshape((1,),name='output_re')(output)
output = Dense(1, activation='sigmoid',name='output_sig')(output)
```
1. 从我们刚刚创建的输入和输出模型构建函数式模型:
```py
# create the functional model for finding word vectors
model = Model(inputs=[target_in,context_in],outputs=output)
model.compile(loss='binary_crossentropy', optimizer='adam')
```
1. 此外,在给定输入目标词的情况下,构建一个模型,用于预测与所有单词的相似性:
```py
# merge the models and create model to check for cosine similarity
similarity = Dot(axes=0,normalize=True,
name='sim_dot')([target,context])
similarity_model = Model(inputs=[target_in,context_in],
outputs=similarity)
```
让我们打印模型摘要:
```py
__________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==========================================================================
target_in (InputLayer) (None, 1) 0
__________________________________________________________________________
context_in (InputLayer) (None, 1) 0
__________________________________________________________________________
target_em (Embedding) (None, 1, 512) 5120000 target_in[0][0]
__________________________________________________________________________
context_em (Embedding) (None, 1, 512) 5120000 context_in[0][0]
__________________________________________________________________________
target_re (Reshape) (None, 512, 1) 0 target_em[0][0]
__________________________________________________________________________
context_re (Reshape) (None, 512, 1) 0 context_em[0][0]
__________________________________________________________________________
output_dot (Dot) (None, 1, 1) 0 target_re[0][0]
context_re[0][0]
__________________________________________________________________________
output_re (Reshape) (None, 1) 0 output_dot[0][0]
__________________________________________________________________________
output_sig (Dense) (None, 1) 2 output_re[0][0]
==========================================================================
Total params: 10,240,002
Trainable params: 10,240,002
Non-trainable params: 0
__________________________________________________________________________
```
1. 接下来,训练模型。我们只训练了 5 个周期,但你应该尝试更多的周期,至少 1000 或 10,000 个周期。
请记住,这将需要几个小时,因为这不是最优化的代码。 欢迎您使用本书和其他来源的提示和技巧进一步优化代码。
```py
n_epochs = 5
batch_size = 1024
model.fit([x,y],labels,batch_size=batch_size, epochs=n_epochs)
```
让我们根据这个模型发现的单词向量打印单词的相似度:
```py
# print closest words to validation set at end of training
top_k = 5
y_val = np.arange(ptb.vocab_len, dtype=np.int32)
y_val = dsu.to2d(y_val,unit_axis=1)
for i in range(valid_size):
x_val = np.full(shape=(ptb.vocab_len,1),fill_value=x_valid[i],
dtype=np.int32)
similarity_scores = similarity_model.predict([x_val,y_val])
similarity_scores=similarity_scores.flatten()
similar_words = (-similarity_scores).argsort()[1:top_k + 1]
similar_str = 'Similar to {0:}:'.format(ptb.id2word[x_valid[i]])
for k in range(top_k):
similar_str = '{0:} {1:},'.format(similar_str,
ptb.id2word[similar_words[k]])
print(similar_str)
```
我们得到以下输出:
```py
Similar to we: rake, kia, sim, ssangyong, memotec,
Similar to been: nahb, sim, rake, punts, rubens,
Similar to also: photography, snack-food, rubens, nahb, ssangyong,
Similar to of: isi, rake, memotec, kia, mlx,
Similar to last: rubens, punts, memotec, sim, photography,
Similar to u.s.: mlx, memotec, punts, rubens, kia,
Similar to an: memotec, isi, ssangyong, rake, sim,
Similar to trading: rake, rubens, swapo, mlx, nahb,
```
到目前为止,我们已经看到了如何使用 TensorFlow 及其高级库 Keras 创建单词向量或嵌入。现在让我们看看如何使用 TensorFlow 和 Keras 来学习模型并将模型应用于一些与 NLP 相关的任务的预测。
\ No newline at end of file
# 使用 TensorFlow 和 Keras 中的 RNN 模型生成文本
文本生成是 NLP 中 RNN 模型的主要应用之一。针对文本序列训练 RNN 模型,然后通过提供种子文本作为输入来生成文本序列。让我们试试 text8 数据集。
让我们加载 text8 数据集并打印前 100 个单词:
```py
from datasetslib.text8 import Text8
text8 = Text8()
# downloads data, converts words to ids, converts files to a list of ids
text8.load_data()
print(' '.join([text8.id2word[x_i] for x_i in text8.part['train'][0:100]]))
```
我们得到以下输出:
```py
anarchism originated as a term of abuse first used against early working class radicals including the diggers of the english revolution and the sans culottes of the french revolution whilst the term is still used in a pejorative way to describe any act that used violent means to destroy the organization of society it has also been taken up as a positive label by self defined anarchists the word anarchism is derived from the greek without archons ruler chief king anarchism as a political philosophy is the belief that rulers are unnecessary and should be abolished although there are differing
```
在我们的笔记本示例中,我们将数据加载剪切为 5,000 字的文本,因为较大的文本需要高级技术,例如分布式或批量,我们希望保持示例简单。
```py
from datasetslib.text8 import Text8
text8 = Text8()
text8.load_data(clip_at=5000)
print('Train:', text8.part['train'][0:5])
print('Vocabulary Length = ',text8.vocab_len)
```
我们看到词汇量现在减少到 1,457 个单词。
```py
Train: [ 8 497 7 5 116]
Vocabulary Length = 1457
```
在我们的示例中,我们构造了一个非常简单的单层 LSTM。为了训练模型,我们使用 5 个单词作为输入来学习第六个单词的参数。输入层是 5 个字,隐藏层是具有 128 个单元的 LSTM 单元,最后一层是完全连接的层,其输出等于词汇量大小。由于我们正在演示这个例子,我们没有使用单词向量,而是使用非常简单的单热编码输出向量。
一旦模型被训练,我们用 2 个不同的字符串作为生成更多字符的种子来测试它:
* `random5`:随机选择 5 个单词生成的字符串。
* `first5`:从文本的前 5 个单词生成的字符串。
```py
random5 = np.random.choice(n_x * 50, n_x, replace=False)
print('Random 5 words: ',id2string(random5))
first5 = text8.part['train'][0:n_x].copy()
print('First 5 words: ',id2string(first5))
```
我们看到种子串是:
```py
Random 5 words: free bolshevik be n another
First 5 words: anarchism originated as a term
```
对于您的执行,随机种子字符串可能不同。
现在让我们首先在 TensorFlow 中创建 LSTM 模型。
\ No newline at end of file
# TensorFlow 中的 LSTM 文本生成
您可以在 Jupyter 笔记本`ch-08b_RNN_Text_TensorFlow`中按照本节的代码进行操作。
我们使用以下步骤在 TensorFlow 中实现文本生成 LSTM:
1. 让我们为`x``y`定义参数和占位符:
```py
batch_size = 128
n_x = 5 # number of input words
n_y = 1 # number of output words
n_x_vars = 1 # in case of our text, there is only 1 variable at each timestep
n_y_vars = text8.vocab_len
state_size = 128
learning_rate = 0.001
x_p = tf.placeholder(tf.float32, [None, n_x, n_x_vars], name='x_p')
y_p = tf.placeholder(tf.float32, [None, n_y_vars], name='y_p')
```
对于输入,我们使用单词的整数表示,因此`n_x_vars`是 1.对于输出,我们使用单热编码值,因此输出的数量等于词汇长度。
1. 接下来,创建一个长度为`n_x`的张量列表:
```py
x_in = tf.unstack(x_p,axis=1,name='x_in')
```
1. 接下来,从输入和单元创建 LSTM 单元和静态 RNN 网络:
```py
cell = tf.nn.rnn_cell.LSTMCell(state_size)
rnn_outputs, final_states = tf.nn.static_rnn(cell, x_in,dtype=tf.float32)
```
1. 接下来,我们定义最终层的权重,偏差和公式。最后一层只需要为第六个单词选择输出,因此我们应用以下公式来仅获取最后一个输出:
```py
# output node parameters
w = tf.get_variable('w', [state_size, n_y_vars], initializer= tf.random_normal_initializer)
b = tf.get_variable('b', [n_y_vars], initializer=tf.constant_initializer(0.0))
y_out = tf.matmul(rnn_outputs[-1], w) + b
```
1. 接下来,创建一个损失函数和优化器:
```py
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
logits=y_out, labels=y_p))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
.minimize(loss)
```
1. 创建我们可以在会话块中运行的准确率函数,以检查训练模式的准确性:
```py
n_correct_pred = tf.equal(tf.argmax(y_out,1), tf.argmax(y_p,1))
accuracy = tf.reduce_mean(tf.cast(n_correct_pred, tf.float32))
```
1. 最后,我们训练模型 1000 个周期,并每 100 个周期打印结果。此外,每 100 个周期,我们从上面描述的种子字符串打印生成的文本。
LSTM 和 RNN 网络需要对大量数据集进行大量周期的训练,以获得更好的结果。 请尝试加载完整的数据集并在计算机上运行 50,000或80,000 个周期,并使用其他超参数来改善结果。
```py
n_epochs = 1000
learning_rate = 0.001
text8.reset_index_in_epoch()
n_batches = text8.n_batches_seq(batch_size=batch_size,n_tx=n_x,n_ty=n_y)
n_epochs_display = 100
with tf.Session() as tfs:
tf.global_variables_initializer().run()
for epoch in range(n_epochs):
epoch_loss = 0
epoch_accuracy = 0
for step in range(n_batches):
x_batch, y_batch = text8.next_batch_seq(batch_size=batch_size,
n_tx=n_x,n_ty=n_y)
y_batch = dsu.to2d(y_batch,unit_axis=1)
y_onehot = np.zeros(shape=[batch_size,text8.vocab_len],
dtype=np.float32)
for i in range(batch_size):
y_onehot[i,y_batch[i]]=1
feed_dict = {x_p: x_batch.reshape(-1, n_x, n_x_vars),
y_p: y_onehot}
_, batch_accuracy, batch_loss = tfs.run([optimizer,accuracy,
loss],feed_dict=feed_dict)
epoch_loss += batch_loss
epoch_accuracy += batch_accuracy
if (epoch+1) % (n_epochs_display) == 0:
epoch_loss = epoch_loss / n_batches
epoch_accuracy = epoch_accuracy / n_batches
print('\nEpoch {0:}, Average loss:{1:}, Average accuracy:{2:}'.
format(epoch,epoch_loss,epoch_accuracy ))
y_pred_r5 = np.empty([10])
y_pred_f5 = np.empty([10])
x_test_r5 = random5.copy()
x_test_f5 = first5.copy()
# let us generate text of 10 words after feeding 5 words
for i in range(10):
for x,y in zip([x_test_r5,x_test_f5],
[y_pred_r5,y_pred_f5]):
x_input = x.copy()
feed_dict = {x_p: x_input.reshape(-1, n_x, n_x_vars)}
y_pred = tfs.run(y_out, feed_dict=feed_dict)
y_pred_id = int(tf.argmax(y_pred, 1).eval())
y[i]=y_pred_id
x[:-1] = x[1:]
x[-1] = y_pred_id
print(' Random 5 prediction:',id2string(y_pred_r5))
print(' First 5 prediction:',id2string(y_pred_f5))
```
结果如下:
```py
Epoch 99, Average loss:1.3972469369570415, Average accuracy:0.8489583333333334
Random 5 prediction: labor warren together strongly profits strongly supported supported co without
First 5 prediction: market own self free together strongly profits strongly supported supported
Epoch 199, Average loss:0.7894854595263799, Average accuracy:0.9186197916666666
Random 5 prediction: syndicalists spanish class movements also also anarcho anarcho anarchist was
First 5 prediction: five civil association class movements also anarcho anarcho anarcho anarcho
Epoch 299, Average loss:1.360412875811259, Average accuracy:0.865234375
Random 5 prediction: anarchistic beginnings influenced true tolstoy tolstoy tolstoy tolstoy tolstoy tolstoy
First 5 prediction: early civil movement be for was two most most most
Epoch 399, Average loss:1.1692512730757396, Average accuracy:0.8645833333333334
Random 5 prediction: including war than than revolutionary than than war than than
First 5 prediction: left including including including other other other other other other
Epoch 499, Average loss:0.5921860883633295, Average accuracy:0.923828125
Random 5 prediction: ever edited interested interested variety variety variety variety variety variety
First 5 prediction: english market herbert strongly price interested variety variety variety variety
Epoch 599, Average loss:0.8356450994809469, Average accuracy:0.8958333333333334
Random 5 prediction: management allow trabajo trabajo national national mag mag ricardo ricardo
First 5 prediction: spain prior am working n war war war self self
Epoch 699, Average loss:0.7057955612738928, Average accuracy:0.8971354166666666
Random 5 prediction: teachings can directive tend resist obey christianity author christianity christianity
First 5 prediction: early early called social called social social social social social
Epoch 799, Average loss:0.772875706354777, Average accuracy:0.90234375
Random 5 prediction: associated war than revolutionary revolutionary revolutionary than than revolutionary revolutionary
First 5 prediction: political been hierarchy war than see anti anti anti anti
Epoch 899, Average loss:0.43675946692625683, Average accuracy:0.9375
Random 5 prediction: individualist which which individualist warren warren tucker benjamin how tucker
First 5 prediction: four at warren individualist warren published considered considered considered considered
Epoch 999, Average loss:0.23202441136042276, Average accuracy:0.9602864583333334
Random 5 prediction: allow allow trabajo you you you you you you you
First 5 prediction: labour spanish they they they movement movement anarcho anarcho two
```
生成的文本中的重复单词是常见的,并且应该更好地训练模型。虽然模型的准确性提高到 96%,但仍然不足以生成清晰的文本。尝试增加 LSTM 单元/隐藏层的数量,同时在较大的数据集上运行模型以获取大量周期。
现在让我们在 Keras 建立相同的模型:
\ No newline at end of file
# 占位符
虽然常量允许我们在定义张量时提供值,但占位符允许我们创建可在运行时提供其值的张量。 TensorFlow 为`tf.placeholder()`函数提供以下签名以创建占位符:
```py
tf.placeholder(
dtype,
shape=None,
name=None
)
```
例如,让我们创建两个占位符并打印它们:
```py
p1 = tf.placeholder(tf.float32)
p2 = tf.placeholder(tf.float32)
print('p1 : ', p1)
print('p2 : ', p2)
```
我们看到以下输出:
```py
p1 : Tensor("Placeholder:0", dtype=float32)
p2 : Tensor("Placeholder_1:0", dtype=float32)
```
现在让我们使用这些占位符定义一个操作:
```py
op4 = p1 * p2
```
TensorFlow 允许使用速记符号进行各种操作。在前面的例子中,`p1 * p2``tf.multiply(p1,p2)`的简写:
```py
print('run(op4,{p1:2.0, p2:3.0}) : ',tfs.run(op4,{p1:2.0, p2:3.0}))
```
上面的命令在 TensorFlow 会话中运行`op4`,为`p1``p2`的值提供 Python 字典(`run()`操作的第二个参数)。
输出如下:
```py
run(op4,{p1:2.0, p2:3.0}) : 6.0
```
我们还可以使用`run()`操作中的`feed_dict`参数指定字典:
```py
print('run(op4,feed_dict = {p1:3.0, p2:4.0}) : ',
tfs.run(op4, feed_dict={p1: 3.0, p2: 4.0}))
```
输出如下:
```py
run(op4,feed_dict = {p1:3.0, p2:4.0}) : 12.0
```
让我们看一下最后一个例子,向量被送到同一个操作:
```py
print('run(op4,feed_dict = {p1:[2.0,3.0,4.0], p2:[3.0,4.0,5.0]}) : ',
tfs.run(op4,feed_dict = {p1:[2.0,3.0,4.0], p2:[3.0,4.0,5.0]}))
```
输出如下:
```py
run(op4,feed_dict={p1:[2.0,3.0,4.0],p2:[3.0,4.0,5.0]}):[ 6\. 12\. 20.]
```
两个输入向量的元素以元素方式相乘。
\ No newline at end of file
# Keras 中的 LSTM 文本生成
您可以在 Jupyter 笔记本`ch-08b_RNN_Text_Keras`中按照本节的代码进行操作。
我们在 Keras 实现文本生成 LSTM,步骤如下:
1. 首先,我们将所有数据转换为两个张量,张量`x`有五列,因为我们一次输入五个字,张量`y`只有一列输出。我们将`y`或标签张量转换为单热编码表示。
请记住,在大型数据集的实践中,您将使用 word2vec 嵌入而不是单热表示。
```py
# get the data
x_train, y_train = text8.seq_to_xy(seq=text8.part['train'],n_tx=n_x,n_ty=n_y)
# reshape input to be [samples, time steps, features]
x_train = x_train.reshape(x_train.shape[0], x_train.shape[1],1)
y_onehot = np.zeros(shape=[y_train.shape[0],text8.vocab_len],dtype=np.float32)
for i in range(y_train.shape[0]):
y_onehot[i,y_train[i]]=1
```
1. 接下来,仅使用一个隐藏的 LSTM 层定义 LSTM 模型。由于我们的输出不是序列,我们还将`return_sequences`设置为`False`
```py
n_epochs = 1000
batch_size=128
state_size=128
n_epochs_display=100
# create and fit the LSTM model
model = Sequential()
model.add(LSTM(units=state_size,
input_shape=(x_train.shape[1], x_train.shape[2]),
return_sequences=False
)
)
model.add(Dense(text8.vocab_len))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')
model.summary()
```
该模型如下所示:
```py
Layer (type) Output Shape Param #
=================================================================
lstm_1 (LSTM) (None, 128) 66560
_________________________________________________________________
dense_1 (Dense) (None, 1457) 187953
_________________________________________________________________
activation_1 (Activation) (None, 1457) 0
=================================================================
Total params: 254,513
Trainable params: 254,513
Non-trainable params: 0
_________________________________________________________________
```
1. 对于 Keras,我们运行一个循环来运行 10 次,在每次迭代中训练 100 个周期的模型并打印文本生成的结果。以下是训练模型和生成文本的完整代码:
```py
for j in range(n_epochs // n_epochs_display):
model.fit(x_train, y_onehot, epochs=n_epochs_display,
batch_size=batch_size,verbose=0)
# generate text
y_pred_r5 = np.empty([10])
y_pred_f5 = np.empty([10])
x_test_r5 = random5.copy()
x_test_f5 = first5.copy()
# let us generate text of 10 words after feeding 5 words
for i in range(10):
for x,y in zip([x_test_r5,x_test_f5],
[y_pred_r5,y_pred_f5]):
x_input = x.copy()
x_input = x_input.reshape(-1, n_x, n_x_vars)
y_pred = model.predict(x_input)[0]
y_pred_id = np.argmax(y_pred)
y[i]=y_pred_id
x[:-1] = x[1:]
x[-1] = y_pred_id
print('Epoch: ',((j+1) * n_epochs_display)-1)
print(' Random5 prediction:',id2string(y_pred_r5))
print(' First5 prediction:',id2string(y_pred_f5))
```
1. 输出并不奇怪,从重复单词开始,模型有所改进,但是可以通过更多 LSTM 层,更多数据,更多训练迭代和其他超参数调整来进一步提高。
```py
Random 5 words: free bolshevik be n another
First 5 words: anarchism originated as a term
```
预测的输出如下:
```py
Epoch: 99
Random5 prediction: anarchistic anarchistic wrote wrote wrote wrote wrote wrote wrote wrote
First5 prediction: right philosophy than than than than than than than than
Epoch: 199
Random5 prediction: anarchistic anarchistic wrote wrote wrote wrote wrote wrote wrote wrote
First5 prediction: term i revolutionary than war war french french french french
Epoch: 299
Random5 prediction: anarchistic anarchistic wrote wrote wrote wrote wrote wrote wrote wrote
First5 prediction: term i revolutionary revolutionary revolutionary revolutionary revolutionary revolutionary revolutionary revolutionary
Epoch: 399
Random5 prediction: anarchistic anarchistic wrote wrote wrote wrote wrote wrote wrote wrote
First5 prediction: term i revolutionary labor had had french french french french
Epoch: 499
Random5 prediction: anarchistic anarchistic amongst wrote wrote wrote wrote wrote wrote wrote
First5 prediction: term i revolutionary labor individualist had had french french french
Epoch: 599
Random5 prediction: tolstoy wrote tolstoy wrote wrote wrote wrote wrote wrote wrote First5 prediction: term i revolutionary labor individualist had had had had had
Epoch: 699
Random5 prediction: tolstoy wrote tolstoy wrote wrote wrote wrote wrote wrote wrote First5 prediction: term i revolutionary labor individualist had had had had had
Epoch: 799
Random5 prediction: tolstoy wrote tolstoy tolstoy tolstoy tolstoy tolstoy tolstoy tolstoy tolstoy
First5 prediction: term i revolutionary labor individualist had had had had had
Epoch: 899
Random5 prediction: tolstoy wrote tolstoy tolstoy tolstoy tolstoy tolstoy tolstoy tolstoy tolstoy
First5 prediction: term i revolutionary labor should warren warren warren warren warren
Epoch: 999
Random5 prediction: tolstoy wrote tolstoy tolstoy tolstoy tolstoy tolstoy tolstoy tolstoy tolstoy
First5 prediction: term i individualist labor should warren warren warren warren warren
```
如果您注意到我们在 LSTM 模型的输出中有重复的单词用于文本生成。虽然超参数和网络调整可以消除一些重复,但还有其他方法可以解决这个问题。我们得到重复单词的原因是模型总是从单词的概率分布中选择具有最高概率的单词。这可以改变以选择诸如在连续单词之间引入更大可变性的单词。
\ No newline at end of file
# 总结
在本章中,我们学习了单词嵌入的方法,以找到更好的文本数据元素表示。随着神经网络和深度学习摄取大量文本数据,单热表示和其他单词表示方法变得低效。我们还学习了如何使用 t-SNE 图来可视化文字嵌入。我们使用简单的 LSTM 模型在 TensorFlow 和 Keras 中生成文本。类似的概念可以应用于各种其他任务,例如情绪分析,问答和神经机器翻译。
在我们深入研究先进的 TensorFlow 功能(如迁移学习,强化学习,生成网络和分布式 TensorFlow)之前,我们将在下一章中看到如何将 TensorFlow 模型投入生产。
\ No newline at end of file
# 使用 TensorFlow 和 Keras 的 CNN
**卷积神经网络****CNN** )是一种特殊的前馈神经网络,在其架构中包含卷积和汇聚层。也称为 ConvNets,CNN 架构的一般模式是按以下顺序包含这些层:
1. 完全连接的输入层
2. 卷积,池化和完全连接层的多种组合
3. 完全连接的输出层,具有 softmax 激活函数
CNN 架构已被证明在解决涉及图像学习的问题(例如图像识别和对象识别)方面非常成功。
在本章中,我们将学习与 ConvNets 相关的以下主题:
* 理解卷积
* 了解池
* CNN 架构模式-LeNet
* LeNet for MNIST 数据集
* 带有 TensorFlow 的 MNIST 的 LeNet
* 带有 Keras 的 MNIST 的 LeNet
* LeNet for CIFAR 数据集
* 带有 TensorFlow 的 CIFAR10 的 LeNet CNN
* 带有 Keras 的 CIFAR10 的 LeNet CNN
让我们从学习 ConvNets 背后的核心概念开始。
\ No newline at end of file
# 理解卷积
**卷积**是 CNN 架构背后的核心概念。简单来说,卷积是一种数学运算,它结合了两个来源的信息来产生一组新的信息。具体来说,它将一个称为内核的特殊矩阵应用于输入张量,以产生一组称为特征图的矩阵。可以使用任何流行的算法将内核应用于输入张量。
生成卷积矩阵的最常用算法如下:
```py
N_STRIDES = [1,1]
1\. Overlap the kernel with the top-left cells of the image matrix.
2\. Repeat while the kernel overlaps the image matrix:
2.1 c_col = 0
2.2 Repeat while the kernel overlaps the image matrix:
2.1.1 set c_row = 0 2.1.2 convolved_scalar = scalar_prod(kernel, overlapped cells)
2.1.3 convolved_matrix(c_row,c_col) = convolved_scalar
2.1.4 Slide the kernel down by N_STRIDES[0] rows.
2.1.5 c_row = c_row + 1
2.3 Slide the kernel to (topmost row, N_STRIDES[1] columns right)
2.4 c_col = c_col + 1
```
例如,我们假设核矩阵是 2 x 2 矩阵,输入图像是 3 x 3 矩阵。下图逐步显示了上述算法:
| | |
| --- | --- |
| ![](img/12748d18-c1b3-49c4-8376-208a077c6116.png) | ![](img/27bc51c5-60bc-4cd0-b030-7253ca8072f6.png) |
| ![](img/1f39630a-7dcf-4fd2-8f38-e5cc1123125c.png) | ![](img/d613bdcd-7ecd-425d-9941-003500a98adf.png) |
在 con 卷积操作结束时,我们得到以下特征图:
| | |
| --- | --- |
| -6 | -8 |
| -12 | -14 |
在上面的示例中,与卷积的原始输入相比,生成的特征映射的大小更小。通常,特征图的大小减小(内核大小-1)。因此,特征图的大小为:
![](img/0bc241d0-3c55-481f-8687-fb8da66ffa09.png)
**三维张量**
对于具有额外深度尺寸的三维张量,您可以将前面的算法视为应用于深度维度中的每个层。将卷积应用于 3D 张量的输出也是 2D 张量,因为卷积运算添加了三个通道。
**大步**
数组 N_STRIDES 中的 **步长** 是您想要将内核滑过的行或列的数字。在我们的例子中,我们使用了 1 的步幅。如果我们使用更多的步幅,那么特征图的大小将根据以下等式进一步减小:
![](img/6db06a54-de55-4fc3-a0c5-485fcf4b35b2.png)
**填充**
如果我们不希望减小特征映射的大小,那么我们可以在输入的所有边上使用填充,使得特征的大小增加填充大小的两倍。使用填充,可以按如下方式计算特征图的大小:
![](img/f3a81e63-5d7a-4e84-9c0b-bf2eb6e1f284.png)
TensorFlow 允许两种填充:SAME 或 VALID。 SAME 填充意味着添加填充,使输出特征图与输入特征具有相同的大小。 VALID 填充意味着没有填充。
应用前面提到的卷积算法的结果是特征图,是原始张量的滤波版本。例如,特征图可能只有从原始图像中过滤出的轮廓。因此,内核也称为过滤器。对于每个内核,您将获得单独的 2D 特征图。
根据您希望网络学习的特征,您必须应用适当的过滤器来强调所需的特征。 但是,使用 CNN,模型可以自动了解哪些内核在卷积层中最有效。
**TensorFlow** 中的卷积运算
TensorFlow 提供实现卷积算法的卷积层。例如,具有以下签名的`tf.nn.conv2d()`操作:
```py
tf.nn.conv2d(
input,
filter,
strides,
padding,
use_cudnn_on_gpu=None,
data_format=None,
name=None
)
```
`input``filter`表示形状`[batch_size, input_height, input_width, input_depth]`的数据张量和形状`[filter_height, filter_width, input_depth, output_depth]`的核张量。内核张量中的 `output_depth`表示应该应用于输入的内核数量。 `strides`张量表示每个维度中要滑动的单元数。如上所述,`padding`是有效的或相同的。
[您可以在此链接中找到有关TensorFlow中可用卷积操作的更多信息](https://www.tensorflow.org/api_guides/python/nn#Convolution)
[您可以在此链接中找到有关 Keras 中可用卷积层的更多信息](https://keras.io/layers/convolutional/)
此链接提供了卷积的详细数学解释:
<http://colah.github.io/posts/2014-07-Understanding-Convolutions/>
<http://ufldl.stanford.edu/tutorial/supervised/FeatureExtractionUsingConvolution/>
<http://colah.github.io/posts/2014-07-Understanding-Convolutions/>
卷积层或操作将输入值或神经元连接到下一个隐藏层神经元。每个隐藏层神经元连接到与内核中元素数量相同数量的输入神经元。所以在前面的例子中,内核有 4 个元素,因此隐藏层神经元连接到输入层的 4 个神经元(3×3 个神经元中)。在我们的例子中,输入层的 4 个神经元的这个区域被称为 CNN 理论中的**感受域**
卷积层具有每个内核的单独权重和偏差参数。权重参数的数量等于内核中元素的数量,并且只有一个偏差参数。内核的所有连接共享相同的权重和偏差参数。因此在我们的例子中,将有 4 个权重参数和 1 个偏差参数,但如果我们在卷积层中使用 5 个内核,则总共将有 5 x 4 个权重参数和 5 个 1 个偏差参数,一组(4)每个特征图的权重,1 个偏差)参数。
\ No newline at end of file
# 了解池化
通常,在卷积操作中,应用几个不同的内核,这导致生成若干特征映射。因此,卷积运算导致生成大尺寸数据集。
例如,将形状为 3 x 3 x 1 的内核应用于具有 28 x 28 x 1 像素形状的图像的 MNIST 数据集,可生成形状为 26 x 26 x 1 的特征映射。如果我们在 a 中应用 32 个这样的滤波器卷积层,则输出的形状为 32 x 26 x 26 x 1,即形状为 26 x 26 x 1 的 32 个特征图。
与形状为 28 x 28 x 1 的原始数据集相比,这是一个庞大的数据集。因此,为了简化下一层的学习,我们应用池化的概念。
**合并**是指计算卷积特征空间区域的聚合统计量。两个最受欢迎的汇总统计数据是最大值和平均值。应用 max-pooling 的输出是所选区域的最大值,而应用平均池的输出是区域中数字的平均值。
例如,假设特征图的形状为 3 x 3,形状的池区域为 2 x 2.以下图像显示了使用[1,1]的步幅应用的最大池操作:
| | |
| --- | --- |
| ![](img/c4bea549-7ee7-491c-9ad7-37ccb55dbf2e.png) | ![](img/4cea41c9-7a13-4e8d-bbec-d7d36ecf69b5.png) |
| ![](img/efdcb6bb-da73-40ea-ab75-88008b176d48.png) | ![](img/4c1f8231-e6d4-4bde-9cdf-2332accbb66d.png) |
在最大池操作结束时,我们得到以下矩阵:
| | |
| --- | --- |
| 5 | 6 |
| 8 | 9 |
通常,池化操作应用非重叠区域,因此步幅张量和区域张量被设置为相同的值。
例如,TensorFlow 具有以下签名的`max_pooling`操作:
```py
max_pool(
value,
ksize,
strides,
padding,
data_format='NHWC',
name=None
)
```
`value` 表示形状 `[batch_size, input_height, input_width, input_depth]` 的输入张量。对矩形形状区域`ksize`执行合并操作。这些区域被形状`strides` 抵消。
[您可以在此链接中找到有关 TensorFlow 中可用的池化操作的更多信息](https://www.tensorflow.org/api_guides/python/nn#Pooling)
[有关 Keras 中可用池化的更多信息,请访问此链接](https://keras.io/layers/pooling/)
[此链接提供了池化的详细数学说明](http://ufldl.stanford.edu/tutorial/supervised/Pooling/)
\ No newline at end of file
# CNN 架构模式 - LeNet
LeNet 是实现 CNN 的流行架构模式。在本章中,我们将学习如何通过按以下顺序创建层来构建基于 LeNet 模式的 CNN 模型:
1. 输入层
2. 卷积层 1,它产生一组特征映射,具有 ReLU 激活
3. 池化层 1 产生一组统计聚合的特征映射
4. 卷积层 2,其产生一组特征映射,具有 ReLU 激活
5. 池化层 2 产生一组统计聚合的特征映射
6. 完全连接的层,通过 ReLU 激活来展平特征图
7. 通过应用简单线性激活产生输出的输出层
**LeNet** 系列模型由 Yann LeCun 及其研究员介绍。有关 LeNet 系列模型的更多详细信息,[请访问此链接](http://yann.lecun.com/exdb/publis/pdf/lecun-01a.pdf)
[Yann LeCun 通过此链接维护 LeNet 系列模型列表](http://yann.lecun.com/exdb/lenet/index.html)
\ No newline at end of file
# 用于 MNIST 数据的 LeNet
您可以按照 Jupyter 笔记本中的代码`ch-09a_CNN_MNIST_TF_and_Keras`
准备 MNIST 数据到测试和训练集:
```py
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets(os.path.join('.','mnist'), one_hot=True)
X_train = mnist.train.images
X_test = mnist.test.images
Y_train = mnist.train.labels
Y_test = mnist.test.labels
```
\ No newline at end of file
# 使用 TensorFlow 的用于 MNIST 的 LeNet CNN
在 TensorFlow 中,应用以下步骤为 MNIST 数据构建基于 LeNet 的 CNN 模型:
1. 定义超参数,以及 x 和 y 的占位符(输入图像和输出标签) :
```py
n_classes = 10 # 0-9 digits
n_width = 28
n_height = 28
n_depth = 1
n_inputs = n_height * n_width * n_depth # total pixels
learning_rate = 0.001
n_epochs = 10
batch_size = 100
n_batches = int(mnist.train.num_examples/batch_size)
# input images shape: (n_samples,n_pixels)
x = tf.placeholder(dtype=tf.float32, name="x", shape=[None, n_inputs])
# output labels
y = tf.placeholder(dtype=tf.float32, name="y", shape=[None, n_classes])
```
将输入 x 重塑为形状(`n_samples``n_width``n_height``n_depth`):
```py
x_ = tf.reshape(x, shape=[-1, n_width, n_height, n_depth])
```
1. 使用形状为 4 x 4 的 32 个内核定义第一个卷积层,从而生成 32 个特征图。
* 首先,定义第一个卷积层的权重和偏差。我们使用正态分布填充参数:
```py
layer1_w = tf.Variable(tf.random_normal(shape=[4,4,n_depth,32],
stddev=0.1),name='l1_w')
layer1_b = tf.Variable(tf.random_normal([32]),name='l1_b')
```
* 接下来,用 `tf.nn.conv2d`函数定义卷积层。函数参数`stride`定义了内核张量在每个维度中应该滑动的元素。维度顺序由`data_format`确定,可以是`'NHWC'``'NCHW'`(默认为`'NHWC'`)。
通常,`stride`中的第一个和最后一个元素设置为“1”。函数参数`padding`可以是`SAME``VALID``SAME` `padding`表示输入将用零填充,以便在卷积后输出与输入的形状相同。使用`tf.nn.relu()`函数添加`relu`激活:
```py
layer1_conv = tf.nn.relu(tf.nn.conv2d(x_,layer1_w,
strides=[1,1,1,1],
padding='SAME'
) +
layer1_b
)
```
* 使用 `tf.nn.max_pool()` 函数定义第一个池化层。参数 `ksize` 表示使用 2×2×1 个区域的合并操作,参数 `stride` 表示将区域滑动 2×2×1 个像素。因此,区域彼此不重叠。由于我们使用 `max_pool` ,池化操作选择 2 x 2 x 1 区域中的最大值:
```py
layer1_pool = tf.nn.max_pool(layer1_conv,ksize=[1,2,2,1],
strides=[1,2,2,1],padding='SAME')
```
第一个卷积层产生 32 个大小为 28 x 28 x 1 的特征图,然后池化成 32 x 14 x 14 x 1 的数据。
1. 定义第二个卷积层,它将此数据作为输入并生成 64 个特征图。
* 首先,定义第二个卷积层的权重和偏差。我们用正态分布填充参数:
```py
layer2_w = tf.Variable(tf.random_normal(shape=[4,4,32,64],
stddev=0.1),name='l2_w')
layer2_b = tf.Variable(tf.random_normal([64]),name='l2_b')
```
* 接下来,用 `tf.nn.conv2d`函数定义卷积层:
```py
layer2_conv = tf.nn.relu(tf.nn.conv2d(layer1_pool,
layer2_w,
strides=[1,1,1,1],
padding='SAME'
) +
layer2_b
)
```
*`tf.nn.max_pool`函数定义第二个池化层:
```py
layer2_pool = tf.nn.max_pool(layer2_conv,
ksize=[1,2,2,1],
strides=[1,2,2,1],
padding='SAME'
)
```
第二卷积层的输出形状为 64 ×14×14×1,然后池化成 64×7×7×1 的形状的输出。
1. 在输入 1024 个神经元的完全连接层之前重新整形此输出,以产生大小为 1024 的扁平输出:
```py
layer3_w = tf.Variable(tf.random_normal(shape=[64*7*7*1,1024],
stddev=0.1),name='l3_w')
layer3_b = tf.Variable(tf.random_normal([1024]),name='l3_b')
layer3_fc = tf.nn.relu(tf.matmul(tf.reshape(layer2_pool,
[-1, 64*7*7*1]),layer3_w) + layer3_b)
```
1. 完全连接层的输出馈入具有 10 个输出的线性输出层。我们在这一层没有使用 softmax,因为我们的损失函数自动将 softmax 应用于输出:
```py
layer4_w = tf.Variable(tf.random_normal(shape=[1024, n_classes],
stddev=0.1),name='l)
layer4_b = tf.Variable(tf.random_normal([n_classes]),name='l4_b')
layer4_out = tf.matmul(layer3_fc,layer4_w)+layer4_b
```
这创建了我们保存在变量`model`中的第一个 CNN 模型:
```py
model = layer4_out
```
鼓励读者探索具有不同超参数值的 TensorFlow 中可用的不同卷积和池操作符。
为了定义损失,我们使用`tf.nn.softmax_cross_entropy_with_logits`函数,对于优化器,我们使用`AdamOptimizer`函数。您应该尝试探索 TensorFlow 中可用的不同优化器函数。
```py
entropy = tf.nn.softmax_cross_entropy_with_logits(logits=model, labels=y)
loss = tf.reduce_mean(entropy)
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(loss)
```
最后,我们通过迭代`n_epochs`来训练模型,并且在`n_batches`上的每个周期列中,每批`batch_size`的大小:
```py
with tf.Session() as tfs:
tf.global_variables_initializer().run()
for epoch in range(n_epochs):
total_loss = 0.0
for batch in range(n_batches):
batch_x,batch_y = mnist.train.next_batch(batch_size)
feed_dict={x:batch_x, y: batch_y}
batch_loss,_ = tfs.run([loss, optimizer],
feed_dict=feed_dict)
total_loss += batch_loss
average_loss = total_loss / n_batches
print("Epoch: {0:04d} loss = {1:0.6f}".format(epoch,average_loss))
print("Model Trained.")
predictions_check = tf.equal(tf.argmax(model,1),tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(predictions_check, tf.float32))
feed_dict = {x:mnist.test.images, y:mnist.test.labels}
print("Accuracy:", accuracy.eval(feed_dict=feed_dict))
```
我们得到以下输出:
```py
Epoch: 0000 loss = 1.418295
Epoch: 0001 loss = 0.088259
Epoch: 0002 loss = 0.055410
Epoch: 0003 loss = 0.042798
Epoch: 0004 loss = 0.030471
Epoch: 0005 loss = 0.023837
Epoch: 0006 loss = 0.019800
Epoch: 0007 loss = 0.015900
Epoch: 0008 loss = 0.012918
Epoch: 0009 loss = 0.010322
Model Trained.
Accuracy: 0.9884
```
现在,与我们在前几章中看到的方法相比,这是一个非常好的准确性。从图像数据中学习 CNN 模型是不是很神奇?
\ No newline at end of file
# 使用 Keras 的用于 MNIST 的 LeNet CNN
让我们重新审视具有相同数据集的相同 LeNet 架构,以在 Keras 中构建和训练 CNN 模型:
1. 导入所需的 Keras 模块:
```py
import keras
from keras.models import Sequential
from keras.layers import Conv2D,MaxPooling2D, Dense, Flatten, Reshape
from keras.optimizers import SGD
```
1. 定义每个层的过滤器数量:
```py
n_filters=[32,64]
```
1. 定义其他超参数:
```py
learning_rate = 0.01
n_epochs = 10
batch_size = 100
```
1. 定义顺序模型并添加层以将输入数据重新整形为形状`(n_width,n_height,n_depth)`
```py
model = Sequential()
model.add(Reshape(target_shape=(n_width,n_height,n_depth),
input_shape=(n_inputs,))
)
```
1. 使用 4 x 4 内核过滤器,`SAME`填充和`relu`激活添加第一个卷积层:
```py
model.add(Conv2D(filters=n_filters[0],kernel_size=4,
padding='SAME',activation='relu')
)
```
1. 添加区域大小为 2 x 2 且步长为 2 x 2 的池化层:
```py
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))
```
1. 以与添加第一层相同的方式添加第二个卷积和池化层:
```py
model.add(Conv2D(filters=n_filters[1],kernel_size=4,
padding='SAME',activation='relu')
)
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))
```
1. 添加层以展平第二个层的输出和 1024 个神经元的完全连接层,以处理展平的输出:
```py
model.add(Flatten())
model.add(Dense(units=1024, activation='relu'))
```
1. 使用`softmax`激活添加最终输出层:
```py
model.add(Dense(units=n_outputs, activation='softmax'))
```
1. 使用以下代码查看模型摘要:
```py
model.summary()
```
该模型描述如下:
```py
Layer (type) Output Shape Param #
=================================================================
reshape_1 (Reshape) (None, 28, 28, 1) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 28, 28, 32) 544
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 14, 14, 32) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 14, 14, 64) 32832
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 7, 7, 64) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 3136) 0
_________________________________________________________________
dense_1 (Dense) (None, 1024) 3212288
_________________________________________________________________
dense_2 (Dense) (None, 10) 10250
=================================================================
Total params: 3,255,914
Trainable params: 3,255,914
Non-trainable params: 0
_________________________________________________________________
```
1. 编译,训练和评估模型:
```py
model.compile(loss='categorical_crossentropy',
optimizer=SGD(lr=learning_rate),
metrics=['accuracy'])
model.fit(X_train, Y_train,batch_size=batch_size,
epochs=n_epochs)
score = model.evaluate(X_test, Y_test)
print('\nTest loss:', score[0])
print('Test accuracy:', score[1])
```
我们得到以下输出:
```py
Epoch 1/10
55000/55000 [===================] - 267s - loss: 0.8854 - acc: 0.7631
Epoch 2/10
55000/55000 [===================] - 272s - loss: 0.2406 - acc: 0.9272
Epoch 3/10
55000/55000 [===================] - 267s - loss: 0.1712 - acc: 0.9488
Epoch 4/10
55000/55000 [===================] - 295s - loss: 0.1339 - acc: 0.9604
Epoch 5/10
55000/55000 [===================] - 278s - loss: 0.1112 - acc: 0.9667
Epoch 6/10
55000/55000 [===================] - 279s - loss: 0.0957 - acc: 0.9714
Epoch 7/10
55000/55000 [===================] - 316s - loss: 0.0842 - acc: 0.9744
Epoch 8/10
55000/55000 [===================] - 317s - loss: 0.0758 - acc: 0.9773
Epoch 9/10
55000/55000 [===================] - 285s - loss: 0.0693 - acc: 0.9790
Epoch 10/10
55000/55000 [===================] - 217s - loss: 0.0630 - acc: 0.9804
Test loss: 0.0628845927377
Test accuracy: 0.9785
```
准确性的差异可归因于我们在这里使用 SGD 优化器这一事实,它没有实现我们用于 TensorFlow 模型的`AdamOptimizer`提供的一些高级功能。
\ No newline at end of file
# 用于 CIFAR10 数据的 LeNet
现在我们已经学会了使用 TensorFlow 和 Keras 的 MNIST 数据集构建和训练 CNN 模型,让我们用 CIFAR10 数据集重复练习。
CIFAR-10 数据集包含 60,000 个 32x32 像素形状的 RGB 彩色图像。图像被平均分为 10 个不同的类别或类别:飞机,汽车,鸟,猫,鹿,狗,青蛙,马,船和卡车。 CIFAR-10 和 CIFAR-100 是包含 8000 万个图像的大图像数据集的子集。 CIFAR 数据集由 Alex Krizhevsky,Vinod Nair 和 Geoffrey Hinton 收集和标记。数字 10 和 100 表示​​图像类别的数量。
有关 CIFAR 数据集的更多详细信息,请访问此链接:
<http://www.cs.toronto.edu/~kriz/cifar.html>
<http://www.cs.toronto.edu/~kriz/learning-features-2009-TR.pdf>
我们选择了 CIFAR 10,因为它有 3 个通道,即图像的深度为 3,而 MNIST 数据集只有一个通道。 为了简洁起见,我们将详细信息留给下载并将数据拆分为训练和测试集,并在本书代码包中的 datasetslib 包中提供代码。
您可以按照 Jupyter 笔记本中的代码`ch-09b_CNN_CIFAR10_TF_and_Keras`
我们使用以下代码加载和预处理 CIFAR10 数据:
```py
from datasetslib.cifar import cifar10
from datasetslib import imutil
dataset = cifar10()
dataset.x_layout=imutil.LAYOUT_NHWC
dataset.load_data()
dataset.scaleX()
```
加载数据使得图像采用`'NHWC'`格式,使数据变形(`number_of_samples, image_height, image_width, image_channels`)。我们将图像通道称为图像深度。图像中的每个像素是 0 到 255 之间的数字。使用 MinMax 缩放来缩放数据集,以通过将所有像素值除以 255 来标准化图像。
加载和预处理的数据在数据集对象变量中可用作`dataset.X_train``dataset.Y_train``dataset.X_test``dataset.Y_test`
\ No newline at end of file
# 从 Python 对象创建张量
我们可以使用带有以下签名的`tf.convert_to_tensor()`操作从 Python 对象(如列表和 NumPy 数组)创建张量:
```py
tf.convert_to_tensor(
value,
dtype=None,
name=None,
preferred_dtype=None
)
```
让我们创建一些张量并打印出来进行练习:
1. 创建并打印 0-D 张量:
```py
tf_t=tf.convert_to_tensor(5.0,dtype=tf.float64)
print('tf_t : ',tf_t)
print('run(tf_t) : ',tfs.run(tf_t))
```
输出如下:
```py
tf_t : Tensor("Const_1:0", shape=(), dtype=float64)
run(tf_t) : 5.0
```
1. 创建并打印 1-D 张量:
```py
a1dim = np.array([1,2,3,4,5.99])
print("a1dim Shape : ",a1dim.shape)
tf_t=tf.convert_to_tensor(a1dim,dtype=tf.float64)
print('tf_t : ',tf_t)
print('tf_t[0] : ',tf_t[0])
print('tf_t[0] : ',tf_t[2])
print('run(tf_t) : \n',tfs.run(tf_t))
```
输出如下:
```py
a1dim Shape : (5,)
tf_t : Tensor("Const_2:0", shape=(5,), dtype=float64)
tf_t[0] : Tensor("strided_slice:0", shape=(), dtype=float64)
tf_t[0] : Tensor("strided_slice_1:0", shape=(), dtype=float64)
run(tf_t) :
[ 1\. 2\. 3\. 4\. 5.99]
```
1. 创建并打印 2-D Tensor:
```py
a2dim = np.array([(1,2,3,4,5.99),
(2,3,4,5,6.99),
(3,4,5,6,7.99)
])
print("a2dim Shape : ",a2dim.shape)
tf_t=tf.convert_to_tensor(a2dim,dtype=tf.float64)
print('tf_t : ',tf_t)
print('tf_t[0][0] : ',tf_t[0][0])
print('tf_t[1][2] : ',tf_t[1][2])
print('run(tf_t) : \n',tfs.run(tf_t))
```
输出如下:
```py
a2dim Shape : (3, 5)
tf_t : Tensor("Const_3:0", shape=(3, 5), dtype=float64)
tf_t[0][0] : Tensor("strided_slice_3:0", shape=(), dtype=float64)
tf_t[1][2] : Tensor("strided_slice_5:0", shape=(), dtype=float64)
run(tf_t) :
[[ 1\. 2\. 3\. 4\. 5.99]
[ 2\. 3\. 4\. 5\. 6.99]
[ 3\. 4\. 5\. 6\. 7.99]]
```
1. 创建并打印 3-D Tensor:
```py
a3dim = np.array([[[1,2],[3,4]],
[[5,6],[7,8]]
])
print("a3dim Shape : ",a3dim.shape)
tf_t=tf.convert_to_tensor(a3dim,dtype=tf.float64)
print('tf_t : ',tf_t)
print('tf_t[0][0][0] : ',tf_t[0][0][0])
print('tf_t[1][1][1] : ',tf_t[1][1][1])
print('run(tf_t) : \n',tfs.run(tf_t))
```
输出如下:
```py
a3dim Shape : (2, 2, 2)
tf_t : Tensor("Const_4:0", shape=(2, 2, 2), dtype=float64)
tf_t[0][0][0] : Tensor("strided_slice_8:0", shape=(), dtype=float64)
tf_t[1][1][1] : Tensor("strided_slice_11:0", shape=(), dtype=float64)
run(tf_t) :
[[[ 1\. 2.][ 3\. 4.]]
[[ 5\. 6.][ 7\. 8.]]]
```
TensorFlow 可以将 NumPy `ndarray`无缝转换为 TensorFlow 张量,反之亦然。
\ No newline at end of file
# 使用 TensorFlow 的用于 CIFAR10 的 ConvNets
我们保持层,滤波器及其大小与之前的 MNIST 示例中的相同,增加了一个正则化层。由于此数据集与 MNIST 相比较复杂,因此我们为正则化目的添加了额外的 dropout 层:
```py
tf.nn.dropout(layer1_pool, keep_prob)
```
在预测和评估期间,占位符`keep_prob`设置为 1。这样我们就可以重复使用相同的模型进行培训以及预测和评估。
有关 CIFAR10 数据的 LeNet 模型的完整代码在笔记本 `ch-09b_CNN_CIFAR10_TF_and_Keras` 中提供。
在运行模型时,我们得到以下输出:
```py
Epoch: 0000 loss = 2.115784
Epoch: 0001 loss = 1.620117
Epoch: 0002 loss = 1.417657
Epoch: 0003 loss = 1.284346
Epoch: 0004 loss = 1.164068
Epoch: 0005 loss = 1.058837
Epoch: 0006 loss = 0.953583
Epoch: 0007 loss = 0.853759
Epoch: 0008 loss = 0.758431
Epoch: 0009 loss = 0.663844
Epoch: 0010 loss = 0.574547
Epoch: 0011 loss = 0.489902
Epoch: 0012 loss = 0.410211
Epoch: 0013 loss = 0.342640
Epoch: 0014 loss = 0.280877
Epoch: 0015 loss = 0.234057
Epoch: 0016 loss = 0.195667
Epoch: 0017 loss = 0.161439
Epoch: 0018 loss = 0.140618
Epoch: 0019 loss = 0.126363
Model Trained.
Accuracy: 0.6361
```
与我们在 MNIST 数据上获得的准确率相比,我们没有获得良好的准确性。通过调整不同的超参数并改变卷积和池化层的组合,可以实现更好的准确性。我们将其作为挑战,让读者探索并尝试不同的 LeNet 架构和超参数变体,以实现更高的准确性。
\ No newline at end of file
# 使用 Keras 的用于 CIFAR10 的 ConvNets
让我们在 Keras 重复 LeNet CNN 模型构建和 CIFAR10 数据训练。我们保持架构与前面的示例相同,以便轻松解释概念。在 Keras 中,dropout 层添加如下:
```py
model.add(Dropout(0.2))
```
用于 CIFAR10 CNN 模型的 Keras 中的完整代码在笔记本 `ch-09b_CNN_CIFAR10_TF_and_Keras` 中提供。
在运行模型时,我们得到以下模型描述:
```py
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_1 (Conv2D) (None, 32, 32, 32) 1568
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 16, 16, 32) 0
_________________________________________________________________
dropout_1 (Dropout) (None, 16, 16, 32) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 16, 16, 64) 32832
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 8, 8, 64) 0
_________________________________________________________________
dropout_2 (Dropout) (None, 8, 8, 64) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 4096) 0
_________________________________________________________________
dense_1 (Dense) (None, 1024) 4195328
_________________________________________________________________
dropout_3 (Dropout) (None, 1024) 0
_________________________________________________________________
dense_2 (Dense) (None, 10) 10250
=================================================================
Total params: 4,239,978
Trainable params: 4,239,978
Non-trainable params: 0
_________________________________________________________________
```
我们得到以下训练和评估结果:
```py
Epoch 1/10
50000/50000 [====================] - 191s - loss: 1.5847 - acc: 0.4364
Epoch 2/10
50000/50000 [====================] - 202s - loss: 1.1491 - acc: 0.5973
Epoch 3/10
50000/50000 [====================] - 223s - loss: 0.9838 - acc: 0.6582
Epoch 4/10
50000/50000 [====================] - 223s - loss: 0.8612 - acc: 0.7009
Epoch 5/10
50000/50000 [====================] - 224s - loss: 0.7564 - acc: 0.7394
Epoch 6/10
50000/50000 [====================] - 217s - loss: 0.6690 - acc: 0.7710
Epoch 7/10
50000/50000 [====================] - 222s - loss: 0.5925 - acc: 0.7945
Epoch 8/10
50000/50000 [====================] - 221s - loss: 0.5263 - acc: 0.8191
Epoch 9/10
50000/50000 [====================] - 237s - loss: 0.4692 - acc: 0.8387
Epoch 10/10
50000/50000 [====================] - 230s - loss: 0.4320 - acc: 0.8528
Test loss: 0.849927025414
Test accuracy: 0.7414
```
再次,我们将其作为挑战,让读者探索并尝试不同的 LeNet 架构和超参数变体,以实现更高的准确性。
\ No newline at end of file
# 总结
在本章中,我们学习了如何使用 TensorFlow 和 Keras 创建卷积神经网络。我们学习了卷积和池化的核心概念,这是 CNN 的基础。我们学习了 LeNet 系列架构,并为 MNIST 和 CIFAR 数据集创建,训练和评估了 LeNet 族模型。 TensorFlow 和 Keras 提供了许多卷积和池化层和操作。鼓励读者探索本章未涉及的层和操作。
在下一章中,我们将继续学习如何使用 AutoEncoder 架构将 TensorFlow 应用于图像数据。
\ No newline at end of file
# 使用 TensorFlow 和 Keras 的自编码器
自编码器是一种神经网络架构,通常与无监督学习,降维和数据压缩相关联。自编码器通过使用隐藏层中较少数量的神经元来学习产生与输入层相同的输出。这允许隐藏层以较少数量的参数学习输入的特征。使用较少数量的神经元来学习输入数据的特征的这个过程反过来减少了输入数据集的维度。
自编码器架构有两个阶段:编码器和解码器。在编码器阶段,模型学习表示具有较小维度的压缩向量的输入,并且在解码器阶段,模型学习将压缩向量表示为输出向量。损失计算为输出和输入之间的熵距离,因此通过最小化损失,我们学习将输入编码成能够产生输入的表示的参数,以及另一组学习参数。
在本章中,您将学习如何使用 TensorFlow 和 Keras 在以下主题中创建自编码器体系结构:
* 自编码器类型
* TensorFlow 和 Keras 中的栈式自编码器
* 在 TensorFlow 和 Keras 中对自编码器进行去噪
* TensorFlow 和 Keras 中的变分自编码器
\ No newline at end of file
# 自编码器类型
自编码器架构可以在各种配置中找到,例如简单自编码器,稀疏自编码器,去噪自编码器和卷积自编码器。
* **简单自编码器:**在简单的自编码器中,与输入相比,隐藏层具有较少数量的节点或神经元。例如,在 MNIST 数据集中,784 个特征的输入可以连接到 512 个节点的隐藏层或 256 个节点,其连接到 784 特征输出层。因此,在训练期间,仅由 256 个节点学习 784 个特征。 简单自编码器也称为欠完整自编码器。
简单的自编码器可以是单层或多层。通常,单层自编码器在生产中表现不佳。多层自编码器具有多个隐藏层,分为编码器和解码器分组。编码器层将大量特征编码为较少数量的神经元,然后解码器层将学习的压缩特征解码回原始特征或减少数量的特征。多层自编码器被称为**栈式自编码器** 。
* **稀疏自编码器**:在稀疏自编码器中,添加正则化项作为惩罚,因此,与简单自编码器相比,表示变得更稀疏。
* **去噪自编码器**(DAE):在 DAE 架构中,输入带有随机噪声。 DAE 重新创建输入并尝试消除噪音。 DAE 中的损失函数将去噪重建输出与原始未损坏输入进行比较。
* **卷积自编码器**(CAE):前面讨论过的自编码器使用全连接层,这种模式类似于多层感知机模型。我们也可以使用卷积层而不是完全连接或密集层。当我们使用卷积层来创建自编码器时,它被称为卷积自编码器。作为一个例子,我们可以为 CAE 提供以下层:
**输入 - &gt;卷积 - &gt;池化 - &gt;卷积 - &gt;池化 - &gt;输出
**第一组卷积和池化层充当编码器,将高维输入特征空间减少到低维特征空间。第二组卷积和池化层充当解码器,将其转换回高维特征空间。
* **变分自编码器**(VAE):变分自编码器架构是自编码器领域的最新发展。 VAE 是一种生成模型,即它产生概率分布的参数,从中可以生成原始数据或与原始数据非常相似的数据。
在 VAE 中,编码器将输入样本转换为潜在空间中的参数,使用该参数对潜在点进行采样。然后解码器使用潜点重新生成原始输入数据。因此,在 VAE 中学习的重点转移到最大化输入数据的概率,而不是试图从输入重建输出。
现在让我们在以下部分中在 TensorFlow 和 Keras 中构建自编码器。我们将使用 MNIST 数据集来构建自编码器。自编码器将学习表示具有较少数量的神经元或特征的 MNIST 数据集的手写数字。
您可以按照 Jupyter 笔记本中的代码`ch-10_AutoEncoders_TF_and_Keras`
像往常一样,我们首先使用以下代码读取 MNIST 数据集:
```py
from tensorflow.examples.tutorials.mnist.input_data import input_data
dataset_home = os.path.join(datasetslib.datasets_root,'mnist')
mnist = input_data.read_data_sets(dataset_home,one_hot=False)
X_train = mnist.train.images
X_test = mnist.test.images
Y_train = mnist.train.labels
Y_test = mnist.test.labels
pixel_size = 28
```
我们从训练和测试数据集中提取四个不同的图像及其各自的标签:
```py
while True:
train_images,train_labels = mnist.train.next_batch(4)
if len(set(train_labels))==4:
break
while True:
test_images,test_labels = mnist.test.next_batch(4)
if len(set(test_labels))==4:
break
```
现在让我们看看使用 MNIST 数据集构建自编码器的代码。
您可以按照 Jupyter 笔记本中的代码`ch-10_AutoEncoders_TF_and_Keras`
\ No newline at end of file
# TensorFlow 中的栈式自编码器
在 TensorFlow 中构建栈式自编码器模型的步骤如下:
1. 首先,定义超参数如下:
```py
learning_rate = 0.001
n_epochs = 20
batch_size = 100
n_batches = int(mnist.train.num_examples/batch_size)
```
1. 定义输入(即特征)和输出(即目标)的数量。输出数量与输入数量相同:
```py
# number of pixels in the MNIST image as number of inputs
n_inputs = 784
n_outputs = n_inputs
```
1. 定义输入和输出图像的占位符:
```py
x = tf.placeholder(dtype=tf.float32, name="x", shape=[None, n_inputs])
y = tf.placeholder(dtype=tf.float32, name="y", shape=[None, n_outputs])
```
1. 添加编码器和解码器层的神经元数量为`[512,256,256,512]`
```py
# number of hidden layers
n_layers = 2
# neurons in each hidden layer
n_neurons = [512,256]
# add number of decoder layers:
n_neurons.extend(list(reversed(n_neurons)))
n_layers = n_layers * 2
```
1. 定义`w``b`参数:
```py
w=[]
b=[]
for i in range(n_layers):
w.append(tf.Variable(tf.random_normal([n_inputs \
if i==0 else n_neurons[i-1],n_neurons[i]]),
name="w_{0:04d}".format(i)
)
)
b.append(tf.Variable(tf.zeros([n_neurons[i]]),
name="b_{0:04d}".format(i)
)
)
w.append(tf.Variable(tf.random_normal([n_neurons[n_layers-1] \
if n_layers > 0 else n_inputs,n_outputs]),
name="w_out"
)
)
b.append(tf.Variable(tf.zeros([n_outputs]),name="b_out"))
```
1. 构建网络并为每个层使用 sigmoid 激活函数:
```py
# x is input layer
layer = x
# add hidden layers
for i in range(n_layers):
layer = tf.nn.sigmoid(tf.matmul(layer, w[i]) + b[i])
# add output layer
layer = tf.nn.sigmoid(tf.matmul(layer, w[n_layers]) + b[n_layers])
model = layer
```
1. 使用`mean_squared_error`定义`loss`函数,使用`AdamOptimizer`定义`optimizer`函数:
```py
mse = tf.losses.mean_squared_error
loss = mse(predictions=model, labels=y)
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
optimizer = optimizer.minimize(loss)
```
1. 训练模型并预测`train``test`集的图像:
```py
with tf.Session() as tfs:
tf.global_variables_initializer().run()
for epoch in range(n_epochs):
epoch_loss = 0.0
for batch in range(n_batches):
X_batch, _ = mnist.train.next_batch(batch_size)
feed_dict={x: X_batch,y: X_batch}
_,batch_loss = tfs.run([optimizer,loss], feed_dict)
epoch_loss += batch_loss
if (epoch%10==9) or (epoch==0):
average_loss = epoch_loss / n_batches
print('epoch: {0:04d} loss = {1:0.6f}'
.format(epoch,average_loss))
# predict images using trained autoencoder model
Y_train_pred = tfs.run(model, feed_dict={x: train_images})
Y_test_pred = tfs.run(model, feed_dict={x: test_images})
```
1. 我们看到以下输出,因为损失在 20 个周期后显着减少:
```py
epoch: 0000 loss = 0.156696
epoch: 0009 loss = 0.091367
epoch: 0019 loss = 0.078550
```
1. 现在模型已经过训练,让我们显示训练模型中的预测图像。我们写了一个辅助函数`display_images`来帮助我们显示图像:
```py
import random
# Function to display the images and labels
# images should be in NHW or NHWC format
def display_images(images, labels, count=0, one_hot=False):
# if number of images to display is not provided, then display all the images
if (count==0):
count = images.shape[0]
idx_list = random.sample(range(len(labels)),count)
for i in range(count):
plt.subplot(4, 4, i+1)
plt.title(labels[i])
plt.imshow(images[i])
plt.axis('off')
plt.tight_layout()
plt.show()
```
使用此函数,我们首先显示训练集中的四个图像和自编码器预测的图像。
第一行表示实际图像,第二行表示生成的图像:
![](img/38171092-c4ce-46a5-8ad6-b85fcdcb4cc6.png)
生成的图像有一点点噪音,可以通过更多训练和超参数调整来消除。现在预测训练集图像并不神奇,因为我们在这些图像上训练了自编码器,因此它知道它们。让我们看一下预测测试集图像的结果。 第一行表示实际图像,第二行表示生成的图像:
![](img/865dec56-0438-4c15-902b-4533b7f21ea3.png)
哇!经过训练的自编码器能够生成相同的数字,只有从 768 中学到的 256 个特征。生成的图像中的噪声可以通过超参数调整和更多训练来改善。
\ No newline at end of file
# Keras 中的栈式自编码器
现在让我们在 Keras 中构建相同的自编码器。
我们使用以下命令清除笔记本中的图,以便我们可以构建一个新图,该图不会占用上一个会话或图中的任何内存:
`tf.reset_default_graph()`
`keras.backend.clear_session()`
1. 首先,我们导入 keras 库并定义超参数和层:
```py
import keras
from keras.layers import Dense
from keras.models import Sequential
learning_rate = 0.001
n_epochs = 20
batch_size = 100
n_batches = int(mnist.train.num_examples/batch_sizee
# number of pixels in the MNIST image as number of inputs
n_inputs = 784
n_outputs = n_i
# number of hidden layers
n_layers = 2
# neurons in each hidden layer
n_neurons = [512,256]
# add decoder layers:
n_neurons.extend(list(reversed(n_neurons)))
n_layers = n_layers * 2
```
1. 接下来,我们构建一个顺序模型并为其添加密集层。对于更改,我们对隐藏层使用`relu`激活,为最终层使用`linear`激活:
```py
model = Sequential()
# add input to first layer
model.add(Dense(units=n_neurons[0], activation='relu',
input_shape=(n_inputs,)))
for i in range(1,n_layers):
model.add(Dense(units=n_neurons[i], activation='relu'))
# add last layer as output layer
model.add(Dense(units=n_outputs, activation='linear'))
```
1. 现在让我们显示模型摘要以查看模型的外观:
```py
model.summary()
```
该模型在五个密集层中共有 1,132,816 个参数:
```py
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_1 (Dense) (None, 512) 401920
_________________________________________________________________
dense_2 (Dense) (None, 256) 131328
_________________________________________________________________
dense_3 (Dense) (None, 256) 65792
_________________________________________________________________
dense_4 (Dense) (None, 512) 131584
_________________________________________________________________
dense_5 (Dense) (None, 784) 402192
=================================================================
Total params: 1,132,816
Trainable params: 1,132,816
Non-trainable params: 0
_________________________________________________________________
```
1. 让我们用上一个例子中的均方损失编译模型:
```py
model.compile(loss='mse',
optimizer=keras.optimizers.Adam(lr=learning_rate),
metrics=['accuracy'])
model.fit(X_train, X_train,batch_size=batch_size,
epochs=n_epochs)
```
在 20 个周期,我们能够获得 0.0046 的损失,相比之前我们得到的 0.078550:
```py
Epoch 1/20
55000/55000 [==========================] - 18s - loss: 0.0193 - acc: 0.0117
Epoch 2/20
55000/55000 [==========================] - 18s - loss: 0.0087 - acc: 0.0139
...
...
...
Epoch 20/20
55000/55000 [==========================] - 16s - loss: 0.0046 - acc: 0.0171
```
现在让我们预测并显示模型生成的训练和测试图像。第一行表示实际图像,第二行表示生成的图像。以下是 t 降雨设置图像:
![](img/f3177e47-afdc-4f5d-a574-257d22403286.png)
以下是测试集图像:
![](img/2f99a937-f842-4d85-96ad-1c41e2e5d396.png)
这是我们在能够从 256 个特征生成图像时实现的非常好的准确性。
\ No newline at end of file
# TensorFlow 中的去噪自编码器
正如您在本章的第一部分中所了解的那样,可以使用去噪自编码器来训练模型,以便它们能够从输入到训练模型的图像中去除噪声:
1. 出于本示例的目的,我们编写以下辅助函数来帮助我们为图像添加噪声:
```py
def add_noise(X):
return X + 0.5 * np.random.randn(X.shape[0],X.shape[1])
```
1. 然后我们为测试图像添加噪声并将其存储在单独的列表中:
```py
test_images_noisy = add_noise(test_images)
```
我们将使用这些测试图像来测试我们的去噪模型示例的输出。
1. 我们按照前面的例子构建和训练去噪自编码器,但有一点不同:在训练时,我们将噪声图像输入到输入层,我们用非噪声图像检查重建和去噪误差,如下面的代码所示:
```py
X_batch, _ = mnist.train.next_batch(batch_size)
X_batch_noisy = add_noise(X_batch)
feed_dict={x: X_batch_noisy, y: X_batch}
_,batch_loss = tfs.run([optimizer,loss], feed_dict=feed_dict)
```
笔记本 `ch-10_AutoEncoders_TF_and_Keras`中提供了去噪自编码器的完整代码。
现在让我们首先显示从 DAE 模型生成的测试图像;第一行表示原始的非噪声测试图像,第二行表示生成的测试图像:
```py
display_images(test_images.reshape(-1,pixel_size,pixel_size),test_labels)
display_images(Y_test_pred1.reshape(-1,pixel_size,pixel_size),test_labels)
```
上述代码的结果如下:
![](img/843e4c1a-9600-4c6c-8300-42cd8a5191cc.png)
接下来,当我们输入噪声测试图像时,我们显示生成的图像:
```py
display_images(test_images_noisy.reshape(-1,pixel_size,pixel_size),
test_labels)
display_images(Y_test_pred2.reshape(-1,pixel_size,pixel_size),test_labels)
```
上述代码的结果如下:
![](img/5f949726-6ef6-4407-8656-47d45e26fc25.png)
那太酷了!!该模型学习了图像并生成了几乎正确的图像,即使是非常嘈杂的图像。通过适当的超参数调整可以进一步提高再生质量。
\ No newline at end of file
# Keras 中的去噪自编码器
现在让我们在 Keras 中构建相同的去噪自编码器。
由于 Keras 负责按批量大小喂养训练集,我们创建了一个嘈杂的训练集作为我们模型的输入:
```py
X_train_noisy = add_noise(X_train)
```
Keras 中 DAE 的完整代码在笔记本 `ch-10_AutoEncoders_TF_and_Keras` 中提供。
DAE Keras 模型如下所示:
```py
Layer (type) Output Shape Param #
=================================================================
dense_1 (Dense) (None, 512) 401920
_________________________________________________________________
dense_2 (Dense) (None, 256) 131328
_________________________________________________________________
dense_3 (Dense) (None, 256) 65792
_________________________________________________________________
dense_4 (Dense) (None, 512) 131584
_________________________________________________________________
dense_5 (Dense) (None, 784) 402192
=================================================================
Total params: 1,132,816
Trainable params: 1,132,816
Non-trainable params: 0
```
由于 DAE 模型很复杂,为了演示,我们不得不将周期数增加到 100 来训练模型:
```py
n_epochs=100
model.fit(x=X_train_noisy, y=X_train,
batch_size=batch_size,
epochs=n_epochs,
verbose=0)
Y_test_pred1 = model.predict(test_images)
Y_test_pred2 = model.predict(test_images_noisy)
```
打印生成的图像:
```py
display_images(test_images.reshape(-1,pixel_size,pixel_size),test_labels)
display_images(Y_test_pred1.reshape(-1,pixel_size,pixel_size),test_labels)
```
第一行是原始测试图像,第二行是生成的测试图像:
![](img/888247bf-9fb1-4fec-aec1-73b4fac5bc85.png)
```py
display_images(test_images_noisy.reshape(-1,pixel_size,pixel_size),
test_labels)
display_images(Y_test_pred2.reshape(-1,pixel_size,pixel_size),test_labels)
```
第一行是噪声测试图像,第二行是生成的测试图像:
![](img/11853759-8390-41a8-9990-83d7b37828de.png)
正如我们所看到的,去噪自编码器可以很好地从噪声版本的图像中生成图像。
\ No newline at end of file
# TensorFlow 中的变分自编码器
变分自编码器是自编码器的现代生成版本。让我们为同一个前面的问题构建一个变分自编码器。我们将通过提供来自原始和嘈杂测试集的图像来测试自编码器。
我们将使用不同的编码风格来构建此自编码器,以便使用 TensorFlow 演示不同的编码风格:
1. 首先定义超参数:
```py
learning_rate = 0.001
n_epochs = 20
batch_size = 100
n_batches = int(mnist.train.num_examples/batch_size)
# number of pixels in the MNIST image as number of inputs
n_inputs = 784
n_outputs = n_inputs
```
1. 接下来,定义参数字典以保存权重和偏差参数:
```py
params={}
```
1. 定义每个编码器和解码器中隐藏层的数量:
```py
n_layers = 2
# neurons in each hidden layer
n_neurons = [512,256]
```
1. 变分编码器中的新增加是我们定义潜变量`z`的维数:
```py
n_neurons_z = 128 # the dimensions of latent variables
```
1. 我们使用激活`tanh`
```py
activation = tf.nn.tanh
```
1. 定义输入和输出占位符:
```py
x = tf.placeholder(dtype=tf.float32, name="x",
shape=[None, n_inputs])
y = tf.placeholder(dtype=tf.float32, name="y",
shape=[None, n_outputs])
```
1. 定义输入层:
```py
# x is input layer
layer = x
```
1. 定义编码器网络的偏差和权重并添加层。变分自编码器的编码器网络也称为识别网络或推理网络或概率编码器网络:
```py
for i in range(0,n_layers):
name="w_e_{0:04d}".format(i)
params[name] = tf.get_variable(name=name,
shape=[n_inputs if i==0 else n_neurons[i-1],
n_neurons[i]],
initializer=tf.glorot_uniform_initializer()
)
name="b_e_{0:04d}".format(i)
params[name] = tf.Variable(tf.zeros([n_neurons[i]]),
name=name
)
layer = activation(tf.matmul(layer,
params["w_e_{0:04d}".format(i)]
) + params["b_e_{0:04d}".format(i)]
)
```
1. 接下来,添加潜在变量的均值和方差的层:
```py
name="w_e_z_mean"
params[name] = tf.get_variable(name=name,
shape=[n_neurons[n_layers-1], n_neurons_z],
initializer=tf.glorot_uniform_initializer()
)
name="b_e_z_mean"
params[name] = tf.Variable(tf.zeros([n_neurons_z]),
name=name
)
z_mean = tf.matmul(layer, params["w_e_z_mean"]) +
params["b_e_z_mean"]
name="w_e_z_log_var"
params[name] = tf.get_variable(name=name,
shape=[n_neurons[n_layers-1], n_neurons_z],
initializer=tf.glorot_uniform_initializer()
)
name="b_e_z_log_var"
params[name] = tf.Variable(tf.zeros([n_neurons_z]),
name="b_e_z_log_var"
)
z_log_var = tf.matmul(layer, params["w_e_z_log_var"]) +
params["b_e_z_log_var"]
```
1. 接下来,定义表示与`z`方差的变量相同形状的噪声分布的 epsilon 变量:
```py
epsilon = tf.random_normal(tf.shape(z_log_var),
mean=0,
stddev=1.0,
dtype=tf.float32,
name='epsilon'
)
```
1. 根据均值,对数方差和噪声定义后验分布:
```py
z = z_mean + tf.exp(z_log_var * 0.5) * epsilon
```
1. 接下来,定义解码器网络的权重和偏差,并添加解码器层。变分自编码器中的解码器网络也称为概率解码器或生成器网络。
```py
# add generator / probablistic decoder network parameters and layers
layer = z
for i in range(n_layers-1,-1,-1):
name="w_d_{0:04d}".format(i)
params[name] = tf.get_variable(name=name,
shape=[n_neurons_z if i==n_layers-1 else n_neurons[i+1],
n_neurons[i]],
initializer=tf.glorot_uniform_initializer()
)
name="b_d_{0:04d}".format(i)
params[name] = tf.Variable(tf.zeros([n_neurons[i]]),
name=name
)
layer = activation(tf.matmul(layer, params["w_d_{0:04d}".format(i)]) +
params["b_d_{0:04d}".format(i)])
```
1. 最后,定义输出层:
```py
name="w_d_z_mean"
params[name] = tf.get_variable(name=name,
shape=[n_neurons[0],n_outputs],
initializer=tf.glorot_uniform_initializer()
)
name="b_d_z_mean"
params[name] = tf.Variable(tf.zeros([n_outputs]),
name=name
)
name="w_d_z_log_var"
params[name] = tf.Variable(tf.random_normal([n_neurons[0],
n_outputs]),
name=name
)
name="b_d_z_log_var"
params[name] = tf.Variable(tf.zeros([n_outputs]),
name=name
)
layer = tf.nn.sigmoid(tf.matmul(layer, params["w_d_z_mean"]) +
params["b_d_z_mean"])
model = layer
```
1. 在变异自编码器中,我们有重建损失和正则化损失。将损失函数定义为重建损失和正则化损失的总和:
```py
rec_loss = -tf.reduce_sum(y * tf.log(1e-10 + model) + (1-y)
* tf.log(1e-10 + 1 - model), 1)
reg_loss = -0.5*tf.reduce_sum(1 + z_log_var - tf.square(z_mean)
- tf.exp(z_log_var), 1)
loss = tf.reduce_mean(rec_loss+reg_loss)
```
1. 根据`AdapOptimizer`定义优化程序函数:
```py
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
.minimize(loss)
```
1. 现在让我们训练模型并从非噪声和噪声测试图像生成图像:
```py
with tf.Session() as tfs:
tf.global_variables_initializer().run()
for epoch in range(n_epochs):
epoch_loss = 0.0
for batch in range(n_batches):
X_batch, _ = mnist.train.next_batch(batch_size)
feed_dict={x: X_batch,y: X_batch}
_,batch_loss = tfs.run([optimizer,loss],
feed_dict=feed_dict)
epoch_loss += batch_loss
if (epoch%10==9) or (epoch==0):
average_loss = epoch_loss / n_batches
print("epoch: {0:04d} loss = {1:0.6f}"
.format(epoch,average_loss))
# predict images using autoencoder model trained
Y_test_pred1 = tfs.run(model, feed_dict={x: test_images})
Y_test_pred2 = tfs.run(model, feed_dict={x: test_images_noisy})
```
我们得到以下输出:
```py
epoch: 0000 loss = 180.444682
epoch: 0009 loss = 106.817749
epoch: 0019 loss = 102.580904
```
现在让我们显示图像:
```py
display_images(test_images.reshape(-1,pixel_size,pixel_size),test_labels)
display_images(Y_test_pred1.reshape(-1,pixel_size,pixel_size),test_labels)
```
结果如下:
![](img/121f4c1e-cabc-4b93-a3d4-28aa4b0c9180.png)
```py
display_images(test_images_noisy.reshape(-1,pixel_size,pixel_size),
test_labels)
display_images(Y_test_pred2.reshape(-1,pixel_size,pixel_size),test_labels)
```
结果如下:
![](img/50581981-df44-410a-a655-05e58413ea89.png)
同样,可以通过超参数调整和增加学习量来改善结果。
\ No newline at end of file
# 变量
到目前为止,我们已经看到了如何创建各种张量对象:常量,操作和占位符。在使用 TensorFlow 构建和训练模型时,通常需要将参数值保存在可在运行时更新的内存位置。该内存位置由 TensorFlow 中的变量标识。
在 TensorFlow 中,变量是张量对象,它们包含可在程序执行期间修改的值。
虽然`tf.Variable`看起来与`tf.placeholder`类似,但两者之间存在细微差别:
| **`tf.placeholder`** | **`tf.Variable`** |
| --- | --- |
| `tf.placeholder`定义了不随时间变化的输入数据 | `tf.Variable`定义随时间修改的变量值 |
| `tf.placeholder`在定义时不需要初始值 | `tf.Variable`在定义时需要初始值 |
在 TensorFlow 中,可以使用`tf.Variable()`创建变量。让我们看一个带有线性模型的占位符和变量的示例:
![](img/e7e3cb1f-7f3a-4ff6-9902-2295abdd0822.png)
1. 我们将模型参数`w``b`分别定义为具有`[.3]``[-0.3]`初始值的变量:
```py
w = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)
```
1. 输入`x`定义为占位符,输出`y`定义为操作:
```py
x = tf.placeholder(tf.float32)
y = w * x + b
```
1. 让我们打印`w``v``x``y`,看看我们得到了什么:
```py
print("w:",w)
print("x:",x)
print("b:",b)
print("y:",y)
```
我们得到以下输出:
```py
w: <tf.Variable 'Variable:0' shape=(1,) dtype=float32_ref>
x: Tensor("Placeholder_2:0", dtype=float32)
b: <tf.Variable 'Variable_1:0' shape=(1,) dtype=float32_ref>
y: Tensor("add:0", dtype=float32)
```
输出显示`x`是占位符张量,`y`是操作张量,而`w``b`是形状`(1,)`和数据类型`float32`的变量。
在 TensorFlow 会话中使用变量之前,必须先初始化它们。您可以通过运行其初始化程序操作来初始化单个变量。
例如,让我们初始化变量`w`
```py
tfs.run(w.initializer)
```
但是,在实践中,我们使用 TensorFlow 提供的便利函数来初始化所有变量:
```py
tfs.run(tf.global_variables_initializer())
```
您还可以使用`tf.variables_initializer()`函数来初始化一组变量。
也可以通过以下方式调用全局初始化程序便利函数,而不是在会话对象的`run()`函数内调用:
```py
tf.global_variables_initializer().run()
```
在初始化变量之后,让我们运行我们的模型来给出 x = [1,2,3,4]的值的输出:
```py
print('run(y,{x:[1,2,3,4]}) : ',tfs.run(y,{x:[1,2,3,4]}))
```
我们得到以下输出:
```py
run(y,{x:[1,2,3,4]}) : [ 0\. 0.30000001 0.60000002 0.90000004]
```
\ No newline at end of file
# Keras 中的变分自编码器
在 Keras 中,构建变分自编码器更容易,并且代码行更少。 Keras 变分自编码器最好使用函数式风格构建。到目前为止,我们已经使用了在 Keras 中构建模型的顺序样式,现在在这个例子中,我们将看到在 Keras 中构建 VAE 模型的函数式风格。在 Keras 建立 VAE 的步骤如下:
1. 定义隐藏层和潜在变量层中的超参数和神经元数量:
```py
import keras
from keras.layers import Lambda, Dense, Input, Layer
from keras.models import Model
from keras import backend as K
learning_rate = 0.001
batch_size = 100
n_batches = int(mnist.train.num_examples/batch_size)
# number of pixels in the MNIST image as number of inputs
n_inputs = 784
n_outputs = n_inputs
# number of hidden layers
n_layers = 2
# neurons in each hidden layer
n_neurons = [512,256]
# the dimensions of latent variables
n_neurons_z = 128
```
1. 构建输入层:
```py
x = Input(shape=(n_inputs,), name='input')
```
1. 构建编码器层,以及潜在变量的均值和方差层:
```py
# build encoder
layer = x
for i in range(n_layers):
layer = Dense(units=n_neurons[i], activation='relu',name='enc_{0}'.format(i))(layer)
z_mean = Dense(units=n_neurons_z,name='z_mean')(layer)
z_log_var = Dense(units=n_neurons_z,name='z_log_v')(layer)
```
1. 创建噪声和后验分布:
```py
# noise distribution
epsilon = K.random_normal(shape=K.shape(z_log_var),
mean=0,stddev=1.0)
# posterior distribution
z = Lambda(lambda zargs: zargs[0] + K.exp(zargs[1] * 0.5) * epsilon,
name='z')([z_mean,z_log_var])
```
1. 添加解码器层:
```py
# add generator / probablistic decoder network layers
layer = z
for i in range(n_layers-1,-1,-1):
layer = Dense(units=n_neurons[i], activation='relu',
name='dec_{0}'.format(i))(layer)
```
1. 定义最终输出层:
```py
y_hat = Dense(units=n_outputs, activation='sigmoid',
name='output')(layer)
```
1. 最后,从输入层和输出层定义模型并显示模型摘要:
```py
model = Model(x,y_hat)
model.summary()
```
我们看到以下摘要:
```py
_________________________________________________________________________
Layer (type) Output Shape Param # Connected to
=========================================================================
input (InputLayer) (None, 784) 0
_________________________________________________________________________
enc_0 (Dense) (None, 512) 401920 input[0][0]
_________________________________________________________________________
enc_1 (Dense) (None, 256) 131328 enc_0[0][0]
_________________________________________________________________________
z_mean (Dense) (None, 128) 32896 enc_1[0][0]
_________________________________________________________________________
z_log_v (Dense) (None, 128) 32896 enc_1[0][0]
_________________________________________________________________________
z (Lambda) (None, 128) 0 z_mean[0][0]
z_log_v[0][0]
_________________________________________________________________________
dec_1 (Dense) (None, 256) 33024 z[0][0]
_________________________________________________________________________
dec_0 (Dense) (None, 512) 131584 dec_1[0][0]
_________________________________________________________________________
output (Dense) (None, 784) 402192 dec_0[0][0]
=========================================================================
Total params: 1,165,840
Trainable params: 1,165,840
Non-trainable params: 0
_________________________________________________________________________
```
1. 定义一个计算重建和正则化损失之和的函数:
```py
def vae_loss(y, y_hat):
rec_loss = -K.sum(y * K.log(1e-10 + y_hat) + (1-y) *
K.log(1e-10 + 1 - y_hat), axis=-1)
reg_loss = -0.5 * K.sum(1 + z_log_var - K.square(z_mean) -
K.exp(z_log_var), axis=-1)
loss = K.mean(rec_loss+reg_loss)
return loss
```
1. 使用此损失函数来编译模型:
```py
model.compile(loss=vae_loss,
optimizer=keras.optimizers.Adam(lr=learning_rate))
```
1. 让我们训练 50 个周期的模型并预测图像,正如我们在前面的部分中所做的那样:
```py
n_epochs=50
model.fit(x=X_train_noisy,y=X_train,batch_size=batch_size,
epochs=n_epochs,verbose=0)
Y_test_pred1 = model.predict(test_images)
Y_test_pred2 = model.predict(test_images_noisy)
```
让我们显示结果图像:
```py
display_images(test_images.reshape(-1,pixel_size,pixel_size),test_labels)
display_images(Y_test_pred1.reshape(-1,pixel_size,pixel_size),test_labels)
```
我们得到如下结果:
![](img/9ced2741-a51f-4bcc-951d-2d73e22a1c89.png)
```py
display_images(test_images_noisy.reshape(-1,pixel_size,pixel_size),
test_labels)
display_images(Y_test_pred2.reshape(-1,pixel_size,pixel_size),test_labels)
```
我们得到以下结果:
![](img/2bf0dce8-3567-4713-baf2-c20cd2178af3.png)
这很棒!!生成的图像更清晰,更清晰。
\ No newline at end of file
# 总结
自编码器是无监督数据学习的绝佳工具。它们通常用于降低维数,因此数据可以用较少数量的特征来表示。在本章中,您了解了各种类型的自编码器。我们使用 TensorFlow 和 Keras 练习构建三种类型的自编码器:栈式自编码器,去噪自编码器和变分自编码器。我们使用 MNIST 数据集作为示例。
在最后的章节中,您学习了如何使用 TensorFlow 和 Keras 构建各种机器学习和深度学习模型,例如回归,分类,MLP,CNN,RNN 和自编码器。在下一章中,您将了解 TensorFlow 和 Keras 的高级功能,这些功能允许我们将模型投入生产。
\ No newline at end of file
# TF 服务:生产中的 TensorFlow 模型
TensorFlow 模型在开发环境中经过训练和验证。一旦发布,它们需要托管在某个地方,提供用工程师和软件工程师使用,以集成到各种应用中。 TensorFlow 为此提供了一个高表现服务器,称为 TensorFlow 服务。
要在生产中提供 TensorFlow 模型,需要在离线训练后保存它们,然后在生产环境中恢复经过训练的模型。 TensorFlow 模型在保存时包含以下文件:
* **元图**:元图表示图的协议缓冲区定义。元图保存在具有`.meta`扩展名的文件中。
* **checkpoint** :检查点代表各种变量的值。检查点保存在两个文件中:一个带有`.index`扩展名,另一个带有`.data-00000-of-00001`扩展名。
在本章中,我们将学习各种保存和恢复模型的方法以及如何使用 TF 服务来提供模型。我们将使用 MNIST 示例来简化操作并涵盖以下主题:
* 使用`Saver`类在 TensorFlow 中保存和恢复模型
* 保存和恢复 Keras 模型
* TensorFlow 服务
* 安装 TF 服务
* 保存 TF 服务的模型
* 用 TF Serving 服务模型
* TF 在 Docker 容器中提供服务
* TF 服务于 Kubernetes
\ No newline at end of file
# 在 TensorFlow 中保存和恢复模型
您可以通过以下两种方法之一在 TensorFlow 中保存和恢复模型和变量:
*`tf.train.Saver`类创建的保护程序对象
*`tf.saved_model_builder.SavedModelBuilder`类创建的基于`SavedModel`格式的对象
让我们看看两种方法的实际应用。
您可以按照 Jupyter 笔记本中的代码`ch-11a_Saving_and_Restoring_TF_Models`
\ No newline at end of file
# 使用保护程序类保存和恢复所有图变量
我们进行如下:
1. 要使用`saver`类,首先要创建此类的对象:
```py
saver = tf.train.Saver()
```
1. 保存图中所有变量的最简单方法是使用以下两个参数调用`save()`方法:会话对象和磁盘上保存变量的文件的路径:
```py
with tf.Session() as tfs:
...
saver.save(tfs,"saved-models/model.ckpt")
```
1. 要恢复变量,调用`restore()`方法:
```py
with tf.Session() as tfs:
saver.restore(tfs,"saved-models/model.ckpt")
...
```
1. 让我们重温一下[第 1 章](../Text/8.html),TensorFlow 101 的例子,在简单的例子中保存变量的代码如下:
```py
# Assume Linear Model y = w * x + b
# Define model parameters
w = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)
# Define model input and output
x = tf.placeholder(tf.float32)
y = w * x + b
output = 0
# create saver object
saver = tf.train.Saver()
with tf.Session() as tfs:
# initialize and print the variable y
tfs.run(tf.global_variables_initializer())
output = tfs.run(y,{x:[1,2,3,4]})
saved_model_file = saver.save(tfs,
'saved-models/full-graph-save-example.ckpt')
print('Model saved in {}'.format(saved_model_file))
print('Values of variables w,b: {}{}'
.format(w.eval(),b.eval()))
print('output={}'.format(output))
```
我们得到以下输出:
```py
Model saved in saved-models/full-graph-save-example.ckpt
Values of variables w,b: [ 0.30000001][-0.30000001]
output=[ 0\. 0.30000001 0.60000002 0.90000004]
```
1. 现在让我们从刚刚创建的检查点文件中恢复变量:
```py
# Assume Linear Model y = w * x + b
# Define model parameters
w = tf.Variable([0], dtype=tf.float32)
b = tf.Variable([0], dtype=tf.float32)
# Define model input and output
x = tf.placeholder(dtype=tf.float32)
y = w * x + b
output = 0
# create saver object
saver = tf.train.Saver()
with tf.Session() as tfs:
saved_model_file = saver.restore(tfs,
'saved-models/full-graph-save-example.ckpt')
print('Values of variables w,b: {}{}'
.format(w.eval(),b.eval()))
output = tfs.run(y,{x:[1,2,3,4]})
print('output={}'.format(output))
```
您会注意到在恢复代码中我们没有调用`tf.global_variables_initializer()`,因为不需要初始化变量,因为它们将从文件中恢复。我们得到以下输出,它是根据恢复的变量计算得出的:
```py
INFO:tensorflow:Restoring parameters from saved-models/full-graph-save-example.ckpt
Values of variables w,b: [ 0.30000001][-0.30000001]
output=[ 0\. 0.30000001 0.60000002 0.90000004]
```
\ No newline at end of file
此差异已折叠。
# 保存和恢复 Keras 模型
在 Keras 中,保存和恢复模型非常简单。 Keras 提供三种选择:
* 使用其网络体系结构,权重(参数),训练配置和优化程序状态保存完整模型。
* 仅保存架构。
* 只保存权重。
要保存完整模型,请使用`model.save(filepath)`函数。这将把完整的模型保存在 HDF5 文件中。可以使用`keras.models.load_model(filepath)`函数加载保存的模型。此函数将所有内容加载回来,然后还编译模型。
要保存模型的体系结构,请使用`model.to_json()``model.to_yaml()`函数。这些函数返回一个可以写入磁盘文件的字符串。在恢复架构时,可以回读字符串,并使用`keras.models.model_from_json(json_string)``keras.models.model_from_yaml(yaml_string)` 函数恢复模型架构。这两个函数都返回一个模型实例。
要保存模型的权重,请使用`model.save_weights(path_to_h5_file)`函数。可以使用`model.load_weights(path_to_h5_file)`函数恢复权重。
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
# Kubernetes 中的 TensorFlow 服务
根据 {Kubernetes](https://kubernets.io):
Kubernetes 是一个开源系统,用于自动化容器化应用的部署,扩展和管理。
TensorFlow 模型可以扩展为使用生产环境中的 Kubernetes 集群从数百或数千个`TF Serving`服务中提供服务。 Kubernetes 集群可以在所有流行的公共云上运行,例如 GCP,AWS,Azure,以及您的本地私有云。因此,让我们直接学习安装 Kubernetes,然后在 Kubernetes Cluster 上部署 MNIST 模型。
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册