Keras 中的 SGD 优化不会垂直于水平曲线移动?

SGD optimization in Keras does not move perpendicular to level curves?

我正在使用 Keras 执行线性回归。我的数据集由 50 个一维输入点和 50 个一维输出点组成。为了执行线性回归,我正在训练一个没有激活函数的单层和单个神经元的神经网络。神经网络定义为

model = Sequential()
model.add(Dense(1, input_dim=1, kernel_initializer='zeros', 
bias_initializer='zeros'))

然后我要求 Keras 找到 w 和 b 的最优值,使用 SGD 作为优化器,使用均方误差作为损失函数。

model.compile(loss='mean_squared_error', optimizer=SGD(lr=0.01))
model.fit(x,y,epochs=100, callbacks=[history], verbose=0, batch_size=50);

其中 history 是我创建的回调,用于在优化的每个步骤中保存当前权重和偏差。

然后我继续绘制损失函数的水平曲线,以及 w x b space 中的优化轨迹。输出如下。

优化轨迹显示为红色圆圈,全局最优显示为蓝色'x'。这似乎是合理的,因为我们从 [0,0] 开始,并且在每次迭代之后我们都接近全局最优值。最终梯度开始变得如此之小以至于我们停止改进。

但是,我知道通过使用梯度下降,人们总是会在当前点沿梯度方向移动(即垂直于水平曲线)。这种优化轨迹似乎并不像那样。 Keras SGD 优化器是否在幕后做其他事情?还是我遗漏了什么?

编辑: 虽然图中看起来水平曲线是平行线,但实际上它们是椭圆体,但很长。选择不同的范围来绘制它们揭示了这一点。

编辑 2: 为了避免与我如何绘制这个问题中显示的图像有关的任何混淆,我现在创建了一个 gist with the code.

首先,您应该意识到,由于您没有使用激活函数,因此您的神经网络只能表示线性系统(相当于矩阵乘法)。非线性激活函数带来了神经网络的表征能力。

您实际上并没有执行线性回归。如果你想这样做,例如使用 2 次多项式,你应该添加平方参数作为输入。由于 http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.PolynomialFeatures.html

,Scikit-learn 提供了这种转换

假设您有一个包含两个输入 x 和 y 的函数,像您那样执行线性回归将具有一个具有 x, x^2, xy, y, y^2 和一个输出神经元的输入层。

编辑: 然而,在 (w,b) space 中,你实际上应该能够达到全局最小值。但是,没有关于收敛速度的结果。如果你看一下你的损失函数,你会注意到它在一个方向上被拉伸了很多:这相当于说 Hessian 矩阵有两个幅度非常不同的特征值。这意味着你将能够在一个方向上快速学习(最大的eingenvalues之一),但在另一个方向上缓慢。

在神经网络优化中,计算Hessian矩阵是没有问题的,因为每一步都需要大量的计算。然而,一些学习算法能够逃避鞍点和糟糕的条件(像你的)优化问题。 SGD 总体表现不佳,几乎不再使用。看看 http://ruder.io/optimizing-gradient-descent/,知道所有这些优化器都包含在 Keras 中。对于你,我会首先尝试增加动量以提高收敛速度,正如你所说,如果你等待足够长它实际上可以收敛。

请记住,您使用的 SGDStochastic Gradient Descent。在下图中可以看到使用 SGD 与普通 GD 获得的轨迹差异的可视化: (source)

可以看到,SGD轨迹并不垂直于水平线,而是移动方向不同。也许这已经在解释你的轨迹形式了。

对不起,如果你已经考虑到了这一点,我看不出你是如何创建图表的。

梯度取决于输入数据。

神经元具有公式 w.x + b,其中 x 是输入。

.

w 和 b 函数的梯度为:(x , 1).

因此,它因输入而异。

但也不要忘记梯度也会受到损失函数的影响,在您的情况下,损失函数是差异的平方。

要查看电平曲线,您必须应用链式法则。

Loss = [(wx + b) - y]^2

所以你的梯度是:

W: 2.[(wx + b) - y].x
B: 2.[(wx + b) - y].1

正交(0.2 对 -5 斜率),但是你的图表的 x/y 单位不一样。沿给定方向缩放不保持正交性。