tensorflow是深度学习训练的常用框架,其代码书写有一些可以学习的套路。这个系列的博客将总结tensorflow构建深度学习网络并训练的几种套路。更进一步,结合tensorboard的使用,在这个系列的博客里还会介绍如何使用tensorboard来可视化实验结果。
相信正在看这篇博客的你已经知道tensorflow是做什么的,也正在面对需要使用tensorflow进行深度学习的问题,你也一定在网上搜索了许多别人写的tensorflow框架下的代码。你一定发现了,不同人写的代码风格是不一样的,有时候这种风格各异会增加阅读代码的困难程度。
这正是我写这系列博客的目的,我同系列的博客里记录了,我遇到的写tensorflow代码的风格以及它们的特点。这个系列的博客会长期更新。
为了方便阅读了这篇博客的你阅读其他博客,这篇博客会设置一个统一的训练问题以及训练环境,接下来的所有博客都是基于这个设置进行的。
# packages
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import datetime
# configs
input_shape = 1
output_shape = 1
EPOCH = 20
这系列博客目的是分享tensorflow代码风格,采用的数据毫无实际意义,是随机产生的数据。
# data prepare
x_train = np.linspace(-1, 1, 100)
y_train = x_train * x_train * x_train + 0.1 * np.random.random(x_train.size)
x_test = np.linspace(-1, 1, 100)
y_test = x_train * x_train * x_train + 0.2 * np.random.random(x_test.size)
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))
这里的模型结构比较朴素简单,可以构建最简单,无分支的深度学习模型。下面的代码参考了keras官网对Sequential class的描述。使用Sequential可以将模型分层叠好,这里需要注意模型的输入输出结构,以及模型模块值域是否能匹配预期。(例如有的激活函数的值域大于0,有的是-1到1之间,需要具体问题具体分析。)
# model define
def build_model(input_shape, output_shape):
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(10, input_dim=input_shape,kernel_initializer='random_normal',bias_initializer='zeros'))
model.add(tf.keras.layers.LeakyReLU(alpha=0.01))
model.add(tf.keras.layers.Dense(10, input_dim=10,kernel_initializer='random_normal',bias_initializer='zeros'))
model.add(tf.keras.layers.LeakyReLU(alpha=0.01))
model.add(tf.keras.layers.Dense(1, input_dim=10,kernel_initializer='random_normal',bias_initializer='zeros'))
model.add(tf.keras.layers.LeakyReLU(alpha=0.01))
return model
这种构建方法更为灵活,可以处理有分支的模型,详情见「知乎帖子」tensorflow笔记:高级封装——keras。事实上官网也对这种代码模式有介绍,见keras官网对model class的描述
def build_model(input_shape, output_shape):
input = tf.keras.layers.Input(shape=(input_shape))
dense1 = tf.keras.layers.Dense(10, input_dim=input_shape,kernel_initializer='random_normal',bias_initializer='zeros',name='dense1')(input)
relu1 = tf.keras.layers.LeakyReLU(alpha=0.01,name='relu1')(dense1)
dense2 = tf.keras.layers.Dense(10, input_dim=10,kernel_initializer='random_normal',bias_initializer='zeros',name='dense2')(relu1)
relu2 = tf.keras.layers.LeakyReLU(alpha=0.01,name='relu2')(dense2)
dense3 = tf.keras.layers.Dense(1, input_dim=10,kernel_initializer='random_normal',bias_initializer='zeros',name='dense3')(relu2)
relu3 = tf.keras.layers.LeakyReLU(alpha=0.01,name='relu3')(dense3)
output = relu3
model = tf.keras.models.Model(inputs = input, outputs = output)
return model
tf.keras.layers.Dense()
中本身可以加一个激活函数,例如inter_1 = tf.keras.layers.Dense(inter_shape, activation=tf.nn.relu)(inputs)
的写法。当然,我们也可以选择单独写一个激活函数层。例如outputs = tf.keras.activations.relu(inter_5, alpha=0.0, max_value=max_value, threshold=threshold)
的写法。
def build_model(input_shape, output_shape, inter_shape, max_value, threshold):
inputs = tf.keras.Input(shape=input_shape)
inter_1 = tf.keras.layers.Dense(inter_shape, activation=tf.nn.relu)(inputs)
inter_2 = tf.keras.layers.Dense(inter_shape, activation=tf.nn.relu)(inter_1)
inter_3 = tf.keras.layers.Dense(inter_shape, activation=tf.nn.relu)(inter_2)
inter_4 = tf.keras.layers.Dense(inter_shape, activation=tf.nn.relu)(inter_3)
inter_5 = tf.keras.layers.Dense(output_shape)(inter_4)
outputs = tf.keras.activations.relu(inter_5, alpha=0.0, max_value=max_value, threshold=threshold)
model = tf.keras.Model(inputs=inputs, outputs=outputs)
return model**
存储实验数据是训练模型中极其关键的一步,我想没有人希望自己费了半天劲训练的模型,最后由于实验数据没存好,不得不重新训练一遍。这里也体现了tensorflow框架的优势。tensorflow+tensorboard是进行实验的绝佳搭配,先用tensorflow进行模型训练,训练过程中,将实验数据保留在tensorboard可以识别的文件,再用tensorboard进行实验结果的可视化。
# summary
log_dir="log/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
重新构建一个模型,其输入为原模型的输入,其输出为指定层的输出。这里我们需要层的名字用于找到这层,层的名字可以用model.summary()
查看
part_model = tf.keras.Model(inputs = model.inputs, outputs = model.get_layer(layer_name).output)
tmp = part_model.predict(x_train)
这里参考博客:Keras框架下输出模型中间结果
tensorflow的模型在训练前首先需要compile
一下,在compile
中定义损失函数和优化器。compile
后进行fit
操作,在fit
中定义训练数据集,训练的轮次,batch的大小以及实验结果的可视化。
model = build_model(input_shape, output_shape)
# model compile and train
model.compile(loss='mse',optimizer=keras.optimizers.Adam())
model.fit (
x = x_train,
y = y_train,
batch_size = 12,
epochs = 20,
validation_data=(x_test,y_test),
shuffle=True,
callbacks=[tensorboard_callback]
)
model.fit()
比较适合刚入门的新手,这种训练方法较为简单粗暴,对于已经比较熟悉深度学习训练的油条,可以使用tf.GradientTape()
进行模型训练。
model = build_model(input_shape, output_shape)
loss_object = tf.keras.losses.MeanSquaredError(reduction='auto', name='mean_squared_error')
optimizer = tf.keras.optimizers.Adam()
train_loss = tf.keras.metrics.Mean('train_loss', dtype=tf.float32)
test_loss = tf.keras.metrics.Mean('test_loss', dtype=tf.float32)
def train_step(model, optimizer, x_train, y_train):
with tf.GradientTape() as tape:
predictions = model(x_train, training=True)
loss = loss_object(y_train, predictions)
grads = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
train_loss(loss)
def test_step(model, x_test, y_test):
predictions = model(x_test)
loss = loss_object(y_test, predictions)
test_loss(loss)
log_dir="log/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
train_log_dir = log_dir + '/train'
test_log_dir = log_dir + '/test'
train_summary_writer = tf.summary.create_file_writer(train_log_dir)
test_summary_writer = tf.summary.create_file_writer(test_log_dir)
for epoch in range(EPOCHS):
for (x_train, y_train) in train_dataset:
train_step(model, optimizer, x_train, y_train)
with train_summary_writer.as_default():
tf.summary.scalar('loss', train_loss.result(), step=epoch)
tf.summary.scalar('accuracy', train_accuracy.result(), step=epoch)
for (x_test, y_test) in test_dataset:
test_step(model, x_test, y_test)
with test_summary_writer.as_default():
tf.summary.scalar('loss', test_loss.result(), step=epoch)
tf.summary.scalar('accuracy', test_accuracy.result(), step=epoch)
template = 'Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}'
print (template.format(epoch+1,
train_loss.result(),
train_accuracy.result()*100,
test_loss.result(),
test_accuracy.result()*100))
# Reset metrics every epoch
train_loss.reset_states()
test_loss.reset_states()
train_accuracy.reset_states()
test_accuracy.reset_states()
运行python脚本,再开一个terminal运行
tensorboard --logdir log
即可查看tensorboard上面的实验结果可视化,具体菜单里每一个选项对应的结果是什么含义可以参考官网上的内容。这里放一张在tensorboard上面的截图。