【问题标题】:scipy.optimize.fmin_bfgs single function computes both f and fprimescipy.optimize.fmin_bfgs 单个函数计算 f 和 fprime
【发布时间】:2017-07-06 13:19:30
【问题描述】:

我正在使用scipy.optimize.fmin_bfgs(f, init_theta, fprime) 来最小化f,它具有渐变fprime。我在一个函数中计算ffprime,因为大部分计算是相同的,所以不需要重复两次。

有什么方法可以调用fmin_bfgs(),指定一个同时返回ffprime 的函数?

【问题讨论】:

    标签: python optimization scipy gradient


    【解决方案1】:

    如果您想节省计算时间,而不是仅仅为了代码方便而将 ff' 的计算结合起来,那么您似乎需要一个额外的函数来缓存值,因为 fmin_bfgs似乎不允许您传递这样的函数(与其他一些优化函数不同)。

    这是一种方法,将最近评估的 10 个点保存在一个小缓存中。 (我不确定对这个函数的调用是否需要是线程安全的:可能不需要,但如果是这样,我猜你可能需要在这里添加一些锁定。)

    def func_wrapper(f, cache_size=10):
        evals = {}
        last_points = collections.deque()
    
        def get(pt, which):
            s = pt.tostring() # get binary string of numpy array, to make it hashable
            if s not in evals:
                evals[s] = f(pt)
                last_points.append(s)
                if len(last_points) >= cache_size:
                    del evals[last_points.popleft()]
            return evals[s][which]
    
        return functools.partial(get, which=0), functools.partial(get, which=1)
    

    如果我们这样做

    >>> def f(x):
    ...    print "evaluating", x
    ...    return (x-3)**2, 2*(x-3)
    
    >>> f_, fprime = func_wrapper(f)
    
    >>> optimize.fmin_bfgs(f_, 1000, fprime)
    evaluating [ 994.93480441]
    evaluating [ 974.67402207]
    evaluating [ 893.63089268]
    evaluating [ 665.93446894]
    evaluating [ 126.99931561]
    evaluating [ 3.]
    Optimization terminated successfully.
             Current function value: 0.000000
             Iterations: 4
             Function evaluations: 7
             Gradient evaluations: 7
    array([ 3.])
    

    我们可以看到我们没有重复任何评估。

    【讨论】:

    • 很好的实现!我想过尝试使用这种策略,但我不确定如何使数组可散列。另外,我希望 scipy.optimize 中已经内置了一个功能来处理这个问题。显然,其他人已经请求了该功能,因为它应该是 scipy 0.11 的一部分,该版本尚未发布。感谢您提供此设计模式!
    【解决方案2】:

    假设你有一个 Python 函数f(x),它返回函数值和梯度:

    In [20]: def f(x):
       ....:     return (x-3)**2, 2*(x-3)
    

    然后像这样单独传递输出:

    In [21]: optimize.fmin_bfgs(lambda x: f(x)[0], 1000, lambda x: f(x)[1])
    Optimization terminated successfully.
             Current function value: 0.000000
             Iterations: 4
             Function evaluations: 7
             Gradient evaluations: 7
    Out[21]: array([ 3.])
    

    【讨论】:

    • 这实际上并没有保存任何计算,它只是抛出了一个或另一个的结果。我猜这只有在 BFGS 经常同时要求函数值和梯度时才重要:我不熟悉算法,但似乎可能。
    • 没关系。 lambda x: f(x)[0]callable。这就是fmin_bfgs 需要的全部。它不关心该可调用对象的内部结构。
    • 是的:显然你的方法会奏效。但它会重复不必要的计算,这似乎是 OP 试图避免的。
    • 哦,我明白了。我将这一点解释为 f 包含函数和梯度共有的计算,而不是 fmin_bfgs 重复计算。
    • 这就是我现在的处理方式。我想节省计算。我注意到我正在寻找的功能在尚未发布的 scipy 0.11 中得到支持。
    【解决方案3】:

    似乎没有办法直接做到这一点。但是scipy.optimize.minimize 确实允许您这样做。您可以为 fprime 传递值 True 而不是函数。这表示 f 返回函数值和梯度的元组。您可以使用 method='BFGS' 调用minimize 以获得您想要的效果。

    看看the source code for minimize 很有启发性。 it 和 fmin_bfgs 最终都会调用 _minimize_bfgs,它将 f 和 fprime 作为单独的函数参数。当 fprime 是布尔值时,minimize 巧妙地将 fprime 构造为一个对象,该对象记住 f 返回的最后一个值,并缓存梯度信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-15
      • 1970-01-01
      • 2010-10-18
      • 2019-03-20
      • 1970-01-01
      • 1970-01-01
      • 2016-05-05
      • 1970-01-01
      相关资源
      最近更新 更多