通过Keras回调函数和Tensorboard来检查并监控深度学习模型

Tensorboard在深度学习中的必要性

我们在训练模式的时候,很多事情一开始都无法预测。尤其是我们不知道需要多少轮才能够得到最佳验证损失。我们常常采用的策略是:训练足够多的轮次,这时模型已经开始过拟合,根据这一次运行来确定训练所需要的正确轮数,然后使用这个最佳轮数从头开始再启动一次新的训练。无疑,这种方法是非常浪费时间和资源的。
处理这个问题的更好方法是,当我们观察到模型的验证损失值不再改善的时候就停止训练。我们可以通过使用Keras设计**回调函数(callback)**来实现这个过程。callback是在调用fit时传入模型的一个对象,我们可以通过它来实现:中断训练、保存模型、加载一组不同的权重或改变模型的状态,同时我们还能够跟踪实验指标,例如损失值loss和正确值accracy,可视化模型图以及将嵌入物到较低维度空间等

下面我们将介绍两种方法来实现tensorboard,以Keras中内置的MNIST数据集为例:

1. 首先我们编写一个函数对数据进行标准化,同时以Keras来创建一个简单的模型使图像分为10类。

mnist = tf.keras.dataset.mnist
(x_train, y_train),(x_test, y_test) = mnist.load_data() 
#读入数据集,x_train、x_test为训练的图片数据集,y_train和y_test为相应标签;
#可在Pycharm中用断点Debug查看变量具体信息
x_train, x_test = x_train / 255.0, x_test / 255.0
#将数据的大小从0-255缩放到0-1之间,以获得更好的训练效果

def create_model():
	#通过Sequential进行简单的线性模型叠加
  return tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    #在使用Dense前先用Flatten进行展开
    tf.keras.layers.Dense(512, activation='relu'),
    #512代表用512个结点,进行全连接,并使用'relu'激活函数
    tf.keras.layers.Dropout(0.2),
    #使用Dropout进行随机丢失以获得更好训练效果
    tf.keras.layers.Dense(10, activation='softmax')
    #由于数据集是手写数字,其是十分类的问题
    #因此最后设计十个结点,并用softmax函数转化为概率分布进行输出
  ])

#运行效果如下:
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step

2. 通过Keras.Model.fit()使用Tensorboard

当使用Keras.Model.fit()函数进行训练时,添加tf.keras.callback.Tensorboard回调可确保创建和存储日志.另外,在每个时期启用histogram_freq = 1的直方图计算功能(默认情况下处于关闭状态),将日志放在带有时间戳的子目录中,以便选择不同的训练运行。

model = create_model() #调用函数创建模型

model.compile(optimizer='adam',
				#选择adam优化器
              loss='sparse_categorical_crossentropy',
              #损失函数选择
              metrics=['accuracy']
              #因为要可视化accuracy的变化,必须指定正确率的计算)

log_dir="logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")

tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
#callback函数的参数选择,用log_dir指定生成的日志目录
#用histogram_freq指定直方图
model.fit(x=x_train, 
          y=y_train, 
          epochs=5, 
          validation_data=(x_test, y_test), 
          callbacks=[tensorboard_callback])
          #模型调用后,设置5个epoch,传入相应参数

在命令行(command)使用以下指令:

tensorboard --logdir logs/fit

结果如下:
通过Keras回调函数和Tensorboard来检查并监控深度学习模型_第1张图片

3. 对顶部导航栏中的选项卡进行简单解释:

  • Scalars 显示损失和指标在每个时期如何变化。 可以使用它来跟踪训练速度,学习率和其他标量值。
  • Graphs 可视化模型,显示层的Keras图,可以用于检查模型是否正确构建。
  • DistributionsHistograms 显示张量随时间的分布。 有利于可视化权重和偏差并验证它们是否以预期的方式变化。

当我们记录其他类型的数据时,会自动启用其他 TensorBoard 插件。 例如,使用 Keras TensorBoard 回调还可以记录图像和嵌入。 可以通过单击右上角的“inactive”下拉列表来查看 TensorBoard 中的其他插件。

4. 通过其他方法使用TensorBoard

通过tf.GradientTape()训练, 使用 tf.summary 记录所需的信息。我们仍然是使用MNIST数据集,但是我们要将其转换为
tf.data.Dataset来使用批处理的功能:
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))
#数据的一个转换过程

train_dataset = train_dataset.shuffle(60000).batch(64)
#shuffle的意思是将60000张图片进行随机打乱,然后每次选取64张进行训练。
#并且每次选取前都会重新随机打乱,但shuffle中的值不要设置太大,电脑配置可能吃不消。
test_dataset = test_dataset.batch(64)
#测试集就不需要打乱了,直接进行batch训练就可以

下面选择损失和优化器,并创建可用于训练期间积累值并在任何时候去记录变化指标

loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
optimizer = tf.keras.optimizers.Adam()
#选择损失函数和优化器

#Define our metrics
# Define our metrics
train_loss = tf.keras.metrics.Mean('train_loss', dtype=tf.float32)
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy('train_accuracy')
test_loss = tf.keras.metrics.Mean('test_loss', dtype=tf.float32)
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy('test_accuracy')
#要指定名字,在TensorBoard会显示相应的指标名

定义训练和测试代码

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)
  #通过gradient函数将损失值传到模型中每个可训练的变量(结点)中
  optimizer.apply_gradients(zip(grads, model.trainable_variables))
  #zip是将梯度值和结点参数值打包成元组并输入进去
  #之后通过Adam优化器,将每个节点的误差梯度用于更新该结点的一个变量的值
  train_loss(loss)
  train_accuracy(y_train, predictions)

def test_step(model, x_test, y_test):
  predictions = model(x_test)
  loss = loss_object(y_test, predictions)
#在测试集中就不需要规定它的误差梯度了,所以没有grads等部分
  test_loss(loss)
  test_accuracy(y_test, predictions)

下面设置摘要编写器,以将摘要写到另一个日志目录中的磁盘中:

current_time = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
train_log_dir = 'logs/gradient_tape/' + current_time + '/train'
test_log_dir = 'logs/gradient_tape/' + current_time + '/test'
train_summary_writer = tf.summary.create_file_writer(train_log_dir)
test_summary_writer = tf.summary.create_file_writer(test_log_dir)

开始训练,在 summary writers 的范围内,在训练/测试期间使用 tf.summary.scalar() 记录指标(损失和准确性),以将摘要写入磁盘。 您可以控制要记录的指标以及记录的频率。 其他的 tf.summary 函数可以记录其他类型的数据。

model = create_model() # reset our model
EPOCHS = 5
#训练五个epoch
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)
	#设置scalar要显示的loss和accuracy
	
  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)
    #设置scalar中要现实的loss和accuracy

  template = 'Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}'
  #显示当前的epoch,loss损失值和accuracy准确率值,结合下面的print函数
  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()
  #因为计算完每一轮损失值后,就要把该论的损失值清0,否则下轮的损失值会受到上轮的影响

运行结果如下:

Epoch 1, Loss: 0.24321186542510986, Accuracy: 92.84333801269531, Test Loss: 0.13006582856178284, Test Accuracy: 95.9000015258789
Epoch 2, Loss: 0.10446818172931671, Accuracy: 96.84833526611328, Test Loss: 0.08867532759904861, Test Accuracy: 97.1199951171875
Epoch 3, Loss: 0.07096975296735764, Accuracy: 97.80166625976562, Test Loss: 0.07875105738639832, Test Accuracy: 97.48999786376953
Epoch 4, Loss: 0.05380449816584587, Accuracy: 98.34166717529297, Test Loss: 0.07712937891483307, Test Accuracy: 97.56999969482422
Epoch 5, Loss: 0.041443776339292526, Accuracy: 98.71833038330078, Test Loss: 0.07514958828687668, Test Accuracy: 97.5

再次在命令行中打开TensorBoard

tensorboard --logdir logs/gradient_tape

通过Keras回调函数和Tensorboard来检查并监控深度学习模型_第2张图片我们可以看到,这张图中只有SCALARS的图,没有模型图和其它的东西,如果想要获取更多可视化信息,我们可以自己通过Keras回调以及tf.summary使用TensorBoard来实现更多的自定义场景。

5. 后言:

以上就是对于通过Keras回调函数和Tensorboard来检查并监控深度学习模型的过程。我把它放在了去模糊的专题当中,因为我觉得在GAN网络中,它的损失函数是处于动态平衡的过程,如果我们单独观察损失函数的值是无法有效去评判模型效果的,并且对于GAN网络的复杂性,训练耗时长,我们很有必要去实时监控,在没有必要训练的时候及时停下并修改模型,同时去检测在训练过程中通过预先准备的测试图片,实时观察图片效果。这可以有效的提高训练GAN网络的效率。同时,在后期我会根据专题进程再写一篇TensorBoard的Blog,来实现TensorBoard更多功能。

如果你有其它疑问,欢迎在评论区与我交流,或者发邮箱到[email protected]向我咨询。

你可能感兴趣的:(#,图像去模糊,计算机视觉,tensorflow,深度学习,可视化)