计算梯度使用时出错 python

error in calculating gradient use python

我用下面的公式计算梯度

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?

你的代码的问题出在下面的行组合上(我展示了fx_addh的例子,fx_minush的情况类似

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

您正在将 f(x) 的结果放入 fx_addh。但问题是您定义 f(x) 的方式只是 lin(x) 的句柄,您是在直接 return 参数。

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

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

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

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)

哪个 returns:

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

如您所料,表示 1 的梯度。

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

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

结果:

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