如何避免卷积神经网络变懒?

5

如何避免卷积神经网络变得懒惰?我用KERAS训练后,我的CNN变得“懒惰”了。无论输入是什么,输出都是恒定的。你认为问题出在哪里?

我试图重复NVIDIA无人驾驶汽车端到端学习的实验the paper。当然,我没有真正的车,而是使用Udacity的simulator。该模拟器生成有关汽车前景的图形。

enter image description here

卷积神经网络接收图像,然后给出转向角度以使汽车安全地行驶在赛道上。游戏规则是保持模拟汽车安全地行驶在赛道上,这并不是很困难。

奇怪的是,有时我用 KERAS 训练完卷积神经网络后得到的是一个懒惰的 CNN,它会给出恒定的转向角度。虚拟汽车会离开赛道,但 CNN 的输出没有任何变化。特别是当层数加深时,例如 论文中 的卷积神经网络。

如果我使用这样的卷积神经网络,我可以在训练之后得到一个有用的模型。

model = Sequential()
model.add(Lambda(lambda x: x/255.0 - 0.5, input_shape = (160,320,3)))
model.add(Cropping2D(cropping=((70,25),(0,0))))
model.add(Conv2D(24, 5, strides=(2, 2)))
model.add(Activation('relu'))
model.add(Conv2D(36, 5, strides=(2, 2)))
model.add(Activation('relu'))
model.add(Conv2D(48, 5, strides=(2, 2)))
model.add(Activation('relu'))
model.add(Flatten())
model.add(Dense(50))
model.add(Activation('sigmoid'))
model.add(Dense(10))
model.add(Activation('sigmoid'))
model.add(Dense(1))

但是,如果我使用更深的卷积神经网络,我就有更多的机会得到一个懒惰的卷积神经网络。 具体来说,如果我使用像NVIDIA一样的卷积神经网络,几乎每次训练后我都会得到一个懒惰的卷积神经网络。

model = Sequential()
model.add(Lambda(lambda x: x/255.0 - 0.5, input_shape = (160,320,3)))
model.add(Cropping2D(cropping=((70,25),(0,0))))
model.add(Conv2D(24, 5, strides=(2, 2)))
model.add(Activation('relu'))
model.add(Conv2D(36, 5, strides=(2, 2)))
model.add(Activation('relu'))
model.add(Conv2D(48, 5, strides=(2, 2)))
model.add(Activation('relu'))
model.add(Conv2D(64, 3, strides=(1, 1)))
model.add(Activation('relu'))
model.add(Conv2D(64, 3, strides=(1, 1)))
model.add(Activation('relu'))
model.add(Flatten())
model.add(Dense(1164))
model.add(Activation('sigmoid'))
model.add(Dense(100))
model.add(Activation('sigmoid'))
model.add(Dense(50))
model.add(Activation('sigmoid'))
model.add(Dense(10))
model.add(Activation('sigmoid'))
model.add(Dense(1))

我在卷积层中使用'relu',全连接层的激活函数是'sigmoid'。我尝试更改激活函数,但没有效果。

这是我的分析。我不认为程序有错误,因为我可以使用相同的代码和更简单的CNN成功驾驶汽车。我认为原因是模拟器或神经网络的结构。在真正的自动驾驶汽车中,训练信号即方向盘转角应包含噪声;因此,在实际道路上,司机从未将方向盘保持静止。但在模拟器中,训练信号非常干净。几乎60%的方向盘转角为零。优化器可以通过将CNN的输出接近零来轻松完成工作。看起来优化器也很懒惰。然而,当我们真正希望这个CNN输出一些内容时,它也会给出零。因此,我为这些零方向盘转角添加了小噪声。我得到懒惰的CNN的机会较小,但并没有消失。

您对我的分析有何看法?我是否可以使用其他策略?我想知道在CNN研究的漫长历史中是否已解决了类似的问题。

资源

相关文件已上传至GitHub。您可以使用这些文件重复整个实验。

相关文件已上传至 [GitHub]https://github.com/BlueBirdHouse/CarND-Behavioral-Cloning-P3/。您可以使用这些文件重复整个实验。 - Blue Bird
请勿使用评论区更新问题 - 请编辑帖子。 - desertnaut
1个回答

2
我无法运行你的模型,因为问题和GitHub存储库都没有包含数据。这就是为什么我对我的答案有90%的把握。

但我认为你的网络的主要问题是在密集层之后使用了 sigmoid 激活函数。我假设当只有两个时,它会训练得很好,但四个太多了。

不幸的是,NVidia的End to End Learning for Self-Driving Cars 论文没有明确指出,但现在默认激活函数不再是 sigmoid(曾经是),而是 relu。如果您想知道原因,请参见 this discussion。因此,我提出的解决方案是尝试这个模型:

model = Sequential()
model.add(Lambda(lambda x: x/255.0 - 0.5, input_shape = (160,320,3)))
model.add(Cropping2D(cropping=((70,25),(0,0))))
model.add(Conv2D(24, (5, 5), strides=(2, 2), activation="relu"))
model.add(Conv2D(36, (5, 5), strides=(2, 2), activation="relu"))
model.add(Conv2D(48, (5, 5), strides=(2, 2), activation="relu"))
model.add(Conv2D(64, (3, 3), strides=(1, 1), activation="relu"))
model.add(Conv2D(64, (3, 3), strides=(1, 1), activation="relu"))
model.add(Flatten())
model.add(Dense(1164, activation="relu"))
model.add(Dense(100, activation="relu"))
model.add(Dense(50, activation="relu"))
model.add(Dense(10, activation="relu"))
model.add(Dense(1))

它模仿了英伟达的网络架构,不会受到梯度消失的影响。

非常感谢您的建议。我最近在处理另一个问题,很遗憾。在某些文化中,忽视他人是非常严重的。我并不是故意忽视,只是我的小脑袋无法处理那么多信息。我会回来的。 - Blue Bird
你的90%自信是正确的。懒惰的卷积神经网络已经被淘汰了。谢谢。看来我有一个梯度消失的问题。如果梯度无法通过网络传递,优化器必须通过提供一个懒惰卷积神经网络来完成工作!这是可能的,但我认为值得研究详细原因。 - Blue Bird

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接