模型子类化
将model类子类化的方法如下:
1 在__init__()方法中,定义模型将使用的层;
2 在call()方法中,定义模型的前向传播,重复使用之前创建的层;
3 将子类实例化,并在数据上调用,从而创建权重
模型子类化代码示例 1
class CustomerTicketModel(keras.Model):
def __init__(self, num_departments):
super().__init__()
self.concat_layer = layers.Concatenate()
self.mixing_layer = layers.Dense(64, activation="relu")
self.priority_scorer = layers.Dense(1, activation="sigmoid")
self.department_classifier = layers.Dense(
num_departments, activation="softmax")
def call(self, inputs):
title = inputs["title"]
text_body = inputs["text_body"]
tags = inputs["tags"]
features = self.concat_layer([title, text_body, tags])
features = self.mixing_layer(features)
priority = self.priority_scorer(features)
department = self.department_classifier(features)
return priority, department
此类子类化模型一般不考虑,从最底层开始向上构筑会容易犯错,且很多内置的功能无法被使用
在日常使用函数式API,我们可以在得到模型概览图的同时,利用其灵活搭建的特性构建自己所需的模型
内置训练循环和评估循环
标准工作流程中已经存在多种可以用于训练的算法,通常一个模型从头到尾的使用中,依次会涉及到compile(),fit(),evaluate()以及predict()等几种函数
from tensorflow.keras.datasets import mnist
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, outputs)
return model
(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"])
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)
当我们需要自定义这个工作流程时,有两种方法:
编写自定义指标;
向fit()方法传入回调函数,以便在训练过程中的特定时间点采取行动。
两种方法可在实际工作中遇到特定需求时考虑
利用tensorboard进行监控和可视化
tensorboard功能:
1 训练过程中以可视化方式监控指标;
2 将模型架构可视化;
3 将激活函数和梯度的直方图可视化;
4 以三维形式研究嵌入;
要将tensorboard与模型和fit方法混合使用,简单的方式是使用keras.callbacks.tensorboard回调函数,一般简单的情况只需指定让回调函数写入日志的位置即可,并在fit中回调函数的位置补充上tensorboard
model = get_mnist_model()
model.compile(optimizer="rmsprop",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"])
tensorboard = keras.callbacks.TensorBoard(
log_dir="/full_path_to_your_log_dir",
)
model.fit(train_images, train_labels,
epochs=10,
validation_data=(val_images, val_labels),
callbacks=[tensorboard])
需要使用时参考书
自定义训练循环和评估循环
暂时不考虑,先使用自带的fit
卷积神经网络
组成一个简单的小型卷积神经网络模型
from tensorflow import keras
from tensorflow.keras import layers
inputs = keras.Input(shape=(28, 28, 1))
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(inputs)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = layers.Flatten()(x)
outputs = layers.Dense(10, activation="softmax")(x)
model = keras.Model(inputs=inputs, outputs=outputs)
试运行该模型
from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images = train_images.reshape((60000, 28, 28, 1))
train_images = train_images.astype("float32") / 255
test_images = test_images.reshape((10000, 28, 28, 1))
test_images = test_images.astype("float32") / 255
model.compile(optimizer="rmsprop",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"])
model.fit(train_images, train_labels, epochs=5, batch_size=64)
以此为切入点,我们理解卷积层各个部分的含义及作用
卷积层从输入特征空间中学习到的称为:“局部模式”(例如:对于mnist数据集中的数字,全局模式就是涉及所有像素的模式,而相对的,局部模式识别到的内容可以理解为“一部分像素”,比如边缘纹理等)。
这个特征使得卷积网络学习的模式具有平移不变性,可以在图像的任何位置识别出相同的模式,由此就能更高效地利用数据,更容易用较少的数据得到泛化能力更强的模型。
卷积网络每一层可以逐层学习到越来越复杂,越来越抽象的视觉概念。即可以学习到模式的空间层次结构
卷积由两个关键参数定义:
1 从输入中提取的图块尺寸:3*3、5*5等
2 输出特征图的深度: 32、128等
padding
面对不同的3*3,5*5像素矩阵时,我们通过向该矩阵四周填充不同数量的内容,使得整个矩阵的每一个块内容都能够使用某个尺寸的卷积核进行遍历
stride
两个连续窗口之间的距离是卷积的一个参数,叫做步幅
最大汇聚层
对特征图进行下采样,将特征图尺寸缩小,并获取模型中样本中更为显著的特征内容
构建卷积模型处理更为现实复杂的问题:猫狗分类
随着图像规模的增大已经问题的进一步复杂化,我们需要相应地增大模型容量,增加两个conv2d和maxpooling2d的组合,既增大了模型容量,又可以进一步缩小特征图(卷积网络一般都是这样的尺寸随着层数深度逐渐缩小的模式)
from tensorflow import keras
from tensorflow.keras import layers
inputs = keras.Input(shape=(180, 180, 3))
x = layers.Rescaling(1./255)(inputs)
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.Flatten()(x)
outputs = layers.Dense(1, activation="sigmoid")(x)
model = keras.Model(inputs=inputs, outputs=outputs)
在对对应的JPEG文件进行预处理时,一些基础的步骤可以直接参考书8.2.4
数据增强
对原本图像进行翻转,等比例放大缩小等产生更多的样本数据
一般我们可以在图像模型的rescaling层(该层主要的功能是将图像各个部分的像素点数字大小缩小便于送入模型训练)前添加一个数据增强代码块。
data_augmentation = keras.Sequential(
[
layers.RandomFlip("horizontal"),
layers.RandomRotation(0.1),
layers.RandomZoom(0.2),
]
)
数据增强一定程度减轻了过拟合,但进一步还可以在卷积层与全连接层衔接的位置添加一个dropout层来进一步削弱过拟合
inputs = keras.Input(shape=(180, 180, 3))
x = data_augmentation(inputs)
x = layers.Rescaling(1./255)(x)
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.Flatten()(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(1, activation="sigmoid")(x)
model = keras.Model(inputs=inputs, outputs=outputs)
model.compile(loss="binary_crossentropy",
optimizer="rmsprop",
metrics=["accuracy"])
由于增加了数据集规模,所以过拟合的出现也会延迟出现,可以在原有的迭代次数上增加一些次数,便于观察过拟合
数据集较少情况下的另一种解决方向
使用预训练模型。
1 特征提取
利用已训练好的模型,基于已存在模型的predict函数构建简单的特征提取函数,将原数据集的内容变为已完成特征提取的数据集,随后将提取的特征直接送入当前的模型中进行fit训练,可以在较短的时间内完成
2 使用数据增强的特征提取
一般情况需要GPU才能正常运行,不考虑使用
3 微调预训练模型
卷积层前期得到的特征相较于后边几层的卷积层来说更加泛用,所以在微调时我们针对最后2-3层卷积层的内容进行调整,使得其提取特征对于当前问题更有针对性