# 三、Keras 101

Keras 是一个高级库，允许使用 TensorFlow 作为后端深度学习库。 TensorFlow 团队将 TrasorFlow Core 中的 Keras 作为模块`tf.keras`。除了 TensorFlow 之外，Keras 在撰写本书时还支持 Theano 和  CNTK。

以下 Keras 的指导原则使其在深度学习社区中非常受欢迎：

*   极简主义提供一致且简单的 API
*   模块化允许将各种元素表示为可插拔模块
*   将新模块添加为类和函数的可扩展性
*   用于代码和模型配置的 Python 原生
*   开箱即用的通用网络架构，支持 CNN，RNN 或两者的组合

在本书的其余部分中，我们将学习如何使用低级 TensorFlow API 和高级 Keras API 构建不同类型的深度学习和机器学习模型。

我们将在本章中介绍以下主题：

*   安装 Keras
*   在 Keras 中创建模型的工作流程
*   使用顺序和函数式 API 创建 Keras 模型
*   Keras 层
*   使用顺序和函数式 API 创建和添加层

*   编译 Keras 模型
*   训练 Keras 模型
*   使用 Keras 模型进行预测
*   Keras 的附加模块
*   MNIST 数据集的 Keras 序列模型示例

# 安装 Keras

使用以下命令可以在 Python 3 中安装 Keras：

```py
pip3 install keras
```

[要在其他环境或源代码中安装 Keras，请参阅此链接](https://keras.io/#installation)。

# Keras 中的神经网络模型

Keras 中的神经网络模型将定义为层图。 Keras 中的模型可以使用顺序或函数式 API 创建。函数式和顺序 API 都可用于构建任何类型的模型。函数式 API 可以更轻松地构建具有多个输入，多个输出和共享层的复杂模型。

因此，根据经验，我们已经看到工程师将顺序 API 用于从简单层构建的简单模型，以及用于涉及分支和共享层的复杂模型的函数式 API。我们还观察到，使用函数式 API 构建简单模型可以更轻松地将模型扩展为具有分支和共享的复杂模型。因此，对于我们的工作，我们总是使用函数式 API。

# 在 Keras 中创建模型的工作流程

Keras 的简单工作流程如下：

1.  创建模型
2.  创建层并将其添加到模型中
3.  编译模型
4.  训练模型
5.  使用该模型进行预测或评估

我们来看看每个步骤。

您可以使用代码包中包含的 Jupyter 笔记本`ch-03_Keras_101`来遵循本章中的代码示例。 尝试修改笔记本中的代码以探索各种选项。

# 创建 Keras 模型

可以使用顺序  API 或函数式  API 创建 Keras 模型。以下两小节给出了以两种方式创建模型的示例  。

# 用于创建 Keras 模型的顺序 API

在顺序 API 中，使用以下代码创建空模型：

```py
model = Sequential()
```

您现在可以将层添加到此模型中，我们将在下一节中看到。

或者，您也可以将所有层作为列表传递给构造器。例如，我们通过使用以下代码将它们传递给构造器来添加四个层：

```py
model = Sequential([ Dense(10, input_shape=(256,)), 
                    Activation('tanh'), 
                    Dense(10), 
                    Activation('softmax')
                   ])
```

# 用于创建 Keras 模型的函数式 API

在函数式 API 中，模型创建为`Model`类的一个实例，它接受输入和输出参数。输入和输出参数分别代表一个或多个输入和输出张量。

例如，使用以下代码从函数式 API 实例化模型：

```py
model = Model(inputs=tensor1, outputs=tensor2)
```

在上面的代码中，`tensor1`和`tensor2`是张量或对象，可以像张量一样对待，例如，Keras `layer`对象。

如果有多个输入和输出张量，则可以将它们作为列表传递，如以下示例所示：

```py
model = Model(inputs=[i1,i2,i3], outputs=[o1,o2,o3])
```

# Keras 层

Keras 为网络架构的简单构建提供了几个内置层类。以下部分概述和描述了 Keras2 在撰写本书时提供的各种类型的层。

# Keras 核心层

Keras 核心层实现基本操作，几乎用于各种网络架构。下表给出了 Keras2 提供的层的摘要和说明：

| **层名称** | **描述** |
| --- | --- |
| `Dense` | 这是一个简单的完全连接的神经网络层。该层生成以下函数的输出：`激活(输入 x 权重 + 偏差)`，其中激活是指传递给层的激活函数，默认为`None`。 |
| `Activation` | 该层将指定的激活函数应用于输出。该层生成以下函数的输出：`激活(输入)`，其中激活是指传递给该层的激活函数。以下激活函数可用于实例化层：`softmax`，`elu`，`selu`，`softplus`，`softsign`，`relu`，`tanh`，`sigmoid`，`hard_sigmoid`和`linear` |
| `Dropout` | 该层以指定的丢弃率将丢弃正则化应用于输入。 |
| `Flatten` | 该层使输入变平，即对于三维输入，它变平并产生一维输出。 |
| `Reshape` | 此层将输入转换为指定的形状。 |
| `Permute` | 此层按照指定的模式重新排序输入尺寸。 |
| `RepeatVector` | 该层以给定次数重复输入。因此，如果输入是 2D 张量的形状`(#samples, #feature)`并且该层被赋予`n`次重复，那么输出将是 3D 张量的形状`(#samples, n, #feature)`。 |
| `Lambda` | 该层将提供的函数包装为层。因此，输入通过提供的自定义函数传递以产生输出。该层为 Keras 用户提供了最终的可扩展性，可以将自己的自定义函数添加为层。 |
| `ActivityRegularization` | 该层将 L1 或 L2 或两种正则化的组合应用于其输入。该层应用于激活层的输出或具有激活函数的层的输出。 |
| `Masking` | 此层在输入张量中屏蔽或跳过这些时间步长，其中输入张量中的所有值都等于作为层参数提供的屏蔽值。 |

# Keras 卷积层

这些层为卷积神经网络实现了不同类型的卷积，采样和裁剪操作：

| **层名称** | **描述** |
| --- | --- |
| `Conv1D` | 该层将单个空间或时间维度上的卷积应用于输入。 |
| `Conv2D` | 该层将二维卷积应用于输入。 |
| `SeparableConv2D` | 该层在每个输入通道上应用深度方式空间卷积，然后是逐点卷积，将所得到的输出通道混合在一起。 |
| `Conv2DTranspose` | 该层将卷积的形状恢复为产生这些卷积的输入的形状。 |
| `Conv3D` | 该层将三维卷积应用于输入。 |
| `Cropping1D` | 该层沿时间维度裁剪输入数据。 |
| `Cropping2D` | 此层沿空间维度裁剪输入数据，例如图像的宽度和高度。 |
| `Cropping3D` | 该层沿着时空裁剪输入数据，即所有三维。 |
| `UpSampling1D` | 该层按时间轴指定的时间重复输入数据。 |
| `UpSampling2D` | 此层沿两个维度按指定时间重复输入数据的行和列维度。 |
| `UpSampling3D` | 该层按三个维度的指定时间重复输入数据的三个维度。 |
| `ZeroPadding1D` | 该层将零添加到时间维度的开头和结尾。 |
| `ZeroPadding2D` | 此层将行和列的零添加到 2D 张量的顶部，底部，左侧或右侧。 |
| `ZeroPadding3D` | 该层将零添加到 3D 张量的三个维度。 |

# Keras 池化层

这些层为卷积神经网络实现不同的池化操作：

| **层名称** | **描述** |
| --- | --- |
| `MaxPooling1D` | 该层实现一维输入数据的最大池化操作。 |
| `MaxPooling2D` | 该层实现二维输入数据的最大池化操作。 |
| `MaxPooling3D` | 该层实现三维输入数据的最大池化操作。 |
| `AveragePooling1D` | 该层实现一维输入数据的平均池化操作。 |
| `AveragePooling2D` | 该层实现二维输入数据的平均池化操作。 |
| `AveragePooling3D` | 该层实现三维输入数据的平均吃阿虎操作。 |
| `GlobalMaxPooling1D` | 该层实现一维输入数据的全局最大池化操作。 |
| `GlobalAveragePooling1D` | 该层实现一维输入数据的全局平均池化操作。 |
| `GlobalMaxPooling2D` | 该层实现二维输入数据的全局最大池化操作。 |
| `GlobalAveragePooling2D` | 该层实现二维输入数据的全局平均池化操作。 |

# Keras 本地连接层

这些层在卷积神经网络中很有用：

| **层名称** | **描述** |
| --- | --- |
| `LocallyConnected1D` | 该层通过在输入的每个不同补丁上应用不同的滤波器组，将单个空间或时间维度上的卷积应用于输入，从而不共享权重。 |
| `LocallyConnected2D` | 该层通过在输入的每个不同补丁上应用不同的滤波器组，将两个维上的卷积应用于输入，从而不共享权重。 |

# Keras 循环层

这些层实现循环神经网络的不同变体：

| **层名称** | **描述** |
| --- | --- |
| `SimpleRNN` | 该层实现了完全连接的循环神经网络。 |
| `GRU` | 该层实现了门控循环单元网络。 |
| `LSTM` | 该层实现了长期短期记忆网络。 |

# Keras 嵌入层

目前，只有一个嵌入层选项可用：

| **层名称** | **描述** |
| --- | --- |
| `Embedding` | 该层采用由下标组成的 2D 张量，形状为`(batch_size, sequence_length)`，并产生由形状`(batch_size, sequence_length, output_dim)`的密集向量组成的张量。 |

# Keras 合并层

这些层合并两个或多个输入张量，并通过应用每个层表示的特定操作产生单个输出张量：

| **层名称** | **描述** |
| --- | --- |
| `Add` | 该层计算输入张量的逐元素加法。 |
| `Multiply` | 该层计算输入张量的逐元素乘法 |
| `Average` | 该层计算输入张量的逐元素平均值。 |
| `Maximum` | 该层计算输入张量的逐元素最大值。 |
| `Concatenate` | 此层沿指定轴连接输入张量。 |
| `Dot` | 该层计算两个输入张量中样本之间的点积。 |
| `add`，`multiply`，`average`，`maximum`，`concatenate`和`dot` | 这些函数表示此表中描述的各个合并层的函数接口。 |

# Keras 高级激活层

这些层实现了高级激活函数，这些函数无法作为简单的底层后端函数实现。它们的操作类似于我们在核心层部分中介绍的`Activation()`层：

| **层名称** | **描述** |
| --- | --- |
| `LeakyReLU` | 该层计算`ReLU`激活函数的泄漏版本。 |
| `PReLU` | 该层计算参数化`ReLU`激活函数。 |
| `ELU` | 该层计算指数线性单元激活函数。 |
| `ThresholdedReLU` | 该层计算阈值版本的`ReLU`激活函数。 |

# Keras 正则化层

目前，只有一个标准化层可用：

| **层名称** | **描述** |
| --- | --- |
| `BatchNormalization` | 该层标准化前一层的每个批量的输出，使得该层的输出近似为具有接近零的平均值和接近 1 的标准偏差。 |

# Keras 噪音层

这些层可以添加到模型中，以防止过拟合添加噪音；它们也被称为正则化层。这些层的操作方式与核心层部分中的`Dropout()`和`ActivityRegularizer()`层相同。

| **层名称** | **描述** |
| --- | --- |
| `GaussianNoise` | 该层将附加的零中心高斯噪声应用于输入。 |
| `GaussianDropout` | 该层将乘法的单中心高斯噪声应用于输入。 |
| `AlphaDropout` | 该层丢弃一定百分比的输入，使得丢弃后输出的均值和方差与输入的均值和方差紧密匹配。 |

# 将层添加到 Keras 模型

上一节中提到的所有层都需要添加到我们之前创建的模型中。在以下部分中，我们将介绍如何使用函数式 API 和顺序 API 添加层。

# 用于向 Keras 模型添加层的顺序 API

在顺序 API 中，可以通过实例化前面部分中给出的某个层类型的对象来创建层。然后使用`model.add()`函数将创建的层添加到模型中。作为示例，我们将创建一个模型，然后为其添加两个层：

```py
model = Sequential() 
model.add(Dense(10, input_shape=(256,)) 
model.add(Activation('tanh'))
model.add(Dense(10))
model.add(Activation('softmax'))

```

# 用于向 Keras 模型添加层的函数式 API

在函数式 API 中，首先以函数方式创建层，然后在创建模型时，输入和输出层作为张量参数提供，如我们在上一节。

这是一个例子：

1.  首先，创建输入层：

```py
input = Input(shape=(64,))
```

1.  接下来，以函数方式从输入层创建密集层：

```py
hidden = Dense(10)(inputs)
```

1.  以同样的方式，以函数方式创建更多隐藏层，构建在前面的层之上：

```py
hidden = Activation('tanh')(hidden)
hidden = Dense(10)(hidden)
output = Activation('tanh')(hidden)
```

1.  最后，使用输入和输出层实例化模型对象：

```py
model = Model(inputs=input, outputs=output)
```

有关创建顺序和函数式 Keras 模型的更深入细节，您可以阅读由 Antonio Gulli 和 Sujit Pal，Packt Publishing，2017 年出版的题为 Deep Learning with Keras 的书。

# 编译 Keras 模型

前面部分中构建的模型需要使用`model.compile()`方法进行编译，然后才能用于训练和预测。`compile()`方法的完整签名如下：

```py
compile(self, optimizer, loss, metrics=None, sample_weight_mode=None)
```

`compile`方法有三个参数：

*   `optimizer`：您可以指定自己的函数或 Keras 提供的函数之一。此函数用于更新优化迭代中的参数。 Keras 提供以下内置优化器函数：
    *   `SGD`
    *   `RMSprop`
    *   `Adagrad`
    *   `Adadelta`
    *   `Adam`
    *   `Adamax`
    *   `Nadam`

*   `loss`：您可以指定自己的损失函数或使用提供的损失函数之一。优化器函数优化参数，以便最小化此损失函数的输出。 Keras 提供以下损失函数：
    *   `mean_squared_error`
    *   `mean_absolute_error`
    *   `mean_absolute_pecentage_error`
    *   `mean_squared_logarithmic_error`
    *   `squared_hinge`
    *   `hinge`
    *   `categorical_hinge`
    *   `sparse_categorical_crossentropy`
    *   `binary_crossentropy`
    *   `poisson`
    *   `cosine proximity`
    *   ``binary_accuracy``
    *   `categorical_accuracy`
    *   `sparse_categorical_accuracy`
    *   `top_k_categorical_accuracy`
    *   `sparse_top_k_categorical_accuracy`
*   `metrics`：第三个参数是训练模型时需要收集的指标列表。如果启用了详细输出，则会为每次迭代打印度量标准。指标就像损失函数；一些由 Keras 提供，能够编写您自己的度量函数。所有损失函数也可用作度量函数。

# 训练 Keras 模型

训练 Keras 模型就像调用`model.fit()`方法一样简单。该方法的完整签名如下：

```py
fit(self, x, y, batch_size=32, epochs=10, verbose=1, callbacks=None, 
    validation_split=0.0, validation_data=None, shuffle=True, 
    class_weight=None, sample_weight=None, initial_epoch=0)
```

我们不会详细介绍这种方法的参数； 您可以在 [Keras 网站](https://keras.io/models/sequential/)上阅读详细信息。

对于我们之前创建的示例模型，使用以下代码训练模型：

```py
model.fit(x_data, y_labels)
```

# 使用 Keras 模型进行预测

经过训练的模型可用于使用`model.predict()`方法来预测值，或用`model.evaluate()`方法评估模型。

这两种方法的签名如下：

```py
predict(self, x, batch_size=32, verbose=0)
```

```py
evaluate(self, x, y, batch_size=32, verbose=1, sample_weight=None)
```

# Keras 的附加模块

Keras 提供了几个补充基本工作流程的附加模块（附加函数在本章开头描述）。部分模块如下：

*   `preprocessing`模块提供了几种预处理序列，图像和文本数据的函数。
*   `datasets`模块提供了多种函数，可以快速访问几个流行的数据集，如 CIFAR10 图像，CIFAR100 图像，IMDB 电影评论，路透社新闻专线主题，MNIST 手写数字和波士顿房价。
*   `initializers`模块提供了几种设置层初始随机权重参数的函数，如`Zeros`，`Ones`，`Constant`，`RandomNormal`，`RandomUniform`，`TruncatedNormal`，`VarianceScaling`，`Orthogonal`，`Identity`，`lecun_normal`，`lecun_uniform`，`glorot_normal`，`glorot_uniform`，`he_normal`和`he_uniform`。
*   `models`模块提供了几种恢复模型架构和权重的函数，如`model_from_json`，`model_from_yaml`，和`load_model`。可以使用`model.to_yaml()`和`model.to_json()`方法保存模型架构。通过调用`model.save()`方法可以保存模型权重。权重保存在 HDF5 文件中。
*   `applications`模块提供了几种预先构建和预训练的模型，例如 Xception，VGG16，VGG19，ResNet50，InceptionV3，InceptionResNetV2 和 MobileNet。我们将学习如何使用预建模型来预测我们的数据集。我们还将学习，如何使用来自略有不同的域的数据集，再训练`applications`模块中的预训练模型。

这就结束了我们对 Keras 的简要介绍，这是 TensorFlow 的高级框架。我们将在本书中提供使用 Keras 构建模型的示例。

# 用于 MNIST 数据集的 Keras 序列模型示例

以下是构建简单多层感知机（在第 5 章中详细介绍）的一个小例子，用于对 MNIST 集中的手写数字进行分类：

```py
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import SGD
from keras import utils
import numpy as np

# define some hyper parameters
batch_size = 100 
n_inputs = 784
n_classes = 10 
n_epochs = 10 

# get the data
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# reshape the two dimensional 28 x 28 pixels
# sized images into a single vector of 784 pixels
x_train = x_train.reshape(60000, n_inputs)
x_test = x_test.reshape(10000, n_inputs)

# convert the input values to float32
x_train = x_train.astype(np.float32)
x_test = x_test.astype(np.float32)

# normalize the values of image vectors to fit under 1
x_train /= 255
x_test /= 255

# convert output data into one hot encoded format
y_train = utils.to_categorical(y_train, n_classes)
y_test = utils.to_categorical(y_test, n_classes)

# build a sequential model
model = Sequential()
# the first layer has to specify the dimensions of the input vector
model.add(Dense(units=128, activation='sigmoid', input_shape=(n_inputs,)))
# add dropout layer for preventing overfitting
model.add(Dropout(0.1))
model.add(Dense(units=128, activation='sigmoid'))
model.add(Dropout(0.1))
# output layer can only have the neurons equal to the number of outputs
model.add(Dense(units=n_classes, activation='softmax'))

# print the summary of our model
model.summary()

# compile the model
model.compile(loss='categorical_crossentropy',
              optimizer=SGD(),
              metrics=['accuracy'])

# train the model
model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=n_epochs)

# evaluate the model and print the accuracy score
scores = model.evaluate(x_test, y_test)

print('\n loss:', scores[0])
print('\n accuracy:', scores[1]) 
```

我们从描述和训练 Keras 模型得到以下输出：

```py
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_7 (Dense)              (None, 128)               100480    
_________________________________________________________________
dropout_5 (Dropout)          (None, 128)               0         
_________________________________________________________________
dense_8 (Dense)              (None, 128)               16512     
_________________________________________________________________
dropout_6 (Dropout)          (None, 128)               0         
_________________________________________________________________
dense_9 (Dense)              (None, 10)                1290      
=================================================================
Total params: 118,282
Trainable params: 118,282
Non-trainable params: 0
_________________________________________________________________
Epoch 1/10
60000/60000 [========================] - 3s - loss: 2.3018 - acc: 0.1312     
Epoch 2/10
60000/60000 [========================] - 2s - loss: 2.2395 - acc: 0.1920     
Epoch 3/10
60000/60000 [========================] - 2s - loss: 2.1539 - acc: 0.2843     
Epoch 4/10
60000/60000 [========================] - 2s - loss: 2.0214 - acc: 0.3856     
Epoch 5/10
60000/60000 [========================] - 3s - loss: 1.8269 - acc: 0.4739     
Epoch 6/10
60000/60000 [========================] - 2s - loss: 1.5973 - acc: 0.5426     
Epoch 7/10
60000/60000 [========================] - 2s - loss: 1.3846 - acc: 0.6028     
Epoch 8/10
60000/60000 [========================] - 3s - loss: 1.2133 - acc: 0.6502     
Epoch 9/10
60000/60000 [========================] - 3s - loss: 1.0821 - acc: 0.6842     
Epoch 10/10
60000/60000 [========================] - 3s - loss: 0.9799 - acc: 0.7157     

 loss: 0.859834249687
 accuracy: 0.788
```

您可以看到，在 Keras 中构建和训练模型是多么容易。

您可以从[他们记录完备的网站](https://keras.io)获取有关 Keras 的更多信息。

# 总结

在本章中，我们了解了 Keras。 Keras 是 TensorFlow 最受欢迎的高级库。我个人更喜欢将 Keras 用于我为商业制作和学术研究开发的所有模型。我们学习了使用函数式和顺序 API 在 Keras 中创建和训练模型所遵循的工作流程。我们了解了各种 Keras 层以及如何将层添加到顺序和函数式模型中。我们还学习了如何编译，训练和评估 Keras 模型。我们还看到了 Keras 提供的一些附加模块。

在本书的其余章节中，我们将介绍核心 TensorFlow 和 Keras 中的大多数示例。 在下一章中，我们将学习如何使用 TensorFlow 构建传统的机器学习模型进行分类和回归。

