1 Keras简介
Keras 是一个用 Python 编写的深度学习 API,能够在 JAX、TensorFlow 或 PyTorch 之上运行。
Keras 具备以下特点:
- 简单 – 但并不简化问题。Keras 减轻了开发者的认知负担,让你能够专注于真正重要的问题部分。
- 灵活 – Keras 采用了渐进式复杂性披露的原则:简单的工作流程应该快速且容易执行,而任意复杂的工作流程应该通过一个清晰的路径成为可能,这个路径建立在你已经学到的知识之上。
- 强大 – Keras 提供了业界级别的性能和可扩展性:它被包括 NASA、YouTube 或 Waymo 在内的组织使用。
1.1 Keras 是一个多框架深度学习 API
作为多框架 API,Keras 可以用来开发与任何框架兼容的模块化组件——JAX、TensorFlow 或 PyTorch。
这种方法有几个关键优势:
-
始终获得最佳性能:在我们的基准测试中,我们发现 JAX 通常在 GPU、TPU 和 CPU 上提供最佳的训练和推理性能——但结果因模型而异,因为非 XLA 的 TensorFlow 偶尔在 GPU 上更快。能够动态选择为你的模型提供最佳性能的后端,而无需更改任何代码,意味着你总是能保证以最高可实现的效率进行训练和服务。
-
最大化模型的生态系统覆盖:任何 Keras 模型都可以被实例化为 PyTorch 模块,可以导出为 TensorFlow SavedModel,或者可以被实例化为无状态的 JAX 函数。这意味着你可以使用 Keras 模型与 PyTorch 生态系统包,使用 TensorFlow 的全套部署和生产工具,以及 JAX 大规模 TPU 训练基础设施。使用 Keras API 编写一个 model.py,就可以访问机器学习世界提供的一切。
-
最大化开源模型发布的分发:想要发布一个预训练模型?想要尽可能多的人能够使用它?如果你用纯 TensorFlow 或 PyTorch 实现它,它将只能被大约一半的市场使用。如果你用 Keras 实现它,它将立即被任何人使用,无论他们选择的框架是什么(即使他们不是 Keras 用户)。在不增加开发成本的情况下,影响力翻倍。
-
使用任何来源的数据管道:Keras 的 fit()/evaluate()/predict() 程序与 tf.data.Dataset 对象、PyTorch DataLoader 对象、NumPy 数组、Pandas 数据框兼容——无论你使用的是哪个后端。你可以在一个 PyTorch DataLoader 上训练 Keras + TensorFlow 模型,或者在一个 tf.data.Dataset 上训练 Keras + PyTorch 模型。
1.2 使用Keras的方法
Keras 的核心数据结构是层(layers)和模型(models)。最简单的模型类型是顺序模型(Sequential model),它是一层接一层的线性堆叠。对于更复杂的架构,你应该使用 Keras 函数式 API,它允许构建任意层的图,或者通过子类化(subclassing)从头开始编写模型。
以下是顺序模型的示例:
import keras
model = keras.Sequential()
在 Keras 中,堆叠层(layers)构建神经网络模型是非常直观的,只需要使用.add方法就能够实现
from keras import layers
model.add(layers.Dense(units=64, activation='relu'))
model.add(layers.Dense(units=10, activation='softmax'))
from keras.models import Sequential
# 初始化顺序模型
model = Sequential()
# 添加第一层,具有 128 个神经元和 'relu' 激活函数
model.add(Dense(128, activation='relu', input_shape=(100,)))
# 添加第二层,具有 64 个神经元和 'relu' 激活函数
model.add(Dense(64, activation='relu'))
# 添加输出层,具有 10 个神经元和 'softmax' 激活函数
model.add(Dense(10, activation='softmax'))
一旦你的模型结构(即层的堆叠)看起来符合你的需求,下一步就是配置模型的学习过程,这通常是通过调用.compile方法来完成的。
# 假设 model 已经是之前定义好的模型
# 配置模型的学习过程
model.compile(optimizer='adam', # 指定优化器
loss='categorical_crossentropy', # 指定损失函数
metrics=['accuracy']) # 指定评估指标
Keras 的设计哲学就是保持简单事情的简单性,同时在用户需要时提供充分的控制权。当涉及到更复杂的配置或定制时,Keras 允许用户通过子类化来扩展源代码,从而实现最终的控制权。
对于优化器(optimizer),Keras 提供了多种预定义的优化算法,如 Adam、SGD(随机梯度下降)、RMSprop 等。但在某些情况下,用户可能需要对这些优化器进行更深入的配置。为此,Keras 允许用户直接访问并配置优化器的参数。
from keras.optimizers import Adam
# 创建一个自定义配置的 Adam 优化器实例
optimizer = Adam(lr=0.001, beta_1=0.9)
# 使用该优化器来编译模型
model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])
一旦你配置了模型的学习过程(通过调用compile()方法),你就可以开始迭代训练数据了,通常是按批次(batches)进行的。在 Keras 中,这是通过调用fit()方法并指定 batch_size参数来实现的。
batch_size参数定义了模型在更新权重之前应查看的样本数。较小的批次大小意味着更新会更频繁,但每次更新时只考虑一小部分数据。较大的批次大小则相反,每次更新会考虑更多的数据,但更新频率会降低。
# 假设 X_train 和 y_train 分别是训练数据和标签
# model 是之前定义并编译好的模型
# 使用 fit 方法训练模型,迭代训练数据,每批次包含 32 个样本
model.fit(X_train, y_train, epochs=10, batch_size=32)
在 Keras 中,你可以使用 evaluate()方法来评估模型在测试集上的性能。这个方法会返回模型在测试集上的损失值和所有指定的评估指标。下面是一个使用 evaluate()方法来评估模型在测试集上的性能的例子:
# 假设 X_test 和 y_test 分别是测试数据和标签
# model 是之前定义并编译好的模型
# 评估模型在测试集上的性能
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=1)
# 打印测试结果
print(f'Test loss: {test_loss}')
print(f'Test accuracy: {test_acc}')
一旦你的模型已经训练好了,你可以使用 predict()方法来生成新数据的预测结果。这个方法会接受一批输入数据,并返回模型对这些数据的预测值。
# 假设 X_new 是你想要预测的新数据
# model 是之前定义并训练好的模型
# 使用模型生成预测结果
classes = model.predict(x_test, batch_size=128)
# 打印预测结果
print(predictions)
Keras 是最基础但同时也是高度灵活的深度学习框架,它非常适合实现最先进的研究想法。Keras 遵循渐进式复杂性披露的原则:它使得初学者容易上手,同时又能处理任意复杂的高级用例,只需要在每个步骤中进行渐进式学习。
就像你能在几行代码中训练和评估一个简单的神经网络一样,你也可以使用 Keras 快速开发新的训练程序或最先进的模型架构。
import keras
from keras import ops
class TokenAndPositionEmbedding(keras.Layer):
def __init__(self, max_length, vocab_size, embed_dim):
super().__init__()
self.token_embed = self.add_weight(
shape=(vocab_size, embed_dim),
initializer="random_uniform",
trainable=True,
)
self.position_embed = self.add_weight(
shape=(max_length, embed_dim),
initializer="random_uniform",
trainable=True,
)
def call(self, token_ids):
# Embed positions
length = token_ids.shape[-1]
positions = ops.arange(0, length, dtype="int32")
positions_vectors = ops.take(self.position_embed, positions, axis=0)
# Embed tokens
token_ids = ops.cast(token_ids, dtype="int32")
token_vectors = ops.take(self.token_embed, token_ids, axis=0)
# Sum both
embed = token_vectors + positions_vectors
# Normalize embeddings
power_sum = ops.sum(ops.square(embed), axis=-1, keepdims=True)
return embed / ops.sqrt(ops.maximum(power_sum, 1e-7))