【问题标题】:Vectorized Regularized Gradient Descent not passing numerical check向量化正则化梯度下降未通过数值检查
【发布时间】:2021-05-09 03:51:15
【问题描述】:

我已经用 Python 编写了一个实现,使用 NumPy 的矢量化正则化梯度下降进行逻辑回归。我使用了数字检查方法来检查我的实现是否正确。数值检查验证了我对线性回归 GD 的实现,但 Logisitc 失败了,我找不到。任何帮助,将不胜感激。所以这里是:

这些是我计算成本和梯度的方法(更新函数计算梯度并更新参数):

@staticmethod
def _hypothesis(parameters, features):
    return Activation.sigmoid(features.dot(parameters))

@staticmethod
def _cost_function(parameters, features, targets):
    m = features.shape[0]
    return np.sum(-targets * (np.log(LogisticRegression._hypothesis(parameters, features)) - (1 - targets) * (
        np.log(1 - LogisticRegression._hypothesis(parameters, features))))) / m

@staticmethod
def _update_function(parameters, features, targets, extra_param):
    regularization_vector = extra_param.get("regularization_vector", 0)
    alpha = extra_param.get("alpha", 0.001)
    m = features.shape[0]

    return parameters - alpha / m * (
        features.T.dot(LogisticRegression._hypothesis(parameters, features) - targets)) + \
           (regularization_vector / m) * parameters

成本函数不包含正则化,但我做的测试是正则化向量为零,所以没关系。我的测试方式:

def numerical_check(features, parameters, targets, cost_function, update_function, extra_param, delta):
gradients = - update_function(parameters, features, targets, extra_param)

parameters_minus = np.copy(parameters)
parameters_plus = np.copy(parameters)
parameters_minus[0, 0] = parameters_minus[0, 0] + delta
parameters_plus[0, 0] = parameters_plus[0, 0] - delta

approximate_gradient = - (cost_function(parameters_plus, features, targets) -
                          cost_function(parameters_minus, features, targets)) / (2 * delta) / parameters.shape[0]

return abs(gradients[0, 0] - approximate_gradient) <= delta

基本上,当我将第一个参数 delta 向左和向右移动时,我会手动计算梯度。然后我将它与从更新函数中获得的渐变进行比较。我使用的初始参数等于 0,因此接收到的更新参数等于梯度除以特征数。阿尔法也等于一。不幸的是,我从这两种方法中得到了不同的值,我不知道为什么。任何有关如何解决此问题的建议将不胜感激。

【问题讨论】:

  • 最后一行不应该是return abs(gradients[0, 0]...吗?
  • 另外,你真的不应该在最后一行的检查中重复使用delta。负数 delta 完全有效,但最后一行中的最后一个 delta 必须是正数(并且很小)。
  • 谢谢,保罗,是的,实际上是gradients[0, 0],这是复制过程中的错误。是的,我会在这里重新考虑使用 delta。
  • 看起来在我们看不到的地方有一个可变的默认值。顺便说一句,如果_update_function 属于LogisticRegression,它可能是classmethod,因为它诉诸~._hypothesis

标签: numpy machine-learning logistic-regression gradient-descent


【解决方案1】:

我想我在您的代码中发现了一个可能的错误,请告诉我这是不是真的。

在您的numerical_check 函数中,您正在调用update_function 来初始化gradient。但是,在上面的 _update_function 中,您实际上并没有返回渐变,而是返回了 parameters 的更新值。

也就是说,注意你的_update_function的return语句是这样的:

return parameters - alpha / m * (
    features.T.dot(LogisticRegression._hypothesis(parameters, features) - targets)) + \
       (regularization_vector / m) * parameters

我想建议您以及我在 ML 算法中所做的是创建一个单独的函数来计算梯度,例如

def _gradient(features, parameters, target):
    m = features.shape[0]
    return features.T.dot(LogisticRegression._hypothesis(parameters, features) - targets)) / m

然后更改您的numerical_check 函数以初始化gradient,如下所示:

gradient = _gradient(features, parameters, target)

我希望这能解决你的问题。

【讨论】:

  • 谢谢,我会编辑的。将梯度与更新分开。但在目前的情况下,并不是因为初始参数是零,所以我们更新参数的事实并不重要,我们仍然会在最后得到梯度。
  • 参数为零仍然不能消除正则化和乘以alpha 的效果,所以最后你必须创建一个单独的函数来获得gradient。如果这有帮助,请点赞并将其标记为正确,哈哈。
【解决方案2】:

您的成本函数有错误。错误是由于括号分配无效。我已经解决了

def _cost_function(parameters, features, targets):
    m = features.shape[0]
    
    return -np.sum(
        (    targets) * (np.log(    LogisticRegression._hypothesis(parameters, features)))
      + (1 - targets) * (np.log(1 - LogisticRegression._hypothesis(parameters, features)))
    ) / m

尝试干净利落地编写代码,这有助于检测此类错误

【讨论】:

  • 非常感谢!今晚我会试一试。希望它有效,我可以批准答案:)
猜你喜欢
  • 2020-03-23
  • 1970-01-01
  • 2014-01-11
  • 2014-01-11
  • 1970-01-01
  • 2017-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多