逻辑回归的 MLE 对数似然给出除以零的错误
MLE Log-likelihood for logistic regression gives divide by zero error
我想计算逻辑回归模型的对数似然。
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_0
logll(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 statistics:
Max: 550.775133944
Min: -141.972597608
Sigma(max): 1.0 => Throws error in y_0 in np.log(1 - 1.0)
Sigma(min): 2.19828642169e-62
编辑 2
我也可以访问这个计算 sigma 的 logsigma 函数 space:
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"
。
确保你用接近零的小值初始化你的网络,并且在多次反向传播迭代后你没有爆炸梯度。
顺便说一下,这是我用于交叉熵损失的代码,它也适用于多 class 问题:
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
UPD:当别无他法时,还有一个数字技巧(在评论中讨论):计算 log(p+epsilon)
和 log(1-p+epsilon)
具有较小的正 epsilon
值。这确保 log(0.0)
永远不会发生。
我想计算逻辑回归模型的对数似然。
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_0
logll(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 statistics:
Max: 550.775133944
Min: -141.972597608
Sigma(max): 1.0 => Throws error in y_0 in np.log(1 - 1.0)
Sigma(min): 2.19828642169e-62
编辑 2
我也可以访问这个计算 sigma 的 logsigma 函数 space:
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"
。
确保你用接近零的小值初始化你的网络,并且在多次反向传播迭代后你没有爆炸梯度。
顺便说一下,这是我用于交叉熵损失的代码,它也适用于多 class 问题:
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
UPD:当别无他法时,还有一个数字技巧(在评论中讨论):计算 log(p+epsilon)
和 log(1-p+epsilon)
具有较小的正 epsilon
值。这确保 log(0.0)
永远不会发生。