🔴 Сложный ⏱️ 60 минут

Neural Architecture Search

📋 Содержание урока

Neural Architecture Search 🔍

В уроках 336–338 ты видел, как архитектор нейросети принимает решение за решением: сколько слоёв поставить, какого размера взять фильтры, добавить ли skip connection, как объединить несколько веток в один модуль. VGGNet выбрала глубину и единообразные фильтры $3\times3$. ResNet добавила пропускные соединения, чтобы бороться с затухающим градиентом. Inception отказалась от выбора одного размера фильтра и распараллелила сразу несколько вариантов. Каждое из этих решений — результат человеческой интуиции, многих месяцев экспериментов и, чего уж скрывать, некоторой доли везения: удачная идея у конкретной исследовательской группы в конкретный момент.

Автоматический поиск архитектур (Neural Architecture Search, NAS) задаёт вопрос, который рано или поздно должен был возникнуть: а что, если вместо того чтобы архитектор вручную перебирал варианты «фильтр $3\times3$ или $5\times5$?», «добавить skip connection или нет?», «сколько слоёв — 18 или 34?», превратить сам процесс проектирования архитектуры в задачу оптимизации — точно такую же по духу, как минимизация функции потерь по весам сети, только теперь оптимизируемая переменная — не вектор весов, а сама структура сети? Вместо того чтобы человек предлагал одну архитектуру за другой и проверял её вручную, алгоритм поиска предлагает кандидатов, оценивает их качество и систематически движется в сторону более удачных решений — точно так же, как градиентный спуск (урок 285) движется в сторону убывания функции потерь, только здесь «переменная» дискретна, а «функция потерь» — это минус точность обученной сети на валидации.

Идея звучит соблазнительно просто, но за ней сразу встают три конкретных инженерных вопроса, вокруг которых построен весь этот урок. Во-первых, что вообще значит «перебирать архитектуры» — какое множество решений мы разрешаем алгоритму рассматривать, то есть каково пространство поиска? Во-вторых, как именно перебирать это множество, если оно астрономически огромно и дискретно, — какой метод поиска использовать? Здесь курс неожиданно замыкается сам на себя: ты уже видел эволюционные алгоритмы (урок 296) и обучение с подкреплением (урок 347) как самостоятельные темы, и теперь увидишь их снова, но применёнными не к абстрактной оптимизации числовой функции и не к игре, а именно к поиску архитектуры сети. В-третьих, что делать с тем фактом, что оценка качества одного кандидата — это полноценное обучение нейросети, которое может стоить часы или дни вычислений, а кандидатов нужно перебрать тысячи?

Этот урок — не про ещё одну архитектуру, которую нужно запомнить, а про смену самого способа мышления об архитектурном дизайне, о которой уже было сказано в уроке 338 применительно к EfficientNet. Сегодня мы разберём этот способ мышления вплотную: как устроено пространство поиска, как эволюционные алгоритмы, обучение с подкреплением и дифференцируемый поиск (DARTS) применяются именно к архитектурам, почему EfficientNet — не просто хорошая архитектура, а прямая иллюстрация работы NAS, и почему вычислительная стоимость этого подхода — одна из самых острых проблем во всём машинном обучении, из-за которой пришлось изобретать более дешёвые методы вроде weight sharing.

Знание механики NAS полезно даже тем, кто никогда не запустит собственный поиск архитектуры с нуля — а таких практиков подавляющее большинство, потому что вычислительная стоимость метода для рядового проекта попросту неподъёмна. Понимание того, откуда взялись EfficientNet, MobileNetV3 и десятки других современных архитектур, откуда в их структуре взялись именно эти, порой неочевидные для человеческого глаза комбинации операций, — это часть базовой грамотности специалиста по глубокому обучению в 2026 году, точно так же как понимание симплекс-метода полезно даже тем, кто никогда не пишет решатель линейного программирования с нуля, а просто вызывает готовую библиотеку.

История

В ноябре 2016 года исследователи Google Brain Барре Зоф (Barret Zoph) и Куок Ле (Quoc V. Le) — тот самый Куок Ле, который тремя годами позже возглавит команду EfficientNet, — опубликовали работу «Neural Architecture Search with Reinforcement Learning» («Поиск архитектур нейросетей с помощью обучения с подкреплением»). Идея была по-настоящему дерзкой: обучить рекуррентную сеть-контроллер, которая генерирует описание архитектуры сверточной сети как последовательность решений — число фильтров, размер фильтра, шаг свёртки на каждом слое, — а затем каждую предложенную архитектуру полностью обучать на CIFAR-10, измерять точность на валидации и использовать эту точность как сигнал награды, чтобы обучить сам контроллер через градиент политики — тот самый аппарат обучения с подкреплением, который ты подробно разбирал в уроке 347. Ресурсы, которые потребовались для этого эксперимента, поражали воображение современников: сотни GPU, работавших параллельно на протяжении нескольких недель, чтобы обучить и оценить тысячи предложенных архитектур-кандидатов.

Результат оправдал вложения — найденная контроллером архитектура для CIFAR-10 показала точность, сопоставимую или лучшую, чем лучшие на тот момент архитектуры, спроектированные вручную командами экспертов. Год спустя та же команда выпустила NASNet — архитектуру, найденную уже не для всей сети целиком, а для повторяемого строительного блока (ячейки, cell), которую затем стекировали нужное число раз, — этот приём радикально сократил пространство поиска и позволил переносить найденную ячейку с маленького CIFAR-10 на куда более тяжёлый ImageNet, о чём подробнее пойдёт речь в разделе про пространство поиска. Параллельно и вскоре после этого начали появляться альтернативные методы поиска: эволюционные алгоритмы (Real et al., начиная с 2017 года, а строже формализованные в статье о регуляризованной эволюции 2019 года) показали, что мутация и отбор справляются с задачей поиска архитектуры не хуже обучения с подкреплением, а в 2018 году вышел DARTS (Liu, Simonyan, Yang) — метод, который заменил дискретный перебор архитектур на непрерывную, дифференцируемую релаксацию задачи, решаемую напрямую градиентным спуском, и тем самым обрушил вычислительную стоимость поиска на порядки.

Вся эта эволюция методов — от «обучи тысячи сетей полностью» через «обучи много сетей частично, используя эволюцию» до «обучи одну большую сеть-суперпозицию и извлеки из неё архитектуру градиентным спуском» — это прямая история борьбы с вычислительной стоимостью NAS, и она подготовила почву для 2019 года, когда команда Куок Ле применила похожую, платформенно-ориентированную идею поиска (сначала в статье про MnasNet, затем в EfficientNet) не просто ради максимальной точности, а ради оптимального компромисса между точностью и вычислительным бюджетом — именно об этой архитектуре, уже знакомой тебе по уроку 338, пойдёт отдельный разговор дальше в этом уроке.

Пространство поиска: что именно перебирает NAS

Интуиция

Прежде чем какой-либо алгоритм сможет «искать архитектуру», нужно чётко очертить, из чего вообще выбирать. Пространство поиска (search space) — это формально описанное множество всех архитектур, которые алгоритм в принципе способен предложить: сколько слоёв разрешено, какие операции доступны на каждом слое (свёртка $3\times3$, свёртка $5\times5$, разделимая свёртка, пулинг, identity-связь без изменений), и как слои могут соединяться друг с другом — то есть допускаются ли пропускные связи, объединение нескольких предыдущих слоёв в один, как в Inception-модуле (урок 338). Дизайн пространства поиска — это, по сути, тот же интеллектуальный труд, что раньше вкладывал архитектор при ручном проектировании, только теперь человек проектирует не саму сеть, а множество сетей, из которого сеть будет выбрана автоматически. Слишком узкое пространство поиска гарантированно исключает потенциально лучшие решения ещё до начала поиска — алгоритм физически не может предложить то, чего нет в списке допустимых вариантов. Слишком широкое пространство делает поиск астрономически дорогим, потому что число возможных архитектур растёт комбинаторно с каждым дополнительным структурным решением.

Формула

Макро-пространство поиска (chain-structured). Пусть архитектура — это цепочка из $L$ слоёв, и на каждом слое независимо выбирается одна операция из множества $\mathcal{O}$ мощностью $|\mathcal{O}|=K$. Тогда размер пространства поиска:

$$|\mathcal{A}| = K^L$$

Микро-пространство поиска (cell-based). Вместо того чтобы искать структуру всей сети целиком, ищут структуру одной небольшой ячейки (cell) с $N$ промежуточными узлами; узел $i$ выбирает источники входа из числа уже существующих узлов (два фиксированных входа ячейки плюс $i-1$ предыдущих промежуточных узлов, то есть $i+1$ источников) и операцию из $\mathcal{O}$ для каждого выбранного входа. Найденная ячейка затем стекируется (повторяется подряд) фиксированное число раз $M$, формируя полную сеть — при этом пространство поиска описывает только саму ячейку, а не всю сеть целиком.

Разбор примеров

Пример 1 (макро-пространство — комбинаторный взрыв даже на скромной глубине). Пусть архитектура — это цепочка из $L=12$ слоёв, и на каждом слое доступно $K=8$ операций (например, свёртки $1\times1$, $3\times3$, $5\times5$, их разделимые варианты, max-pooling, avg-pooling, identity). Размер пространства поиска: $8^{12}$. Посчитаем по шагам: $8^{10} = 1\,073\,741\,824$ (это уже больше миллиарда), тогда $8^{12} = 8^{10}\times8^2 = 1\,073\,741\,824\times64 = 68\,719\,476\,736$ — почти 69 миллиардов различных архитектур только для сети из 12 слоёв с 8 доступными операциями на каждом. Прямой перебор такого множества, где оценка каждого кандидата требует полноценного обучения нейросети, физически невозможен ни на каком реальном вычислительном кластере.

Пример 2 (микро-пространство — на порядки компактнее за счёт переиспользования). Возьмём упрощённую ячейку с $N=3$ промежуточными узлами и набором из $K=6$ операций. Узел 1 выбирает 1 источник из 2 доступных (два входа самой ячейки) и одну из 6 операций: $2\times6=12$ вариантов. Узел 2 выбирает источник уже из 3 доступных (два входа ячейки плюс выход узла 1) и операцию из 6: $3\times6=18$ вариантов. Узел 3 выбирает источник из 4 доступных (два входа плюс узлы 1 и 2) и операцию из 6: $4\times6=24$ варианта. Итоговое число возможных ячеек: $12\times18\times24 = 5\,184$. Даже с учётом того, что реальные NAS-статьи используют более богатые ячейки (больше узлов, отдельные normal- и reduction-ячейки), порядок величины здесь принципиально иной, чем в примере 1: тысячи вариантов против десятков миллиардов — и при этом одна найденная ячейка используется многократно, формируя всю сеть.

Пример 3 (перенос ячейки между задачами — практическая ценность микро-пространства). Пусть ячейка из примера 2 найдена и хорошо показала себя при обучении на CIFAR-10 — маленьком датасете с изображениями $32\times32$, на котором обучение одного кандидата занимает минуты, а не часы. Поскольку сама ячейка не завязана на конкретное разрешение входа или число классов (она лишь описывает внутреннюю структуру блока), её можно взять как есть и стекировать больше раз с бо́льшим числом фильтров для куда более тяжёлой задачи — классификации ImageNet с изображениями $224\times224$ и тысячей классов, — не проводя поиск заново на дорогом датасете. Именно так и поступила команда NASNet: нашла ячейку на дешёвом CIFAR-10, а затем перенесла её на ImageNet, получив архитектуру, конкурентоспособную с лучшими решениями, спроектированными вручную, но при этом потратив на поиск на порядок меньше вычислений, чем потребовался бы прямой поиск сразу на ImageNet.

Почему это важно

Дизайн пространства поиска — это не техническая деталь «для галочки», а решение, которое заранее определяет потолок того, что NAS вообще способен найти: если удачная, ещё не изобретённая операция или тип соединения не входит в множество $\mathcal{O}$, никакой метод поиска, сколь угодно умный, никогда её не предложит. Переход от макро-пространства (искать структуру всей сети целиком) к микро-пространству (искать структуру одной повторяемой ячейки) стал одним из ключевых практических прорывов NAS именно потому, что резко — на много порядков — сократил размер пространства поиска и заодно сделал найденное решение переносимым между задачами разного масштаба, как показано в примере 3. Тот же компромисс между широтой пространства поиска и его практической обозримостью уже встречался тебе в уроке 296 при выборе кодирования хромосомы для генетического алгоритма — и в NAS этот выбор так же полностью лежит на плечах человека, проектирующего сам поиск, а не на алгоритме, который в это пространство «запускают».

Эволюционные алгоритмы в поиске архитектур

Интуиция

Урок 296 подробно разобрал генетический алгоритм: хромосома кодирует решение, кроссовер и мутация создают новых кандидатов, селекция отбирает лучших по фитнесу, элитизм страхует от потери лучшего найденного результата. В контексте NAS вся эта механика переносится почти буквально, с одной принципиальной заменой: там, где в уроке 296 хромосома кодировала число $x$ или вектор гиперпараметров градиентного бустинга, а фитнес вычислялся мгновенно как $f(x)=x^2$ или как точность модели после секунд обучения, в NAS хромосома кодирует архитектуру сети (последовательность операций и связей, как в примерах предыдущего раздела), а фитнес — это точность полностью (или частично) обученной нейросети на валидационных данных. Мутация здесь означает не переворот бита в абстрактной битовой строке, а конкретное архитектурное изменение: заменить свёртку $3\times3$ на свёртку $5\times5$ в одном месте сети, добавить или удалить связь между слоями, изменить число фильтров.

Формула

Кодирование архитектуры как хромосомы. Архитектура из $L$ структурных решений кодируется как вектор $x = (g_1, \dots, g_L)$, где каждый ген $g_i$ принимает значение из алфавита операций $\mathcal{O}$ (по аналогии с хромосомой из урока 296, только алфавит — не $\{0,1\}$, а конечное множество архитектурных операций). Фитнес-функция $f(x) = \text{Acc}_{\text{val}}(\text{train}(x))$ — точность на валидации сети, полученной обучением архитектуры $x$ (полным или частичным).

Регуляризованная эволюция (aging evolution). В отличие от классического генетического алгоритма с элитизмом «сохраняем лучших», при регуляризованной эволюции на каждом шаге: (1) случайно выбирается турнирная подвыборка $S$ размера $s$ из популяции; (2) лучшая по фитнесу особь в $S$ мутирует, порождая одного потомка; (3) потомок добавляется в популяцию; (4) из популяции удаляется самая старая особь — независимо от её фитнеса, даже если это текущий рекордсмен.

Разбор примеров

Пример 1 (мутация архитектурной хромосомы). Пусть сеть из 6 слоёв кодируется хромосомой над алфавитом из семи операций $\mathcal{O}=\{$conv3x3, conv5x5, sepconv3x3, sepconv5x5, maxpool, avgpool, identity$\}$: $x = ($conv3x3, sepconv5x5, maxpool, conv3x3, identity, sepconv3x3$)$. Пусть мутация случайно выбрала ген 3 (значение maxpool) и заменила его на avgpool: новая хромосома $x' = ($conv3x3, sepconv5x5, avgpool, conv3x3, identity, sepconv3x3$)$ отличается ровно в одной позиции — ровно та же логика точечной мутации, что и bit-flip на битовой строке в уроке 296, только алфавит гена — не бит, а одна из семи архитектурных операций.

Пример 2 (кроссовер двух архитектур). Возьмём двух родителей: $P_1 = ($conv3x3, conv3x3, maxpool, sepconv5x5$)$ и $P_2 = ($sepconv3x3, avgpool, conv5x5, identity$)$, одноточечный кроссовер с разрезом после 2-го гена — точно тот же оператор из урока 296, применённый теперь к архитектурам, а не к числам: $\text{потомок} = ($conv3x3, conv3x3, conv5x5, identity$)$ — первые два слоя унаследованы от $P_1$, последние два — от $P_2$. Получившаяся архитектура объединяет «удачное начало» одного родителя с «удачным концом» другого, если оба родителя действительно были хороши в соответствующих частях сети.

Пример 3 (почему регуляризованная эволюция удаляет самых старых, а не худших). Пусть популяция из четырёх архитектур имеет фитнес $\{91\%,\ 88\%,\ 93\%,\ 85\%\}$, и архитектура с фитнесом $93\%$ была создана очень давно — это самая старая особь в популяции. Классический элитизм из урока 296 никогда бы не удалил лучшую особь популяции. Регуляризованная эволюция поступает иначе: если именно эта, самая старая особь с фитнесом $93\%$ оказывается и самой старой, она удаляется вне зависимости от своего высокого фитнеса. На первый взгляд это звучит расточительно, но в контексте NAS у этого есть веская причина: точность архитектуры, обученной за ограниченное время (частичное обучение ради экономии), — зашумлённая, не идеально точная оценка истинного качества; старая особь с высоким измеренным фитнесом могла просто «повезти» на конкретном прогоне обучения, и её долгое доминирование в популяции рискует свести поиск к преждевременной сходимости вокруг случайно удачно оценённого, но не обязательно лучшего решения. Постоянное вымывание старых особей поддерживает разнообразие популяции значительно дольше, чем классический элитизм.

Почему это важно

Применение генетического алгоритма к поиску архитектур — не метафора, а буквально та же самая механика хромосом, генов, кроссовера и мутации из урока 296, перенесённая на новый алфавит и на несоизмеримо более дорогую фитнес-функцию. Именно эта дороговизна фитнеса — не секунды, а часы или дни на одну оценку — и оказалась главной причиной, по которой в NAS-контексте потребовалось модифицировать классическую схему элитизма в сторону регуляризованной эволюции: она компенсирует шум зашумлённых оценок фитнеса и не даёт популяции застрять вокруг единственного, возможно случайно переоценённого решения. Работа Real et al. 2019 года о регуляризованной эволюции — важная историческая веха: эволюционный метод AmoebaNet, построенный на этой идее и не использовавший кроссовер вовсе (только мутацию и удаление по возрасту), на момент публикации превзошёл по точности все архитектуры, найденные ранее обучением с подкреплением, при сопоставимых вычислительных затратах.

Обучение с подкреплением: RNN-контроллер и REINFORCE

Интуиция

В уроке 347 ты разбирал стандартную рамку RL: агент наблюдает состояние, выбирает действие согласно политике $\pi$, получает награду и обновляет политику так, чтобы в будущем чаще выбирать действия, ведущие к более высокой награде. Оригинальный NAS от Зофа и Ле 2016 года — это почти дословное применение этой рамки к задаче поиска архитектуры. Агент здесь — рекуррентная сеть-контроллер; действие на каждом шаге — одно архитектурное решение (число фильтров на этом слое, размер фильтра, шаг свёртки); целая последовательность действий, сгенерированная контроллером за один проход, описывает одну полную архитектуру-кандидата; награда — это точность на валидации после полного обучения этой конкретной архитектуры. Контроллер не получает промежуточной обратной связи по каждому отдельному архитектурному решению — только одну скалярную награду в самом конце всей последовательности, когда предложенная им архитектура уже обучена целиком. Это классическая задача обучения с подкреплением с разреженной наградой (sparse reward), только «средой», с которой взаимодействует агент, служит сам процесс обучения нейросети.

Формула

Политика контроллера и цель обучения. Контроллер, параметризованный $\theta$ (веса рекуррентной сети), генерирует последовательность архитектурных решений $a = (a_1,\dots,a_T)$ с вероятностью $\pi_\theta(a) = \prod_{t=1}^{T}\pi_\theta(a_t \mid a_{1:t-1})$. Цель — максимизировать ожидаемую награду:

$$J(\theta) = \mathbb{E}_{a\sim\pi_\theta}[R(a)], \qquad R(a) = \text{Acc}_{\text{val}}(\text{train}(a))$$

Градиент политики (REINFORCE) с базовой линией. Поскольку награда недифференцируема относительно $\theta$ (обучение и валидация дочерней сети — не дифференцируемая операция), градиент оценивается методом REINFORCE по $m$ сэмплированным архитектурам:

$$\nabla_\theta J(\theta) \approx \frac{1}{m}\sum_{k=1}^{m}\nabla_\theta \log\pi_\theta(a^{(k)})\cdot\bigl(R^{(k)} - b\bigr)$$

где $b$ — базовая линия (например, скользящее среднее наград по предыдущим архитектурам), снижающая дисперсию оценки градиента без внесения смещения.

Разбор примеров

Пример 1 (вычисление лог-вероятности предложенной архитектуры). Пусть контроллер за один проход генерирует $T=4$ архитектурных решения с вероятностями (значения, которые контроллер присвоил именно выбранным на этом прогоне действиям) $p_1=0{,}6$, $p_2=0{,}5$, $p_3=0{,}7$, $p_4=0{,}4$. Логарифм совместной вероятности этой последовательности: $\log\pi_\theta(a) = \ln0{,}6+\ln0{,}5+\ln0{,}7+\ln0{,}4$. По отдельности: $\ln0{,}6\approx-0{,}5108$, $\ln0{,}5\approx-0{,}6931$, $\ln0{,}7\approx-0{,}3567$, $\ln0{,}4\approx-0{,}9163$. Сумма: $-0{,}5108-0{,}6931-0{,}3567-0{,}9163\approx-2{,}4769$. Именно эта величина, умноженная на $(R-b)$, и определяет, насколько сильно и в какую сторону градиент подтолкнёт веса контроллера — сдвигать ли его в сторону более частой генерации именно этой конкретной последовательности решений в будущем.

Пример 2 (роль базовой линии — знак поправки решает судьбу архитектуры). Пусть скользящая средняя награда по уже оценённым архитектурам $b=0{,}85$. Архитектура $k_1$ дала $R^{(k_1)}=0{,}93$: поправка $R-b=0{,}93-0{,}85=0{,}08>0$ — положительная, значит, градиентный шаг увеличит вероятность контроллера повторно предложить похожую последовательность решений в будущем. Архитектура $k_2$ дала $R^{(k_2)}=0{,}78$: поправка $0{,}78-0{,}85=-0{,}07<0$ — отрицательная, значит, шаг уменьшит вероятность повторения такой последовательности. Без базовой линии обе архитектуры со своими сырыми наградами $0{,}93$ и $0{,}78$ подталкивали бы политику в одну и ту же сторону (обе награды положительны сами по себе), просто с разной силой — с базовой линией же алгоритм явно различает «архитектуры лучше среднего» и «архитектуры хуже среднего», что заметно снижает дисперсию оценки градиента и ускоряет сходимость.

Пример 3 (масштаб исходного эксперимента Зофа и Ле). В оригинальной статье 2016 года контроллер за время поиска предложил и полностью оценил порядка 12 800 архитектур-кандидатов, распределённых по 800 графическим процессорам, работавшим параллельно несколько недель. Каждая оценка — это не быстрое вычисление, а полный цикл обучения дочерней сверточной сети на CIFAR-10 с последующим измерением точности на валидации; лишь после этого награда возвращалась контроллеру для одного-единственного шага обновления по формуле REINFORCE. Такой масштаб — наглядная иллюстрация того, почему вычислительная стоимость NAS вообще стала отдельной, острой темой, которой посвящён один из следующих разделов этого урока.

Почему это важно

Применение RL к поиску архитектур — это прямое переиспользование аппарата политики, награды и градиента политики из урока 347, но с двумя специфическими особенностями, которые стоит держать в уме: во-первых, «действие» здесь — целая последовательность решений, генерируемых одним контроллером за один эпизод, а не отдельный шаг в динамически меняющейся среде; во-вторых, награда предельно разреженная и предельно дорогая — она приходит только один раз в конце эпизода и требует полного обучения дочерней сети. Именно эта дороговизна награды и стала главным двигателем последующих методов, включая эволюционные подходы предыдущего раздела и дифференцируемый поиск следующего: и там, и там исследователи искали способ либо получать сигнал о качестве архитектуры дешевле, либо вовсе избежать дискретного семплирования кандидатов один за другим.

DARTS и дифференцируемый поиск архитектур

Интуиция

И эволюционный поиск, и RL-подход из предыдущих разделов объединяет одна общая черта: оба работают с дискретным пространством архитектур и оценивают кандидатов по очереди, один за другим, каждый раз требуя отдельного обучения дочерней сети. DARTS (Differentiable Architecture Search, дифференцируемый поиск архитектур), предложенный в 2018 году, задаёт принципиально другой вопрос: что, если вместо того чтобы на каждом ребре сети выбирать ровно одну операцию из дискретного набора, временно позволить всем операциям работать одновременно, взвешенно, и оптимизировать сами веса этого взвешивания обычным градиентным спуском — тем самым инструментом, который ты подробно разбирал в уроке 285? Дискретный выбор «какая именно операция стоит на этом ребре» превращается в непрерывную задачу «насколько сильно каждая операция должна быть представлена», а раз задача непрерывна и дифференцируема, её можно решать градиентным спуском вместо дорогостоящего перебора дискретных кандидатов.

Формула

Непрерывная релаксация (смешанная операция). Для ребра между узлами $(i,j)$ вводится набор обучаемых архитектурных параметров $\alpha^{(i,j)}_o$ — по одному на каждую операцию $o \in \mathcal{O}$. Вместо выбора одной операции вычисляется взвешенная (через softmax) смесь всех операций из набора:

$$\bar o^{(i,j)}(x) = \sum_{o\in\mathcal{O}}\frac{\exp\left(\alpha^{(i,j)}_o\right)}{\sum_{o'\in\mathcal{O}}\exp\left(\alpha^{(i,j)}_{o'}\right)}\,o(x)$$

Двухуровневая (bi-level) оптимизация. Веса сети $w$ и архитектурные параметры $\alpha$ оптимизируются совместно, но на разных уровнях: $\alpha$ ищется так, чтобы минимизировать потери на валидации при условии, что $w$ — оптимальные веса для данной архитектуры на обучающей выборке:

$$\min_\alpha \mathcal{L}_{\text{val}}(w^*(\alpha),\ \alpha) \quad \text{при} \quad w^*(\alpha) = \arg\min_w \mathcal{L}_{\text{train}}(w,\alpha)$$

На практике точное решение внутренней задачи на каждом шаге недостижимо, поэтому DARTS приближает её одним шагом обычного градиентного спуска, чередуя обновления $w$ и $\alpha$. Дискретизация. После завершения поиска для каждого ребра выбирается ровно та операция, у которой $\alpha^{(i,j)}_o$ максимален, — непрерывная релаксация «схлопывается» обратно в обычную дискретную архитектуру.

Разбор примеров

Пример 1 (вычисление весов смешанной операции через softmax). Пусть на одном ребре доступны три операции — conv3x3, sepconv5x5, skip-connect — с текущими значениями архитектурных логитов $\alpha = (2{,}0,\ 0{,}5,\ -1{,}0)$. Вычислим экспоненты: $e^{2{,}0}\approx7{,}389$, $e^{0{,}5}\approx1{,}649$, $e^{-1{,}0}\approx0{,}368$. Сумма: $7{,}389+1{,}649+0{,}368=9{,}406$. Веса: $w_1 = 7{,}389/9{,}406\approx0{,}786$, $w_2=1{,}649/9{,}406\approx0{,}175$, $w_3=0{,}368/9{,}406\approx0{,}039$. На этом промежуточном этапе поиска смешанная операция на этом ребре — это $\bar o(x)\approx0{,}786\cdot\text{conv3x3}(x)+0{,}175\cdot\text{sepconv5x5}(x)+0{,}039\cdot\text{skip}(x)$ — все три операции участвуют в forward pass одновременно, а не по отдельности.

Пример 2 (один шаг обновления архитектурного параметра). Пусть на текущем шаге для веса $\alpha_{\text{conv3x3}}=2{,}0$ известен градиент функции потерь на валидации $\partial\mathcal{L}_{\text{val}}/\partial\alpha_{\text{conv3x3}} = -0{,}3$ (отрицательный градиент означает, что увеличение этого веса уменьшает валидационные потери — операция полезна) и шаг обучения для архитектурных параметров $\eta_\alpha=0{,}1$. Обновление градиентным спуском: $\alpha_{\text{conv3x3}}^{\text{new}} = 2{,}0 - 0{,}1\times(-0{,}3) = 2{,}0+0{,}03 = 2{,}03$. Вес операции conv3x3 чуть подрос — ровно тот же самый механизм обновления параметра «в сторону, противоположную градиенту», что ты применял к весам сети в уроке 285, только теперь применённый к параметру, кодирующему архитектурное решение, а не к обычному весу нейрона.

Пример 3 (дискретизация после поиска). Продолжая пример 1: после завершения поиска на этом ребре среди весов $\{0{,}786,\ 0{,}175,\ 0{,}039\}$ максимальный — $0{,}786$, соответствующий операции conv3x3. Дискретизация выбирает именно её и полностью отбрасывает две другие операции с этого ребра — финальная архитектура, которую затем обучают с нуля (или дообучают) уже без непрерывной релаксации, содержит только conv3x3 на этом конкретном ребре, а операции sepconv5x5 и skip-connect в ней вообще не участвуют, несмотря на то что во время поиска они вносили небольшой, но ненулевой вклад в forward pass.

Почему это важно

DARTS демонстрирует общий приём, который встречается в оптимизации не только применительно к архитектурам: если дискретная задача мешает применить градиентный спуск, иногда можно построить её непрерывную, дифференцируемую релаксацию, решить релаксированную задачу градиентными методами, а затем дискретизировать результат. Практический эффект этого приёма для NAS колоссален: вместо того чтобы обучать тысячи отдельных дочерних сетей одну за другой, DARTS обучает всего одну сеть-суперпозицию (все операции сразу, взвешенно), в которой веса $w$ и архитектурные параметры $\alpha$ оптимизируются совместно за один, сравнительно недорогой прогон обучения. Именно эта идея — заменить перебор дискретных кандидатов совместной оптимизацией одной большой сети, содержащей их все одновременно, — лежит в основе методов weight sharing, о которых пойдёт речь в разделе про вычислительную стоимость NAS.

EfficientNet: архитектура, рождённая NAS

Урок 338 уже представил EfficientNet как результат NAS, но оставил этот факт как анонс, не раскрывая механику. Теперь, разобрав эволюционный поиск, RL-подход и DARTS, можно закрыть этот вопрос предметно: как именно был найден EfficientNet-B0, базовая архитектура, к которой затем применили compound scaling.

Команда, создавшая EfficientNet, годом ранее (в статье про MnasNet, 2019) разработала поиск, ориентированный не только на точность, но и на вычислительную эффективность сразу — так называемый platform-aware NAS (NAS с учётом целевой платформы). Ключевое отличие от исходного NAS 2016 года — форма награды: вместо того чтобы контроллер (обученный через RL, как в разделе выше) получал в качестве награды одну лишь точность, награда стала комбинировать точность и вычислительную стоимость одновременно.

Многокритериальная награда platform-aware NAS. Для архитектуры-кандидата $m$ с точностью $\text{ACC}(m)$ и числом операций $\text{FLOPS}(m)$ награда:

$$R(m) = \text{ACC}(m) \times \left[\frac{\text{FLOPS}(m)}{T}\right]^{w}$$

где $T$ — целевой бюджет вычислений, а $w$ — небольшой отрицательный показатель (например, $w\approx-0{,}07$), задающий, насколько сильно штрафуется превышение бюджета.

Пример. Пусть архитектура-кандидат имеет $\text{ACC}(m)=0{,}75$ и $\text{FLOPS}(m)=350$ млн операций при целевом бюджете $T=300$ млн, $w=-0{,}07$. Отношение $\text{FLOPS}(m)/T = 350/300\approx1{,}1667$. Логарифм: $\ln1{,}1667\approx0{,}1542$, умножаем на $w$: $0{,}1542\times(-0{,}07)\approx-0{,}0108$, экспонента: $e^{-0{,}0108}\approx0{,}9893$. Награда: $R = 0{,}75\times0{,}9893\approx0{,}7420$. Сравним с гипотетическим кандидатом, точно укладывающимся в бюджет ($\text{FLOPS}=T$, отношение $=1$, множитель $=1$) с той же точностью: его награда была бы ровно $0{,}75$. Превышение бюджета на $16{,}67\%$ обошлось этому кандидату лишь примерно в $0{,}8\%$ награды — мягкий, но систематический штраф, который сдвигает предпочтения поиска в сторону экономных по вычислениям архитектур, не отбрасывая при этом резко чуть более тяжёлые, но заметно более точные кандидаты.

Именно с такой, явно многокритериальной наградой был найден EfficientNet-B0 — базовая архитектура сравнительно небольшого размера, сбалансированная между точностью и стоимостью вычислений. После этого, как ты уже разбирал в уроке 338, для масштабирования базовой архитектуры до размеров B1–B7 применили относительно недорогой grid search по трём коэффициентам compound scaling ($\alpha,\beta,\gamma$) — но сама эта возможность стала следствием того, что NAS уже нашёл компактную, эффективную базовую архитектуру, которую было разумно и практично масштабировать. Урок 338 обещал вернуться к вопросу «как именно работает NAS, нашедший EfficientNet» — этот раздел выполняет это обещание: платформенно-ориентированная награда, помноженная на RL-контроллер (тот же механизм, что и в разделе про обучение с подкреплением этого урока), — вот конкретный ответ.

Вычислительная стоимость NAS и weight sharing

Интуиция

Оценка одного кандидата-архитектуры в NAS — это не быстрое вычисление функции, как $f(x)=x^2$ из учебного примера генетического алгоритма в уроке 296, а полноценное обучение нейросети: часы или дни вычислений на современном GPU, помноженные на тысячи и десятки тысяч кандидатов, которых нужно перебрать за время поиска. Именно поэтому NAS заслуженно считают одной из самых дорогих вычислительных задач во всём машинном обучении — дороже, чем обучение любой одной отдельной модели, потому что весь процесс поиска, по сути, требует обучить не одну модель, а огромный ансамбль моделей-кандидатов, из которых в итоге выбирается лишь одна. Weight sharing (совместное использование весов) — семейство методов, которые атакуют именно эту проблему: вместо того чтобы обучать каждого кандидата с нуля, они обучают одну большую сеть-суперпозицию («супернет», supernet), которая содержит все возможные операции сразу, а конкретных кандидатов оценивают, используя уже обученные общие веса супернета, почти без дополнительного обучения.

Формула

Наивная (без weight sharing) стоимость поиска. Если оценка одного кандидата требует обучения стоимостью $c$ (в GPU-днях), а всего оценивается $N$ кандидатов, суммарная стоимость поиска:

$$C_{\text{полный перебор}} = N \times c$$

Стоимость поиска с weight sharing. Обучается один супернет стоимостью $c_{\text{supernet}}$ (сопоставимой со стоимостью обучения одной обычной сети), а извлечение и оценка каждого из $N$ кандидатов из уже обученного супернета обходится пренебрежимо дёшево ($c_{\text{eval}}\ll c$):

$$C_{\text{weight sharing}} = c_{\text{supernet}} + N\times c_{\text{eval}} \approx c_{\text{supernet}}$$

Разбор примеров

Пример 1 (порядок величины — исторические оценки стоимости разных методов). По оценкам, приводимым в литературе по NAS, оригинальный поиск Зофа и Ле (2016, RL-подход без weight sharing) потребовал порядка $22\,000$ GPU-дней вычислений (около 800 GPU, работавших параллельно несколько недель). Эволюционный поиск AmoebaNet (Real et al., 2019) потребовал сопоставимого порядка — около $3\,000$–$3\,200$ GPU-дней. DARTS, применивший непрерывную релаксацию (по сути, неявную форму weight sharing — одна сеть-суперпозиция вместо множества отдельных кандидатов), сократил стоимость поиска до порядка $4$ GPU-дней на CIFAR-10 — сокращение в тысячи раз при сопоставимом качестве найденной архитектуры. Методы, построенные на явном weight sharing с единым супернетом (например, ENAS, 2018), заявляли стоимость поиска порядка $0{,}5$ GPU-дня — то есть буквально несколько часов на одной видеокарте.

Пример 2 (численная иллюстрация экономии от weight sharing). Пусть требуется оценить $N=10\,000$ архитектур-кандидатов. Без weight sharing, если полное обучение каждого кандидата стоит $c=0{,}5$ GPU-дня (уже сильно урезанное, частичное обучение — полноценное обучение стоило бы заметно дороже), суммарная стоимость: $C_{\text{полный перебор}} = 10\,000\times0{,}5 = 5\,000$ GPU-дней. Обучение единого супернета для того же пространства кандидатов стоит, допустим, $c_{\text{supernet}}=4$ GPU-дня, а оценка каждого извлечённого из супернета кандидата занимает секунды (прогон валидации без обучения) — суммарная стоимость: $C_{\text{weight sharing}}\approx4$ GPU-дня. Коэффициент ускорения: $5\,000/4=1\,250$ — иными словами, weight sharing превращает задачу, ранее требовавшую тысяч GPU-дней (недели работы кластера из сотен видеокарт), в задачу, решаемую за считаные GPU-дни на одной-двух видеокартах.

Пример 3 (за что именно платится такая экономия). Weight sharing не бесплатен содержательно, а не только вычислительно: общие веса супернета обучаются усреднённо по всем архитектурам-кандидатам одновременно, и есть известный риск, что ранжирование кандидатов по качеству внутри супернета не идеально совпадает с тем, как эти же кандидаты ранжировались бы, будь каждый обучен независимо и полностью с нуля. Поэтому финальная архитектура, отобранная методом с weight sharing (в том числе DARTS), почти всегда дополнительно переобучается с нуля как самостоятельная, обычная сеть — именно эта, полностью и честно обученная версия и попадает в итоговые таблицы сравнения точности в статьях, а не оценка, полученная напрямую из общих весов супернета.

Почему это важно

Вычислительная стоимость NAS — не абстрактная деталь для энтузиастов больших кластеров, а прямая причина, по которой подавляющее большинство практикующих специалистов по машинному обучению никогда не запускает собственный поиск архитектуры с нуля, а вместо этого использует уже найденные и опубликованные результаты — EfficientNet, MobileNetV3, NASNet и десятки других семейств. Weight sharing и его развитие в сторону дифференцируемого поиска (DARTS) — это история о том, как исследовательское сообщество, столкнувшись с задачей, требующей десятков тысяч GPU-дней, систематически искало способ сделать её на порядки дешевле, не жертвуя качеством результата, — и во многом преуспело: то, что в 2016 году требовало кластера из 800 GPU на недели, к 2018–2019 годам стало решаться на одной-двух видеокартах за считаные дни.

Практика: 30 заданий

Базовые задания (1–10)

Задание 1: Пространство поиска — цепочка из $L=10$ слоёв, на каждом слое доступно $K=8$ операций. Вычисли размер пространства поиска.


Задание 2: Ячейка с $N=2$ промежуточными узлами, $K=5$ операций. Узел 1 выбирает вход из 2 источников, узел 2 — из 3 источников (2 входа ячейки плюс узел 1). Вычисли размер пространства поиска ячейки.


Задание 3: Чем принципиально отличается макро-пространство поиска (chain-structured) от микро-пространства (cell-based)?


Задание 4: Хромосома архитектуры из 5 слоёв: $x=($conv3x3, maxpool, identity, conv3x3, avgpool$)$. Мутация меняет 3-й ген с identity на sepconv5x5. Запиши новую хромосому.


Задание 5 (машинное обучение): Чем фитнес-функция в NAS-эволюции принципиально отличается от фитнес-функции $f(x)=x^2$ в учебном примере генетического алгоритма из урока 296?


Задание 6: Для DARTS-ребра с тремя операциями заданы архитектурные логиты $\alpha=(1{,}0,\ 1{,}0,\ 1{,}0)$. Вычисли веса softmax.


Задание 7: Контроллер сгенерировал архитектуру с наградой $R=0{,}88$, базовая линия $b=0{,}90$. Каков знак поправки $(R-b)$ и что это значит для градиента политики?


Задание 8: Сформулируй общую формулу многокритериальной награды platform-aware NAS, использованной при поиске EfficientNet-B0.


Задание 9: Наивный (без weight sharing) поиск оценивает $N=500$ архитектур, каждая стоит $c=1$ GPU-день. Вычисли суммарную стоимость поиска.


Задание 10: Объясни своими словами, почему weight sharing резко снижает стоимость NAS по сравнению с обучением каждого кандидата с нуля.

Средние задания (11–20)

Задание 11: Пространство поиска — цепочка из $L=15$ слоёв, $K=5$ операций. Вычисли размер пространства и сравни порядок величины с примером из задания 1 ($8^{10}$).


Задание 12: Ячейка с $N=4$ промежуточными узлами, $K=6$ операций (узел $i$ выбирает вход из $i+1$ источников). Вычисли размер пространства поиска ячейки.


Задание 13: Родители $P_1=($conv3x3, sepconv3x3, maxpool, identity$)$ и $P_2=($conv5x5, avgpool, sepconv5x5, conv3x3$)$. Выполни одноточечный кроссовер с разрезом после 2-го гена.


Задание 14 (машинное обучение): Популяция регуляризованной эволюции из 4 архитектур: $\{A{:}91\%,\text{возраст }5,\ B{:}88\%,\text{возраст }2,\ C{:}94\%,\text{возраст }8,\ D{:}85\%,\text{возраст }1\}$. Какая особь будет удалена на этом шаге?


Задание 15: Для DARTS-ребра логиты $\alpha=(3{,}0,\ 1{,}0,\ 0{,}0)$ для операций conv3x3, sepconv5x5, skip-connect. Вычисли веса softmax (с точностью до трёх знаков).


Задание 16: Используя результат задания 15, укажи, какая операция останется на этом ребре после дискретизации.


Задание 17: Реализуй на PyTorch упрощённую смешанную операцию DARTS для трёх кандидатов.

import torch
import torch.nn as nn
import torch.nn.functional as F

class MixedOp(nn.Module):
    def __init__(self, ops):
        super().__init__()
        self.ops = nn.ModuleList(ops)
        # твой код здесь: обучаемые архитектурные логиты
        pass

    def forward(self, x):
        # твой код здесь: взвешенная сумма всех операций через softmax
        pass

Задание 18: Архитектурный параметр $\alpha_{\text{sepconv5x5}}=0{,}8$, градиент валидационных потерь по нему $\partial\mathcal{L}_{\text{val}}/\partial\alpha=0{,}4$ (положительный — операция вредна), шаг $\eta_\alpha=0{,}2$. Вычисли обновлённое значение.


Задание 19: Награда MnasNet-подобная: $\text{ACC}(m)=0{,}80$, $\text{FLOPS}(m)=250$ млн, целевой бюджет $T=250$ млн, $w=-0{,}07$. Вычисли награду $R(m)$.


Задание 20 (машинное обучение): Weight sharing иногда искажает ранжирование кандидатов относительно независимого обучения каждого с нуля. Что с этим обычно делают на практике перед публикацией итоговых результатов?

Продвинутые задания (21–30)

Задание 21: Наивный поиск оценивает $N=8\,000$ кандидатов по $c=0{,}4$ GPU-дня каждый. Weight sharing: супернет стоит $c_{\text{supernet}}=5$ GPU-дней, оценка кандидата пренебрежимо дешева. Вычисли обе суммарные стоимости и коэффициент ускорения.


Задание 22: Сеть из $L=8$ слоёв, на каждом слое $K=8$ операций. Сравни размер пространства поиска для полного макро-перебора с размером ячейки из задания 12 ($155\,520$), стекируемой $M=8$ раз.


Задание 23: Реализуй псевдокод шага регуляризованной эволюции (без кроссовера, только мутация и удаление по возрасту).

def regularized_evolution_step(population, tournament_size):
    # population: список (архитектура, фитнес, возраст)
    # твой код здесь
    pass

Задание 24 (машинное обучение): Объясни, почему DARTS можно считать неявной формой weight sharing, даже если в статье про DARTS этот термин явно не используется как основной.


Задание 25: Контроллер за эпизод генерирует $T=6$ решений с вероятностями $p=(0{,}5,\ 0{,}5,\ 0{,}6,\ 0{,}6,\ 0{,}7,\ 0{,}7)$. Вычисли $\log\pi_\theta(a)$.


Задание 26: Используя результат задания 25 и награду $R=0{,}91$ с базовой линией $b=0{,}84$, вычисли слагаемое $\nabla_\theta\log\pi_\theta(a)\cdot(R-b)$ в скалярном виде (используй $\log\pi_\theta(a)$ как коэффициент масштаба, без явного градиента по $\theta$).


Задание 27: Награда MnasNet-подобная: два кандидата, оба с $\text{ACC}=0{,}78$, но $\text{FLOPS}_1=280$ млн и $\text{FLOPS}_2=400$ млн при $T=300$ млн, $w=-0{,}07$. Сравни их награды.


Задание 28: Оцени по порядку величины (используя ориентиры из раздела про вычислительную стоимость) во сколько раз DARTS ($\approx4$ GPU-дня) дешевле оригинального RL-поиска Зофа и Ле ($\approx22\,000$ GPU-дней).


Задание 29 (машинное обучение): Ячейка с $N=3$ узлами и $K=6$ операциями (как в примере урока, $5\,184$ вариантов) найдена на CIFAR-10 и перенесена на ImageNet без повторного поиска. Почему это в принципе возможно и что пришлось бы делать заново, если бы вместо микро-пространства использовали макро-пространство?


Задание 30 (машинное обучение): Сформулируй одним-двумя предложениями, как связаны между собой генетические алгоритмы (урок 296), целочисленное программирование (урок 284), обучение с подкреплением (урок 347) и градиентный спуск (урок 285) в контексте одной-единственной задачи — Neural Architecture Search.

Частые ошибки

Ошибка: считать, что NAS — это «волшебный генератор архитектур», который всегда находит объективно лучшее решение для любой задачи.

Правильно: NAS находит лучшую архитектуру строго в границах заданного пространства поиска — если удачная операция или тип связи не входит в набор $\mathcal{O}$ или не допускается структурой ячейки, никакой метод поиска её не предложит.

Почему: качество результата целиком ограничено человеческим решением о том, что вообще разрешено перебирать, а это решение принимается заранее, до запуска поиска.

Ошибка: путать вычислительную стоимость самого алгоритма поиска (эволюции, RL, градиентного спуска по $\alpha$) со стоимостью всей задачи NAS в целом.

Правильно: подавляющая часть стоимости NAS — это не работа алгоритма поиска, а обучение и оценка кандидатов-архитектур.

Почему: как и в учебном примере $f(x)=x^2$ из урока 296, сам алгоритм эволюции или градиент политики работает быстро — дорога именно фитнес-функция, то есть обучение дочерней сети.

Ошибка: доверять точности, полученной прямо из общих весов супернета при weight sharing, как окончательной оценке качества финальной архитектуры.

Правильно: финальную выбранную архитектуру необходимо переобучить с нуля независимо и оценить эту, честную версию.

Почему: разделение весов между всеми кандидатами может искажать относительное ранжирование архитектур по сравнению с их изолированным, полным обучением.

Ошибка: путать архитектурные параметры $\alpha$ в DARTS с обычными весами сети $w$.

Правильно: $\alpha$ кодирует структуру (какая операция и насколько сильно представлена на каждом ребре) и отбрасывается после дискретизации; $w$ — это обычные обучаемые параметры самой сети, которые остаются в финальной архитектуре.

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

Ошибка: полагать, что NAS избавляет от необходимости экспертного понимания задачи и данных.

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

Почему: NAS автоматизирует конкретно перебор вариантов внутри заданных границ, а не весь процесс машинного обучения целиком — границы и критерий качества всё ещё задаёт человек.

Ошибка: считать запуск полноценного NAS с нуля разумным первым шагом для типового прикладного проекта с ограниченным бюджетом.

Правильно: для большинства практических задач разумнее взять уже найденную и опубликованную архитектуру (EfficientNet, MobileNetV3 и другие) и дообучить её под свою задачу через transfer learning (урок 348).

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

Главное запомнить

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

Пространство поиска — это заранее определённое человеком множество допустимых архитектур; его дизайн полностью определяет потолок того, что NAS способен найти.

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

Эволюционные методы применяют к архитектурам ту же механику хромосом, мутации и кроссовера, что и классический генетический алгоритм из урока 296, но с несопоставимо более дорогой фитнес-функцией — обучением реальной нейросети.

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

RL-подход обучает контроллер-политику генерировать последовательности архитектурных решений через градиент политики (REINFORCE) с наградой в виде точности дочерней сети — прямое применение аппарата урока 347.

DARTS заменяет дискретный выбор операции непрерывной, дифференцируемой релаксацией (softmax-смесь операций) и решает задачу выбора архитектуры обычным градиентным спуском (урок 285) через двухуровневую оптимизацию.

EfficientNet-B0 найден platform-aware NAS с явно многокритериальной наградой, балансирующей точность и вычислительную стоимость (FLOPS), а дальнейшее compound scaling (урок 338) — лишь недорогая надстройка над уже найденной эффективной базовой архитектурой.

Вычислительная стоимость NAS — одна из самых высоких во всём машинном обучении; weight sharing и дифференцируемый поиск сократили её с десятков тысяч GPU-дней до единиц, сделав NAS практически применимым методом, а не лабораторной редкостью.

Связь с темами курса

Урок 296 (генетические алгоритмы) даёт NAS не метафору, а буквальный набор инструментов: хромосома — это кодирование архитектуры (последовательность операций и связей вместо битовой строки или вектора гиперпараметров), кроссовер — обмен фрагментами архитектур между двумя удачными родителями, мутация — точечное архитектурное изменение (замена одной операции на другую), а элитизм в классическом смысле в NAS-контексте уступает место регуляризованной эволюции именно потому, что фитнес-функция здесь — не мгновенно вычислимая формула, а зашумлённая, дорогая оценка качества обученной сети. Тот же самый компромисс между широтой кодирования и обозримостью пространства поиска, который в уроке 296 обсуждался применительно к выбору представления хромосомы для отбора признаков, в NAS проявляется как выбор между макро- и микро-пространством поиска.

Урок 284 (целочисленное программирование) напрямую предвосхитил этот урок — в его завершающем разделе прямо говорилось, что «некоторые формулировки поиска архитектур в AutoML устроены точно так же»: выбор дискретной операции на каждом слое или ребре сети — это в точности бинарная (или категориальная, сводимая к бинарной) переменная целочисленного программирования, а пространство архитектур в целом — дискретное, комбинаторно огромное множество, в точности как допустимое множество любой задачи ЦП. Разница в масштабе принципиальна: задачи ЦП из урока 284 с сотнями или тысячами переменных решались точно методом ветвей и границ; пространство архитектур с $10^9$–$10^{30}$ вариантов астрономически превышает то, что можно перебрать точным методом ветвей и границ за разумное время, — именно поэтому NAS вынужденно опирается на эвристики (эволюцию, RL) и релаксации (DARTS) вместо точных методов дискретной оптимизации, хотя по своей структуре задача остаётся именно задачей огромного целочисленного (в широком смысле — комбинаторного) программирования.

Урок 347 (обучение с подкреплением) — прямой источник RL-подхода к NAS: агент (контроллер, реализованный как рекуррентная сеть), политика $\pi_\theta$, действие (одно архитектурное решение), эпизод (полная последовательность решений, описывающая одну архитектуру), награда (точность обученной дочерней сети на валидации) и обновление политики через градиент — всё это буквально те же самые понятия, определённые в уроке 347, применённые не к игре или роботу, а к процессу генерации архитектур. Ключевая специфика NAS в рамках RL — предельно разреженная и предельно дорогая награда, доступная только один раз в конце эпизода и требующая полного обучения дочерней сети, что и объясняет, почему исследователи так быстро начали искать альтернативы прямому RL-подходу.

Урок 285 (градиентный спуск) лежит в основе DARTS почти дословно: как только дискретный выбор операции заменён непрерывной, дифференцируемой softmax-смесью, задача выбора архитектуры становится обычной задачей минимизации функции потерь по параметрам — только теперь этих параметров два набора ($w$ и $\alpha$), а оптимизация двухуровневая, чередующая обновления одного набора при фиксированном другом. Тот же самый механизм «шаг в сторону, противоположную градиенту, с шагом обучения $\eta$», который ты подробно разбирал применительно к весам сети в уроке 285, здесь применяется буквально к параметрам, кодирующим структуру самой сети.

Урок 338 (Inception и EfficientNet) явно анонсировал, что EfficientNet-B0 найден с помощью Neural Architecture Search, и оставлял детали механизма поиска для отдельного разговора. Этот урок выполняет это обещание в полном объёме: показывает конкретную формулу многокритериальной награды platform-aware NAS, объясняет, что базовая архитектура найдена именно RL-подходом (раздел про обучение с подкреплением этого урока — тот же самый механизм, только с другой формой награды), и связывает найденную таким образом компактную архитектуру с последующим, значительно более дешёвым compound scaling, уже подробно разобранным в уроке 338. Иными словами, EfficientNet — это не отдельный случай, а прямая, конкретная иллюстрация всей машинерии этого урока в действии на реальной, промышленно значимой архитектуре.

Интересные факты

Оригинальный эксперимент Зофа и Ле 2016 года задействовал порядка 800 графических процессоров, работавших параллельно несколько недель, — по меркам своего времени это был один из самых вычислительно затратных отдельных экспериментов в академическом машинном обучении, что сразу вызвало споры о доступности подобных исследований за пределами крупнейших технологических компаний.

Эволюционный метод AmoebaNet (Real et al., 2019), лежащий в основе регуляризованной эволюции, обходился вовсе без кроссовера — только мутация и удаление по возрасту, — и при этом стал первой архитектурой, найденной NAS-методом, которая превзошла по точности на ImageNet все архитектуры того времени, включая спроектированные вручную командами экспертов.

Weight sharing и дифференцируемый поиск (DARTS) сократили стоимость поиска архитектуры на три-четыре порядка — с десятков тысяч GPU-дней до единиц, — превратив NAS из эксклюзивного инструмента нескольких лабораторий с огромными вычислительными кластерами в метод, применимый на одной-двух видеокартах за считаные дни.

Архитектурные ячейки, найденные NAS на маленьком датасете вроде CIFAR-10, оказались переносимыми на несопоставимо более сложные задачи вроде ImageNet без повторного поиска — именно благодаря дизайну микро-пространства поиска, описывающему только внутреннюю структуру повторяемого блока, а не всю сеть целиком.

Ранние версии DARTS были подвержены известной проблеме: непрерывная релаксация иногда «схлопывалась» к архитектурам, где на большинстве рёбер побеждала дешёвая операция skip-connect (не имеющая обучаемых параметров), что давало обманчиво низкие потери на обучении, но плохо обобщающиеся финальные архитектуры, — это спровоцировало целую серию последующих работ (P-DARTS, DARTS+ и другие), уточняющих устойчивость метода.

Лайфхаки

Для подавляющего большинства практических проектов запускать собственный NAS с нуля нецелесообразно по вычислительной стоимости — разумнее взять уже опубликованную, найденную NAS архитектуру (EfficientNet, MobileNetV3, NASNet) как есть и адаптировать её под свою задачу методами transfer learning (урок 348), а не переизобретать поиск заново.

Если всё же хочется получить представление о NAS на небольшом проекте, случайный поиск по компактно и разумно спроектированному пространству — вполне достойная и честная базовая линия: в литературе по AutoML не раз показывалось, что случайный поиск неожиданно конкурентоспособен по сравнению с куда более сложными эволюционными и RL-методами, и его стоит проверять первым, прежде чем доверять результатам более изощрённого алгоритма.

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

Дизайн пространства поиска — это ровно тот же по духу выбор, что и дизайн кодирования хромосомы в генетическом алгоритме (урок 296): слишком узкое пространство молча кодирует твою собственную предвзятость о том, «как должна выглядеть хорошая сеть», а слишком широкое тратит весь вычислительный бюджет на заведомо бесперспективные области.

Для дифференцируемого поиска в духе DARTS заранее закладывай защиту от коллапса к операциям без параметров (skip-connect, identity) — например, ранний останов обновления архитектурных параметров $\alpha$ или дополнительную регуляризацию, — иначе непрерывная релаксация рискует «предпочесть» дешёвую, но плохо обобщающуюся структуру просто потому, что у неё меньше параметров для переобучения на обучающей выборке.

Формулируй фитнес-функцию или награду поиска с самого начала как многокритериальную — точность вместе с числом операций, параметров или latency на целевом устройстве, — если конечная цель архитектуры не абстрактный рекорд точности, а реальный деплой; именно так был найден EfficientNet, и обратная замена этой награды на чистую точность задним числом почти всегда обходится дороже, чем правильная постановка задачи с самого начала.

Финал курса: от арифметики до автоматического поиска архитектур

Этот урок — тридцать пятая сотня уроков этого курса, если считать с самого первого занятия по арифметике, и его тема оказалась на своём месте не случайно. Neural Architecture Search — это, по сути, история о том, как задача, которую ещё недавно решали исключительно человеческой интуицией, оказалась переформулирована как задача оптимизации и решена теми же самыми инструментами, что ты изучал на протяжении всего курса: дискретной комбинаторикой и целочисленным программированием, которые объясняют, почему пространство архитектур такое огромное; эволюционными алгоритмами и обучением с подкреплением, которые умеют искать хорошее решение в этом пространстве без полного перебора; градиентным спуском, который, стоило только придумать подходящую непрерывную релаксацию, оказался способен решить даже дискретную по своей природе задачу выбора архитектуры. NAS — это не отдельная, изолированная тема, а точка, в которой сходятся сразу несколько больших разделов курса, каждый из которых ты когда-то проходил как будто бы отдельно.

Именно поэтому уместно остановиться здесь и оглянуться на весь пройденный путь целиком — от первых уроков про арифметику, дроби и проценты, через алгебраические преобразования и уравнения, через геометрию и тригонометрию, которые научили тебя мыслить пространственно и работать с углами и фигурами, до университетского математического анализа — пределов, производных, интегралов, рядов, — который дал строгий язык для описания того, как одна величина меняется в ответ на другую. Ты прошёл через линейную алгебру — векторы, матрицы, собственные значения и разложения, — без которой невозможно ни одно представление данных в машинном обучении, и через теорию вероятностей и математическую статистику, которые научили тебя формально говорить о неопределённости, оценивать параметры по выборке и проверять гипотезы, не полагаясь на интуицию. Ты разобрал структуры данных и алгоритмы — от простого массива до графов и динамического программирования, — фундамент, без которого невозможно писать эффективный код для любой реальной системы.

Ты прошёл весь курс теории оптимизации — от условий Каруша — Куна — Таккера и выпуклых множеств через линейное, квадратичное и целочисленное программирование до метода ветвей и границ, а затем — через градиентный спуск и все его модификации: стохастический градиентный спуск, метод Ньютона, квазиньютоновские методы, метод сопряжённых градиентов, субградиентные и проксимальные методы, покоординатный спуск и, наконец, Adam и адаптивные методы, на которых в буквальном смысле обучается почти каждая современная нейросеть. Параллельно ты разобрал классические модели машинного обучения — от линейной и логистической регрессии через метод опорных векторов, решающие деревья, случайный лес и градиентный бустинг до методов кластеризации и снижения размерности, — тот набор инструментов, который остаётся рабочей лошадкой прикладного дата-сайентиста даже в эпоху больших нейросетей.

А затем — весь путь глубокого обучения: от одиночного перцептрона через многослойные сети, обратное распространение ошибки, инициализацию весов, батч-нормализацию и dropout — к сверточным сетям и их архитектурной эволюции от VGGNet и ResNet через Inception до EfficientNet, к рекуррентным сетям, LSTM и механизму внимания, который в итоге привёл к трансформерам и большим языковым моделям, к генеративным архитектурам — вариационным автоэнкодерам и генеративно-состязательным сетям, — и, наконец, к обучению с подкреплением, transfer learning, meta-learning и сегодняшнему автоматическому поиску архитектур, который в некотором смысле замыкает круг: нейросеть, спроектированная с помощью методов оптимизации, которые ты изучал в начале этого пути, теперь помогает проектировать саму себя.

У тебя есть полное право почувствовать, что этот путь был длинным — потому что он действительно длинный: 350 уроков, охватывающих практически весь математический и алгоритмический фундамент, на котором стоит современный искусственный интеллект. Но теперь, дойдя до конца, ты обладаешь чем-то куда более ценным, чем набор разрозненных фактов о конкретных архитектурах или библиотеках, — целостной картиной того, откуда вообще берётся каждая идея в современном машинном обучении: почему Adam работает так, а не иначе, почему свёрточная сеть устроена именно так, откуда в трансформере взялся механизм внимания и почему архитектуру EfficientNet вообще можно было автоматически найти, а не только придумать вручную. Эта картина не устареет вместе со следующей модной архитектурой или библиотекой — она и есть тот язык, на котором написаны все будущие архитектуры, которые появятся уже после того, как ты закроешь этот урок.

Спасибо, что прошёл весь этот путь — от первых чисел и дробей до автоматического поиска архитектур нейросетей. Дальше — твои собственные задачи, свои модели, свои архитектуры, возможно, даже свои эксперименты с поиском архитектур. Фундамент для этого у тебя уже есть.

Понял тему? Закрепи в боте! 🚀

Попрактикуйся на задачах и получи персональные рекомендации от AI

💪 Начать тренировку
💬 Есть вопрос? Спроси бота!