如何防止懒惰的卷积神经网络?

How to prevent a lazy Convolutional Neural Network?

如何防止懒惰的卷积神经网络?在用 KERAS 训练后,我以一个“懒惰的 CNN”结尾。无论输入是什么,输出都是恒定的。你认为问题是什么?

我尝试重复 NVIDIA 的自动驾驶汽车端到端学习实验 the paper. Absolutely, I do not have a real car but a Udacity’s simulator。模拟器生成有关汽车前景的图形。

CNN 接收到图形,它给出了使汽车保持在轨道上的转向角。游戏规则是让模拟车在赛道上安全行驶。这不是很困难。

奇怪的是,有时我在使用 KERAS 训练后以惰性 CNN 结束,它提供恒定的转向角。模拟车会跑偏,但 CNN 的输出没有任何变化。特别是该层变得更深,例如the paper 中的 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))

但是,如果我使用更深的 CNN,我就有更多机会获得惰性 CNN。 具体来说,如果我使用喜欢 NVIDIA 的 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(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 回购都不包含数据。这就是为什么我对我的答案有 90% 的把握。

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

不幸的是,NVidia 的 End to End Learning for Self-Driving Cars paper doesn't specify it explicitly, but these days the default activation is no longer sigmoid (as it once was), but relu. See 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))

它模仿了 NVidia 的网络架构,并且不受梯度消失的影响。