【发布时间】:2020-07-22 15:14:47
【问题描述】:
我正在研究一个二元分类问题。我有大约 150 万个数据点,特征空间的维数是 100 万。该数据集存储为稀疏数组,密度约为 0.0001。对于这篇文章,我将限制范围假设模型是浅层前馈神经网络,并假设维度已经优化(因此不能减少到 100 万以下)。从这些数据中创建小批量以馈送到网络的简单方法将花费大量时间(例如,从输入数组的torch.sparse.FloatTensor 表示创建TensorDataset(地图样式)的基本方法,并在其周围包裹一个DataLoader,这意味着~20s 可以获得一个 32 的 mini-batch 到网络,而不是说 ~0.1s 来执行实际训练)。我正在寻找加快速度的方法。
我尝试过的
- 我首先想到,在
DataLoader的每次迭代中从如此大的稀疏数组中读取是计算密集型的,因此我将这个稀疏数组分解为更小的稀疏数组 - 为了让
DataLoader以迭代方式从这些多个稀疏数组中读取数据,我将DataLoader中的地图样式数据集替换为IterableDataset,并将这些较小的稀疏数组流式传输到这个IterableDataset 中,例如所以:
from itertools import chain
from scipy import sparse
class SparseIterDataset(torch.utils.data.IterableDataset):
def __init__(self, fpaths):
super(SparseIter).__init__()
self.fpaths = fpaths
def read_from_file(self, fpath):
data = sparse.load_npz(fpath).toarray()
for d in data:
yield torch.Tensor(d)
def get_stream(self, fpaths):
return chain.from_iterable(map(self.read_from_file, fpaths))
def __iter__(self):
return self.get_stream(self.fpaths)
通过这种方法,我能够将时间从大约 20 秒的幼稚基本情况缩短到每 32 个小批量的大约 0.2 秒。但是,鉴于我的数据集有大约 150 万个样本,这仍然意味着很多甚至一次通过数据集所花费的时间。 (作为比较,即使它有点苹果对橘子,在原始稀疏数组上对 scikit-learn 运行逻辑回归大约需要 6 秒,每次迭代通过整个数据集。使用 pytorch,使用方法我刚刚概述了,仅在一个 epoch 中加载所有 minibatch 大约需要 3000 秒)
我知道但尚未尝试的一件事是通过在DataLoader 中设置num_workers 参数来使用多进程数据加载。我相信这在可迭代样式数据集的情况下有它自己的问题。另外,即使是 10 倍的加速,仍然意味着每个 epoch 加载小批量约 300 秒。我觉得我的速度太慢了!您是否可以提出任何其他方法/改进/最佳实践建议?
【问题讨论】:
-
坦率地说,这不是很多数据——它是什么,150m 的值?最大的瓶颈将是
toarray(),它必须分配大量的内存来保存所有这些零。为什么不直接将 coo 索引推送到torch.sparse_coo_tensor中?我认为没有任何理由必须对这个数组进行加密。
标签: pytorch bigdata sparse-matrix