使用 Scipy 检查梯度

问题描述 投票:0回答:2

我想使用

scipy.optimize.check_grad
来检查我实现的 sigmoid 函数的梯度;这是我的 Python 函数:

def sigmoid(x, gradient=False):
    y = 1 / (1 + numpy.exp(-x))
    return numpy.multiply(y, 1 - y) if gradient else y

这里是参数和对

check_grad
的调用:

x0 = numpy.random.uniform(-30, 30, (4, 5))
func = sigmoid
grad = lambda x: sigmoid(x, gradient=True)
error = scipy.optimize.check_grad(func, grad, x0)

我收到以下错误。形状不匹配是指操作

xk+d
。知道是什么原因造成的吗?

文件“scipy\optimize\optimize.py”,第 597 行,在 approx_fprime
梯度[k] = (f(*((xk+d,)+args)) - f0) / d[k]
ValueError:操作数无法与形状 (4,5) (4) 一起广播

python math scipy gradient
2个回答
2
投票

您收到的错误是因为

check_gradient
只接受平面点数组。如果您使用形状为
x0
的数组
(20,)
而不是
(4, 5)
,它应该可以工作。但事实并非如此!

这是

approx_fprime
在我的安装中的实现(
scipy.__version__ = '0.9.0'
):

def approx_fprime(xk,f,epsilon,*args):
    f0 = f(*((xk,)+args))
    grad = numpy.zeros((len(xk),), float)
    ei = numpy.zeros((len(xk),), float)
    for k in range(len(xk)):
        ei[k] = epsilon
        grad[k] = (f(*((xk+ei,)+args)) - f0)/epsilon
        ei[k] = 0.0
    return grad

我已经看过好几次了,发现很难相信这样残暴的代码可能在 scipy 发行版中,确信我一定错过了一些东西......但我担心这是错误的。如果将其替换为:

def approx_fprime(xk,f,epsilon,*args):
    return (f(*((xk + epsilon,) + args)) - f(*((xk,) + args))) / epsilon

它现在对我有用。通过

x0.shape = (20,)
我得到:

In [2]: error
Out[2]: 1.746097524556073e-08

还有

x0.shape = (4, 5)

In [4]: error
Out[4]: 
array([  1.03560895e-08,   1.45994321e-08,   8.54143390e-09,
         1.09225833e-08,   9.85988655e-09])

所以看来其他地方的非平面数组也确实还没有准备好。但无论如何,实现都非常糟糕:您应该提交错误报告。


0
投票

关于你的代码(需要 Vectorization - 如果你确实需要 - 做 flatten()ravel()):

import numpy as np
from scipy import optimize

x = np.array(np.random.uniform(-30, 30, (4, 5)))

def sigmoid_obj(xx, gradient= False):
        print(xx)
        x= np.array(xx).ravel()     # to vectorize further
        y = 1 / (1 + np.exp(-1*x))
        res= np.multiply(y, 1 - y) if gradient else y
        return sum(res)

eps = np.sqrt(np.finfo(float).eps)

def num_gradient(x):
        return optimize.approx_fprime(x.ravel(), sigmoid_obj, eps)  # to vectorize

error = optimize.check_grad(sigmoid_obj, num_gradient, x.ravel() )  # to vectorize
print(error)

但通常,

objective_func
仅用于一个
x_point
投影到
y_target
,从
x0=guess
开始优化。在最简单的代码版本中:

import numpy as np
from scipy import optimize

def sigmoid_obj(x, gradient=False):
    y = 1 / (1 + np.exp(-1*x))
    res= np.multiply(y, 1 - y) if gradient else y
    return res

def num_gradient(x):
    return optimize.approx_fprime(x, sigmoid_obj, eps)

x = np.array(np.random.uniform(-30, 30, (4, 5)))
x0= [0,]        # guess !! var(s) used in objective_func

eps = np.sqrt(np.finfo(float).eps)

error = optimize.check_grad(sigmoid_obj, num_gradient, x0 )
print(error)

但是你的输入形状即使是

(0,0(0,0))
也会引发
ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (3,) + inhomogeneous part
。无论如何,你最好在优化之前转换你的特征数组。

附注

optimize.check_grad()
内部使用
optimize.approx_fprime()
,最新的计算为一个点...或者可以通过分析计算它(使用SymPy或手动,如文档示例中所示): 将 numpy 导入为 np 从 scipy 导入优化

def func(x):
    return x[0]**2 - 0.5 * x[1]**3
def grad(x):
    return [2 * x[0], -1.5 * x[1]**2]
from scipy.optimize import check_grad
print(check_grad(func, grad, [1.5, -1.5]))
© www.soinside.com 2019 - 2024. All rights reserved.