Char8-Keras高层接口
第八章中讲解的是高层接口Keras的使用。Keras的几个特点
Python
语言开发- 前后端分离
- 后端基于现有的
TF、CNTK
等框架 - 前端有自己的接口
API
- 后端基于现有的
TF
的高层唯一API
接口Keras
被实现在tf.keras
子模块中
常见功能模块
Keras提供常见的神经网络类和函数
- 数据集加载函数
- 网络层类
- 模型容器
- 损失函数
- 优化器类
- 经典模型
常见网络层
- 张量方式
tf.nn
模块中 - 层方式
tf.keras.layers
提供大量的接口,需要完成__call__()
- 全连接层
- 激活含水层
- 池化层
- 卷积层
import tensorflow as tf
from tensorflow import keras # 导入keras模型,不能使用import keras,它导入的是标准的Keras库
from tensorflow.keras import layers # 导入常见的网络层类
x = tf.constant([1,2,3.0,4.0])
layer = layers.Softmax(axis=-1) # 创建Softmax层
layer(x) # 调用softmax前向计算
网络容器
主要使用的Sequential
类
2层全连接层加上激活函数层通过Sequntial
容器构成一个网络
import tensorflow as tf
from tensorflow.keras import layers, Sequential
network = Sequential([ # 封装一个网格
layer.Dense(3, activation=None), # 指定全连接层和激活函数层
layer.ReLU(),
layer.Dense(2, activation=None),
layer.ReLU()
])
x = tf.random.normal([4,3])
network(x) # 输入从第一层开始,逐层传播至最后一层
# 通过add()方法追加新的网络层
layers_num = 2
network = Sequential([]) # 先创建空的网格
for _ in range(layers_num):
# 添加两个层:全连接层和激活函数层
network.add(layers.Dense(3))
network.add(layers.ReLU())
network.build(input_shape=(None, 4)) # 指定网格参数
network.summary() # 打印出网络结构和参数量
for p in network.trainable_variables: # 常看待优化的张量列表
print(p.name, p.shape)
模型装配、训练和测试
装配
通过两个主要的类实现:
- keras.Model,网络的母类,
Sequentail
类是其子类 - keras.layers.Layer,网络层的母类
通过compile()
函数指定优化器、损失函数等
# 创建全连接层网络
network = Sequntial([layers.Dense(256, activition='relu'),
layers.Dense(128, activition='relu'),
layers.Dense(64, activition='relu'),
layers.Dense(32, activition='relu'),
layers.Dense(10)])
# 指定网格参数和查看网络结构和参数量
network.build(input_shape=None, 28*28)
network.summary()
# 导入优化器和损失模块
from tensorflow.keras import optimisers, losses
# 采用Adam优化器,学习率为0.01,采用交叉熵损失函数
network.compile(optimizer=optimizers.Adam(lr=0.01),
loss=losses.CategoricalCrossentropy(from_logtis=-True),
metrics=['accuracy'])# 设置测量指标为准确率
训练
通过fit()
函数实现
train_db
为tf.data_Dataset
对象- epoch:训练5个epoch,每2个epoch验证一次
history = network.fit(train_db, epoch=5, validation=val_db,validation_freq=2)
history.history # 打印训练记录
测试
代码语言:javascript复制x, y = next(iter(db_test))
out = network.predict(x) # 模型预测,out为网络输出
print(out)
network.evaluate(db_test) # 模型测试
模型加载
张量方式
文件中保存的仅仅是参数张量的数值,没有其他的结构参数,需要使用相同的网络结构才能恢复网络数据,一般在拥有源文件的情况下使用。
代码语言:javascript复制network.save_weights('weights.ckpt') # 保存模型到参数文件上
del network # 删除网络对象
network = Sequential([layers.Dense(256, activation='relu'),
layers.Dense(128, activation='relu'),
layers.Dense(64, activation='relu'),
layers.Dense(32, activation='relu'),
layers.Dense(10)])
# 采用Adam优化器,学习率为0.01,采用交叉熵损失函数
network.compile(optimizer=optimizers.Adam(lr=0.01),
loss=losses.CategoricalCrossentropy(from_logtis=-True),
metrics=['accuracy'])# 设置测量指标为准确率
# 从参数文件总读取并且保存到当前网络中
network.load_weights('weigts.ckpt')
网络方式
- 不需要网络源文件
- 仅仅是需要模型参数文件就可以恢复网络模型
- 通过Model.save()
network.save('model.h5')
del network
network = tf.keras.models.load_model('model.h5')
SaveModel方式
通过 tf.keras.experimental.export_saved_model(network, path)
即可将模型以 SavedModel
方式保存到 path
目录中:
tf.keras.experimental.export_saved_model(network, 'model-savedmodel') # 保存模型结构与参数
del network
# 从文件中恢复网络
network = tf.keras.experimental.load_from_saved_model('model-savedmodel')
自定义类
自定义网络类
需要实现call()
和__init__()
方法
# 初始化工作
class MyDense(layers.Layer): # 继承关系
def __init__(self, inp_dim, outp_dim):
super(MyDense, self).__init__()
self.kernel = self.add__variable('w', [inp_dim, outp_dim], trainable=True) # True表示张量需要被优化
net = MyDense(4,3)
print(net.variables)
# 实现前项运算逻辑
def call(self, inputs, training=None): # training为T执行训练模式,F为测试模式默认是None
out = inputs @ self.kernel
out = tf.nn.relu(out)
自定义网络
代码语言:javascript复制network = Squential([MyDense(784, 256), # 使用自定义的网络类MyDense
MyDense(256, 128),
MyDense(128, 64),
MyDense(64, 32),
MyDense(32, 10)])
network.build(input_shape(None, 28*28))
- 通过堆叠使用自定义的网络类
- 5层全连接没有偏置张量,同时使用激活啊函数ReLU
使用基类实现
可以继承基类来实现任意逻辑的自定义网络类
代码语言:javascript复制class MyModel(keras.Model):
# 自定义网络类,继承自Model基类
def __init__(self):
super(MyModel, self).__init__():
self.fc1 = MyDense(28*28, 256)
self.fc2 = MyDense(256, 128)
self.fc3 = MyDense(128, 64)
self.fc4 = MyDense(64, 32)
self.fc5 = MyDense(32, 10)
# 实现自定义网络的前向运算逻辑
# 经过5层网络
x = self.fc1(inputs)
x = self.fc2(x)
x = self.fc3(x)
x = self.fc4(x)
x = self.fc5(x)
return x
测量工具
- 新建测量器
loss_meter = metrics.Mean()
- 写入数据
loss_meter.update_state(float(loss))
- 读取统计信息
loss_meter.result()
- 清除历史状态的信息
loss_meter.reset_states()
可视化
- TensorBoard
- Visdom
模型端
需要写入监控数据、图片数据、查看数据的直方分布图、文本信息。
代码语言:javascript复制# 监控标量数据
summary_writter= tf.summary.create_file_writer(log_dir)
with summary_writer.as_default():
tf.summary.scalar('train-loss', float(loss), step=step)
# 监控图片数据
with summary_writer.as_default():
tf.summmary.scalar('test-acc', float(total_correct/total), step=step)
tf.summary.image('val-onebyone-images:', val_images, max_outputs=9, step=step)
浏览器端
通过tensorboard --logdir path
来指定web后端监控的文件目录,浏览器端口默认是6006
# 查看张量的数据脂肪分布图和打印文本信息
with summary_writer.as_defualt():
# 当前时间戳 step 上的数据为 loss,写入到 ID 位 train-loss 对象中
tf.summary.scalar('train-loss', float(loss), step=step) # 可视化真实标签的直方图分布
tf.summary.histogram('y-hist',y, step=step)
tf.summary.text('loss-text',str(float(loss))) # 查看文本信息