#pytorch #gpu
Вопрос:
В процессе отслеживания ошибки OOM GPU я сделал следующие контрольные точки в своем коде Pytorch (работает на Google Colab P100):
learning_rate = 0.001
num_epochs = 50
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print('check 1')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
model = MyModel()
print('check 2')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
model = model.to(device)
print('check 3')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
print('check 4')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
for epoch in range(num_epochs):
train_running_loss = 0.0
train_accuracy = 0.0
model = model.train()
print('check 5')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
## training step
for i, (name, output_array, input) in enumerate(trainloader):
output_array = output_array.to(device)
input = input.to(device)
comb = torch.zeros(1,1,100,1632).to(device)
print('check 6')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
## forward backprop loss
output = model(input, comb)
print('check 7')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
loss = my_loss(output, output_array)
print('check 8')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
optimizer.zero_grad()
print('check 9')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
loss.backward()
print('check 10')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
## update model params
optimizer.step()
print('check 11')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
train_running_loss = loss.detach().item()
print('check 12')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
temp = get_accuracy(output, output_array)
print('check 13')
!nvidia-smi | grep MiB | awk '{print $9 $10 $11}'
train_accuracy = temp
со следующим выводом:
check 1
2MiB/16160MiB
check 2
2MiB/16160MiB
check 3
3769MiB/16160MiB
check 4
3769MiB/16160MiB
check 5
3769MiB/16160MiB
check 6
3847MiB/16160MiB
check 7
6725MiB/16160MiB
check 8
6725MiB/16160MiB
check 9
6725MiB/16160MiB
check 10
9761MiB/16160MiB
check 11
16053MiB/16160MiB
check 12
16053MiB/16160MiB
check 13
16053MiB/16160MiB
check 6
16053MiB/16160MiB
check 7
16071MiB/16160MiB
check 8
16071MiB/16160MiB
check 9
16071MiB/16160MiB
check 10
16071MiB/16160MiB
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-11-f566d09448f9> in <module>()
65
66 ## update model params
---> 67 optimizer.step()
68
69 print('check 11')
3 frames
/usr/local/lib/python3.7/dist-packages/torch/optim/optimizer.py in wrapper(*args, **kwargs)
86 profile_name = "Optimizer.step#{}.step".format(obj.__class__.__name__)
87 with torch.autograd.profiler.record_function(profile_name):
---> 88 return func(*args, **kwargs)
89 return wrapper
90
/usr/local/lib/python3.7/dist-packages/torch/autograd/grad_mode.py in decorate_context(*args, **kwargs)
26 def decorate_context(*args, **kwargs):
27 with self.__class__():
---> 28 return func(*args, **kwargs)
29 return cast(F, decorate_context)
30
/usr/local/lib/python3.7/dist-packages/torch/optim/adam.py in step(self, closure)
116 lr=group['lr'],
117 weight_decay=group['weight_decay'],
--> 118 eps=group['eps'])
119 return loss
/usr/local/lib/python3.7/dist-packages/torch/optim/_functional.py in adam(params, grads, exp_avgs, exp_avg_sqs, max_exp_avg_sqs, state_steps, amsgrad, beta1, beta2, lr, weight_decay, eps)
92 denom = (max_exp_avg_sqs[i].sqrt() / math.sqrt(bias_correction2)).add_(eps)
93 else:
---> 94 denom = (exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(eps)
95
96 step_size = lr / bias_correction1
RuntimeError: CUDA out of memory. Tried to allocate 2.32 GiB (GPU 0; 15.78 GiB total capacity; 11.91 GiB already allocated; 182.75 MiB free; 14.26 GiB reserved in total by PyTorch)
Для меня имеет смысл, что model = model.to(device)
создает 3,7 Г памяти.
Но почему запуск модели output = model(input, comb)
создает еще один объем памяти 3G?
А затем loss.backward()
создает еще один объем памяти 3G?
А затем optimizer.step()
создает еще 6,3 Г памяти?
Я был бы признателен, если бы кто-нибудь объяснил, как работает модель распределения памяти GPU PyTorch в этом примере.
Ответ №1:
- Вывод
По умолчанию вывод в вашей модели будет выделять память для хранения активаций каждого слоя (активация, как на входах промежуточного слоя). Это необходимо для обратного распространения, когда эти тензоры используются для вычисления градиентов. Простым, но эффективным примером является функция, определяемая
f: x -> x²
. Здесьdf/dx = 2x
, то есть для того , чтобы вычислятьdf/dx
, вы должны хранитьx
в памяти.Если вы используете
torch.no_grad()
контекстный менеджер, вы позволите PyTorch не сохранять эти значения, тем самым экономя память. Это особенно полезно при оценке или тестировании вашей модели, т. е. при выполнении обратного распространения. Конечно, вы не сможете использовать это во время тренировок! - Обратное распространение
Вызов обратного прохода выделит дополнительную память на устройстве для хранения значения градиента каждого параметра. Только конечные узлы тензора (параметры модели и входные данные) сохраняют свой градиент в
grad
атрибуте. Вот почему использование памяти только увеличивается между выводом иbackward
вызовами. - Обновление параметров модели
Поскольку вы используете оптимизатор с отслеживанием состояния (Adam), для сохранения некоторых параметров требуется дополнительная память. Прочитайте соответствующий пост на форуме PyTorch об этом. Если вы попытаетесь использовать оптимизатор без состояния (например, SGD), у вас не должно быть никаких накладных расходов на память
step
при вызове.
Все три шага могут иметь потребности в памяти. Таким образом, объем памяти, выделенной на вашем устройстве, будет эффективно зависеть от трех элементов:
- Размер вашей нейронной сети: чем больше модель, тем больше активаций слоев и градиентов будет сохранено в памяти.
- Независимо от того, находитесь ли вы в
torch.no_grad
контексте: в этом случае в памяти должно быть только состояние вашей модели (никаких активаций или градиентов не требуется). - Тип используемого оптимизатора: с сохранением состояния (сохраняет некоторые текущие оценки во время обновления параметров) или без состояния (не требует этого).
требуется ли вам сделать это обратно
Комментарии:
1. Спасибо тебе, Иван!