加速sklearn逻辑回归算法

18

我正在使用sklearn中的LogisticRegression构建一个模型,该模型具有数千个特征和大约60,000个样本。我正在尝试拟合该模型,目前已经运行了约10分钟。我的计算机可用几个内核和千兆字节的RAM,请问是否有任何方法可以加快这个过程。

编辑 这台计算机有24个内核,以下是顶部输出的结果,以提供内存使用情况的想法。

Processes: 94 total, 8 running, 3 stuck, 83 sleeping, 583 threads      20:10:19
Load Avg: 1.49, 1.25, 1.19  CPU usage: 4.34% user, 0.68% sys, 94.96% idle
SharedLibs: 1552K resident, 0B data, 0B linkedit.
MemRegions: 51959 total, 53G resident, 46M private, 676M shared.
PhysMem: 3804M wired, 57G active, 1042M inactive, 62G used, 34G free.
VM: 350G vsize, 1092M framework vsize, 52556024(0) pageins, 85585722(0) pageouts
Networks: packets: 172806918/25G in, 27748484/7668M out.
Disks: 14763149/306G read, 26390627/1017G written.

我正在尝试使用以下内容来训练模型

classifier = LogisticRegression(C=1.0, class_weight = 'auto')
classifier.fit(train, response)

train有大约3000行数据(全是浮点数),而在response中,每行数据只有0或1两个取值。我有大约50000个观测值。


这么长时间让人感到惊讶。你确定你已经正确设置了你的模型吗? - agconti
你的特征向量大小是多少? - Madison May
2
你能在你的机器上发布一些真实的统计数据吗?1GB和8GB RAM之间的差别非常大,2个核心和8个核心之间的差别也很大。更不用说当谈论单核小于1GB的进程时,这两者都不是非常相关的。 - Slater Victoroff
我已经进行了一些编辑,以解决这些评论。我展示了RAM的顶部输出,只是因为我不是唯一使用该机器的人,所以并不总是能够访问所有物理内存,但看起来我应该有足够的内存。 - sedavidw
5个回答

17

更新 - 2017:

在scikit-learn的当前版本中,LogisticRegression()现在具有n_jobs参数以利用多个核心。

然而,用户指南的实际文本表明,在计算的后半部分仍然只使用了多个核心。截至本次更新,LogisticRegression的修订用户指南现在表示njobs选择“交叉验证循环期间使用的CPU核心数”,而原始回答中引用的另外两个项目,RandomForestClassifier()RandomForestRegressor(),都说明njobs指定“要并行运行的拟合和预测作业数量”。换句话说,这里故意采用对比措辞似乎是在指出,LogisticRegression()中的njobs参数虽然已经实现,但并没有像在其他两种情况下那样完全实现或以相同的方式实现。

因此,虽然现在可能可以通过使用多个核来加速LogisticRegression(),但我的猜测是,它可能不会与使用的核心数量成线性关系,因为听起来初始的“拟合”步骤(算法的前一半)可能不太适合并行化。

原始回答:

在我看来,主要问题不是内存,而是你只使用了一个核心。根据top命令,你的系统负载为4.34%。如果你的逻辑回归过程占用了24个核心中的1个核心,那么就相当于100/24 = 4.167%。剩余的0.17%可能是其他进程在机器上运行所占用的资源,它们被系统调度在第二个不同的核心上并行运行。

如果你点击下面的链接并查看scikit-learn API,你会发现一些集成方法比如RandomForestClassifier()RandomForestRegressor()有一个名为n_jobs的输入参数,它直接控制着该软件包尝试在哪些核心上并行运行。你正在使用的类LogisticRegression()没有定义这个输入参数。scikit-learn的设计者似乎创建了一个界面,对于不同的类之间是相当一致的,因此,如果某个特定的输入参数没有为给定的类定义,那么这可能意味着开发人员根本找不到一种有意义的方式来实现该选项。也许逻辑回归算法只是不太适合并行化;即,可以实现的潜在加速效果并不足以证明使用并行架构去实现它是有意义的。
假设情况确实如此,那么不,你并没有太多办法让代码运行更快。如果底层库函数本身就无法利用这些核心,那么24个核心也无济于事。

我想我原本希望可以实现并行化,但看起来你是正确的,这样做没有好的方法。我会研究其他分类形式。 - sedavidw

12

在sklearn中,LogisticRegression的默认求解器为liblinear,适用于普通数据集。对于大型数据集,请尝试使用随机梯度下降求解器,如sag

model = LogisticRegression(solver='sag')

牛顿平方法呢,它更快吗? - Rocketq

12

尝试减少数据集大小并更改容差参数。例如,您可以尝试 classifier = LogisticRegression(tol = 0.1)


9
值得注意的是,现在LogisticRegression()接受num_jobs作为输入并默认为1。
我本想对已被接受的答案进行评论,但积分不足。

2
尝试更改您的求解器。 文档 表明,Scikit-learn有5种不同的求解器可供使用('liblinear'、'sag'、'saga'、'newton-cg'和'lbfgs')。
对于小数据集,“liblinear”(曾是默认设置)是一个很好的选择,而对于大数据集,“sag”和“saga”更快。
对于多类问题,只有“newton-cg”、“sag”、“saga”和“lbfgs”处理多项式损失;“liblinear”仅限于一对多方案。
import time
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

# Set training and validation sets
X, y = make_classification(n_samples=1000000, n_features=1000, n_classes = 2)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=10000)

# Solvers
solvers = ['liblinear', 'newton-cg', 'sag', 'saga', 'lbfgs']

for sol in solvers: 
    start = time.time()
    logreg = LogisticRegression(solver=sol)
    logreg.fit(X_train, y_train)
    end = time.time()
    print(sol + " Fit Time: ",end-start)

输出结果(来自16GB 4核MacBook):

enter image description here

选择正确的求解器可以节省很多时间(代码改编自此处)。要确定哪个求解器适合您的问题,您可以查看文档中的表格以了解更多信息。

solver table

此外,由于您不进行多类分类,因此您的模型可能无法很好地并行化。根据scikit-learn文档,如果multi_class='ovr',n_jobs是在对类别进行并行化时使用的CPU核心数。

2
有多大才算大?是指特征数量还是观测数量?文档似乎没有明确说明。 - Nuclear03020704
虽然这可能不是一个有用的答案,但我认为如果训练时间太长,那么大模型可能会更好。即使是在使用liblinear进行MNIST的情况下,它也需要2893.1秒才能以91.45%的准确率运行(参考链接:https://towardsdatascience.com/logistic-regression-using-python-sklearn-numpy-mnist-handwriting-recognition-matplotlib-a6b31e2b166a)。当solver = lbfgs时,只需52.86秒即可获得91.3%的准确率。 - Michael James Kali Galarnyk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接