tensorflow的网络多少层 如何检查 tensorflow输出网络结构_tensorflow输出网络结构


最新tensorflow采用了keras封装,和古早写法相比变化很大,但是用起来确更加方便了,恰逢最近需要倒腾tensorflow,所以记录一下。

这是一个系列文章,将从浅入深地介绍新的tensorflow的用法,文章列表:


林青:学习tensorflow(00)--从源代码编译tensorflowzhuanlan.zhihu.com

tensorflow的网络多少层 如何检查 tensorflow输出网络结构_tensorflow_02

林青:学习tensorflow2(01) -- 让tensorflow跑起来zhuanlan.zhihu.com


tensorflow的网络多少层 如何检查 tensorflow输出网络结构_神经网络_03


本文以记录用tensorflow完成fashion mnist问题的流程,行文逻辑如下:第一部分介绍tensorflow的安装,以及训练数据的获取;第二部分介绍神经网络训练流程,包括数据准备,网络搭建,学习率配置,中间模型暂存;第三部分介绍如何对训练好的模型进行评估,包括在validation集上测试,包括对给定的图进行inference。

一 预先准备

1. 安装tensorflow


python3 -m pip install tensorflow-gpu --user --upgrade


2. 问题和数据集

mnist一般被认为是神经网络的hello world,不过似乎太过于简单,以至于“即使搞定mnist,也不一定能够真正入门”,所以这里使用fashion-mnist数据集。解决的问题还是分类,数据集的样子都和mnist非常像。

直接传送门:zalandoresearch/fashion-mnist,down下来的文件是这样的:


tensorflow的网络多少层 如何检查 tensorflow输出网络结构_封装_04

fashion mnist数据集

二 神经网络训练

神经网络训练又被称为炼丹,通常有准备原料(准备数据),准备单方(构建模型),训练设定(设定优化方式),开始训练(需要考虑模型暂存)。

1. 准备原料

准备训练数据的图片和标签:


import gzip
import numpy as np
images_path_train = "./data/fashion/train-images-idx3-ubyte.gz"
with gzip.open(images_path_train, 'rb') as imgpath:
    images_train = np.frombuffer(imgpath.read(), dtype=np.uint8,offset=16).reshape(-1, 28,28)
    
labels_path_train = "./data/fashion/train-labels-idx1-ubyte.gz"
with gzip.open(labels_path_train, 'rb') as lbpath:
    labels_train = np.frombuffer(lbpath.read(), dtype=np.uint8,offset=8)


在tensorflow中,小的数据集用 numpyndarray来处理,大的数据集合则使用tf.data来处理。

2. 准备单方

就是搭建模型。这是关键的一步。tensorflow的keras封装已经将这个过程给简化了,通常有两种方式来搭建。

  • 基于keras.Sequential进行模型搭建
  • 基于keras.model自己搭建

当然,前一种方式简单,但是实现的功能有限,后一种方式比较复杂,但是可以实现高级的功能。

2.1 预先导入包


from tensorflow import keras


2.2 基于keras.Sequential进行构建

sequential的意思是顺序的,所以keras.Sequential构建出的网络可以理解为神经网络按照层堆叠。


model = keras.Sequential(
	[
  		keras.layers.Flatten(input_shape=(28,28)),
		keras.layers.Dense(128,activation=tf.nn.relu),
		keras.layers.Dense(128,activation=tf.nn.relu),
		keras.layers.Dense(128,activation=tf.nn.relu),
		keras.layers.Dense(128,activation=tf.nn.relu),
		keras.layers.Dense(10,activation=tf.nn.softmax)
	]
)


这是一个多个全连接层组成的网络。对于每一层,其实还有一些可以调节的参数,如初始化方式,如正则化方式。 不过并不是所有的keras封装的层都满足我们的要求,如果我们要构建自己的层,可以参考其它资料。https://www.tensorflow.org/beta/tutorials/eager/custom_layers

还有另外一种写法,就是先构建一个keras.Sequential,然后再add


model = keras.Sequential()
model.add(keras.layers.Flatten(input_shape=(28,28)))
model.add(keras.layers.Dense(128,activation=tf.nn.relu))


基于keras.Sequential进行构建模型方式十分直观,但是在灵活性上就缺少了不少。如果要构建resnet,就显得十分吃力了。所以这里引入另外的构建方式。

2.2 基于inputoutput的构建方式

各个层的输入和输出都明确写出来,便于进一步操作:


inputs = tf.keras.Input(shape=(32,))  # Returns a placeholder tensor
## A layer instance is callable on a tensor, and returns a 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)


最后的softmax包含一个fc。

3 训练设定

这个和之前tensorflow很不一样:之前的tensorflow要自己构建图,然后运行图;keras封装的结果,简直不要太简单:


model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])


简单的compile一下,就完成了之前复杂的过程,有木有很爽!其中第一个参数是优化的方式,第二个参数是loss,第三个参数是用于监控的指标,如这里是监控在训练结合上的准确率。

4 开始训练

最简单的版本就是fit,一句话搞定,神经网络的训练也是在这里发生的。


model.fit(images_train,labels_train,epochs=1000,)


在训练过程中,我们有暂存中间结果的需要:

  • 每隔一定epoch进行保存一个结果,对这些结果进行测试,从中选取最好的
  • 网络训练突然挂掉,重新开始时候希望能够基于之前结果继续

神经网络的训练是一个不断迭代优化的过程,我们并不知道哪一个epoch的结果最好。所以会每隔一定epoch就保存中间结果,然后对暂存的模型进行测试,选取其中表现最好的模型。此外,有时候训练也不是很稳定,我们并不想每次都从头开始训练一个新的神经网络,所以也需要能够载入之前训练的结果继续训练。需要实现的是:

  • 保存和载入一个网络
  • 每隔一定epoch就暂存模型

4.1 保存和载入网络

神经网络包含网络的权重和网络的结构两部分,神经网络的权重经过学习获取(这是训练的目的),而结构则是我们自己指定。有时候我们只是关心结构,而不关心权重;而有时候我们对两者都关心。

4.1.1 保存网络结构(不带权重)

如果只是想保留结构,而不是每次都用复杂的代码来构建,可以按照如下方式:


jmodel = model.to_json()
ymodel = model.to_yaml()


其中第一种方式将model序列化为json,然后可以按照json的方式存储。第二种方式则是序列化成yaml。基于存储结果来构建网络:


new_model = tf.keras.models.model_from_json(json_string)
new_model = tf.keras.models.model_from_yaml(yaml)


4.1.2 保存网络结构和权重

这就是中间模型,一般是保留为checkpoint,可以指定保存checkpoint的方式为hdf5

  • 保留最终训练的结果
model.save_weights("./epoch-100",save_format='h5')


最后的h5就是选择保存格式的

  • 每隔一定epoch就进行保存

这时候要使用callback


checkpoint_path = "train_log/epoch-{epoch:04d}"
# build a callback function
cp_callback = tf.keras.callbacks.ModelCheckpoint(checkpoint_path, verbose=1, save_weights_only=True,period=5)


fit时候调用


model.fit(images_train,labels_train,epochs=1000,callbacks = [cp_callback,],validation_data = (images_test,labels_test),verbose=1)


每隔5个epoch就存储一个模型。

三 模型评估

在训练过程中,我们希望能够对训练的模型进行评估,最终挑选出在benchmark上表现最好的模型。评估的方式有两种,第一种是在测试集或者验证集上进行评估,第二种是任意给一张图片进行inference

3.1 测试集上进行评估

按照读取训练集的方式来读取测试集,使用evaluate就可以在测试集上进行评估。


test_loss, test_acc = model.evaluate(test_images, test_labels)


3.2 测试给定的图片

使用predict 函数:


predictions = model.predict(test_images)


单张图片 -> 一个softmax

而多张图片 -> softmax的堆叠

四 总结

tensorflow使用keras封装,大大降低了模型构建的难度。

本文介绍了使用tensorflow新的keras封装,实现fashion-mnist的一半流程,介绍的新的api的用法。当然这只是初级功能,实现了让神经网络跑起来这一初级阶段的基本任务。后续会继续介绍数据可视化的方式,查看网络结构,基于tensorboard监视训练等一系列教程,敬请期待。