【问题标题】:Gradient for log regression loss对数回归损失的梯度
【发布时间】:2020-02-29 17:48:44
【问题描述】:

我正在尝试为日志回归编写小批量梯度下降。

给定 numpy 矩阵 X_batch(形状为 (n_samples, n_features))和 y_batch(形状为 (n_samples,))。

天真的方法是写循环:

def calc_loss_grad(self, X_batch, y_batch):
    n_samples, n_features = X_batch.shape
    loss_grad = np.zeros((n_features,))
    for i in range(n_samples):
        sigm = sigmoid(X_batch[i] @ self.weights)
        loss_grad += - (y_batch[i] - sigm) * X_batch[i]            
    return loss_grad

但似乎使用循环是一个坏主意 w.r.t.速度。还有更好的方法吗?没有循环的纯numpy?以某种方式重写梯度表达式?

【问题讨论】:

  • n_samples、n_features 通常有多大? weights 的大小为 n_features 对吗?
  • 是什么让你说“使用 [a] 循环在速度方面是个坏主意”?你的问题是这段代码工作正常吗,它似乎在你的计算机上运行缓慢(在这种情况下,这可能属于codereview.stackexchange.com)?或者您是否遇到了基本的复杂性问题,您拥有的输入元素越多,循环似乎变得越来越慢?要么...? (基本上:不要谈论看起来,谈论。你要解决的真正问题是什么?)
  • @max9111 我会说大约 10^5 个样本,少一些特征。
  • @Mike 它的运行速度比它可以运行的慢。 (至少与 sklearn 实现相比)。我认为这更多的是数学问题,如何以矩阵形式重写表达式,所以它只能在 numpy 操作中编码。
  • 能否也提供sklearn的实现进行比较?

标签: gradient-descent sgd gradient numpy


【解决方案1】:

请注意,此算法受内存带宽限制。如果您在更大的上下文(实际应用程序)中对此进行优化,则很可能会获得更高的加速。

示例

import numpy as np

#https://stackoverflow.com/a/29863846/4045774
def sigmoid(x):  
    return np.exp(-np.logaddexp(0, -x))

def calc_loss_grad_1(weights, X_batch, y_batch):
    n_samples, n_features = X_batch.shape
    loss_grad = np.zeros((n_features,))
    for i in range(n_samples):
        sigm = sigmoid(X_batch[i,:] @ weights)
        loss_grad += - (y_batch[i] - sigm) * X_batch[i]            
    return loss_grad

def calc_loss_grad_2(weights, X_batch, y_batch):
    sigm =-y_batch+sigmoid(X_batch@weights)          
    return sigm@X_batch

weights=np.random.rand(n_features)
X_batch=np.random.rand(n_samples,n_features)
y_batch=np.random.rand(n_samples)

#n_samples=int(1e5)
#n_features=int(1e4)
%timeit res=calc_loss_grad_1(weights, X_batch, y_batch)
#1.79 s ± 35.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res=calc_loss_grad_2(weights, X_batch, y_batch)
#539 ms ± 21.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

#n_samples=int(1e3)
#n_features=int(1e2)
%timeit res=calc_loss_grad_1(weights, X_batch, y_batch)
#3.68 ms ± 44.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit res=calc_loss_grad_2(weights, X_batch, y_batch)
#49.1 µs ± 503 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 

【讨论】:

    猜你喜欢
    • 2016-11-29
    • 2020-08-25
    • 2016-07-01
    • 2019-03-12
    • 1970-01-01
    • 2021-01-18
    • 2020-07-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多