繁体   English   中英

为什么我的DataLoader比for循环慢得多?

[英]Why is my DataLoader so much slower than a for loop?

我正在为MNIST数据集编写一个基于神经网络的分类器。 我首先尝试使用时期和批次的循环和索引手动加载数据。 在教程中,我看到有人使用torch.utils.data.DataLoader执行此确切任务,因此我将代码更改为使用DataLoader。 这导致学习过程的持续时间存在重大差异。

我试图通过使用基准测试来缩小范围来解决这个问题。 我总是在CPU(i7 8700k)和GPU(1080ti)上进行基准测试,数据存储在我的ssd(970 evo)上。

我首先尝试比较使用和不使用DataLoader的Batch Gradient Descent,然后使用和不使用DataLoader来比较Mini-Batch Gradient Descent。 结果对我来说相当混乱。

|                 | BGD         | BGD with DL | MB-GD       | MB-GD with DL |
|-----------------|-------------|-------------|-------------|---------------|
| Time on CPU     | 00:00:56.70 | 00:05:59.31 | 00:01:31.29 | 00:07:46.56   |
| Accuracy on CPU | 82.47       | 33.44       | 94.84       | 87.67         |
| Time on GPU     | 00:00:15.89 | 00:05:41.79 | 00:00:17.48 | 00:05:37.33   |
| Accuracy on GPU | 82.3        | 30.66       | 94.88       | 87.74         |
| Batch Size      | M           | M           | 500         | 500           |
| Epoch           | 100         | 100         | 100         | 100           |

这是使用DataLoader的代码,精简到精华。

num_epoch = 100
train_loader = DataLoader(batch_size=500, shuffle=False, dataset=dataset_train)

for epoch in range(num_epoch):
    for i, (images, labels) in enumerate(train_loader):
        images = images.view(-1, 28 * 28)
        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

vs使用循环的代码

num_epoch = 100
batch_size = 500
num_batch = int(len(dataset_train) / batch_size)

for epoch in range(num_epoch):
    for batch_idx in range(num_batch):
        images = dataset_train.data[batch_idx*batch_size:(batch_idx+1)*batch_size].view(-1, 28 * 28)
        labels = dataset_train.targets[batch_idx*batch_size:(batch_idx+1)*batch_size]
        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

我希望DataLoader能够在时间和性能方面至少接近循环,但不会慢10倍。 我也很困惑为什么DataLoader会影响模型的准确性。

我使用DataLoader是错误的,还是这只是错误的用例,循环更适合我正在做的事情?

编辑:这里有两个小提琴,包含循环的完整代码和dataloader变体

编辑:我相信我可能已经想出如何解决我的主要问题,dataloader和循环之间的性能差异。 通过将加载器的num_workers参数设置为8,我设法将GPU上的DL小批量的时间减少到大约1分钟。 虽然这肯定好于5分钟,但它仍然很糟糕,考虑到在GPU上使用DL的miniatch与具有CPU循环的minibatch的性能相当。

transforms.ToTensor()需要PIL Imagenp.ndarray在范围[0, 255]作为输入,并把它转换成一个torch.FloatTensor范围[0.0, 1.0]如果np.ndarray具有dtype=np.uint8PIL Image属于其中一种模式(L, LA, P, I, F, RGB, YCbCr, RGBA, CMYK, 1) docs

重新缩放和更改数据类型会影响模型的准确性。 此外, DataLoader比批量循环更多的操作,因此时间上的差异。

PS在进行小型训练培训时,您应该随机播放训练数据

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM