Советы по PyTorch, чтобы повысить вашу производительность
Советы по PyTorch для повышения производительности
Введение
Вы когда-нибудь тратили часы на отладку модели машинного обучения, но не можете найти причину, по которой точность не улучшается? Вы когда-нибудь чувствовали, что все должно работать отлично, но по некоторой таинственной причине вы не получаете превосходных результатов?
Но больше нет. Исследование PyTorch для начинающих может быть пугающим. В этой статье вы исследуете протестированные и проверенные рабочие процессы, которые наверняка улучшат ваши результаты и повысят производительность вашей модели.
- Прорыв в области искусственного интеллекта от IBM перевод COBOL на Java стал проще
- Понятное объяснение линейной регрессии
- Познакомьтесь с CoDeF искусственным интеллектом (ИИ) моделью, позволяющей вам выполнять реалистичное редактирование стиля видео, трекинг на основе сегментации и суперразрешение видео.
1. Переобучение на одном пакете
Вы когда-нибудь обучали модель в течение нескольких часов на большом наборе данных, чтобы обнаружить, что потери не уменьшаются, а точность остается на одном уровне? Что ж, сначала проведите проверку на здравый смысл.
Обучение и оценка на большом наборе данных может занимать много времени, а для отладки моделей на первом этапе лучше использовать небольшой набор данных. Как только мы убедимся, что модель работает, мы сможем легко масштабировать обучение на полный набор данных.
Вместо обучения на всем наборе данных, всегда обучайтесь на одном пакете для проверки на здравый смысл.
batch = next(iter(train_dataloader)) # Получить один пакет
# Обучение на одном пакете для всех эпох
for epoch in range(num_epochs):
inputs, targets = batch
predictions = model.train(inputs)
Рассмотрим приведенный выше код. Предположим, у нас уже есть загрузчик тренировочных данных и модель. Вместо итерации по всему набору данных мы легко можем получить первый пакет данных. Затем мы можем обучаться на одном пакете для проверки, может ли модель выучить паттерны и вариацию в этой небольшой части данных.
Если потери уменьшаются до очень малого значения, мы знаем, что модель может переобучиться на этих данных и можем быть уверены в том, что она учится за короткое время. Затем мы можем обучить модель на полном наборе данных, просто изменив одну строку следующим образом:
# Обучение на всех эпохах по всем пакетам данных
for epoch in range(num_epochs):
for batch in iter(dataloader):
inputs, targets = batch
predictions = model.train(inputs)
Если модель может переобучиться на одном пакете данных, она должна быть способна выучить паттерны в полном наборе данных. Этот метод переобучения на одном пакете упрощает отладку. Если модель не может даже переобучиться на одном пакете, мы можем быть уверены, что проблема заключается в реализации модели, а не в данных.
2. Нормализация и перемешивание данных
Для наборов данных, в которых последовательность данных не имеет значения, полезно перемешивать данные. Например, для задач классификации изображений модель будет лучше подстраиваться под данные, если в одном пакете будут изображения разных классов. Если мы передаем данные в том же порядке, мы рискуем моделью выучить паттерны на основе последовательности переданных данных, вместо того, чтобы выучить внутреннюю вариацию данных. Поэтому лучше передавать перемешанные данные. Для этого мы просто можем использовать объект DataLoader, предоставленный PyTorch, и установить shuffle в True.
from torch.utils.data import DataLoader
dataset = # Загрузка данных
dataloder = DataLoader(dataset, shuffle=True)
Кроме того, важно нормализовать данные при использовании моделей машинного обучения. Это необходимо, когда в наших данных есть большая вариация, а определенный параметр имеет значения выше, чем все остальные атрибуты в наборе данных. Это может привести к тому, что один из параметров будет доминировать над всеми остальными, что приведет к низкой точности. Мы хотим, чтобы все входные параметры находились в одном диапазоне, и лучше иметь среднее значение 0 и дисперсию 1.0. Для этого нам нужно преобразовать наш набор данных. Зная среднее и дисперсию набора данных, мы просто можем использовать функцию torchvision.transforms.Normalize.
import torchvision.transforms as transforms
image_transforms = transforms.Compose([
transforms.ToTensor(),
# Нормализация значений в наших данных
transforms.Normalize(mean=(0.5,), std=(0.5))
])
Мы можем передать наши средние значения и стандартное отклонение для каждого канала в функцию transforms.Normalize, и она автоматически преобразует данные, чтобы они имели среднее значение 0 и стандартное отклонение 1.
3. Обрезка градиента
Взрывающийся градиент – это известная проблема в RNN и LSTM. Однако она ограничивается не только этими архитектурами. Любая модель с глубокими слоями может страдать от взрывающихся градиентов. Обратное распространение по высоким градиентам может привести к расходимости вместо постепенного снижения потерь.
Рассмотрим следующий фрагмент кода.
for epoch in range(num_epochs):
for batch in iter(train_dataloader):
inputs, targets = batch
predictions = model(inputs)
optimizer.zero_grad() # Удаление всех предыдущих градиентов
loss = criterion(targets, predictions)
loss.backward() # Вычисление градиентов для весов модели
# Обрезка градиентов весов модели до указанного значения max_norm.
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1)
# Оптимизация весов модели ПОСЛЕ ОБРЕЗКИ
optimizer.step()
Чтобы решить проблему взрывающегося градиента, мы используем технику обрезки градиента, которая ограничивает значения градиента в указанном диапазоне. Например, если мы используем 1 в качестве значения обрезки или нормы, как указано выше, все градиенты будут обрезаны в диапазоне [-1, 1]. Если у нас есть взрывающееся значение градиента равное 50, оно будет обрезано до 1. Таким образом, обрезка градиента решает проблему взрывающегося градиента, позволяя медленную оптимизацию модели к сходимости.
4. Переключение режима Обучение / Оценка
Эта одна строка кода, безусловно, увеличит точность модели на тестовых данных. Почти всегда модель глубокого обучения будет использовать слои исключения и нормализации. Они требуются только для стабильного обучения и обеспечения того, чтобы модель не переобучалась или расходилась из-за изменчивости данных. Слои, такие как BatchNorm и Dropout, обеспечивают регуляризацию параметров модели во время обучения. Однако, после обучения они не требуются. Изменение модели на режим оценки отключает слои, которые нужны только для обучения, и полные параметры модели используются для предсказания.
Для лучшего понимания рассмотрим следующий фрагмент кода.
for epoch in range(num_epochs):
# Использование режима обучения при итерации по обучающему набору данных
model.train()
for batch in iter(train_dataloader):
# Код обучения и оптимизации потерь
# Использование режима оценки при проверке точности на валидационном наборе данных
model.eval()
for batch in iter(val_dataloader):
# Только предсказания и расчет потерь. Обратного распространения нет
# Отсутствует шаг оптимизации, поэтому мы можем опустить ненужные слои.
При оценке нам не нужно оптимизировать параметры модели. Мы не вычисляем градиенты во время этапов валидации. Для более точной оценки мы можем опустить слои Dropout и другие слои нормализации. Например, это позволит использовать все параметры модели вместо только подмножества весов, как в слое Dropout. Это значительно повысит точность модели, так как вы сможете использовать полную модель.
5. Использование Module и ModuleList
Модель PyTorch обычно наследуется от базового класса torch.nn.Module. Согласно документации:
Подмодули, назначенные таким образом, будут зарегистрированы и их параметры будут преобразованы при вызове to() и т.д.
То, что позволяет базовый класс модуля, – это регистрация каждого слоя внутри модели. Мы можем использовать функции model.to() и аналогичные функции, такие как model.train() и model.eval(), и они будут применяться к каждому слою внутри модели. Если этого не сделать, устройство или режим обучения для каждого слоя, содержащегося в модели, не изменится. Вам придется делать это вручную. Базовый класс Module автоматически выполняет преобразования для вас, как только вы просто используете функцию на объекте модели.
Кроме того, некоторые модели содержат похожие последовательные слои, которые можно легко инициализировать с помощью цикла for и поместить в список. Это упрощает код. Однако это вызывает ту же проблему, что и выше, так как модули в простом списке Python не регистрируются автоматически внутри модели. Мы должны использовать ModuleList для хранения похожих последовательных слоев внутри модели.
import torch
import torch.nn as nn
# Наследование от базового класса Module
class Model(nn.Module):
def __init__(self, input_size, output_size):
# Инициализация родительского класса Module
super().__init__()
self.dense_layers = nn.ModuleList()
# Добавление 5 линейных слоев и помещение их в ModuleList
for i in range(5):
self.dense_layers.append(
nn.Linear(input_size, 512)
)
self.output_layer = nn.Linear(512, output_size)
def forward(self, x):
# Упрощает прямое распространение.
# Вместо повторения одной строки для каждого слоя, используйте цикл
for layer in range(len(self.dense_layers)):
x = layer(x)
return self.output_layer(x)
Вышеуказанный фрагмент кода показывает правильный способ создания модели и подуровней с использованием модели. Использование Module и ModuleList помогает избежать непредвиденных ошибок при обучении и оценке модели.
Заключение
Вышеупомянутые методы являются лучшими практиками для фреймворка машинного обучения PyTorch. Они широко используются и рекомендуются в документации PyTorch. Использование таких методов должно быть основным способом организации кода в машинном обучении и, безусловно, улучшит ваши результаты. Мухаммад Архам – инженер глубокого обучения, работающий в области компьютерного зрения и обработки естественного языка. Он работал над развертыванием и оптимизацией нескольких приложений искусственного интеллекта, которые попали в мировые хит-парады на платформе Vyro.AI. Он заинтересован в создании и оптимизации моделей машинного обучения для интеллектуальных систем и верит в постоянное совершенствование.