pytorch - 有哪些方法可以加快 Pytorch 中大型稀疏数组(~100 万 x 100 万,密度~0.0001)的数据加载速度?
问题描述
我正在研究二进制分类问题。我有大约 150 万个数据点,特征空间的维数是 100 万。该数据集存储为稀疏数组,密度约为 0.0001。对于这篇文章,我将限制范围假设模型是浅层前馈神经网络,并假设维度已经优化(因此不能减少到 100 万以下)。从这些数据中创建小批量以馈送到网络的天真方法将花费大量时间(例如,从输入数组TensorDataset
的表示创建(地图样式)并将其包裹起来的基本方法, 意味着大约 20 秒可以将 32 个小批量输入网络,而不是说大约 0.1 秒来执行实际训练)。我正在寻找加快速度的方法。torch.sparse.FloatTensor
DataLoader
我试过的
- 我首先想到在每次迭代中从如此大的稀疏数组中读取
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,使用我刚刚概述的方法,它需要~3000s 只是为了在一个 epoch 中加载所有小批量)
我知道但尚未尝试的一件事是通过num_workers
在DataLoader
. 我相信这在可迭代样式数据集的情况下有它自己的问题。另外,即使是 10 倍的加速,仍然意味着每个 epoch 加载小批量约 300 秒。我觉得我的速度太慢了!您是否可以建议任何其他方法/改进/最佳实践?
解决方案
您的非稀疏形式的数据集将是 1.5M x 1M x 1 字节 = 1.5TB 作为 uint8,或 1.5M x 1M x 4 字节 = 6TB 作为 float32。在现代 CPU 上,简单地将 6TB 从内存读取到 CPU 可能需要 5-10 分钟(取决于架构),并且从 CPU 到 GPU 的传输速度会比这慢一些(PCIe 上的 NVIDIA V100 理论上有 32GB/s)。
方法:
单独对所有内容进行基准测试 - 例如在 jupyter
%%timeit 数据 = sparse.load_npz(fpath).toarray()
%%timeit dense = data.toarray() # un-sparsify 进行比较
%%timeit t = torch.tensor(data) # 大概和上面那行差不多
还要打印出所有内容的形状和数据类型,以确保它们符合预期。我没有尝试运行你的代码,但我很确定(a)sparse.load_npz 非常快,不太可能成为瓶颈,但是(b)torch.tensor(data) 产生密集张量并且在这里也很慢
- 使用torch.sparse。我认为在大多数情况下,torch 稀疏张量可以用作常规张量。你必须做一些数据准备才能从 scipy.sparse 转换为 torch.sparse:
稀疏张量表示为一对密集张量:值的张量和索引的 2D 张量。可以通过 提供这两个张量以及稀疏张量的大小来构造一个稀疏张量
你提到torch.sparse.FloatTensor
但我很确定你没有在你的代码中制作稀疏张量 - 没有理由期望这些会简单地通过将 scipy.sparse 数组传递给常规张量构造函数来构造,因为它们不是这样的通常制作。
如果你找到了一个好的方法,我建议你将它作为项目或 git 发布到 github 上,这将非常有用。
- 如果 torch.sparse 不起作用,请考虑其他方法将数据转换为仅在 GPU 上密集,或避免完全转换。
另见: https ://towardsdatascience.com/sparse-matrices-in-pytorch-be8ecaccae6 https://github.com/rusty1s/pytorch_sparse
推荐阅读
- c++ - 为什么 `it1++` 有效,但 `it1=it1+1` 无效,其中 it1 是列表容器的迭代器
- android - ExoPlayer 是否为 ConcatenatingMediaSource 中的每个媒体源创建一个 windowIndex?
- python-3.x - 如何使用 google 的电子表格 API 来检索电子表格的创建日期和时间?
- unity3d - unity : 为射击游戏制作功率计
- javascript - 使用 Swup - 在每个文件上重新加载 javascript
- mongodb - 从 multer-GridFs-storage 和 mongoose 中检索图像
- prolog - CLPFD ins 运算符产生未充分实例化的错误
- reactjs - AWS 放大存储和 React 前端的“缺少区域错误”
- c# - 如何将全局过滤器值传递给数据库上下文
- google-sheets - Google 表格:需要在 SortN 中进行过滤