Как можно оптимизировать использование памяти в 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гб всего? <br/> Скорее всего твой датасет не помещается в память видеокарты... уменьши размер батча (вообще то его увеличивают чтобы значительно ускорить обучение, но тебе 'не до жиру') до 1. <br/> Перейди на fp16, это уменьшит размер весов модели (правда если она уже уменьшена, дистиллирована и прочее, это может помешать обучению) <br/> <pre><code>training_args = TrainingArguments(
    fp16=True,</code></pre> <br/> Так же можно поделить свою обучающую выборку на части и обучать сетку по ее частям (это замедляет процесс и ухудшает но все еще лучше чем на процессоре все делать) <br/> <pre><code>training_args = TrainingArguments(
    gradient_accumulation_steps=4,</code></pre>
Похожие вопросы