Tensorflow和Keras原本是两个深度学习的框架。Keras有着更高级的API,构建模型要比Tensorflow简单许多;Keras有许多后端(backend)可以选,Tensorflow就是其中一种后端。
2017年01月17日,Keras的作者、谷歌AI研究员Francois Chollet宣布了一条激动人心的消息:Keras将会成为第一个被添加到TensorFlow核心中的高级别框架,这将会让Keras变成Tensorflow的默认API。也就是说Tensorflow内置Keras了。
最新版Tensorflow已经内置了Keras模块(最新的Tensorflow版本是1.11.0),其对应的Keras的版本为2.1.6-tf,只要安装了Tensorflow 1.11.0及以上版本,就已经能使用Tensorflow内置的Keras了。
此部分文档是官分文档的翻译,根据自己的理解进行了翻译,帮助大家入门。原文链接Tensorflow Keras
tf.keras是Keras API的Tensorflow实现,是一个用于构建和训练模型的高级API,其中包括对TensorFlow特定功能的一流支持,例如Eager Execution,tf.data Pipeline和Estimators。 tf.keras使TensorFlow更易于使用,而不会牺牲灵活性和性能。
导入tf.keras的代码为:
import tensorflow as tf
from tensorflow.keras import layers
# 打印Tensorflow和内置的Keras版本
print(tf.VERSION)
print(tf.keras.__version__)
tf.keras可以运行任何与Keras兼容的代码,但请记住:
在Keras中,您可以组装层(Layer)来构建模型(Model)。 最常见的模型类型是层的堆叠:tf.keras.Sequential模型。
构建一个简单的,完全连接的网络(即多层感知器):
model = tf.keras.Sequential()
# 添加一个有64个单元全连接层到模型
# 顺便说一句,densely-connected layer=fully-connected layer
model.add(layers.Dense(64, activation='relu'))
# 再添加一个
model.add(layers.Dense(64, activation='relu'))
# 添加一个有10个输出单元的softmax层
model.add(layers.Dense(10, activation='softmax'))
tf.keras.layers一些常见的构造函数参数:
下面使用构造函数参数实例化tf.keras.layers.Dense的一些例子:
# 创建一个sigmoid层:
layers.Dense(64, activation='sigmoid')
# 另外一种方法
layers.Dense(64, activation=tf.sigmoid)
# 定义一个线性层(linear layer),核矩阵(kernel matrix)使用一个因子为0.01的L1正则化器
layers.Dense(64, kernel_regularizer=tf.keras.regularizers.l1(0.01))
# 定义一个线性层,偏置向量( bias vector)使用一个因子为0.01的L2正则化器
layers.Dense(64, bias_regularizer=tf.keras.regularizers.l2(0.01))
# 定义了一个线性层,核使用的初始化器为orthogonal(核会被初始化为一个随机正交矩阵)
layers.Dense(64, kernel_initializer='orthogonal')
# 定义了一个线性层,偏置向量的初始化去器为constant(偏置向量的所有元素都会被初始化为2.0)
layers.Dense(64, bias_initializer=tf.keras.initializers.constant(2.0))
构建模型后,通过调用compile函数编译(原文为configure,我这里翻译为编译):
model = tf.keras.Sequential([
# 添加一个有64个单元的全连接层,激活函数为relu
layers.Dense(64, activation='relu'),
# 再添加一个
layers.Dense(64, activation='relu'),
# 添加一个有10个输出单元的softmax层
layers.Dense(10, activation='softmax')])
model.compile(optimizer=tf.train.AdamOptimizer(0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
tf.keras.Model.compile有三个重要参数(建议参考下Keras compile document):
以下显示了编译模型的几个示例:
# 编译均方误差回归模型(a model for mean-squared error regression)
model.compile(optimizer=tf.train.AdamOptimizer(0.01),
loss='mse', # 最小均方误差(mean squared error)
metrics=['mae']) # 平均绝对误差(mean absolute error)
# 编译一个分类模型(a model for categorical classification)
# 多元分类问题例子,比如手写数字识别
model.compile(optimizer=tf.train.RMSPropOptimizer(0.01),
loss=tf.keras.losses.categorical_crossentropy,
metrics=[tf.keras.metrics.categorical_accuracy])
# 和上面的相同
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
# 二元分类例子
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])
可以注意到,上面的程序中第一个的loss和metrics传的是字符串,第二种传的是可调用的对象。
对于小型数据集,请使用内存中的NumPy数组来训练和评估模型。 使用fit方法将模型“拟合”到训练数据:
import numpy as np
data = np.random.random((1000, 32))
labels = np.random.random((1000, 10))
model.fit(data, labels, epochs=10, batch_size=32)
tf.keras.Model.fit有三个重要参数:
这是使用validation_data的示例:
import numpy as np
data = np.random.random((1000, 32))
labels = np.random.random((1000, 10))
val_data = np.random.random((100, 32))
val_labels = np.random.random((100, 10))
model.fit(data, labels, epochs=10, batch_size=32,
validation_data=(val_data, val_labels))
若要使用大型数据集或多设备训练,要使用Dateset API ,将tf.data.Dataset实例传递给fit方法:
# 实例化玩具数据集实例:
dataset = tf.data.Dataset.from_tensor_slices((data, labels))
dataset = dataset.batch(32)
dataset = dataset.repeat()
# 在数据集上调用`fit`时,不要忘记指定`steps_per_epoch`
model.fit(dataset, epochs=10, steps_per_epoch=30)
这里,fit方法函数steps_per_epoch参数 - 这是模型在训练集上训练一遍(也就是一个epoch)的训练步数。 由于Dataset生成批次数据,因此此代码段不需要batch_size。
如果要传入验证集:
dataset = tf.data.Dataset.from_tensor_slices((data, labels))
dataset = dataset.batch(32).repeat()
val_dataset = tf.data.Dataset.from_tensor_slices((val_data, val_labels))
val_dataset = val_dataset.batch(32).repeat()
model.fit(dataset, epochs=10, steps_per_epoch=30,
validation_data=val_dataset,
validation_steps=3)
tf.keras.Model.evaluate和tf.keras.Model.predict函数可以使用NumPy数组和tf.data.Dataset作为参数。
如果要评估(evaluate)所提供数据的模型的损失和指标(也就是深度学习中评估测试集的损失loss和前面compile函数中metrics指定的指标),代码如下:
data = np.random.random((1000, 32))
labels = np.random.random((1000, 10))
model.evaluate(data, labels, batch_size=32)
model.evaluate(dataset, steps=30)
NumPy数组作为参数,输出模型最后一层的输出(也就是预测一个样本):
result = model.predict(data, batch_size=32)
print(result.shape)
tf.keras.Sequential模型是一个简单的层的堆叠,不能构建任意模型。 使用Keras函数式API构建复杂的模型,例如:
使用函数式API构建模型的方法如下:
以下示例使用函数式API构建一个简单,全连接(fully-connected)的网络:
inputs = tf.keras.Input(shape=(32,)) # Returns a placeholder tensor
# 层的实例可调用,参数为tensor,返回一个tensor
x = layers.Dense(64, activation='relu')(inputs)
x = layers.Dense(64, activation='relu')(x)
predictions = layers.Dense(10, activation='softmax')(x)
实例化指定输入和输出的模型
model = tf.keras.Model(inputs=inputs, outputs=predictions)
# 编译这个步骤指定了训练的配置(the training configuration)
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
# 训练5个epoch
model.fit(data, labels, batch_size=32, epochs=5)
通过继承tf.keras.Model并定义自己的前向传播来构建完全可自定义的模型。 在__init__
函数中创建图层并将它们设置为类实例的属性。 在call函数中定义前向传播。
当启用Eager Execution时,模型子类化特别有用(原文说很有用,但我还不知道)。
以下示例显示了继承tf.keras.Model,使用自定义前向传播:
class MyModel(tf.keras.Model):
def __init__(self, num_classes=10):
super(MyModel, self).__init__(name='my_model')
self.num_classes = num_classes
# 在__init__函数中定义层
self.dense_1 = layers.Dense(32, activation='relu')
self.dense_2 = layers.Dense(num_classes, activation='sigmoid')
def call(self, inputs):
# 在call函数中定义前向传播
# 使用在__init__中定义的层
x = self.dense_1(inputs)
return self.dense_2(x)
def compute_output_shape(self, input_shape):
# 如果你需要把这个子类化的模型当作一个函数式模型的一部分,那么你需要重载这个函数。
# 否则,这个函数是可选的
shape = tf.TensorShape(input_shape).as_list()
shape[-1] = self.num_classes
return tf.TensorShape(shape)
实例化上述模型的代码为:
model = MyModel(num_classes=10)
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(data, labels, batch_size=32, epochs=5)
要自定义层,需要继承 tf.keras.layers.Layer并且实现如下几个函数:
下面是自定义层的示例,它实现了一个使输入(Input)和核(Kernel)矩阵相乘(matmul):
class MyLayer(layers.Layer):
def __init__(self, output_dim, **kwargs):
self.output_dim = output_dim
super(MyLayer, self).__init__(**kwargs)
def build(self, input_shape):
shape = tf.TensorShape((input_shape[1], self.output_dim))
# 为此层创建一个可训练的权重
self.kernel = self.add_weight(name='kernel',
shape=shape,
initializer='uniform',
trainable=True)
# 确保在函数结束时调用下面的语句
super(MyLayer, self).build(input_shape)
def call(self, inputs):
# 这里定义了这层要实现的操作,也就是前向传播的操作
return tf.matmul(inputs, self.kernel)
def compute_output_shape(self, input_shape):
# 计算输出tensor的shape
shape = tf.TensorShape(input_shape).as_list()
shape[-1] = self.output_dim
return tf.TensorShape(shape)
def get_config(self):
base_config = super(MyLayer, self).get_config()
base_config['output_dim'] = self.output_dim
return base_config
@classmethod
def from_config(cls, config):
return cls(**config)
使用自定义层:
model = tf.keras.Sequential([
MyLayer(10),
layers.Activation('softmax')])
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(data, labels, batch_size=32, epochs=5)
回调是传递给模型的对象,用于在训练模型期间自定义和扩展其行为。 可以编写自己的自定义回调,或使用以下内置的tf.keras.callbacks:
若要使用tf.keras.callbacks.Callback,请将其传递给模型的fit方法:
callbacks = [
# 如果`val_loss`在超过两个epoch都没有提升,那么中断训练
tf.keras.callbacks.EarlyStopping(patience=2, monitor='val_loss'),
# 把TensorBoard的日志写入文件夹`./logs`
tf.keras.callbacks.TensorBoard(log_dir='./logs')
]
model.fit(data, labels, batch_size=32, epochs=5, callbacks=callbacks,
validation_data=(val_data, val_labels))
参考tf.keras.Model.save_weights
# 把权重保存为TensorFlow Checkpoint文件
model.save_weights('./weights/my_model')
# 载入权重。要求模型和保存权重的模型具有相同的架构
model.load_weights('./weights/my_model')
如果要把权重保存为Keras的HDF5格式,可使用如下代码
# 把权重保存为HDF5这种格式的文件
model.save_weights('my_model.h5', save_format='h5')
# 载入权重
model.load_weights('my_model.h5')
模型的配置(原文为model’s configuration,可以理解为模型的结构)是可以保存的。 这可以在没有任何权重的情况下序列化模型体系结构。 即使没有定义原始模型的代码,保存的配置也可以重新创建和初始化相同的模型。 Keras支持JSON和YAML序列化格式:
把模型序列化为json字符串
json_string = model.to_json()
print(json_string)
从json字符串恢复模型:
fresh_model = tf.keras.models.model_from_json(json_string)
把模型序列化为YAML格式:
yaml_string = model.to_yaml()
print(yaml_string)
从YAML字符串恢复模型:
fresh_model = tf.keras.models.model_from_yaml(yaml_string)
如果保存模型结构与权重(甚至还包括优化器的配置),下次可以恢复模型结构和权重接着训练且不需要访问原始代码。
# 创建一个简单的模型
model = tf.keras.Sequential([
layers.Dense(10, activation='softmax', input_shape=(32,)),
layers.Dense(10, activation='softmax')
])
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(data, labels, batch_size=32, epochs=5)
# 将整个模型保存到HDF5文件
model.save('my_model.h5')
# 重新创建完全相同的模型,包括权重和优化器。
model = tf.keras.models.load_model('my_model.h5')
Eager execution是一个必要的编程环境,可以立即评估操作。 这对于Keras不是必需的,但是由tf.keras支持,对于检查程序和调试很有用。
所有tf.keras API都与Eager execution兼容。 虽然可以使用顺序模型和函数式API,但是Eager execution尤其有利于模型子类化和构建自定义层 。
有关使用具有自定义训练和tf.GradientTape的Keras模型的示例,请参阅Eager execution 指南。
Estimators API用于分布式环境的训练模型的API。 可以导出模型进行大型数据集的分布式训练,并得到可以商用的模型。
使用tf.keras.estimator.model_to_estimator将模型转换为tf.estimator.Estimator对象,就可以使用tf.estimator API训练tf.keras.Model。 请参阅Creating Estimators from Keras models。
model = tf.keras.Sequential([layers.Dense(10,activation='softmax'),
layers.Dense(10,activation='softmax')])
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
# 把模型转换为Estimator
estimator = tf.keras.estimator.model_to_estimator(model)
tf.keras模型可以使用tf.contrib.distribute.DistributionStrategy在多个GPU上训练。 此API在多个GPU上提供分布式训练,几乎不对现有代码进行任何更改。
目前,tf.contrib.distribute.MirroredStrategy是唯一受支持的分布式策略。 要将DistributionStrategy与Keras一起使用,请使用tf.keras.estimator.model_to_estimator将tf.keras.Model转换为tf.estimator.Estimator,然后训练Estimator。
以下示例在单个计算机上的多个GPU之间分布式训练tf.keras.Model。
首先,定义一个简单的模型:
model = tf.keras.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10,)))
model.add(layers.Dense(1, activation='sigmoid'))
optimizer = tf.train.GradientDescentOptimizer(0.2)
model.compile(loss='binary_crossentropy', optimizer=optimizer)
model.summary()
定义输入管线(Input Pipeline)。input_fn返回一个tf.data.Dataset对象,用于在多个设备之间分配数据 - 每个设备处理输入数据(Input batch)的一部分。
def input_fn():
x = np.random.random((1024, 10))
y = np.random.randint(2, size=(1024, 1))
x = tf.cast(x, tf.float32)
dataset = tf.data.Dataset.from_tensor_slices((x, y))
dataset = dataset.repeat(10)
dataset = dataset.batch(32)
return dataset
接下来,创建一个tf.estimator.RunConfig并将train_distribute参数设置为tf.contrib.distribute.MirroredStrategy。 创建MirroredStrategy时,可以指定设备列表或设置num_gpus参数。 默认使用所有可用的GPU,如下所示:
strategy = tf.contrib.distribute.MirroredStrategy()
config = tf.estimator.RunConfig(train_distribute=strategy)
将Keras模型转换为tf.estimator.Estimator实例:
keras_estimator = tf.keras.estimator.model_to_estimator(
keras_model=model,
config=config,
model_dir='/tmp/model_dir')
最后,通过提供input_fn和steps参数来训练Estimator实例:
keras_estimator.train(input_fn=input_fn, steps=10)