Я выполняю задачу, в которой размер пакета равен 1, т.е. каждая партия содержит только 1 изображение. Поэтому мне приходится выполнять группировку вручную: когда количество накопленных потерь достигает числа, усредните потери, а затем выполните обратное распространение. Мой исходный код:
real_batchsize = 200
for epoch in range(1, 5):
net.train()
total_loss = Variable(torch.zeros(1).cuda(), requires_grad=True)
iter_count = 0
for batch_idx, (input, target) in enumerate(train_loader):
input, target = Variable(input.cuda()), Variable(target.cuda())
output = net(input)
loss = F.nll_loss(output, target)
total_loss = total_loss + loss
if batch_idx % real_batchsize == 0:
iter_count += 1
ave_loss = total_loss/real_batchsize
ave_loss.backward()
optimizer.step()
if iter_count % 10 == 0:
print("Epoch:{}, iteration:{}, loss:{}".format(epoch,
iter_count,
ave_loss.data[0]))
total_loss.data.zero_()
optimizer.zero_grad()
Этот код выдаст сообщение об ошибке
RuntimeError: попытка вернуться по графику второй раз, но буферы уже освобождены. При обратном вызове в первый раз укажите keep_graph = True.
Я пробовал следующий способ,
Первый способ (не удалось)
Я прочитал сообщение об этом сообщении об ошибке, но не могу его полностью понять. Измените ave_loss.backward()
на ave_loss.backward(retain_graph=True)
, чтобы предотвратить появление сообщения об ошибке, но потери не улучшаются и вскоре становятся nan
.
Второй способ (не удалось)
Я также пробовал изменить total_loss = total_loss + loss.data[0]
, это тоже предотвратит появление сообщения об ошибке. Но проигрыши всегда одни и те же. Значит, должно быть что-то не так.
Третий путь (успех)
Следуя инструкциям в этом сообщении, для каждой потери изображения я делю потеря на real_batchsize
и обратное распространение. Когда количество входных изображений достигает real_batchsize
, я выполняю одно обновление параметра, используя optimizer.step()
. Потери постепенно уменьшаются по мере тренировочного процесса. Но скорость обучения очень медленная, потому что мы делаем обратное распространение для каждого изображения.
Мой вопрос
Что означает сообщение об ошибке в моем случае? Кроме того, почему не работают первый и второй способ? Как правильно написать код, чтобы мы могли передавать градиент каждые real_batchsize
изображений и обновлять градиент один раз, чтобы ускорить обучение? Я знаю, что мой код почти правильный, но я просто не знаю, как его изменить.