Пишем ИИ для Змейки на чистом Си

freeCodeCamp.org 12,7 тыс. 2 ч 18 мин 20 мин 19.08.2026
Главное

Обучение нейросетей с нуля на чистом Си без единой внешней библиотеки — задача, от которой у большинства разработчиков сдадут нервы, но Харш Бхатт доказал её выполнимость на примере классической «Змейки». Создав собственный движок автодифференцирования, эффективный арена-аллокатор памяти и алгоритм REINFORCE прямо в procedural-парадигме, он наглядно показал, как устроены ML-фреймворки изнутри. Это хардкорное погружение в инженерию искусственного интеллекта без магии высокоуровневых абстракций.

🛠️ Фундамент RL-библиотеки на Си: архитектура и управление памятью 0:00

Обзор проекта: RL-библиотека на Си с нуля 0:00

В современном программировании создание нейросетей обычно ассоциируется с высокоуровневыми фреймворками, такими как PyTorch или TensorFlow, однако Харш Бхатт (Harsh Bhatt) предлагает радикально иной подход. Цель данного курса — построить полноценную библиотеку для обучения с подкреплением (Reinforcement Learning) на чистом языке Си, не используя сторонние ML-библиотеки . Основной фокус направлен на реализацию алгоритма градиента политики REINFORCE . Чтобы доказать работоспособность системы, автор планирует не просто написать математическое ядро, но и реализовать с нуля окружение классической игры «Змейка», где агент будет учиться навигации и поиску пищи в режиме реального времени .

Харш Бхатт (Harsh Bhatt) подчёркивает, что для понимания курса желательно иметь базовое представление о цикле взаимодействия агента со средой: как совершаются действия, как среда возвращает награды и каким образом происходит обучение на основе обратной связи . Проект разделен на несколько фундаментальных блоков: создание движка автоматического дифференцирования (autograd), разработку модели нейросети, проектирование игрового окружения и реализацию самого алгоритма обучения . Вдохновением для проекта послужили работы других разработчиков в области низкоуровневых ML-библиотек, что подталкивает к исследованию того, как именно нейронные сети функционируют «под капотом» на уровне указателей и структур данных .

Проектирование движка автоградиентных вычислений 2:27

Сердцем любой современной библиотеки глубокого обучения является механизм автоматического дифференцирования. Харш Бхатт (Harsh Bhatt) начинает проектирование с этого фундаментального элемента, так как обучение нейросети требует прохождения вычислительного графа в двух направлениях: прямом (forward pass) для получения предсказания и обратном (backward pass) для вычисления градиентов . Этот процесс позволяет автоматически определять, как изменение каждого веса влияет на итоговую ошибку, что и называется автодифференцированием .

Основной единицей данных в этой системе выступает структура var (переменная). Она спроектирована как узел графа и содержит следующие элементы:

Для описания операций вводится структура VarType, которая хранит указатели на функции прямого и обратного прохода, имя операции и параметры её формы (shape) . Харш Бхатт (Harsh Bhatt) уточняет, что такие операции, как ReLU или Softmax, требуют только одного входа, в то время как сложение или умножение матриц — минимум двух . Это разделение на типы переменных позволяет движку гибко выстраивать цепочки вычислений любой сложности .

Управление памятью и структура мем-арены 10:00

Одной из самых сложных задач при написании ML-библиотеки на Си является эффективное выделение памяти под тысячи узлов графа и тензоров. Чтобы избежать фрагментации и накладных расходов от стандартного malloc, Харш Бхатт (Harsh Bhatt) использует концепцию «арены памяти» (Memory Arena), подключая заголовочный файл arena.h . Арена представляет собой заранее выделенный большой буфер памяти, из которого последовательно нарезаются блоки для нужд приложения .

Для управления глобальным состоянием системы создается структура Model, которая интегрируется с ареной. В этой структуре хранятся:

  1. Текущее количество созданных переменных (number_of_vars) .
  2. Значения преимуществ (advantages), необходимые для алгоритмов RL .
  3. Указатель на саму арену для аллокации новых узлов.

При создании новой матрицы внутри графа используется функция push_array, которая просто сдвигает указатель внутри арены на нужный размер (количество строк умноженное на количество столбцов) . Это гарантирует, что все данные графа лежат в памяти компактно. При инициализации переменной через create_var автор также вводит систему флагов, например requires_grad . Если флаг установлен, система автоматически выделяет память под матрицу градиентов; если нет — экономит ресурс, создавая только матрицу значений . Каждая новая переменная автоматически регистрируется в состоянии модели, инкрементируя общий счетчик, что позволяет легко отслеживать размер вычислительного графа в реальном времени . В завершение Харш Бхатт (Harsh Bhatt) подготавливает структуру самого графа, которая будет содержать массив указателей на все задействованные переменные .

🏗️ Проектирование узлов и механизмы формирования графа 25:01

На данном этапе Харш Бхатт (Harsh Bhatt) переходит от базовых структур данных к архитектуре вычислительного графа, который станет «сердцем» нейросетевого движка. Главная задача здесь — обеспечить связность операций и автоматизировать проверку математической корректности вычислений еще на этапе сборки модели .

Создание узлов и логика вычислительных операций 25:01

Основой графа является узел (node), который Харш Бхатт определяет как структуру, инкапсулирующую переменную и её связи . В отличие от простых массивов данных, узел в автоградиентном движке должен «знать», из каких входных компонентов он был получен. Функция create_node принимает ссылки на две родительские переменные — A и B . Это позволяет движку восстанавливать цепочку вычислений в обратном направлении.

Внутри реализации узла Харш Бхатт выделяет несколько критических компонентов:

Ранее в разговоре автор касался структуры мем-арены, и здесь она используется для выделения памяти под новые переменные в рамках модели . Каждый узел также получает свой тип (v_type), определяющий, какая именно математическая операция будет выполняться при прямом проходе .

Алгоритм обхода графа в обратном порядке 35:57

Когда узлы созданы и связаны, возникает следующая проблема: в каком порядке их нужно выполнять? Харш Бхатт объясняет, что для нейронной сети порядок вычислений при прямом проходе должен быть строго последовательным, от входа к выходу, а при обратном — наоборот . Для автоматизации этого процесса он реализует алгоритм поиска в глубину (DFS) с использованием стека .

Процесс построения графа начинается с финального узла — например, функции активации Softmax на выходе сети . Отталкиваясь от этого «выходного провода» (outwire), алгоритм начинает рекурсивно искать все зависимости, которые привели к получению данного результата .

Харш Бхатт детально разбирает проблему дублирования зависимостей, демонстрируя это на слайдах . В сложных графах одна и та же переменная может использоваться в разных ветвях вычислений (например, переменная B может быть входом и для узла X, и для узла Y) . Если просто добавлять все найденные узлы в стек, переменная B окажется там дважды, что приведет к ошибкам при расчете градиентов и избыточным операциям .

Для решения этой проблемы автор вводит следующие механизмы:

  1. Массив посещенных узлов (visited): Каждому узлу присваивается индекс, и алгоритм помечает его как «посещенный», чтобы не заходить в одну и ту же ветку дважды .
  2. Динамическое переупорядочивание стека: Если алгоритм обнаруживает, что узел уже находится в стеке, но встречается снова как зависимость другого пути, происходит «сдвиг» . Харш Бхатт реализует логику перемещения элементов: старая позиция узла удаляется, а сам узел переносится в правильное место, чтобы гарантировать топологический порядок выполнения .
  3. Итеративный цикл: Вместо классической рекурсии, которая может привести к переполнению стека в глубоких сетях на Си, Харш использует цикл while stack_size > 0 .

Результатом работы этого алгоритма становится массив узлов, выстроенный в идеальном порядке для выполнения вычислений . Харш Бхатт подчеркивает, что такая архитектура позволяет строить графы любой сложности, сохраняя при этом контроль над памятью и эффективностью, что особенно важно при разработке на языке Си с нуля .

🧠 Реализация операторов: от функций активации до матричных вычислений 50:04

После того как фундамент вычислительного графа заложен, Харш Бхатт (Harsh Bhatt) переходит к «сердцу» библиотеки — реализации конкретных математических операций, которые будут выполняться в узлах этого графа . На этом этапе фокус смещается с абстрактных структур на прикладную математику нейронных сетей, начиная от базовых функций активации и заканчивая сложными алгоритмами матричного умножения с поддержкой транспонирования .

Математика активаций: Softmax, ReLU и проверка размерностей 51:09

Реализация нейросетевых операторов начинается с определения типов переменных (v_type) и написания вспомогательных функций для валидации данных . Харш Бхатт подчёркивает, что перед выполнением любой операции необходимо убедиться в совместимости тензоров . Для этого внедряется функция var_shape, которая проверяет, совпадают ли строки и столбцы у операндов . Если формы корректны, функция обновляет метаданные узла, фиксируя правильные размерности для выходного тензора .

Особое внимание уделяется функции Softmax, которая критически важна для модели Actor (в рамках алгоритма REINFORCE, выбранного автором из-за его относительной простоты по сравнению с PPO) . При кодировании Softmax в прямом проходе (forward) Харш использует стандартный подход с обеспечением численной стабильности . Алгоритм включает в себя:

Параллельно реализуется функция ReLU . Её логика в Си-коде предельно проста: итерация по массиву данных и обнуление всех отрицательных значений, в то время как положительные остаются без изменений . Это базовый кирпичик нелинейности, который позволяет сети обучаться сложным зависимостям . Ранее в разговоре автор уже упоминал, что все эти операции вписываются в общую структуру узлов графа, где для каждого типа прописаны указатели на функции прямого и обратного прохода .

Поэлементные операции и градиенты 1:03:41

Помимо функций активации, нейросети требуют выполнения множества арифметических действий над тензорами. Харш Бхатт реализует поэлементное сложение (add) и вычитание (sub) . Код этих операций строится по схожему шаблону: вычисляется общий размер данных (количество столбцов, помноженное на количество строк), после чего запускается цикл, выполняющий операцию для каждого индекса .

При реализации градиентов (обратного прохода) для этих операций логика остаётся прямолинейной: для сложения градиент просто передаётся дальше, так как производная суммы по каждому слагаемому равна единице . Эти низкоуровневые манипуляции с памятью напрямую взаимодействуют с системой управления ресурсами, созданной в начале проекта, что позволяет избегать утечек при постоянном создании временных тензоров во время обучения .

Матричное умножение и магия транспонирования 1:04:29

Самой сложной и важной частью этого этапа является реализация матричного умножения (MatMul) . В отличие от простых поэлементных функций, MatMul требует трёх вложенных циклов и строгой проверки совместимости (число столбцов первой матрицы должно быть равно числу строк второй) .

Харш Бхатт объясняет, что в библиотеке используется «строчный порядок» (row-major order) хранения данных в памяти . Это означает, что двумерная матрица разворачивается в одномерный массив, и для доступа к элементу используется формула: index = row * num_columns + column .

Для эффективного обучения нейросети (Backpropagation) недостаточно просто уметь умножать матрицы A и B. Часто требуется умножать транспонированные матрицы (например, при расчёте градиентов по весам или по входу) . Вместо того чтобы физически копировать и переставлять данные в памяти (что затратно), Харш реализует логику «виртуального» транспонирования через изменение формул индексации внутри алгоритма умножения :

  1. mat_n: Стандартное умножение (No Transpose) .
  2. mat_nt: Умножение A на транспонированную B .
  3. mat_tn: Умножение транспонированной A на B .
  4. mat_tt: Оба операнда транспонированы .

Такой подход позволяет динамически изменять порядок обхода памяти. Например, если матрица A транспонирована, то вместо итерации по строкам алгоритм начинает интерпретировать её структуру так, будто строки стали столбцами, меняя переменные i и k в формуле смещения . В завершение Харш объединяет все эти случаи в одну универсальную функцию mat, которая выбирает нужный алгоритм индексации в зависимости от флагов, переданных узлом вычислительного графа .

🎮 Проектирование игрового окружения и векторизация состояний 1:15:04

Прежде чем переходить к архитектуре нейронной сети, Харш Бхатт завершает работу над вычислительным бэкендом, реализуя функции для градиентов REINFORCE . Он подчёркивает, что для этого алгоритма градиент рассчитывается как отношение вознаграждения к вероятности действия с отрицательным знаком . Завершив математическую подготовку, включая вычисление градиента Softmax через скалярное произведение данных , автор переходит к созданию полигона для обучения агента — классической игры «Змейка» .

Логика и структура окружения «Змейка» 1:23:47

Харш Бхатт решает создать среду «Змейки» (Snake Environment) как простую, но эффективную задачу для демонстрации возможностей RL-библиотеки на Си . Проектирование начинается с определения перечислений для действий (actions): влево (0), вправо (1), вверх (2) и вниз (3) . В основе окружения лежит структура snake_env, которая хранит в себе полное состояние игрового мира: положение тела змейки, координаты еды, текущий счёт и количество пройденных шагов .

Ключевым аспектом механики является POV (Point of View) — точка обзора или текущее направление движения змейки . В отличие от классических аркад, где змейка может мгновенно изменить направление по нажатию клавиши, в этой реализации модель управляет направлением движения (POV), которое сохраняется до следующего шага . Если модель решает не предпринимать никаких действий (none), змейка продолжает двигаться в текущем направлении POV .

Для управления игровым полем автор использует сетку, размеры которой определяются через строки (rows) и столбцы (columns) . Сетка чаще всего проектируется квадратной, где положение каждой точки (например, головы змейки или еды) задаётся координатами X и Y . Начальное состояние инициализируется в левом нижнем углу (0, 0) с направлением движения вправо . Также реализована функция сброса среды (reset_env), которая возвращает змейку в исходную точку и генерирует новое случайное положение еды с помощью встроенного генератора псевдослучайных чисел .

Сбор опыта и буфер воспроизведения (Replay Buffer) 1:26:13

Одной из фундаментальных особенностей обучения с подкреплением является отсутствие заранее подготовленных данных — агент создаёт их сам в процессе взаимодействия со средой . Харш Бхатт вводит понятие «роллаутов» (rollouts) — процесса сбора коллекций данных в ходе игры . Для хранения этого опыта создаётся структура replay_buffer, которая аккумулирует траектории движения .

Каждая траектория включает в себя:

Размер буфера в данном проекте определён в 1024 записи, а максимальная длина эпизода ограничена 100–200 шагами . Это предотвращает бесконечные циклы, если змейка начнёт двигаться по кругу, не достигая цели . Автор поясняет, что после завершения эпизода (или заполнения буфера) накопленный опыт используется для корректировки весов модели, чтобы «исправить» действия агента в будущем . Ранее в разговоре они кратко касались структуры мем-арены, и здесь Харш также использует арену для эффективного выделения памяти под игровое окружение .

Векторизация состояния и система наград 1:36:16

Чтобы нейронная сеть могла «видеть» игровое поле, Харш Бхатт реализует механизм векторизации — преобразования структуры игры во входной вектор (embeddings/one-hot vector) . Поскольку модель не может напрямую обрабатывать координаты объектов, мир змейки представляется в виде плоского массива (flat vector) . Для поля размером 6x6 (36 ячеек) создаётся вектор, где позиции головы змейки и еды помечаются значением 1.0, а пустые клетки — 0.0 .

Процесс перевода 2D-координат (x, y) в индекс плоского массива выполняется по формуле: index = x + (y * columns) . Таким образом, если голова змейки находится в определённой ячейке, соответствующий индекс в векторе состояния получает сигнал . В этот же вектор добавляется информация о текущем POV, что позволяет модели учитывать инерцию движения .

Система вознаграждений в окружении построена на простых правилах :

  1. Положительная награда: начисляется при поедании еды, что увеличивает общий счёт (score) .
  2. Штраф (отрицательная награда): применяется, если змейка врезается в стену или собственное тело .
  3. Стимул к эффективности: каждое действие, не приводящее к смерти, может иметь небольшой штраф или нейтральное значение, чтобы поощрять поиск кратчайшего пути к еде .

Этот векторный вход становится основой для обучения: модель анализирует паттерны расположения еды и стен, чтобы предсказать действие, максимизирующее суммарную награду за эпизод .

🏗️ Построение пайплайна обучения и сбор опыта (Rollouts) 1:44:07

После того как Харш Бхатт (Harsh Bhatt) завершил работу над логикой вознаграждений в окружении «Змейка», где агент получает штрафы за столкновения и бонусы за еду , он переходит к критически важному этапу — созданию пайплайна обучения. В Reinforcement Learning (RL) этот процесс представляет собой циклическую последовательность: сбор траекторий (rollouts), расчет возвратов, сохранение опыта в буфер и последующее обновление весов модели .

Сердцем этого процесса является функция train, которая управляет жизненным циклом агента на протяжении множества эпох. Харш Бхатт (Harsh Bhatt) подчеркивает, что структура обучения в Си, несмотря на отсутствие высокоуровневых абстракций вроде тех, что есть в PyTorch, строится на тех же принципах . Основные этапы пайплайна включают:

  1. Цикл по эпохам: Глобальный итератор, определяющий общую продолжительность обучения .
  2. Сбор роллаутов (Rollouts): Внутри каждой эпохи агент взаимодействует с окружением в течение фиксированного количества шагов или до завершения эпизода .
  3. Использование буфера траекторий: Для хранения данных о текущем опыте создается структура trajectory, которая выступает в роли временного буфера . В ней фиксируются состояния, действия и полученные награды.
  4. Управление гиперпараметрами: На этом этапе инициализируются такие значения, как длина эпизода (episode length) и коэффициент дисконтирования гамма (gamma), необходимые для будущих расчетов .

Особое внимание Харш уделяет организации взаимодействия модели с графом вычислений. Для каждого шага в роллауте необходимо построить вычислительный граф, выполнить прямой проход для получения вероятностей действий и сохранить состояние графа для последующего обратного прохода . Ранее в разговоре автор уже упоминал структуру мем-арены, и здесь она становится незаменимой, позволяя быстро выделять и очищать память для временных узлов графа во время каждой итерации сбора опыта .

Чтобы эффективно собирать опыт, Харш реализует цикл, ограниченный длиной эпизода . На каждом шаге агент анализирует вектор состояния, полученный из окружения, и выбирает действие . Все эти переходы должны быть атомарно записаны в буфер, чтобы алгоритм обучения мог корректно соотнести действия агента с итоговым результатом.

🧠 Инициализация архитектуры Actor-Critic и весовых слоев 1:59:22

Для управления поведением «Змейки» Харш Бхатт (Harsh Bhatt) приступает к проектированию архитектуры Actor-Critic модели. Несмотря на название, в данном фрагменте основной упор делается на инициализацию слоев, которые будут предсказывать вероятности действий (Actor) . Реализация на чистом Си требует ручного создания каждого тензора весов и смещений, а также определения их связей в графе.

Архитектура нейросети, предложенная автором, имеет следующие параметры:

Процесс инициализации в функции create_actor_critic_model начинается с выделения памяти через мем-арену для структур весов (weights) и смещений (bias) . Харш Бхатт (Harsh Bhatt) использует функцию для заполнения параметров случайными значениями (random initialization), что критически важно для предотвращения симметрии нейронов при старте обучения . Для каждого тензора параметров устанавливается флаг requires_grad, указывающий движку автограда, что для этих узлов необходимо вычислять градиенты .

Связывание слоев происходит через создание узлов матричного умножения (v_mat_mul) и сложения (v_add) . Автор буквально «прошивает» архитектуру:

  1. Результат умножения входа на первые веса (weight0) суммируется со смещением (bias0) .
  2. Полученное значение проходит через функцию активации ReLU для внесения нелинейности и нормализации промежуточных вычислений .
  3. Финальный слой завершается операцией Softmax, которая превращает сырые значения (логиты) в распределение вероятностей действий .

Харш отмечает, что такая «ручная» сборка в стиле PyTorch, но на низком уровне Си, позволяет наглядно увидеть, как формируются узлы графа и как данные текут от входного вектора к финальному решению агента . В завершение инициализации подготавливаются переменные для функции потерь (Reinforce loss) и преимуществ (advantages), которые будут заполнены данными уже в процессе обучения .

🏁 Финализация обучения: от расчета возвратов до первых успехов REINFORCE 2:05:22

На финальном этапе разработки RL-библиотеки Харш Бхатт (Harsh Bhatt) переходит к самой ответственной части — превращению собранного опыта в обновленные веса нейросети. После того как процесс сбора данных (rollouts) завершен , необходимо математически интерпретировать полученные награды, чтобы агент мог понять, какие действия привели к успеху, а какие — к гибели «Змейки».

Расчет дисконтированных возвратов и преимуществ 2:07:41

Процесс обучения начинается с вычисления «возвратов» (returns) для каждого шага внутри траектории. Харш Бхатт (Harsh Bhatt) объясняет, что просто суммировать награды недостаточно — необходимо использовать коэффициент дисконтирования ($\gamma$, gamma) . Это позволяет алгоритму отдавать приоритет немедленным наградам перед отдаленными и математически стабилизирует сходимость.

Алгоритм расчета реализован через обратный проход по траектории (от конца эпизода к началу) . Основные шаги выглядят следующим образом:

Во время отладки автор замечает, что на первых итерациях змейка постоянно получает отрицательные награды . Это ожидаемо: необученная модель совершает хаотичные движения и быстро врезается в стены или собственное тело . Чтобы алгоритм REINFORCE работал эффективнее, вычисляется «преимущество» (advantage) — разница между реальным полученным возвратом и средним значением (baseline) . Харш Бхатт (Harsh Bhatt) подчеркивает, что использование среднего значения в качестве базовой линии помогает снизить высокую дисперсию, характерную для градиентных методов политики .

Оптимизация весов и градиентный спуск 2:10:11

Когда преимущества для каждого шага рассчитаны, наступает фаза непосредственного обучения. Первым делом необходимо очистить градиенты во всем вычислительном графе, чтобы накопленные значения с предыдущих итераций не искажали текущий шаг оптимизации . Хотя ранее в курсе обсуждалось проектирование движка автодифференцирования, именно здесь его работа становится критической.

Для обновления весов Харш Бхатт (Harsh Bhatt) выполняет цикл по всему буферу опыта (rollout buffer) . На каждой итерации:

  1. Состояние из траектории подается на вход сети .
  2. Выполняется прямой проход (forward pass) через граф для получения предсказаний .
  3. Рассчитывается градиент функции потерь, масштабированный на величину «преимущества» для конкретного выбранного действия .
  4. Запускается обратный проход (backward pass) по графу стоимости (cost graph) .

Завершается цикл шагом оптимизатора. В этой минималистичной реализации на Си автор применяет классический градиентный спуск . Веса обновляются путем вычитания градиента, умноженного на коэффициент скорости обучения (learning rate), который дополнительно масштабируется на количество образцов в батче (sample count) для стабилизации обучения . Харш Бхатт (Harsh Bhatt) отмечает, что он намеренно избегал сложных проверок безопасности и дополнительных абстракций, чтобы сохранить код лаконичным и уместить всю логику обучения в 400–500 строк .

Итоги тренировки алгоритма REINFORCE 2:16:45

После настройки всех компонентов и запуска цикла обучения автор демонстрирует результаты работы агента. Несмотря на то что REINFORCE считается довольно нестабильным алгоритмом из-за высокого стандартного отклонения градиентов , спустя 20–30 минут тренировки «Змейка» начинает демонстрировать осмысленное поведение.

В логах обучения отчетливо виден прогресс: если изначально возвраты были глубоко отрицательными, то по мере накопления опыта они переходят в положительную зону . Это означает, что агент научился не только избегать немедленной гибели, но и находить еду на игровом поле . Харш Бхатт (Harsh Bhatt) подчеркивает, что даже такая простая реализация policy gradient способна достигать хороших результатов, если дать ей достаточно времени на исследование среды .

Автор признает, что в процессе написания кода «в прямом эфире» он мог допустить мелкие ошибки, но общая структура библиотеки остается работоспособной и пригодной для дальнейшего расширения . Главная цель курса — показать, что Reinforcement Learning на низком уровне (без использования PyTorch или TensorFlow) вполне достижим .

Завершение курса и планы на будущее 2:17:37

Подводя итоги, Харш Бхатт (Harsh Bhatt) отмечает, что формат одного видео накладывает определенные ограничения. Изначально он планировал реализовать в рамках этого курса и более продвинутые алгоритмы, такие как PPO (Proximal Policy Optimization) . Однако из-за огромного хронометража (более двух часов только на базовую структуру) было решено вынести более сложные методы в следующие видео.

Курс завершается призывом к зрителям экспериментировать с созданной библиотекой и улучшать её . В будущих материалах автор обещает рассмотреть:

Проект доказал свою жизнеспособность, превратившись из набора структур данных на Си в полноценный инструмент, способный обучить нейронную сеть играть в «Змейку» с нуля.

💬 Цитаты

«Мы построим движок autograd, который представляет собой вычислительный граф градиентов — именно так обучаются нейронные сети.»

Харш Бхатт 01:33

«Для доступа к памяти мы используем row-major порядок: индекс равен колонке плюс строка, умноженная на количество колонок.»

«Reinforcement learning doesn't require training data because it generates the training data — the experience from the snake.»

«В обучении RL вы делаете роллауты, собираете опыт, вычисляете возвраты и затем обучаете модель на данных из буфера. Это и есть весь пайплайн.»

«Reinforce — очень нестабильный алгоритм с высоким стандартным отклонением, но он всё равно может обучаться и показывать отличные результаты при длительной тренировке.»

👥 Спикер
📖 Термины
Вычислительный граф
Структура данных, представляющая математические операции в виде графа для автоматического вычисления производных (autograd).
REINFORCE
Классический алгоритм обучения с подкреплением на основе policy gradient, использующий траектории для обновления весов модели.
Арена памяти
Метод управления памятью, при котором блок памяти выделяется заранее, что позволяет быстро распределять и освобождать мелкие объекты без фрагментации.
Искусственный интеллект Харш Бхатт REINFORCE Си Вычислительный граф Искусственный интеллект