我正在尝试在Python中实现softmax熵损失的梯度。但是,我可以看到解析梯度与数值梯度不匹配。这是我的 Python 代码:
import numpy as np
def softmax(z):
expp = np.exp(z)
return np.divide(expp, np.sum(expp))
def cost(z, y):
s = softmax(z)
return -np.sum(y * np.log(s)) / len(y)
def costprime(z, y):
prime = []
for i in range(len(z)):
values = z.copy()
values[i] += 1.0e-10
prime.append((cost(values, y) - cost(z, y)) / 1.0e-10)
return prime
z = np.array([1.1, 2.2, 0.3, -1.7])
y_expected = np.array([0, 0, 1, 0])
s = softmax(z)
cost_gradient = s - y_expected
numerical_derivative = costprime(z, y_expected)
print(cost_gradient)
print(numerical_derivative)
结果是:
[0.22151804 0.66547696 -0.90046553 0.01347053]
[0.05538014491435206, 0.16636914068612896, -0.2251154818111445, 0.0033673064336881]
它们看起来非常不同。然而,当我尝试更改 z 的值以查看它们对成本的影响时,我发现数值导数比解析导数 (cost_gradient) 更准确
您需要从 z 的其余部分中减去最大值以获得数值稳定性
expp = np.exp(z - np.max(z))
return expp / np.sum(expp)
由于 softmax 函数使用指数,您可以获得超出浮点表示容量的值。
通过减去数组中的最大值,可以消除这个问题,同时保持相对值。为了避免这些问题,我们可以在应用指数函数之前从所有元素中减去向量 z 的最大值。这个技巧确保所有输入值都移向零,防止溢出,同时保持分数之间正确的相对差异。