You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何scikit-learn的LogisticRegression不采用更快的列主序系数存储?

问题

在处理带有大量稀疏特征(文档TF-IDF向量)的多分类任务时,使用LogisticRegression并升级scikit-learn新版本后,推理性能大幅下降。性能分析显示,推理阶段的两次ravel调用占用了大量时间。发现将coef_矩阵转为列主序(用np.asfortranarray)后可恢复性能,且该问题仅在输入为稀疏矩阵时出现。

想知道:

  • 是否有方法让行主序下的推理达到最优性能?
  • 是否有scikit-learn参数可以让模型采用列主序存储,避免推理时的ravel调用?

示例代码

import scipy
import numpy as np

from sklearn.linear_model import LogisticRegression

X = np.random.rand(10_000, 10_000)
y = np.random.randint(0, 500, size=10_000)
clf = LogisticRegression(max_iter=10).fit(X, y)

%timeit clf.predict_proba(scipy.sparse.rand(1, 10_000))
# 21.9 ms ± 973 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%prun
#   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
#        2    0.019    0.010    0.019    0.010 {method 'ravel' of 'numpy.ndarray' objects}
#        1    0.003    0.003    0.022    0.022 _compressed.py:493(_mul_multivector)

clf.coef_ = np.asfortranarray(clf.coef_)

%timeit clf.predict_proba(scipy.sparse.rand(1, 10_000))
# 467 µs ± 11 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

%prun clf.predict_proba(scipy.sparse.rand(1, 10_000))
#   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
#        1    0.000    0.000    0.000    0.000 {built-in method scipy.sparse._sparsetools.csr_matvecs}
#        1    0.000    0.000    0.000    0.000 {method 'choice' of 'numpy.random.mtrand.RandomState' objects}
解决方案与分析

1. 行主序下优化推理性能的方案

转置输入矩阵会带来额外内存和计算开销,不推荐。更高效的方式包括:

  • 固定稀疏矩阵格式:确保输入为CSR格式(scikit-learn默认推荐),并提前调用.sorted_indices()方法让索引有序,减少内部运算的额外开销。
  • 手动实现简化推理逻辑:跳过scikit-learn内部触发ravel的冗余步骤,直接计算X @ clf.coef_.T + clf.intercept_,再应用softmax得到概率,绕开原代码中对数组形状的强制调整。

2. 让模型默认采用列主序存储coef_

目前scikit-learn没有直接参数控制coef_的存储顺序,因为训练阶段的优化器默认采用行主序布局。但可以通过两种方式间接实现:

  • 训练后一键转换:训练完成后执行clf.coef_ = np.asfortranarray(clf.coef_),该操作仅修改数组内存视图,不复制数据,几乎无额外开销。
  • 自定义模型包装:封装LogisticRegression子类,在fit方法结束后自动将coef_转为列主序,省去手动操作步骤。

3. 性能差异的根本原因

当coef_为行主序时,scikit-learn处理稀疏矩阵乘法会先将其通过ravel转为一维数组,再调用_mul_multivector,这个过程会触发大内存块的连续化复制,对高维度coef_(如500类×10000特征)来说开销极大。而列主序的coef_可直接与CSR稀疏矩阵调用底层csr_matvecs函数完成高效乘法,无需额外数组转换,因此性能提升显著。

内容的提问来源于stack exchange,提问作者Max Russek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 13:01:07