我想计算逻辑回归模型的对数似然函数。
def sigma(x): return 1 / (1 + np.exp(-x))def logll(y, X, w): """" Parameters y : ndarray of shape (N,) Binary labels (either 0 or 1). X : ndarray of shape (N,D) Design matrix. w : ndarray of shape (D,) Weight vector. """ p = sigma(X @ w) y_1 = y @ np.log(p) y_0 = (1 - y) @ (1 - np.log(1 - p)) return y_1 + y_0logll(y, Xz, np.linspace(-5,5,D))
应用这个函数会导致以下结果:
/opt/conda/lib/python3.6/site-packages/ipykernel_launcher.py:16: RuntimeWarning: divide by zero encountered in log app.launch_new_instance()
我期望y_0是一个负浮点数。我如何避免这个错误?代码中是否存在某个错误?
编辑1
X @ w 统计数据:Max: 550.775133944Min: -141.972597608Sigma(max): 1.0 => 在y_0中抛出错误,在np.log(1 - 1.0)中Sigma(min): 2.19828642169e-62
编辑2
我还可以访问这个logsigma函数,它在对数空间中计算sigma:
def logsigma (x): return np.vectorize(np.log)(sigma(x))
不幸的是,我找不到重写y_0的方法。以下是我的方法,但显然不正确。
def l(y, X, w): y_1 = np.dot(y, logsigma(X @ w)) y_0 = (1 - y) @ (1 - np.log(1 - logsigma(X @ w))) return y_1 + y_0
回答:
首先,我认为你在对数似然公式中犯了一个错误:它应该是y_0
和y_1
的简单求和,而不是指数的求和:
除以零的错误可能是由X @ w
中的大负值(我指的是绝对值很大)引起的,例如,在我的机器上sigma(-800)
正好是0.0
,因此对其取对数会导致"RuntimeWarning: divide by zero encountered in log"
。
确保你用接近零的小值初始化你的网络,并且在几次反向传播迭代后没有出现梯度爆炸。
顺便说一下,这是我用于交叉熵损失的代码,它也适用于多类问题:
def softmax_loss(x, y): """ - x: Input data, of shape (N, C) where x[i, j] is the score for the jth class for the ith input. - y: Vector of labels, of shape (N,) where y[i] is the label for x[i] and 0 <= y[i] < C """ probs = np.exp(x - np.max(x, axis=1, keepdims=True)) probs /= np.sum(probs, axis=1, keepdims=True) N = x.shape[0] return -np.sum(np.log(probs[np.arange(N), y])) / N
更新:当其他方法都无效时,还有一个数值技巧(在评论中讨论):计算log(p+epsilon)
和log(1-p+epsilon)
,其中epsilon
是一个小的正值。这样可以确保不会发生log(0.0)
的情况。