使用张量流逃避局部最小值
Escaping local minimum with tensorflow
我正在用 tensorflow 求解这个方程组:
f1 = y - x*x = 0
f2 = x - (y - 2)*(y - 2) + 1.1 = 0
如果我选择了错误的起点 (x,y)=(-1.3,2),那么我会使用以下代码进入局部最小值优化 f1^2+f2^2:
f1 = y - x*x
f2 = x - (y - 2)*(y - 2) + 1.1
sq=f1*f1+f2*f2
o = tf.train.AdamOptimizer(1e-1).minimize(sq)
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run([init])
for i in range(50):
sess.run([o])
r=sess.run([x,y,f1,f2])
print("x",r)
如何使用内置的 tensorflow 工具避开这个局部最小值?从这个坏点开始,我可以使用任何其他 TF 方法来求解这个等式吗?
Tensorflow (TF) 不包含内置的全局优化方法。根据初始化的不同,TF 中所有基于梯度的方法(例如 Adam)都可以收敛到非凸损失函数的局部最小值。由于在接近全局最小值时出现过度拟合问题,这对于大型神经网络来说通常是可以接受的(如果不希望的话)。
对于这个特定问题,您可能需要的是 scipy:
中的求根例程
https://docs.scipy.org/doc/scipy/reference/optimize.html#root-finding
暂时还没有tensorflow内置的全局优化方法。通过 ScipyOptimizerInterface
在 scipy 世界上打开了一个 window,但它(目前?)仅包装 scipy 的 minimize
,这是一个局部最小化器.
但是,您仍然可以将 tensorflow 的执行结果视为任何其他函数,可以将其提供给您选择的优化器。假设您想试用 scipy 的 basinhopping
全局优化器。你可以写
import numpy as np
from scipy.optimize import basinhopping
import tensorflow as tf
v = tf.placeholder(dtype=tf.float32, shape=(2,))
x = v[0]
y = v[1]
f1 = y - x*x
f2 = x - (y - 2)*(y - 2) + 1.1
sq = f1 * f1 + f2 * f2
starting_point = np.array([-1.3, 2.0], np.float32)
with tf.Session() as sess:
o = basinhopping(lambda x: sess.run(sq, {v: x}), x0=starting_point, T=10, niter=1000)
print(o.x)
# [0.76925635 0.63757862]
(我不得不调整 basinhopping
的温度和迭代次数,因为默认值通常不会让解决方案脱离此处作为起点的局部最小值盆地)。
通过将 tensorflow 视为优化器的黑盒,您失去的是后者无法访问由 tensorflow 自动计算的梯度。从这个意义上说,它不是最优的——尽管您仍然受益于 GPU 加速来计算您的函数。
编辑
由于您可以明确地向 basinhopping
使用的局部最小化器提供梯度,因此您可以输入 tensorflow 梯度的结果:
import numpy as np
from scipy.optimize import basinhopping
import tensorflow as tf
v = tf.placeholder(dtype=tf.float32, shape=(2,))
x = v[0]
y = v[1]
f1 = y - x*x
f2 = x - (y - 2)*(y - 2) + 1.1
sq = f1 * f1 + f2 * f2
sq_grad = tf.gradients(sq, v)[0]
init_value = np.array([-1.3, 2.0], np.float32)
with tf.Session() as sess:
def f(x):
return sess.run(sq, {v: x})
def g(x):
return sess.run(sq_grad, {v: x})
o = basinhopping(f, x0 = init_value, T=10.0, niter=1000, minimizer_kwargs={'jac': g})
print(o.x)
# [0.79057982 0.62501636]
出于某种原因,这比不提供梯度要慢得多 -- 然而可能是提供了梯度,最小化算法不一样,所以比较可能没有意义。
我正在用 tensorflow 求解这个方程组:
f1 = y - x*x = 0
f2 = x - (y - 2)*(y - 2) + 1.1 = 0
如果我选择了错误的起点 (x,y)=(-1.3,2),那么我会使用以下代码进入局部最小值优化 f1^2+f2^2:
f1 = y - x*x
f2 = x - (y - 2)*(y - 2) + 1.1
sq=f1*f1+f2*f2
o = tf.train.AdamOptimizer(1e-1).minimize(sq)
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run([init])
for i in range(50):
sess.run([o])
r=sess.run([x,y,f1,f2])
print("x",r)
如何使用内置的 tensorflow 工具避开这个局部最小值?从这个坏点开始,我可以使用任何其他 TF 方法来求解这个等式吗?
Tensorflow (TF) 不包含内置的全局优化方法。根据初始化的不同,TF 中所有基于梯度的方法(例如 Adam)都可以收敛到非凸损失函数的局部最小值。由于在接近全局最小值时出现过度拟合问题,这对于大型神经网络来说通常是可以接受的(如果不希望的话)。
对于这个特定问题,您可能需要的是 scipy:
中的求根例程https://docs.scipy.org/doc/scipy/reference/optimize.html#root-finding
暂时还没有tensorflow内置的全局优化方法。通过 ScipyOptimizerInterface
在 scipy 世界上打开了一个 window,但它(目前?)仅包装 scipy 的 minimize
,这是一个局部最小化器.
但是,您仍然可以将 tensorflow 的执行结果视为任何其他函数,可以将其提供给您选择的优化器。假设您想试用 scipy 的 basinhopping
全局优化器。你可以写
import numpy as np
from scipy.optimize import basinhopping
import tensorflow as tf
v = tf.placeholder(dtype=tf.float32, shape=(2,))
x = v[0]
y = v[1]
f1 = y - x*x
f2 = x - (y - 2)*(y - 2) + 1.1
sq = f1 * f1 + f2 * f2
starting_point = np.array([-1.3, 2.0], np.float32)
with tf.Session() as sess:
o = basinhopping(lambda x: sess.run(sq, {v: x}), x0=starting_point, T=10, niter=1000)
print(o.x)
# [0.76925635 0.63757862]
(我不得不调整 basinhopping
的温度和迭代次数,因为默认值通常不会让解决方案脱离此处作为起点的局部最小值盆地)。
通过将 tensorflow 视为优化器的黑盒,您失去的是后者无法访问由 tensorflow 自动计算的梯度。从这个意义上说,它不是最优的——尽管您仍然受益于 GPU 加速来计算您的函数。
编辑
由于您可以明确地向 basinhopping
使用的局部最小化器提供梯度,因此您可以输入 tensorflow 梯度的结果:
import numpy as np
from scipy.optimize import basinhopping
import tensorflow as tf
v = tf.placeholder(dtype=tf.float32, shape=(2,))
x = v[0]
y = v[1]
f1 = y - x*x
f2 = x - (y - 2)*(y - 2) + 1.1
sq = f1 * f1 + f2 * f2
sq_grad = tf.gradients(sq, v)[0]
init_value = np.array([-1.3, 2.0], np.float32)
with tf.Session() as sess:
def f(x):
return sess.run(sq, {v: x})
def g(x):
return sess.run(sq_grad, {v: x})
o = basinhopping(f, x0 = init_value, T=10.0, niter=1000, minimizer_kwargs={'jac': g})
print(o.x)
# [0.79057982 0.62501636]
出于某种原因,这比不提供梯度要慢得多 -- 然而可能是提供了梯度,最小化算法不一样,所以比较可能没有意义。