Почему мой DataLoader намного медленнее, чем цикл for? - PullRequest
0 голосов
/ 12 мая 2019

Я пишу классификатор на основе нейронных сетей для набора данных MNIST.Сначала я попытался загрузить данные вручную, используя циклы и индексы для эпох и пакетов.В учебном пособии я видел, как кто-то использовал torch.utils.data.DataLoader для этой конкретной задачи, поэтому я изменил свой код, чтобы вместо него использовать DataLoader.Это привело к значительным различиям в продолжительности процесса обучения.

Я пытался решить эту проблему, пытаясь сузить ее с помощью тестов.Я всегда проводил тестирование как на CPU (i7 8700k), так и на GPU (1080ti), а данные хранятся на моем ssd (970 evo).

Сначала я попытался сравнить Batch Gradient Descent с DataLoader и без него, а затем Mini-Пакетный градиентный спуск с и без DataLoader.Результаты меня несколько смутили.

|                 | 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()

против кода с использованием цикла

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

РЕДАКТИРОВАТЬ: я думаю, что я мог выяснить, как исправитьМоя главная проблема - разница в производительности между загрузчиком данных и циклом.Установив параметр num_workers загрузчика на 8, мне удалось сократить время для мини-пакета с DL на графическом процессоре примерно до 1 минуты.Хотя это определенно лучше, чем 5 минут, это все же плохо, учитывая, что мини-пакет с DL на GPU находится на одном уровне с производительностью мини-пакета с циклом на процессоре.

1 Ответ

0 голосов
/ 16 мая 2019

transforms.ToTensor() принимает PIL Image или np.ndarray в диапазоне [0, 255] в качестве входных данных и преобразует его в torch.FloatTensor в диапазоне [0.0, 1.0], если np.ndarray имеет dtype=np.uint8 или PIL Image принадлежат одному из режимов (L, LA, P, I, F, RGB, YCbCr, RGBA, CMYK, 1) документы

Изменение масштаба и изменение типа данных влияют на точность модели. Также DataLoader выполняет больше операций, чем ваши циклы по пакетам, поэтому разница во времени.

P.S. Вы должны перетасовать свои тренировочные данные при выполнении минибатного тренинга

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...