为什么在此示例中,kerasSGDOptimizer.minimize不能达到全局最小值?

问题描述

我正在通过DataCamp完成TensorFlow教程,并且正在转录/复制我在自己的Jupyter笔记本中正在处理的代码示例。

以下是编码问题的原始说明:

enter image description here

我正在运行以下代码段,但无法获得与在教程中生成的结果相同的结果,通过连接的散点图x vs. loss_function(x),我确认该结果是正确的值如下所示。

# imports
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow import Variable,keras

def loss_function(x):
    import math
    return 4.0*math.cos(x-1)+np.divide(math.cos(2.0*math.pi*x),x)

# Initialize x_1 and x_2
x_1 = Variable(6.0,np.float32)
x_2 = Variable(0.3,np.float32)

# Define the optimization operation
opt = keras.optimizers.SGD(learning_rate=0.01)

for j in range(100):
    # Perform minimization using the loss function and x_1
    opt.minimize(lambda: loss_function(x_1),var_list=[x_1])
    # Perform minimization using the loss function and x_2
    opt.minimize(lambda: loss_function(x_2),var_list=[x_2])

# Print x_1 and x_2 as numpy arrays
print(x_1.numpy(),x_2.numpy())

我绘制了一个快速连接的散点图,以确认(成功)我使用的损失函数使我回到示例提供的同一图形(如上图所示)

# Generate loss_function(x) values for given range of x-values
losses = []
for p in np.linspace(0.1,6.0,60):
    losses.append(loss_function(p))

# Define x,y coordinates
x_coordinates = list(np.linspace(0.1,60))
y_coordinates = losses

# Plot
plt.scatter(x_coordinates,y_coordinates)
plt.plot(x_coordinates,y_coordinates)
plt.title('Plot of Input values (x) vs. Losses')
plt.xlabel('x')
plt.ylabel('loss_function(x)')
plt.show()     

enter image description here

分别是根据DataCamp环境得出的全局最小值和局部最小值:

enter image description here

4.38 是正确的全局最小值,并且 0.42 实际上对应于图形上的第一个局部最小值RHS(从x_2 = 0.3开始)

这是我的环境所产生的结果,两者都与试图最小化损失值时应朝的方向相反:

enter image description here

在过去90分钟的大部分时间里,我一直在努力弄清为什么我的结果与DataCamp控制台的结果不一致/为什么对于这个简单的玩具示例,优化器无法将这种损失降到最低...?

在您自己的环境中运行所提供的代码后,您可能会有任何建议,我非常感谢!

解决方法

事实证明,输出的差异是由默认精度tf.division()(vs np.division())和tf.cos()(vs math.cos())引起的。在loss_function()的定义中(我转录为“自定义”)指定。

loss_function()已在本教程的主体中预定义,当我使用 inspect包(使用inspect.getsourcelines(loss_function))“检查”它时,可以在我的本机中重新定义它。在自己的环境中,上述检查的输出未明确表明已使用tf.division&tf.cos代替了其NumPy对应版本(我的代码版本已使用过)。

实际差异很小,但显然足以将优化器推向相反的方向(远离两个各自的最小值)。

交换了tf.division()和tf.cos(如下所示)后,我能够获得与DC控制台相同的结果。

以下是loss_function的代码,它将返回与控制台中显示的相同结果(屏幕截图):

def loss_function(x):
    import math
    return 4.0*tf.cos(x-1)+tf.divide(tf.cos(2.0*math.pi*x),x)