计算梯度使用python时出错

时间:2016-10-28 07:48:27

标签: python-2.7 gradient

我使用以下formule来计算渐变

gradient = [f(x+h) - f(x-h)] / 2h

我用线性函数测试它,但是出了点问题。 代码在这里:

import numpy as np

def evla_numerical_gradient(f, x):

    gradient = np.zeros(x.shape, dtype=np.float64)
    delta_x = 0.00001

    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])

    while not it.finished:
        index = it.multi_index
        x_old = x[index]

        x[index] = x_old + delta_x
        fx_addh = f(x)
        print(fx_addh)

        x[index] = x_old - delta_x
        fx_minush = f(x)
        print(fx_minush)

        x[index] = x_old

        print((fx_addh - fx_minush) / (2 * delta_x))
        gradient[index] = (fx_addh - fx_minush) / (2. * delta_x)

        it.iternext()

    return gradient


def lin(x):
    return x

if __name__ == '__main__':
    x = np.array([0.001])
    grad = evla_numerical_gradient(lin, x)
    print(grad)

结果在这里:

[ 0.00101]
[ 0.00099]
[ 0.]
[ 0.]

为什么x处的梯度为0?

2 个答案:

答案 0 :(得分:0)

您的代码存在以下行的组合问题(我展示了fx_addh的示例,fx_minush的情况类似

fx_addh = f(x)
x[index] = x_old

您要将f(x)的结果放入fx_addh。但问题是你定义f(x)的方式,它只是你lin(x)的句柄,你直接返回参数。

在Python赋值操作中,不要复制对象,而是在目标(赋值=左侧)和对象(赋值=右侧)之间创建绑定。有关here的更多信息。

为了说服自己发生这种情况,您可以在设置print(fx_addh)的行之后放置另一个x[index] = x_old;你会看到它现在包含零值。

要解决此问题,您可以修改lin(x)函数以返回作为参数传入的对象的副本:

import numpy as np
import copy

def evla_numerical_gradient(f, x):

    gradient = np.zeros(x.shape, dtype=np.float64)
    delta_x = 0.00001

    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])

    while not it.finished:
        index = it.multi_index
        x_old = x[index]

        x[index] = x_old + delta_x
        fx_addh = f(x)
        print(fx_addh)

        x[index] = x_old - delta_x
        fx_minush = f(x)
        print(fx_minush)

        x[index] = x_old

        print((fx_addh - fx_minush) / (2 * delta_x))
        gradient[index] = (fx_addh - fx_minush) / (2. * delta_x)

        it.iternext()

    return gradient


def lin(x):
    return copy.copy(x)

if __name__ == '__main__':
    x = np.array([0.001])
    grad = evla_numerical_gradient(lin, x)
    print(grad)

返回:

[ 0.00101]
[ 0.00099]
[ 1.]
[ 1.]

按照您的预期指示1的渐变。

答案 1 :(得分:0)

因为fx_addhfx_minush指向内存的相同索引。将lin函数更改为:

def lin(x):
    return x.copy()

结果:

[ 0.00101]
[ 0.00099]
[ 1.]
[ 1.]