Scikit Learn 随机森林内存错误
我正在尝试在mnist手写数字数据集上运行scikit learn的随机森林算法。在训练算法的时候,系统出现了内存错误。请告诉我该如何解决这个问题。
CPU统计信息: 英特尔双核处理器,4GB内存
数据集的形状是60000, 784。在linux终端上显示的完整错误信息如下:
> File "./reducer.py", line 53, in <module>
> main() File "./reducer.py", line 38, in main
> clf = clf.fit(data,labels) #training the algorithm File "/usr/lib/pymodules/python2.7/sklearn/ensemble/forest.py", line 202,
> in fit
> for i in xrange(n_jobs)) File "/usr/lib/pymodules/python2.7/joblib/parallel.py", line 409, in
> __call__
> self.dispatch(function, args, kwargs) File "/usr/lib/pymodules/python2.7/joblib/parallel.py", line 295, in
> dispatch
> job = ImmediateApply(func, args, kwargs) File "/usr/lib/pymodules/python2.7/joblib/parallel.py", line 101, in
> __init__
> self.results = func(*args, **kwargs) File "/usr/lib/pymodules/python2.7/sklearn/ensemble/forest.py", line 73, in
> _parallel_build_trees
> sample_mask=sample_mask, X_argsorted=X_argsorted) File "/usr/lib/pymodules/python2.7/sklearn/tree/tree.py", line 476, in fit
> X_argsorted=X_argsorted) File "/usr/lib/pymodules/python2.7/sklearn/tree/tree.py", line 357, in
> _build_tree
> np.argsort(X.T, axis=1).astype(np.int32).T) File "/usr/lib/python2.7/dist-packages/numpy/core/fromnumeric.py", line
> 680, in argsort
> return argsort(axis, kind, order) MemoryError
4 个回答
请用一棵树来训练随机森林,并检查这棵树的深度。默认情况下,scikit-learn会生成完整的树。树的深度可能会非常大,所以即使森林里只有几棵树,也会占用很多内存。你可以尝试使用max_depth
这个参数来限制树的深度。
我做了一个实验,把树的深度从42(森林中树的平均深度)减少到6。结果内存减少了66倍,而性能稍微提升了大约4%。
一个解决办法是使用最新版本的scikit-learn(0.19)。在更新日志中,他们在修复错误的部分提到了一些重要的改进:
Fixed excessive memory usage in prediction for random forests estimators. #8672 by Mike Benfield.
你可以通过以下方式安装这个版本:
pip3 install scikit-learn==0.19.0
Scikit-learn开发团队在内存管理和性能上有了很大改善
尊重其他人的观点,但scikit-learn 0.16.1
并没有像早期版本那样存在令人不快的X
和y
的重复问题。
由于一些其他原因,我花了相当长的时间研究RandomForestRegressor()
的超参数,包括它们的内存占用问题。
在0.16.1
版本中,使用并行处理时,内存需求的增加不到2%,从默认的n_jobs = 1
增加到{ 2, 3, ... }
。
最近的scikit-learn
版本的共同创始人@glouppe发布了一份精彩且富有洞察力的演示文稿(2014年8月,版本0.15.0),其中包括与基于R的其他已知随机森林框架的比较。
在我看来,演示文稿的第25页及以后讨论了一些提高速度的技术,包括np.asfortranarray(...)
,但这些看起来(没有任何实验证明)更像是Scikit-learn开发团队内部共享的方向,而不是给我们这些生活在“外部世界”的普通人的建议。
回归还是分类?
这个问题很重要。如果没有进行全面的特征集向量袋装,可能需要一些额外的特征工程工作和测试。你的学习器似乎是分类器,所以可以深入研究:
- 尝试非默认设置的
max_features
等参数 - 如果在调整学习器后需要,可以使用操作系统服务来处理更大的虚拟内存,使用
mkswap
和swapon
。
附录
经过另一轮测试,出现了一个有趣的观察。
当使用.set_params( n_jobs = -1 ).fit( X, y )
配置成功训练RandomForestRegressor()
后,后来在尝试使用.predict( X_observed )
时却遇到了意外的问题。
在这里,报告了一个类似的内存问题(现在是0.17.0版本)。
不过,使用.set_params( n_jobs = 1 ).predict( X_observed )
的单线程工作在.predict()
上表现良好。
要么把 n_jobs=1
设置成1,要么升级到最新的scikit-learn版本。现在发布的版本使用多个进程来同时训练树模型,这就意味着数据(X
和y
)需要被复制到这些进程里。下一个版本会改用线程而不是进程,这样树模型的学习者就可以共享内存了。