我有一个庞大的数据集,我希望对其进行PCA。我受限于RAM和PCA的计算效率。因此,我转而使用迭代PCA。
数据集大小(140000、3504)
文档说明This algorithm has constant memory complexity, on the order of batch_size, enabling use of np.memmap files without loading the entire file into memory.
这真的很好,但不确定如何利用它。
我试着加载一个memmap,希望它能在块中访问它,但我的RAM吹了。我下面的代码最终使用了大量的内存:
ut = np.memmap('my_array.mmap', dtype=np.float16, mode='w+', shape=(140000,3504))
clf=IncrementalPCA(copy=False)
X_train=clf.fit_transform(ut)
当我说"my RAM blow"时,我看到的Traceback是:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:Python27libsite-packagessklearnbase.py", line 433, in fit_transfo
rm
return self.fit(X, **fit_params).transform(X)
File "C:Python27libsite-packagessklearndecompositionincremental_pca.py",
line 171, in fit
X = check_array(X, dtype=np.float)
File "C:Python27libsite-packagessklearnutilsvalidation.py", line 347, in
check_array
array = np.array(array, dtype=dtype, order=order, copy=copy)
MemoryError
我如何通过减少批大小来改善这一点而不影响准确性?
My ideas to diagnosis:
我看了sklearn
源代码,在fit()
函数源代码中,我可以看到以下内容。这对我来说是有意义的,但我仍然不确定我的情况是什么问题。
for batch in gen_batches(n_samples, self.batch_size_):
self.partial_fit(X[batch])
return self
编辑:最坏的情况是,我将不得不为iterativePCA编写自己的代码,该代码通过读取和关闭.npy文件进行批处理。但这将破坏利用已经存在的黑客的目的。
Edit2: 如果我能删除一批处理过的memmap file
。这很有意义。
Edit3: 理想情况下,如果IncrementalPCA.fit()只是使用批处理,它应该不会使我的RAM崩溃。张贴整个代码,只是为了确保我没有在之前将memmap完全刷新到磁盘时犯错误。
temp_train_data=X_train[1000:]
temp_labels=y[1000:]
out = np.empty((200001, 3504), np.int64)
for index,row in enumerate(temp_train_data):
actual_index=index+1000
data=X_train[actual_index-1000:actual_index+1].ravel()
__,cd_i=pywt.dwt(data,'haar')
out[index] = cd_i
out.flush()
pca_obj=IncrementalPCA()
clf = pca_obj.fit(out)
令人惊讶的是,我注意到out.flush
并没有释放我的内存。是否有一种方法可以使用del out
来完全释放我的内存,然后有人将文件的指针传递给IncrementalPCA.fit()
.
您在32位环境中遇到sklearn
问题。我假设你正在使用np.float16
,因为你在一个32位的环境中,你需要允许你创建memmap
对象而没有numpy thowing错误。
在64位环境中(在Windows上使用Python3.3 64位进行测试),您的代码可以开箱即用。所以,如果你有一台64位的计算机,安装64位的python和64位的numpy
, scipy
, scikit-learn
,你就可以开始了。
不幸的是,如果您不能做到这一点,就没有简单的修复方法。我在github上提出了一个问题,但它不容易修补。最根本的问题是,在库中,如果类型是float16
,就会触发数组到内存的一个副本。详情如下:
所以,我希望您可以访问具有大量RAM的64位环境。如果没有,您将不得不自己拆分数组并批处理它,这是一个相当大的任务…
N。B
看到您去源代码诊断您的问题真是太好了:)但是,如果您查看代码失败的行(来自Traceback),您将看到您发现的for batch in gen_batches
代码从未到达。
详细诊断:
OP代码产生的实际错误:
import numpy as np
from sklearn.decomposition import IncrementalPCA
ut = np.memmap('my_array.mmap', dtype=np.float16, mode='w+', shape=(140000,3504))
clf=IncrementalPCA(copy=False)
X_train=clf.fit_transform(ut)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:Python27libsite-packagessklearnbase.py", line 433, in fit_transfo
rm
return self.fit(X, **fit_params).transform(X)
File "C:Python27libsite-packagessklearndecompositionincremental_pca.py",
line 171, in fit
X = check_array(X, dtype=np.float)
File "C:Python27libsite-packagessklearnutilsvalidation.py", line 347, in
check_array
array = np.array(array, dtype=dtype, order=order, copy=copy)
MemoryError
调用check_array
(代码链接)使用dtype=np.float
,但原始数组使用dtype=np.float16
。即使check_array()
函数默认为copy=False
并将其传递给np.array()
,它也会被忽略(根据文档),以满足dtype
不同的要求;因此,np.array
制作了一个副本。
这可以在IncrementalPCA代码中解决,通过确保dtype in (np.float16, np.float32, np.float64)
的数组保留dtype
。然而,当我尝试这个补丁时,它只是将MemoryError
推到了执行链的更远的地方。
同样的复制问题发生在代码从主scipy代码调用linalg.svd()
时,这次错误发生在调用gesdd()
(来自lapack
的包装本机函数)期间。因此,我不认为有一种方法来修补这个(至少不是一个简单的方法-它是在核心代码的最小修改)。
是否单独触发崩溃?
X_train_mmap = np.memmap('my_array.mmap', dtype=np.float16,
mode='w+', shape=(n_samples, n_features))
clf = IncrementalPCA(n_components=50).fit(X_train_mmap)
如果没有,那么您可以使用该模型将(迭代地投影您的数据)转换为使用批处理的较小数据:
X_projected_mmap = np.memmap('my_result_array.mmap', dtype=np.float16,
mode='w+', shape=(n_samples, clf.n_components))
for batch in gen_batches(n_samples, self.batch_size_):
X_batch_projected = clf.transform(X_train_mmap[batch])
X_projected_mmap[batch] = X_batch_projected
我还没有测试过这段代码,但我希望你能明白。