Copyright © Microsoft Corporation. All rights reserved. 适用于License版权许可
为了简化起见,我们先用一个简单的二元二次函数来模拟损失函数的等高线图,测试一下我们在前面实现的各种优化器。但是以下测试结果只是一个示意性质的,可以理解为在绝对理想的条件下(样本无噪音,损失函数平滑等等)的各算法的表现。
$$z = {x^2 \over 10} + y^2 \tag{1}$$
公式1是模拟均方差函数的形式,它的正向计算和反向计算的Python代码如下:
def f(x, y):
return x**2 / 10.0 + y**2
def derivative_f(x, y):
return x / 5.0, 2.0*y
我们依次测试4种方法:
每种方法都迭代20次,记录下每次反向过程的(x,y)坐标点,绘图如下:
下面我们用第四章线性回归的例子来做实际的测试。为什么要用线性回归的例子呢?因为在它只有w, b两个变量需要求解,可以在二维平面或三维空间来表现,这样我们就可以用可视化的方式来解释算法的效果。
下面列出了用Python代码实现的前向计算、反向计算、损失函数计算的函数:
def ForwardCalculationBatch(W,B,batch_x):
Z = np.dot(W, batch_x) + B
return Z
def BackPropagationBatch(batch_x, batch_y, batch_z):
m = batch_x.shape[1]
dZ = batch_z - batch_y
dB = dZ.sum(axis=1, keepdims=True)/m
dW = np.dot(dZ, batch_x.T)/m
return dW, dB
def CheckLoss(W, B, X, Y):
m = X.shape[1]
Z = np.dot(W, X) + B
LOSS = (Z - Y)**2
loss = LOSS.sum()/m/2
return loss
损失函数用的是均方差,回忆一下公式:
$$J(w,b) = {1 \over 2}(Z-Y)^2 \tag{2}$$
如果把公式2展开的话:
$$J = {1 \over 2} (Z^2 + Y^2 - 2ZY)$$
其形式比公式1多了最后一项,所以画出来的损失函数的等高线是斜向的椭圆。下面是画等高线的代码:
def show_contour(ax, loss_history, optimizer):
# draw w,b training history
ax.plot(loss_history.w_history, loss_history.b_history)
# read example data
X,Y = ReadData()
# generate w,b data grid array for 3D, w = x_axis, b = y_axis
w = np.arange(1, 3, 0.01)
b = np.arange(2, 4, 0.01)
W, B = np.meshgrid(w, b)
m = X.shape[1]
# calculate Z (z_axis)
Z = np.zeros((W.shape))
for i in range(Z.shape[0]):
for j in range(Z.shape[1]):
w = W[i,j]
b = B[i,j]
z = np.dot(w, X) + b
LOSS = (z - Y)**2
loss = LOSS.sum()/m/2
Z[i,j] = loss
#end for
#end for
# draw contour
ax.contour(W, B, Z, levels=np.logspace(-4, 4, 35), norm=LogNorm(), cmap=plt.cm.jet)
# set the drawing rectangle area
ax.axis([1, 3, 2, 4])
ax.set_xlabel("w")
ax.set_ylabel("b")
l,w,b,i = loss_history.GetLast()
ax.set_title(str.format("{0} loss={1:.4f} w={2:.2f} b={3:.3f} ite={4}", optimizer, l, w, b, i))
这里有个matplotlib的绘图知识:
SGD当学习率为0.1时,需要很多次迭代才能逐渐向中心靠近 | SGD当学习率为0.5时,会比较快速地向中心靠近,但是在中心的附近有较大震荡 |
由于惯性存在,一下子越过了中心点,但是很快就会得到纠正 | Nag是Momentum的改进,有预判方向功能 |
AdaGrad的学习率在开始时可以设置大一些,因为会很快衰减 | AdaDelta即使把学习率设置为0,也不会影响,因为有内置的学习率策略 |
RMSProp解决AdaGrad的学习率下降问题,即使学习率设置为0.1,收敛也会快 | Adam到达中点的路径比较直接 |
在上图中,观察4组优化器的训练轨迹:
为了能看清最后几步的行为,我们放大每张图,再看一下:
ch15, Level4