Keras:TensorFlow2 的高级 API详解

在本章中,我们将讨论 Keras,这是 TensorFlow 2 的高级 API。Keras 是由 FrançoisChollet 在 Google 上开发的。 Keras 在快速原型制作,深度学习模型的构建和训练以及研究和生产方面非常受欢迎。 Keras 是一个非常丰富的 API。 正如我们将看到的,它支持急切的执行和数据管道以及其他功能。

自 2017 年以来,Keras 已可用于 TensorFlow,但随着 TensorFlow 2.0 的发布,其用途已扩展并进一步集成到 TensorFlow 中。 TensorFlow 2.0 已将 Keras 用作大多数深度学习开发工作的首选 API。

可以将 Keras 作为独立模块导入,但是在本书中,我们将集中精力在 TensorFlow 2 内部使用 Keras。因此,该模块为tensorflow.keras

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

下图显示了 Keras 在工业和研究领域的广泛应用。 PowerScore 排名由 Jeff Hale 设计,他使用了 7 个不同类别的 11 个数据源来评估框架的使用,兴趣和受欢迎程度。 然后,他对数据进行了加权和合并,如 2018 年 9 月的这篇文章所示

Keras 具有许多优点,其中包括:

  • 它专为新用户和专家而设计,提供一致且简单的 API
  • 通过简单,一致的接口对用户友好,该接口针对常见用例进行了优化
  • 它为用户错误提供了很好的反馈,这些错误很容易理解,并且经常伴随有用的建议
  • 它是模块化且可组合的; Keras 中的模型是通过结合可配置的构建块来构建的
  • 通过编写自定义构建块很容易扩展
  • 无需导入 Keras,因为它可以作为tensorflow.keras获得

如果您想知道 TensorFlow 随附的 Keras 版本,请使用以下命令:

import tensorflow as tf
print(tf.keras.__version__)

在撰写本文时,这产生了以下内容(来自 TensorFlow 2 的 Alpha 版本):

2.2.4-tf

Keras 的其他功能包括对多 GPU 数据并行性的内置支持,以及 Keras 模型可以转化为 TensorFlow Estimators 并在 Google Cloud 上的 GPU 集群上进行训练的事实。

Keras 可能是不寻常的,因为它具有作为独立开源项目维护的参考实现,位于 www.keras.io

尽管 TensorFlow 在tf.keras模块中确实具有 Keras 的完整实现,但它独立于 TensorFlow 进行维护。 默认情况下,该实现具有 TensorFlow 特定的增强功能,包括对急切执行的支持。

急切的执行意味着代码的执行是命令式编程环境,而不是基于图的环境,这是在 TensorFlow(v1.5 之前)的初始产品中工作的唯一方法。 这种命令式(即刻)风格允许直观的调试,快速的开发迭代,支持 TensorFlow SavedModel格式,并内置支持对 CPU,GPU 甚至 Google 自己的硬件张量处理单元TPU)进行分布式训练。

TensorFlow 实现还支持tf.data,分发策略,导出模型(可通过 TensorFlow Lite 部署在移动和嵌入式设备上)以及用于表示和分类结构化数据的特征列。

Linux 用户的默认配置文件如下:

$HOME/.keras/keras.json

对于 Windows 用户,将$HOME替换为%USERPROFILE%

它是在您第一次使用 Keras 时创建的,可以进行编辑以更改默认值。 以下是.json文件包含的内容:

{ "image_data_format": "channels_last", "epsilon": 1e-07, "floatx": "float32", "backend": "tensorflow" }

默认值如下:

  • image_data_format:这是图像格式的字符串,"channels_last"channels_first。 在 TensorFlow 之上运行的 Keras 使用默认值。

  • epsilon:这是一个浮点数,是一个模糊常数,用于在某些操作中避免被零除。

  • floatx:这是一个字符串,指定默认的浮点精度,为"float16""float32""float64"之一。

  • backend:这是一个字符串,指定 Keras 在"tensorflow""theano""cntk"中的一种之上发现自己的工具。

对于所有这些值,在keras.backend中有获取器和设置器方法。 参见这里

例如,在以下集合中,供 Keras 使用的浮点类型为floatx,其中floatx参数是以下命令中所示的三种精度之一:

keras.backend.set_floatx(floatx)

由于其模型级别的库结构,Keras 可能具有处理低级操作(例如卷积,张量乘积等)的不同张量操纵引擎。 这些引擎称为后端。 其他后端可用; 我们在这里不考虑它们。

相同的链接可带您使用许多keras.backend函数。

使用 Keras backend的规范方法是:

from keras import backend as K

例如,以下是有用函数的签名:

K.constant(value, dtype=None, shape=None, name=None)

value是要赋予常数的值,dtype是创建的张量的类型,shape是创建的张量的形状,name是可选名称。

实例如下:

from tensorflow.keras import backend as K
const = K.constant([[42,24],[11,99]], dtype=tf.float16, shape=[2,2])
const

这将产生以下恒定张量。 注意,由于启用了急切执行,(默认情况下)在输出中给出常量的值:

<tf.Tensor: id=1, shape=(2, 2), dtype=float16, numpy= array([[42., 24.], [11., 99.]], dtype=float16)>

急切不启用,输出将如下所示:

<tf.Tensor 'Const:0' shape=(2, 2) dtype=float16>

Keras 数据类型dtypes)与 TensorFlow Python 数据类型相同,如下表所示:

Python 类型 描述
tf.float16 16 位浮点
tf.float32 32 位浮点
tf.float64 64 位浮点
tf.int8 8 位有符号整数
tf.int16 16 位有符号整数
tf.int32 32 位有符号整数
tf.int64 64 位有符号整数
tf.uint8 8 位无符号整数
tf.string 可变长度字节数组
tf.bool 布尔型
tf.complex64 由两个 32 位浮点组成的复数-一个实部和虚部
tf.complex128 由两个 64 位浮点组成的复数-一个实部和一个虚部
tf.qint8 量化运算中使用的 8 位有符号整数
tf.qint32 量化运算中使用的 32 位有符号整数
tf.quint8 量化运算中使用的 8 位无符号整数

Keras 基于神经网络模型的概念。 主要模型称为序列,是层的线性栈。 还有一个使用 Keras 函数式 API 的系统。

要构建 Keras Sequential模型,请向其中添加层,其顺序与您希望网络进行计算的顺序相同。

建立模型后,您可以编译; 这样可以优化要进行的计算,并且可以在其中分配优化器和希望模型使用的损失函数。

下一步是使模型拟合数据。 这通常称为训练模型,是所有计算发生的地方。 可以分批或一次将数据呈现给模型。

接下来,您评估模型以建立其准确率,损失和其他指标。 最后,在训练好模型之后,您可以使用它对新数据进行预测。 因此,工作流程是:构建,编译,拟合,评估,做出预测。

有两种创建Sequential模型的方法。 让我们看看它们中的每一个。

首先,可以将层实例列表传递给构造器,如以下示例所示。

在下一章中,我们将对层进行更多的讨论。 目前,我们将仅作足够的解释,以使您了解此处发生的情况。

采集数据。 mnist是手绘数字的数据集,每个数字在28 x 28像素的网格上。 每个单独的数据点都是一个无符号的 8 位整数(uint8),如标签所示:

mnist = tf.keras.datasets.mnist
(train_x,train_y), (test_x, test_y) = mnist.load_data()

epochs变量存储我们将数据呈现给模型的次数:

epochs=10
batch_size = 32 # 32 is default in fit method but specify anyway

接下来,将所有数据点(x)归一化为float32类型的浮点数范围为 0 到 1。 另外,根据需要将标签(y)投射到int64

train_x, test_x = tf.cast(train_x/255.0, tf.float32), tf.cast(test_x/255.0, tf.float32)
train_y, test_y = tf.cast(train_y,tf.int64),tf.cast(test_y,tf.int64) 

模型定义如下。

注意在模型定义中我们如何传递层列表:

  • Flatten接受28 x 28(即 2D)像素图像的输入,并产生 784(即 1D)向量,因为下一个(密集)层是一维的。
  • Dense是一个完全连接的层,意味着其所有神经元都连接到上一层和下一层中的每个神经元。 下面的示例有 512 个神经元,其输入通过 ReLU(非线性)激活函数传递。
  • Dropout随机关闭上一层神经元的一部分(在这种情况下为 0.2)。 这样做是为了防止任何特定的神经元变得过于专业化,并导致模型与数据过拟合,从而影响测试数据上模型的准确率指标(在后面的章节中将对此进行更多介绍)。
  • 最后的Dense层具有一个称为softmax的特殊激活函数,该函数将概率分配给可能的 10 个输出单元中的每一个:
model1 = tf.keras.models.Sequential([
 tf.keras.layers.Flatten(),
 tf.keras.layers.Dense(512,activation=tf.nn.relu),
 tf.keras.layers.Dropout(0.2),
 tf.keras.layers.Dense(10,activation=tf.nn.softmax)
])

model.summary()函数是一种有用的同义词方法,并为我们的模型提供以下输出:

401920的数字来自输入28 x 28 = 784 x 512dense_2层)输出784 * 512 = 401,408以及每个dense_1层神经元的偏置单元 ,则401,408 + 512 = 401,920

5130的数字来自512 * 10 + 10 = 5,130

接下来,我们编译模型,如以下代码所示:

optimiser = tf.keras.optimizers.Adam()
model1.compile (optimizer= optimiser, loss='sparse_categorical_crossentropy', metrics = ['accuracy'])

optimizer是一种方法,通过该方法可以调整模型中加权连接的权重以减少损失。

loss是模型所需输出与实际输出之间差异的度量,而metrics是我们评估模型的方式。

为了训练我们的模型,我们接下来使用fit方法,如下所示:

model1.fit(train_x, train_y, batch_size=batch_size, epochs=epochs)

调用fit()的输出如下,显示了周期训练时间,损失和准确率:

Epoch 1/10 60000/60000 [==============================] - 5s 77us/step - loss: 0.2031 - acc: 0.9394 ...
Epoch 10/10 60000/60000 [==============================] - 4s 62us/step - loss: 0.0098 - acc: 0.9967

最后,我们可以使用evaluate方法检查我们训练有素的模型的准确率:

model1.evaluate(test_x, test_y)

这将产生以下输出:

10000/10000 [==============================] - 0s 39us/step [0.09151900197149189, 0.9801]

这表示测试数据的损失为 0.09,准确率为 0.9801。 精度为 0.98 意味着该模型平均可以识别出 100 个测试数据点中的 98 个。

对于同一体系结构,将层列表传递给Sequential模型的构造器的替代方法是使用add方法,如下所示:

model2 = tf.keras.models.Sequential();
model2.add(tf.keras.layers.Flatten())
model2.add(tf.keras.layers.Dense(512, activation='relu'))
model2.add(tf.keras.layers.Dropout(0.2))
model2.add(tf.keras.layers.Dense(10,activation=tf.nn.softmax))
model2.compile (optimizer= tf.keras.Adam(), loss='sparse_categorical_crossentropy', 
 metrics = ['accuracy'])

如我们所见,fit()方法执行训练,使用模型将输入拟合为输出:

model2.fit(train_x, train_y, batch_size=batch_size, epochs=epochs)

然后,我们使用test数据评估模型的表现:

model2.evaluate(test_x, test_y)

这给我们带来了0.07的损失和0.981的准确率。

因此,这种定义模型的方法产生的结果与第一个结果几乎相同,这是可以预期的,因为它是相同的体系结构,尽管表达方式略有不同,但具有相同的optimizerloss函数。 现在让我们看一下函数式 API。

与以前看到的Sequential模型的简单线性栈相比,函数式 API 使您可以构建更复杂的体系结构。 它还支持更高级的模型。 这些模型包括多输入和多输出模型,具有共享层的模型以及具有剩余连接的模型。

这是函数式 API 的使用的简短示例,其架构与前两个相同。

设置代码与先前演示的相同:

import tensorflow as tf
mnist = tf.keras.datasets.mnist
(train_x,train_y), (test_x, test_y) = mnist.load_data()
train_x, test_x = train_x/255.0, test_x/255.0
epochs=10

这是模型定义。

注意如何在tensor上调用层并返回张量作为输出,然后如何使用这些输入和输出张量来定义模型:

inputs = tf.keras.Input(shape=(28,28)) # Returns a 'placeholder' tensor
x = tf.keras.layers.Flatten()(inputs)
x = tf.layers.Dense(512, activation='relu',name='d1')(x)
x = tf.keras.layers.Dropout(0.2)(x)
predictions = tf.keras.layers.Dense(10,activation=tf.nn.softmax, name='d2')(x)

model3 = tf.keras.Model(inputs=inputs, outputs=predictions)

请注意,此代码如何产生与model1model2相同的体系结构:

None出现在这里是因为我们没有指定我们有多少输入项(即批量大小)。 这确实意味着未提供

其余代码与前面的示例相同:

optimiser = tf.keras.optimizers.Adam()
model3.compile (optimizer= optimiser, loss='sparse_categorical_crossentropy', metrics = ['accuracy'])

model3.fit(train_x, train_y, batch_size=32, epochs=epochs)

model3.evaluate(test_x, test_y)

对于相同的体系结构,这同样会产生0.067的损失和0.982的精度。

接下来,让我们看看如何对 Keras model类进行子类化。

Keras Model类可以被子类化,如下面的代码所示。 Google 指出,函数风格(如前面的示例所示)比子类风格更可取(我们在此包括其内容是出于完整性的考虑,因为它很有趣)。

首先,请注意如何在构造器(.__init__())中分别声明和命名层。

然后,注意在call()方法中各层如何以函数风格链接在一起。 此方法封装了前向传播

class MyModel(tf.keras.Model):
 def __init__(self, num_classes=10):
  super(MyModel, self).__init__()
 # Define your layers here.
   inputs = tf.keras.Input(shape=(28,28)) # Returns a placeholder tensor
   self.x0 = tf.keras.layers.Flatten()
   self.x1 = tf.keras.layers.Dense(512, activation='relu',name='d1')
   self.x2 = tf.keras.layers.Dropout(0.2)
   self.predictions = tf.keras.layers.Dense(10,activation=tf.nn.softmax, name='d2')

 def call(self, inputs):
 # This is where to define your forward pass
 # using the layers previously defined in `__init__`
   x = self.x0(inputs)
   x = self.x1(x)
   x = self.x2(x) 
   return self.predictions(x)

model4 = MyModel()

该定义可以代替本章中的任何较早的模型定义使用,它们具有相同的数据下载支持代码,以及相似的用于训练/评估的代码。 下面的代码显示了最后一个示例:

model4 = MyModel()
batch_size = 32
steps_per_epoch = len(train_x.numpy())//batch_size
print(steps_per_epoch)

model4.compile (optimizer= tf.keras.Adam(), loss='sparse_categorical_crossentropy', 
 metrics = ['accuracy'])

model4.fit(train_x, train_y, batch_size=batch_size, epochs=epochs)

 model4.evaluate(test_x, test_y)

结果是0.068的损失,准确率为0.982; 再次与本章中其他三种模型构建风格产生的结果几乎相同。

也可以使用以下代码将数据作为tf.data.Dataset()迭代器传递到fit方法中(数据获取代码与先前描述的相同)。 from_tensor_slices()方法将 NumPy 数组转换为数据集。 注意batch()shuffle()方法链接在一起。 接下来,map()方法在输入图像x上调用一种方法,该方法在y轴上随机翻转其中的两个,有效地增加了图像集的大小。 标签y在这里保持不变。 最后,repeat()方法意味着在到达数据集的末尾(连续)时,将从头开始重新填充该数据集:

batch_size = 32
buffer_size = 10000

train_dataset = tf.data.Dataset.from_tensor_slices((train_x, train_y)).batch(32).shuffle(10000)

train_dataset = train_dataset.map(lambda x, y: (tf.image.random_flip_left_right(x), y))
train_dataset = train_dataset.repeat()

test设置的代码类似,除了不进行翻转:

test_dataset = tf.data.Dataset.from_tensor_slices((test_x, test_y)).batch(batch_size).shuffle(10000)

test_dataset = train_dataset.repeat()

现在,在fit()函数中,我们可以直接传递数据集,如下所示:

steps_per_epoch = len(train_x)//batch_size # required because of the repeat on the dataset
optimiser = tf.keras.optimizers.Adam()
model5.compile (optimizer= optimiser, loss='sparse_categorical_crossentropy', metrics = ['accuracy'])
model.fit(train_dataset, batch_size=batch_size, epochs=epochs, steps_per_epoch=steps_per_epoch)

编译和评估代码与之前看到的类似。

使用data.Dataset迭代器的优点在于,管道可以处理通常用于准备数据的大部分管道,例如批量和改组。 我们也已经看到,各种操作可以链接在一起。

TensorFlow 中的 Keras API 具有轻松保存和恢复模型的能力。 这样做如下,并将模型保存在当前目录中。 当然,这里可以通过更长的路径:

model.save('./model_name.h5')

这将保存模型体系结构,权重,训练状态(lossoptimizer)和优化器的状态,以便您可以从上次中断的地方继续训练模型。

加载保存的模型的步骤如下。 请注意,如果您已经编译了模型,那么负载将使用保存的训练配置来编译模型:

from tensorflow.keras.models import load_model
new_model = load_model('./model_name.h5')

也可以仅保存模型权重并以此加载它们(在这种情况下,必须构建体系结构以将权重加载到其中):

model.save_weights('./model_weights.h5')

然后使用以下内容加载它:

model.load_weights('./model_weights.h5')

可从 Keras 中获得以下数据集:boston_housingcifar10cifar100fashion_mnistimdbmnistreuters

它们都可以通过load_data()函数访问。 例如,要加载fashion_mnist数据集,请使用以下命令:

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()

可以在这个页面中找到更多详细信息。

在本章中,我们使用通用注释和见解探索了 Keras API,然后以四种不同的方式表示相同的基本体系结构,以训练mnist数据集。

在下一章中,我们将通过探索许多监督的学习场景,包括线性回归,逻辑回归和 K 近邻,开始认真使用 TensorFlow。

教程来源于Github,感谢apachecn大佬的无私奉献,致敬!

技术教程推荐

如何设计一个秒杀系统 -〔许令波〕

分布式协议与算法实战 -〔韩健〕

Selenium自动化测试实战 -〔郭宏志〕

技术面试官识人手册 -〔熊燚(四火)〕

React Hooks 核心原理与实战 -〔王沛〕

Go进阶 · 分布式爬虫实战 -〔郑建勋〕

零基础学Python(2023版) -〔尹会生〕

B端体验设计入门课 -〔林远宏(汤圆)〕

结构思考力 · 透过结构看思考 -〔李忠秋〕