训练神经网络通常是一种高风险高回报的策略。如果调整得当,可能会得到一个为特定任务工作的最先进的工作模型。以图像生成为例,这是神经网络的最新突破之一。只需几笔人工画笔,就可以创造出看起来非常真实的自然场景图像。然而,另一方面,训练一个生成性神经网络极其困难。必须经历一个严格的试错阶段才能把事情做对。几天前,当试图为年龄检测问题构建一个工作模型时,经历了类似的训练神经网络的经历。当为这个问题制作第一个模型时,它绝对拒绝训练。在这篇文章中,将分享如何调试神经网络的方法。请继续关注,因为有一个快乐的结局!
解决年龄检测问题与神经网络
在开始解决问题之前,让先概述一下这个问题是什么。印度演员年龄检测是一个最近发布的实践问题,涉及提取面部特征进行年龄分析。由于这是一个图像处理问题,自然选择了神经网络来解决这个问题。但正如之前所说,网络无法训练。即使让它训练超过一个小时200次迭代,准确率也没有变化。这里有一个证据!显然,这行不通!
检查神经网络架构
当构建神经网络时,首先要检查的是是否有正确定义架构。在这里,有一个三类问题,数据集中的图像大小不一。为了简化事情,将所有图像转换为32×32大小。根据这个,定义了如下架构:
# 定义变量
input_num_units = 32 * 32 * 3 # 图像是3D(RGB),因此乘以3
hidden_num_units = 500
output_num_units = 3
epochs = 50
batch_size = 128
model = Sequential([
InputLayer(input_shape=(input_num_units,)),
Dense(units=hidden_num_units, activation='relu'),
Dense(units=output_num_units, activation='softmax'),
])
看不出神经网络架构有任何问题。
检查神经网络的超参数
在看来,这是处理神经网络时最重要的步骤。这是因为有很多参数需要调整,有时尝试它们所有可能会令人沮丧。(附注:在这篇文章中调查了超参数以及如何调整它们)幸运的是,使用了一个非常简单的神经网络,只有一个隐藏层,使用经典的梯度下降算法(SGD)进行训练。
model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy'])
需要注意的一点是,当使用SGD训练神经网络时,它可能会训练得很慢。为了克服这个问题,可以使用自适应梯度下降来更快地训练网络。
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
但问题是,即使将训练算法从SGD更改为Adam(即自适应梯度下降),网络也没有训练。这意味着网络有根本性的问题。不得不使用Thor的锤子来打破这个问题!
TensorBoard概览
在理解神经网络的过程中,使用了许多构建和可视化神经网络的工具。在它们所有中,发现TensorBoard是一个重要的资产。它可以在训练神经网络时给有用的洞察。
除此之外,它还提供了一个漂亮的仪表板视图,这对于向利益相关者解释发现非常重要。在上面看到的证据图像本身就是TensorBoard的仪表板。
将介绍如何在系统中安装TensorBoard的步骤。建议自己尝试一下。
pip install Tensorboard
安装后,可以通过在终端输入以下命令来打开TensorBoard:
tensorboard --logdir=logs/
上面的“logs/”文件夹应该包含神经网络训练的历史。可以通过在Keras中包含一个TensorBoard回调来简单地获得这个历史。
model.fit(train_x, train_y, batch_size=batch_size, epochs=epochs, verbose=1, validation_split=0.2, callbacks=[keras.callbacks.TensorBoard(log_dir="logs/final/{}".format(time()), histogram_freq=1, write_graph=True, write_images=True)])
在这个例子中,传递了所有参数,以便保存所有内容。参数的含义如下:
- write_graph:打印神经网络内部定义的图。
- write_images:通过组合神经网络的权重创建图像。
- histogram_freq:绘制神经网络中权重和偏差的分布。
检查网络复杂性
从短暂旅行回来后,接下来尝试的是检查构建的网络是否足以学习问题分布。为此,将架构从简单的神经网络更改为卷积神经网络。效果是准确率从一开始就急剧上升(从33%上升到54%)。但即使训练后,它仍然保持不变。
看来小实验失败了🙁
检查输入数据结构
在彻底检查了网络架构之后,是时候检查否有正确的数据集本身了。需要检查的一些事情是:
- 所有记录是否都是相同大小?
- 问题是否不平衡?
- 是否进行了适当的预处理?
在这里,应该检查否有一个正确处理的输入。例如,在图像处理问题中,如果处理了图像,并且结果输入具有不规则的纵横比,神经网络显然会被它迷惑。
由于这是一个简单的网络,实际上没有进行任何预处理步骤。所以这不是问题。
在耗尽了可能遇到的大部分问题之后,开始感到有点沮丧,不知道真正的问题可能是什么。幸运的是,旅程结束了,因为发现了一个奇怪的错误,应该早就抓住了。
问题是发送给网络的输入数据范围是0到255。理想情况下,这个范围应该在0和1之间。输入数据的分布如下:
让向解释为什么归一化(将范围设置为0到1)很重要(因为亲自经历了找到它是什么麻烦😛)
temp = []
for img_name in train.ID:
img_path = os.path.join(data_dir, 'Train', img_name)
img = imread(img_path)
img = imresize(img, (32, 32))
temp.append(img.astype('float32'))
train_x = np.stack(temp)
train_x = train_x / 255. # 归一化步骤
- 检查架构
- 检查神经网络的超参数
- 检查网络复杂性
- 检查输入数据结构
- 检查数据分布