我们在训练模式的时候,很多事情一开始都无法预测。尤其是我们不知道需要多少轮才能够得到最佳验证损失。我们常常采用的策略是:训练足够多的轮次,这时模型已经开始过拟合,根据这一次运行来确定训练所需要的正确轮数,然后使用这个最佳轮数从头开始再启动一次新的训练。无疑,这种方法是非常浪费时间和资源的。
处理这个问题的更好方法是,当我们观察到模型的验证损失值不再改善的时候就停止训练。我们可以通过使用Keras设计**回调函数(callback)**来实现这个过程。callback是在调用fit时传入模型的一个对象,我们可以通过它来实现:中断训练、保存模型、加载一组不同的权重或改变模型的状态,同时我们还能够跟踪实验指标,例如损失值loss和正确值accracy,可视化模型图以及将嵌入物到较低维度空间等
下面我们将介绍两种方法来实现tensorboard,以Keras中内置的MNIST数据集为例:
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
当使用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
当我们记录其他类型的数据时,会自动启用其他 TensorBoard 插件。 例如,使用 Keras TensorBoard 回调还可以记录图像和嵌入。 可以通过单击右上角的“inactive”下拉列表来查看 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
我们可以看到,这张图中只有SCALARS的图,没有模型图和其它的东西,如果想要获取更多可视化信息,我们可以自己通过Keras回调以及tf.summary使用TensorBoard来实现更多的自定义场景。
以上就是对于通过Keras回调函数和Tensorboard来检查并监控深度学习模型的过程。我把它放在了去模糊的专题当中,因为我觉得在GAN网络中,它的损失函数是处于动态平衡的过程,如果我们单独观察损失函数的值是无法有效去评判模型效果的,并且对于GAN网络的复杂性,训练耗时长,我们很有必要去实时监控,在没有必要训练的时候及时停下并修改模型,同时去检测在训练过程中通过预先准备的测试图片,实时观察图片效果。这可以有效的提高训练GAN网络的效率。同时,在后期我会根据专题进程再写一篇TensorBoard的Blog,来实现TensorBoard更多功能。
如果你有其它疑问,欢迎在评论区与我交流,或者发邮箱到[email protected]向我咨询。