《python深度学习》读书笔记(5) - 深入Keras

构建Keras模型的不同方法

序贯模型

最简单常用的模型 ,本质上是个列表

两种方法来构建模型

但是要注意,此时模型还没有权重, 必须调用build 并给定输入形状时 模型才具有权重

直接调用weights 会报错

summary函数可以显示模型的内容,这对调试很有用

还可以指定每层layer的名称

这个None,3 大家理解成 是一个 任意样本数量,每个样本有3个特征 即可

提前声明模型的输入形状时,可以在没有build的情况下 直接观察模型

函数式api

序贯模型 只能表示 具有单一输入和单一输出的模型。按顺序逐层处理,但大部分时候,我们会碰到 多输入模型和多输出模型(预测数据的不同方面)。 或具有非线上拓扑结构的模型。

可以把前面的例子 用函数式 来实现一遍 可以体会胰腺癌

假设我们有如下需求

构建一个ai系统,按优先级对客户支持工单进行排序,并将工单转给相应的部门。 这个模型 有3个输入:

  1. 工单标题(文本输入)
  2. 工单的文本正文(文本输入)
  3. 用户添加的标签(分类输入,假定为 one-shot编码)

可以将 文本输入编码 为由1和0组成的数组,数组大小为voc_size,

模型有2个输出;

工单的优先级分数,sigmoid输出 应处理工单的部门,对所有部门做softmax

python 复制代码
voc_size = 10000
num_tags = 100
num_depart = 4
# 定义模型的输入
title = keras.Input(shape=(voc_size,), name="title")
text_body = keras.Input(shape=(voc_size,), name="text_body")
tags = keras.Input(shape=(num_tags,), name="tags")
# 通过拼接将输入特征组合成张量features
features = layers.Concatenate()([title, text_body, tags])
features = layers.Dense(64, activation="relu")(features)
# 定义模型的输出
priority = layers.Dense(1, activation="sigmoid", name="priority")(features)
department = layers.Dense(num_depart,activation='softmax',name="department")(features)
# 利用中间层 将输入特征 重组为更丰富的表示
model = keras.Model(inputs=[title,text_body,tags],outputs=[priority,department])
model.summary()

用随机数据来训练这个模型:

python 复制代码
import numpy as np
num_samples = 1280
title_data = np.random.randint(0, 2, size=(num_samples, voc_size))
text_body_data = np.random.randint(0, 2, size=(num_samples, voc_size))
tags_data = np.random.randint(0, 2, size=(num_samples, num_tags))
priority_data = np.random.random(size=(num_samples, 1))
department_data = np.random.randint(0, 2, size=(num_samples, num_depart))
model.compile(optimizer="rmsprop", loss=["mean_squared_error", "categorical_crossentropy"],
              metrics=[["mean_absolute_error"], ["accuracy"]])
model.fit([title_data, text_body_data, tags_data], [priority_data, department_data], epochs=1)
model.evaluate([title_data, text_body_data, tags_data], [priority_data, department_data])
priority_preds, department_preds = model.predict([title_data, text_body_data, tags_data])

用字典的方式来训练模型的写法 更加易读

python 复制代码
import numpy as np
num_samples = 1280
title_data = np.random.randint(0, 2, size=(num_samples, voc_size))
text_body_data = np.random.randint(0, 2, size=(num_samples, voc_size))
tags_data = np.random.randint(0, 2, size=(num_samples, num_tags))
priority_data = np.random.random(size=(num_samples, 1))
department_data = np.random.randint(0, 2, size=(num_samples, num_depart))
model.compile(optimizer="rmsprop", loss={"priority": "mean_squared_error", "department": "categorical_crossentropy"},
              metrics={"priority": ["mean_squared_error"], "department": ["accuracy"]})
model.fit([title_data, text_body_data, tags_data], [priority_data, department_data], epochs=1)
model.fit({"title": title_data, "text_body": text_body_data, "tags": tags_data},
          {"priority": priority_data, "department": department_data}, epochs=1)
model.evaluate([title_data, text_body_data, tags_data], [priority_data, department_data])
priority_preds, department_preds = model.predict({"title": title_data, "text_body": text_body_data, "tags": tags_data})

我们还可以获取层的连接方式 并把他用图的形式展示出来

python 复制代码
priority_preds, department_preds = model.predict(
    {"title": title_data, "text_body": text_body_data, "tags": tags_data})
keras.utils.plot_model(model, "tickets.png", show_shapes=True)

可以看出来这个是None,也就是说 这个模型接受任意大小的批量

模型子类化

这个比较复杂,而且本书中也强调了 后面的例子都是函数式api,所以模型子类化的写法 这里就跳过了,有需要的自行百度关键字查询写法即可

回顾一下 模型的标准写法

python 复制代码
import keras
from tensorflow.keras.datasets import mnist
from tensorflow.keras import layers


def get_mnist_model():
    inputs = keras.Input(shape=(28 * 28,))
    features = layers.Dense(512, activation='relu')(inputs)
    features = layers.Dropout(0.5)(features)
    outputs = layers.Dense(10, activation='softmax')(features)
    model = keras.Model(inputs=inputs, outputs=outputs)
    return model


if __name__ == '__main__':
    (images, labels), (test_images, test_labels) = mnist.load_data()
    images = images.reshape((60000, 28 * 28)).astype('float32') / 255
    test_images = test_images.reshape((10000, 28 * 28)).astype('float32') / 255
    # 区分下训练集和验证集
    train_images, val_images = images[10000:], images[:10000]
    train_labels, val_labels = labels[10000:], labels[:10000]
    model = get_mnist_model()
    # 编译模型
    model.compile(optimizer='rmsprop', loss="sparse_categorical_crossentropy", metrics=["accuracy"])
    # fit训练模型,提供验证数据 来监控模型在 没有见过的数据中的性能 也就是泛化的性能
    model.fit(train_images, train_labels, epochs=3, validation_data=(val_images, val_labels))
    test_metrics = model.evaluate(test_images, test_labels)
    predictions = model.predict(test_images)
    

编写自定义指标

python 复制代码
class RootMeanSquaredError(keras.metrics.Metric):
    # 在构造函数中定义状态变量
    def __init__(self, name="rmse", **kwargs):
        super().__init__(name=name, **kwargs)
        self.mse_sum = self.add_weight(name="mse_sum", initializer="zeros")
        self.total_samples = self.add_weight(name="total_samples", initializer="zeros", dtype="int32")

    # 在update_state方法中 实现状态更新逻辑
    # 为了匹配mnist模型吗,需要分类预测值和整数标签
    # y_true 一个数据批量对应的标签, y_pred 对应的模型预测值,最后一个参数可以忽略
    def update_state(self, y_true, y_pred, sample_weight=None):
        y_true = tf.one_hot(y_true, depth=tf.shape(y_pred)[1])
        mse = tf.reduce_sum(tf.square(y_true - y_pred))
        self.mse_sum.assign_add(mse)
        num_samples = tf.shape(y_pred)[0]
        self.total_samples.assign_add(num_samples)

    # 返回指标的当前值
    def result(self):
        return tf.sqrt(self.mse_sum / tf.cast(self.total_samples,tf.float32))

    # 重置指标状态,而不需要重新实例化,
    # 这样相同的指标对象 可以在不同的训练轮次中使用
    def reset_states(self):
        self.mse_sum.assign(0.)
        self.total_samples.assign_add(0)
python 复制代码
# 编译模型
model.compile(optimizer='rmsprop', loss="sparse_categorical_crossentropy", metrics=["accuracy",RootMeanSquaredError()])

看下执行结果

回调函数

模型在开始训练 就是调用fit函数以后,一旦开始无法结束,我们可以在这个fit的过程中 利用一些回调函数 来做一些事情,这在某些场景下会非常好用

有很多回调函数可以利用,这里介绍其中集中常用的

EarlyStopping

此回调函数用于 发现验证损失不再改善时,停止训练。

python 复制代码
callback_list = [
    # 如果精度在两轮内都不再改善,则终端训练
    keras.callbacks.EarlyStopping(
        monitor='val_accuracy', patience=2,
    ),
    # 在每轮过后保存当前权重
    # 参数的含义是 只有当val_loss改善时,才会覆盖模型文件,这样就可以一直保存训练过程中的最佳模型
    keras.callbacks.ModelCheckpoint(filepath="checkpoint_path.keras", monitor="val_loss", save_best_only=True, )]
model = get_mnist_model()

# 编译模型
model.compile(optimizer='rmsprop', loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])
# fit训练模型,提供验证数据 来监控模型在 没有见过的数据中的性能 也就是泛化的性能
model.fit(train_images, train_labels, epochs=10, validation_data=(val_images, val_labels), callbacks=callback_list)
test_metrics = model.evaluate(test_images, test_labels)
predictions = model.predict(test_images)

编写自定义回调函数

python 复制代码
# 自定义回调函数
# 参数logs 代表 前一个批量,前一个轮次,或者前一次训练的信息
# 这个回调函数 训练过程中 保存每个批量损失值组成的列表,还在每轮结束时保存这些损失值组成的图
class LossHistory(keras.callbacks.Callback):
    # 在训练开始时被调用
    def on_train_begin(self, logs):
        self.per_batch_losses = []
    # 在处理每个批量之后被调用
    def on_batch_end(self, batch, logs):
        self.per_batch_losses.append(logs.get("loss"))
    # 在每轮结束时被调用
    def on_epoch_end(self, epoch, logs):
        plt.clf()
        plt.plot(range(len(self.per_batch_losses)), self.per_batch_losses, label="Training loss for each batch")
        plt.xlabel(f"Batch (epoch={epoch})")
        plt.ylabel("Loss")
        plt.legend()
        plt.savefig(f"plot_at_epoch_{epoch}")
        self.per_batch_losses = []

TensorBoard

官方提供的监控模型的最佳方式

python 复制代码
tensorboard = keras.callbacks.TensorBoard(
    log_dir="./logs",
)
# fit训练模型,提供验证数据 来监控模型在 没有见过的数据中的性能 也就是泛化的性能
model.fit(train_images, train_labels, epochs=10, validation_data=(val_images, val_labels), callbacks=[tensorboard])

然后输入命令:

tensorboard --logdir logs

然后点击这个网址即可

总结

构建模型有 序贯模型,函数式api 以及模型子类化。 多数情况下 我们使用前2者 要训练和评估模型 最简单的方式时fit和evaluate 除了fit,还可以完全从头开始编写自定义的训练循环,不过这是对研究全新的训练算法 才有用的,对于我们这种api 调用的,可以忽略这种技巧

相关推荐
MYH5162 天前
sklearn 和 pytorch tensorflow什么关系
pytorch·tensorflow·sklearn
QQ676580084 天前
基于 TensorFlow 2 的 WGAN来生成表格数据、数值数据和序列数据。 WGAN生成对抗网络。代码仅供参考
生成对抗网络·tensorflow·neo4j·表格数据·wgan·对抗网络·序列数据
八戒社5 天前
如何使用插件和子主题添加WordPress自定义CSS(附:常见错误)
前端·css·tensorflow·wordpress
CC_IsMe7 天前
Linux服务器 TensorFlow找不到GPU
linux·jupyter·ssh·conda·tensorflow
雾迟sec8 天前
TensorFlow 的基本概念和使用场景
人工智能·python·tensorflow
盼小辉丶11 天前
TensorFlow深度学习实战(18)——K-means 聚类详解
深度学习·tensorflow·kmeans
之之为知知11 天前
深度学习能取代机器学习吗?
人工智能·pytorch·python·深度学习·机器学习·数据挖掘·tensorflow
kovlistudio11 天前
大模型应用开发第五讲:成熟度模型:从ChatGPT(L2)到未来自主Agent(L4)
人工智能·深度学习·学习·机器学习·chatgpt·tensorflow
kovlistudio12 天前
大模型应用开发第二讲:核心能力:自主性、适应性、推理能力
人工智能·深度学习·机器学习·大模型·tensorflow
郜太素12 天前
自然语言处理入门及文本预处理
人工智能·自然语言处理·nlp·tensorflow·word2vec