【问题标题】:Finding gradient of an unknown function at a given point in Python在Python中的给定点查找未知函数的梯度
【发布时间】:2018-05-18 08:56:44
【问题描述】:

我被要求在 python 中使用签名gradient(f, P0, gamma, epsilon) 编写梯度下降的实现,其中 f 是未知且可能是多元函数,P0 是梯度下降的起点,gamma 是恒定步长,epsilon 是停止标准。

我觉得棘手的是如何在不知道f 的任何内容的情况下评估fP0 处的梯度。我知道有numpy.gradient,但我不知道如何在我不知道f 的尺寸的情况下使用它。另外,numpy.gradient 使用函数的样本,那么如何在没有函数和点的任何信息的情况下选择正确的样本来计算某个点的梯度?

【问题讨论】:

  • 你可以试试有限差分法:en.wikipedia.org/wiki/Numerical_differentiation
  • 你写“如何选择......没有任何关于功能和点的信息?”,但你开始定义“P0是起点”
  • 是的,但如果我理解正确(我不确定)numpy.gradient 不会将函数作为参数,而是在某些点对函数进行采样以近似梯度。那么,每次我需要计算给定点的梯度时,我该如何选择一组通用的样本呢?以及如何用 Python 正确地做到这一点?
  • 我不清楚现在对该功能了解什么,不了解什么。它真的是数学意义上的函数吗?调用 function 的维度是否因调用而异?或者您的实现是否应该能够处理所有类型的先验已知维度?
  • 对不起,如果我不清楚。是的,它是一个数学函数,我只需要通用方法来计算它的梯度,因为我不知道它的维度。

标签: python numpy gradient gradient-descent


【解决方案1】:

我在这里假设So how can i choose a generic set of samples each time I need to compute the gradient at a given point? 的意思是,函数的维度是固定的,可以从您的起点推导出来。

考虑这是一个演示,使用 scipy 的 approx_fprime,这是一种更易于使用 wrapper-method 进行数值微分的方法,并且在需要 jacobian 时也用于 scipy 的优化器,但没有给出。

当然不能忽略参数epsilon,它可以根据数据有所不同。

(此代码也忽略了优化的 args 参数,这通常是个好主意;我使用的是 A 和 b 在此处范围内的事实;肯定不是最佳实践)

import numpy as np
from scipy.optimize import approx_fprime, minimize
np.random.seed(1)

# Synthetic data
A = np.random.random(size=(1000, 20))
noiseless_x = np.random.random(size=20)
b = A.dot(noiseless_x) + np.random.random(size=1000) * 0.01

# Loss function
def fun(x):
    return np.linalg.norm(A.dot(x) - b, 2)

# Optimize without any explicit jacobian
x0 = np.zeros(len(noiseless_x))
res = minimize(fun, x0)
print(res.message)
print(res.fun)

# Get numerical-gradient function
eps = np.sqrt(np.finfo(float).eps)
my_gradient = lambda x: approx_fprime(x, fun, eps)

# Optimize with our gradient
res = res = minimize(fun, x0, jac=my_gradient)
print(res.message)
print(res.fun)

# Eval gradient at some point
print(my_gradient(np.ones(len(noiseless_x))))

输出:

Optimization terminated successfully.
0.09272331925776327
Optimization terminated successfully.
0.09272331925776327
[15.77418041 16.43476772 15.40369129 15.79804516 15.61699104 15.52977276
 15.60408688 16.29286766 16.13469887 16.29916573 15.57258797 15.75262356
 16.3483305  15.40844536 16.8921814  15.18487358 15.95994091 15.45903492
 16.2035532  16.68831635]

使用:

# Get numerical-gradient function with a way too big eps-value
eps = 1e-3
my_gradient = lambda x: approx_fprime(x, fun, eps)

表明 eps 是一个关键参数,导致:

Desired error not necessarily achieved due to precision loss.
0.09323354898565098

【讨论】:

  • scipy.approx_fprime 正是我想要的!谢谢!但是为什么不每次都选择 epsilon 的最小浮点值呢?什么是好的通用 epsilon?
  • 我准确地说 所以每次我需要计算给定点的梯度时,我如何选择一组通用的样本? 是为numpy.gradient 而设计的需要函数的样本而不是可执行函数。我希望现在很清楚! ;)
  • 如果你先验地知道你需要什么样的精度,你可以使用更大的 epsilon。在其他情况下,是的,请关注this(我实际上并没有合并一些 sqrt)。
  • scipy.approx_fprime 是否也适用于将矩阵作为输入的函数?因为我收到这个错误:ValueError: operands could not be broadcast together with shapes (6,1682) (6,)
  • 仅限平面一维输入向量。这是 scipy 最小化模块中的核心设计决策!如果您的函数在矩阵上自然工作,您可以在它的第一行进行重塑。
猜你喜欢
  • 2020-08-03
  • 2020-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-14
相关资源
最近更新 更多