Как можно оптимизировать использование памяти в PyTorch, чтобы избежать ошибки Torch.OutOfMemoryError?

Здравствуйте! Я столкнулся с проблемой при запуске тренировки модели mbart many-to-many на графической карте rtx 3050 ti, которая имеет 4 ГБ видеопамяти и 7 ГБ общей памяти. PyTorch, по всей видимости, использует всю доступную видеопамять. <br/> Могу ли я получить советы по этому вопросу, так как, возможно, я что-то неправильно понимаю? <br/> <br/> <pre><code class="python">import os
os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'expandable_segments:True'
import torch
from torch.utils.data import Dataset
from transformers import MBartForConditionalGeneration, MBart50TokenizerFast
import pandas as pd
from torch.utils.data import DataLoader
from transformers import Trainer, TrainingArguments

model = MBartForConditionalGeneration.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
tokenizer = MBart50TokenizerFast.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

tokenizer.pad_token = tokenizer.eos_token

class TextDataset(Dataset):
    def __init__(self, encodings):
        self.input_ids = encodings['input_ids']
        self.attention_mask = encodings['attention_mask']
        self.labels = encodings['input_ids'].clone()

    def __len__(self):
        return len(self.input_ids)

    def __getitem__(self, idx):
        return {
            'input_ids': self.input_ids[idx],
            'attention_mask': self.attention_mask[idx],
            'labels': self.labels[idx], 
        }

@dp.message_handler(commands=['train'])
async def get_users_handler(message: types.Message):

    # dataset
    df = pd.read_csv("dataset.csv")
    if 'Вопрос' not in df.columns or 'Ответ' not in df.columns:
        return
    texts = df['Вопрос'] + " " + df['Ответ']

    encodings</code></pre>
  • 16 ноября 2024 г. 14:23
Ответы на вопрос 2
Оптимизация использования памяти в PyTorch — это важная задача, особенно когда вы работаете на видеокартах с ограниченной видеопамятью, таких как RTX 3050 Ti с 4 ГБ VRAM. Вот несколько стратегий, которые могут помочь вам избежать ошибок `Torch.OutOfMemoryError`:

1. **Уменьшение размера батча**:
   Начните с уменьшения размера батча (`batch_size`). Меньший размер батча требует меньше памяти. Вы можете попробовать уменьшить его на 1/2 или даже 1/4 от текущего значения.

   ```python
   training_args = TrainingArguments(
       per_device_train_batch_size=4,  # Попробуйте меньший размер батча
       ...
   )
   ```

2. **Заморозка некоторых слоев**:
   Если вы можете заморозить некоторые слои вашей модели, это также позволит сэкономить память. Вы можете это сделать, задав `requires_grad = False` для непрограммируемых слоев:

   ```python
   for param in model.parameters():
       param.requires_grad = False
   ```

3. **Использование `mixed precision`**:
   Вы можете использовать обучение с низкой точностью (Mixed Precision Training) с библиотекой `torch.cuda.amp`. Это может существенно сократить объем занимаемой памяти.

   ```python
   from torch.cuda.amp import GradScaler, autocast

   scaler = GradScaler()

   # В обучающем цикле
   with autocast():
       outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
       loss = outputs.loss

   scaler.scale(loss).backward()
   scaler.step(optimizer)
   scaler.update()
   ```

4. **Удаление лишних переменных**:
   Убедитесь, что у вас нет лишних переменных, которые вы не используете. Для этого вы можете использовать команду `torch.cuda.empty_cache()` после удаления переменных, чтобы освободить память.

   ```python
   del variable
   torch.cuda.empty_cache()
   ```

5. **Использование `gradient accumulation`**:
   Если ваш размер батча слишком мал для эффективного обучения, вы можете использовать накапливание градиентов. Это позволяет вам тренировать модель с большим эффективным размером батча, но фактически не загружая в память все данные сразу:

   ```python
   accumulation_steps = 4  # Количество шагов накопления градиентов
   optimizer.zero_grad()
   for i, batch in enumerate(train_loader):
       outputs = model(**batch)
       loss = outputs.loss
       loss = loss / accumulation_steps  # Делим потерю на количество шагов
       loss.backward()  # Обратное распространение
       if (i + 1) % accumulation_steps == 0:  # Обновляем параметры после накопления
           optimizer.step()
           optimizer.zero_grad()
   ```

6. **Сброс градиентов**:
   Убедитесь, что вы сбрасываете градиенты между итерациями. Используйте `optimizer.zero_grad()` перед расчетом потерь.

7. **Профилирование памяти**:
   Используйте `torch.cuda.memory_summary()` в конце каждой итерации, чтобы мониторить использование памяти и выявлять, где она может не освобождаться.

Каждая из этих стратегий может помочь вам оптимизировать использование памяти в PyTorch, чтобы избежать ошибок из-за переполнения. Начните с простых изменений, таких как уменьшение размера батча, и поэкспериментируйте с другими методами.
Твоя видеокарта всего 4гб, откуда ты взял 7гб всего? 
Скорее всего твой датасет не помещается в память видеокарты... уменьши размер батча (вообще то его увеличивают чтобы значительно ускорить обучение, но тебе 'не до жиру') до 1.
Перейди на fp16, это уменьшит размер весов модели (правда если она уже уменьшена, дистиллирована и прочее, это может помешать обучению)
training_args = TrainingArguments(
    fp16=True,

Так же можно поделить свою обучающую выборку на части и обучать сетку по ее частям (это замедляет процесс и ухудшает но все еще лучше чем на процессоре все делать)
training_args = TrainingArguments(
    gradient_accumulation_steps=4,
Похожие вопросы