我必须实现一个等效函数来计算逻辑损失的 hessian 矩阵,将其写为指数项对数之和。我在Python中实现了以下功能:
def hessian(self,w,hess_trick=0):
hess = 0
for x_i,y_i in zip(self.data, self.labels):
hess += np.exp(y_i * np.dot(w.T, x_i))/((1 + np.exp(y_i * np.dot(w.T,x_i)))**2) * np.outer(x_i,x_i.T)
return hess + lambda_reg * np.identity(w.shape[0]) + hess_trick * 10**(-12) * np.identity(w.shape[0])
我的问题是如何在不使用慢速 python 的情况下编写等效但更快的函数?
由于我对 numpy 不太有信心,我尝试编写以下函数:
def new_hessian(self, w, hess_trick=0):
exp_term = np.exp(self.labels * np.dot(self.data, w))
sigmoid_term = 1 + exp_term
inv_sigmoid_sq = 1 / sigmoid_term ** 2
diag_elements = np.sum((exp_term * inv_sigmoid_sq)[:, np.newaxis] * self.data ** 2, axis=0)
off_diag_elements = np.dot((exp_term * inv_sigmoid_sq) * self.data.T, self.data)
hess = np.diag(diag_elements) + off_diag_elements
regularization = lambda_reg * np.identity(w.shape[0])
hess += hess_trick * 1e-12 * np.identity(w.shape[0])
return hess + regularization
通过调试这个函数,我发现有一个根本性的问题。对于特征数量较小的值(例如小于 200),hessian 的两种实现不相等。当我增加特征数量时,这两个函数似乎是相等的。问题是,当使用牛顿方法测试这些实现来优化对数损失时,更快的实现比第一个实现在更多迭代中收敛(但在运行时速度上更慢)。
这是其矢量化版本:
a = np.exp(y[:,None] * X @ w)[:,None]
b = np.sqrt(a)*X/(1 + a)
b.T @ b