scikit-learn joblib 错误:多处理池 self.value 超出“i”格式代码的范围,仅适用于大型 numpy 数组
Posted
技术标签:
【中文标题】scikit-learn joblib 错误:多处理池 self.value 超出“i”格式代码的范围,仅适用于大型 numpy 数组【英文标题】:scikit-learn joblib bug: multiprocessing pool self.value out of range for 'i' format code, only with large numpy arrays 【发布时间】:2014-08-15 21:56:27 【问题描述】:我的代码在较小的测试样本上运行良好,例如 X_train
、y_train
中的 10000 行数据。当我为数百万行调用它时,我得到了结果错误。包中的错误,还是我可以做一些不同的事情?我正在使用 Anaconda 2.0.1 中的 Python 2.7.7,并将 Anaconda 的多处理包中的 pool.py 和 scikit-learn 的外部包中的 parallel.py 放在我的 Dropbox 上。
测试脚本是:
import numpy as np
import sklearn
from sklearn.linear_model import SGDClassifier
from sklearn import grid_search
import multiprocessing as mp
def main():
print("Started.")
print("numpy:", np.__version__)
print("sklearn:", sklearn.__version__)
n_samples = 1000000
n_features = 1000
X_train = np.random.randn(n_samples, n_features)
y_train = np.random.randint(0, 2, size=n_samples)
print("input data size: %.3fMB" % (X_train.nbytes / 1e6))
model = SGDClassifier(penalty='elasticnet', n_iter=10, shuffle=True)
param_grid = [
'alpha' : 10.0 ** -np.arange(1,7),
'l1_ratio': [.05, .15, .5, .7, .9, .95, .99, 1],
]
gs = grid_search.GridSearchCV(model, param_grid, n_jobs=8, verbose=100)
gs.fit(X_train, y_train)
print(gs.grid_scores_)
if __name__=='__main__':
mp.freeze_support()
main()
这导致输出:
Vendor: Continuum Analytics, Inc.
Package: mkl
Message: trial mode expires in 28 days
Started.
('numpy:', '1.8.1')
('sklearn:', '0.15.0b1')
input data size: 8000.000MB
Fitting 3 folds for each of 48 candidates, totalling 144 fits
Memmaping (shape=(1000000L, 1000L), dtype=float64) to new file c:\users\laszlos\appdata\local\temp\4\joblib_memmaping_pool_6172_78765976\6172-284752304-75223296-0.pkl
Failed to save <type 'numpy.ndarray'> to .npy file:
Traceback (most recent call last):
File "C:\Anaconda\lib\site-packages\sklearn\externals\joblib\numpy_pickle.py", line 240, in save
obj, filename = self._write_array(obj, filename)
File "C:\Anaconda\lib\site-packages\sklearn\externals\joblib\numpy_pickle.py", line 203, in _write_array
self.np.save(filename, array)
File "C:\Anaconda\lib\site-packages\numpy\lib\npyio.py", line 453, in save
format.write_array(fid, arr)
File "C:\Anaconda\lib\site-packages\numpy\lib\format.py", line 406, in write_array
array.tofile(fp)
ValueError: 1000000000 requested and 268435456 written
Memmaping (shape=(1000000L, 1000L), dtype=float64) to old file c:\users\laszlos\appdata\local\temp\4\joblib_memmaping_pool_6172_78765976\6172-284752304-75223296-0.pkl
Vendor: Continuum Analytics, Inc.
Package: mkl
Message: trial mode expires in 28 days
Vendor: Continuum Analytics, Inc.
Package: mkl
Message: trial mode expires in 28 days
Vendor: Continuum Analytics, Inc.
Package: mkl
Message: trial mode expires in 28 days
Vendor: Continuum Analytics, Inc.
Package: mkl
Message: trial mode expires in 28 days
Vendor: Continuum Analytics, Inc.
Package: mkl
Message: trial mode expires in 28 days
Vendor: Continuum Analytics, Inc.
Package: mkl
Message: trial mode expires in 28 days
Vendor: Continuum Analytics, Inc.
Package: mkl
Message: trial mode expires in 28 days
Vendor: Continuum Analytics, Inc.
Package: mkl
Message: trial mode expires in 28 days
Traceback (most recent call last):
File "S:\laszlo\gridsearch_largearray.py", line 33, in <module>
main()
File "S:\laszlo\gridsearch_largearray.py", line 28, in main
gs.fit(X_train, y_train)
File "C:\Anaconda\lib\site-packages\sklearn\grid_search.py", line 597, in fit
return self._fit(X, y, ParameterGrid(self.param_grid))
File "C:\Anaconda\lib\site-packages\sklearn\grid_search.py", line 379, in _fit
for parameters in parameter_iterable
File "C:\Anaconda\lib\site-packages\sklearn\externals\joblib\parallel.py", line 651, in __call__
self.retrieve()
File "C:\Anaconda\lib\site-packages\sklearn\externals\joblib\parallel.py", line 503, in retrieve
self._output.append(job.get())
File "C:\Anaconda\lib\multiprocessing\pool.py", line 558, in get
raise self._value
struct.error: integer out of range for 'i' format code
编辑:ogrisel
的答案确实适用于 scikit-learn-0.15.0b1 的手动内存映射。不要忘记一次只运行一个脚本,否则你仍然会耗尽内存并且线程过多。 (我的 CSV 文件大小约为 12.5 GB 的数据,使用 8 个线程,运行大约 60 GB。)
【问题讨论】:
你能发布你正在使用的 Anaconda 版本吗?如果可能,请发布 parallel.py 和 pool.py。可能是您创建了太多并行进程。反正这种东西更适合做bug报告。 你能发布你正在使用的python和scikit-learn的版本吗?在官方存储库中查看该特定版本的代码会很有帮助。那时你就不需要发布文件了。 这听起来像是 joblib 中的一个严重错误,但是我无法通过运行以下脚本来重现它:gist.github.com/ogrisel/dab225fc9d0a365119b6 您能否提供一个带有随机数据的独立脚本,可以触发您机器上的错误?你有哪个 numpy 版本? 当你在 Windows 上时,不要忘记放置一个if __name__ == '__main__':
块来保护调用 scikit-learn 的部分涉及 n_jobs=8
。
仅供参考,我可以在一个大的 windows 盒子上运行我以前的 gist 中的代码而不会崩溃。
【参考方案1】:
作为一种解决方法,您可以尝试将数据显式地手动映射为explained in the joblib documentation。
编辑#1:这是重要的部分:
from sklearn.externals import joblib
joblib.dump(X_train, some_filename)
X_train = joblib.load(some_filename, mmap_mode='r+')
然后将这个 memmap 的数据传递给 scikit-learn 0.15+ 下的GridSearchCV
。
编辑#2: 此外:如果您使用 32 位版本的 Anaconda,每个 python 进程将被限制为 2GB,这也会限制内存。
我刚刚在 Python 3.4 下为 numpy.save
找到了一个 bug,但即使已修复,随后对 mmap 的调用也会失败:
OSError: [WinError 8] Not enough storage is available to process this command
所以请使用 64 位版本的 Python(Anaconda 作为 AFAIK,目前没有其他 64 位软件包用于 numpy / scipy / scikit-learn==0.15.0b1)。
编辑 #3: 我发现了另一个可能导致 Windows 下内存使用过多的问题:当前 joblib.Parallel
内存默认将输入数据映射到 mmap_mode='c'
:此写入时复制设置似乎会导致 Windows 耗尽页面文件,有时会触发“[错误 1455] 页面文件太小,无法完成此操作”错误。设置mmap_mode='r'
或mmap_mode='r+'
不会触发该问题。我将运行测试,看看我是否可以在下一个版本的 joblib 中更改默认模式。
【讨论】:
@ogrisel 这解决了原始崩溃被规避的问题。然而,系统停了下来,当我终于可以启动资源监视器时,我看到 RAM 的使用量很小,但 HDD 的使用非常愉快。在那之后不久,我得到了一个新的内存错误,我将其添加到问题中,尽管也许它值得另一个线程。对此有什么想法吗?感谢您的宝贵时间! 我编辑了我的答案,指出您不应该使用 32 位版本的 Anaconda。 @ogrisel 快速说明一下,问题出现在其他对象上,不仅是 GridSearchCV,即 ElasticNetCV,而且解决方法也适用于此。 我做了一些进一步的基准测试,似乎 Windows 处理 mmap 由于某种原因正在大量使用分页文件(这是在 Rackspace VM 中测试的,因为我没有大型 Windows 服务器在眼前)。对于类似硬件上的大型 mmap 数据,Linux 似乎效率更高。 windows下的问题源于mmap_mode='c'
的使用(copy on write)。使用mmap_mode='r'
效果更好(无需在后台分页)。我更改了 joblib master 中的默认值。以上是关于scikit-learn joblib 错误:多处理池 self.value 超出“i”格式代码的范围,仅适用于大型 numpy 数组的主要内容,如果未能解决你的问题,请参考以下文章
使用 joblib 加载腌制 scikit-learn 模型时出现 KeyError
加载训练有素的 scikit-learn/imblearn 管道模型时出现问题
线程 QueueManagerThread 中的异常 - scikit-learn