Fork me on GitHub

TF-char8-Keras高层接口

Char8-Keras高层接口

第八章中讲解的是高层接口Keras的使用。Keras的几个特点

  • Python语言开发
  • 前后端分离
    • 后端基于现有的TF、CNTK等框架
    • 前端有自己的接口API
  • TF的高层唯一API接口
  • Keras被实现在tf.keras子模块中


常见功能模块

Keras提供常见的神经网络类和函数

  • 数据集加载函数
  • 网络层类
  • 模型容器
  • 损失函数
  • 优化器类
  • 经典模型

常见网络层

  1. 张量方式tf.nn模块中
  2. 层方式tf.keras.layers提供大量的接口,需要完成__call__()
    1. 全连接层
    2. 激活含水层
    3. 池化层
    4. 卷积层
1
2
3
4
5
6
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容器构成一个网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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()函数指定优化器、损失函数等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 创建全连接层网络
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_dbtf.data_Dataset对象
  • epoch:训练5个epoch,每2个epoch验证一次
1
2
history = network.fit(train_db, epoch=5, validation=val_db,validation_freq=2)
history.history # 打印训练记录

测试

1
2
3
4
x, y = next(iter(db_test))
out = network.predict(x) # 模型预测,out为网络输出
print(out)
network.evaluate(db_test) # 模型测试

模型加载

张量方式

文件中保存的仅仅是参数张量的数值,没有其他的结构参数,需要使用相同的网络结构才能恢复网络数据,一般在拥有源文件的情况下使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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()
1
2
3
4
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 目录中:

1
2
3
4
5
tf.keras.experimental.export_saved_model(network, 'model-savedmodel')  # 保存模型结构与参数
del network

# 从文件中恢复网络
network = tf.keras.experimental.load_from_saved_model('model-savedmodel')

自定义类

自定义网络类

需要实现call()__init__()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
# 初始化工作
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)

自定义网络

1
2
3
4
5
6
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

使用基类实现

​ 可以继承基类来实现任意逻辑的自定义网络类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

模型端

需要写入监控数据、图片数据、查看数据的直方分布图、文本信息。

1
2
3
4
5
6
7
8
9
# 监控标量数据
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

1
2
3
4
5
6
# 查看张量的数据脂肪分布图和打印文本信息
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))) # 查看文本信息

本文标题:TF-char8-Keras高层接口

发布时间:2019年12月10日 - 12:12

原始链接:http://www.renpeter.cn/2019/12/10/TF-char8-Keras%E9%AB%98%E5%B1%82%E6%8E%A5%E5%8F%A3.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

Coffee or Tea