Основы глубокого обучения: PyTorch, ресурсы и эффективность 0:04
Создание языковых моделей «с нуля» требует глубокого понимания механики работы фреймворков, таких как PyTorch, и жесткого контроля за использованием вычислительных ресурсов. Вторая лекция курса CS336 в Стэнфордском университете посвящена практическим аспектам построения моделей: от работы с тензорами до оценки затрат на обучение. Главная мысль автора заключается в том, что при масштабировании моделей эффективность вычислений напрямую конвертируется в финансовые затраты, поэтому точный расчет операций (FLOPs) и управления памятью становится критически важным навыком.
🏗️ Тензоры и управление памятью 5:14
Тензоры являются фундаментальными блоками глубокого обучения, хранящими параметры, градиенты, данные и состояния оптимизатора. Понимание того, как они устроены в PyTorch, позволяет писать более эффективный код.
- Структура и представления: Тензоры в PyTorch — это указатели на области памяти с метаданными, определяющими доступ к данным (stride). Многие операции, такие как создание представлений (view), транспонирование или нарезка, не создают копий, что экономит память.
- Контигуальность: Некоторые операции (например, транспонирование) могут делать тензор «неконтигуальным» (разрывным в памяти). В таких случаях перед изменением формы (reshape) необходимо принудительно сделать тензор контигуальным, что создает копию данных.
- Типы данных (Precision): Выбор точности напрямую влияет на потребление памяти и стабильность:
- float32 (FP32): «Золотой стандарт», обеспечивающий стабильность, но требующий больше памяти.
- float16: Сокращает память вдвое, но страдает от проблем с динамическим диапазоном (underflow/overflow).
- bfloat16 (Brain Float): Разработан для глубокого обучения; обеспечивает динамический диапазон FP32 при размере FP16, что делает его отличным выбором для вычислений.
- FP8: Современный стандарт (представлен NVIDIA в 2022 году) для еще большей экономии, поддерживаемый архитектурой H100.
🧮 Вычислительная эффективность и FLOPs 33:24
Автор делает акцент на том, что FLOPs (Floating Point Operations) — это количество выполненных вычислений, в то время как FLOPS (с верхним регистром S) — это скорость оборудования. Для ясности в курсе используется запись FLOP/s.
- Магическое число 2: Для матричного умножения количество FLOPs равно $2 \times (\text{размер}_1 \times \text{размер}_2 \times \text{размер}_3)$. Это базовый инструмент для «напкин-расчетов» при планировании обучения.
- MFU (Model FLOPs Utilization): Полезная метрика, равная отношению реально выполненных полезных операций к теоретически доступной производительности железа. Значение выше 0.5 считается хорошим результатом.
- Роль тензорных ядер: Современные GPU, включая H100, используют специализированные тензорные ядра для матричных вычислений. PyTorch автоматически задействует их, что важно учитывать при оценке производительности.
📈 Градиенты и бэкпропагация 49:43
При обучении линейной модели стоимостью «двух слоев» автор демонстрирует, что количество вычислительных затрат на обратный проход (backward pass) в два раза превышает затраты на прямой проход (forward pass).
- Соотношение затрат: Для простой линейной модели прямой проход требует $2 \times \text{данные} \times \text{параметры}$, а обратный — $4 \times \text{данные} \times \text{параметры}$, что в сумме дает $6 \times \text{данные} \times \text{параметры}$.
- Активации: Потребность в хранении активаций в памяти обусловлена необходимостью вычисления градиентов на обратном пути. Методы вроде activation checkpointing позволяют экономить память, пересчитывая активации вместо их хранения.
🛠️ Практические советы по разработке 64:04
- Воспроизводимость: Автор настоятельно рекомендует всегда использовать фиксированные случайные сиды для инициализации, dropout и других стохастических процессов.
- Оптимизаторы: В рамках обучения подробно разбирается переход от SGD к Adam через AdaGrad. Реализация собственного оптимизатора в PyTorch требует управления словарем состояния (
state), в котором хранятся тензоры (например, накопленные квадраты градиентов). - Смешанная точность: Оптимальная стратегия — использовать низкую точность (например, bf16) для матричных умножений и высокую (float32) для хранения параметров и состояний оптимизатора, чтобы избежать нестабильности обучения.