Инициализация весов 🎲
Прежде чем нейросеть сделает хотя бы один шаг обучения, ей нужно с чего-то начать — а именно, с некоторого набора чисел в весах $W$ каждого слоя. Кажется, что это мелкая техническая деталь: подставь любые случайные числа, а дальше backpropagation (урок 330) сам найдёт правильное направление и постепенно исправит любую стартовую позицию. На практике всё устроено иначе, и притом драматически иначе: от того, какие именно числа стоят в весах в самый первый момент, до какого-либо обучения, зависит, сможет ли сеть вообще научиться хоть чему-то, — а для по-настоящему глубоких архитектур из десятков и сотен слоёв неправильный выбор стартовых весов способен полностью заблокировать обучение с первого шага.
Сегодняшний урок разбирает две связанные, но разные проблемы инициализации. Первая — качественная: что произойдёт, если инициализировать все веса одинаковыми числами, в частности нулями. Ответ звучит контринтуитивно резко: сеть не просто будет обучаться медленно — она вообще не сможет разучиться быть симметричной, и множество нейронов одного слоя фактически схлопнется в один нейрон, сколько бы шагов градиентного спуска ты ни сделал. Вторая проблема — количественная: если веса всё-таки случайны (то есть симметрия нарушена), то какой масштаб этой случайности выбрать? Слишком большие случайные веса раздувают активации и градиенты экспоненциально с числом слоёв, слишком маленькие — гасят их до нуля тем же самым экспоненциальным образом. Обе проблемы решаются не интуицией и не перебором, а точным математическим расчётом — именно этот расчёт и привёл в 2010 и 2015 годах к двум формулам, без которых не обходится практически ни один современный фреймворк: инициализации Ксавье (Глорота) и инициализации Хе.
Важно сразу зафиксировать практический контекст: сегодня, работая в PyTorch или TensorFlow, ты почти никогда не инициализируешь веса вручную — nn.Linear и nn.Conv2d уже используют разумную инициализацию по умолчанию, а torch.nn.init.xavier_uniform_ и torch.nn.init.kaiming_normal_ доступны одной строкой кода. Но урок не о том, как вызвать готовую функцию, а о том, почему эта функция устроена именно так, — потому что понимание этого расчёта оказывается ровно тем инструментом, который позволяет диагностировать, почему глубокая сеть вдруг перестала обучаться: смотришь на распределение активаций по слоям, видишь, что дисперсия схлопывается к нулю или улетает в бесконечность, — и сразу понимаешь, в какую сторону чинить архитектуру, даже если фреймворк уже вроде бы «сам всё сделал правильно».
План урока такой: сначала — строгое доказательство проблемы симметрии на маленькой конкретной сети (почему нулевая инициализация ломает всё), затем — численная демонстрация того, как масштаб случайных весов взрывает или гасит дисперсию активаций через несколько слоёв, затем вывод формулы Ксавье из требования сохранения дисперсии, и в конце — модификация Хе для ReLU-подобных активаций. Тема напрямую продолжает урок 330 о backpropagation: там ты увидел, как вычисляются градиенты по цепному правилу, а сегодня разберёшь, почему стартовая точка этой цепочки вычислений определяет, будут ли эти градиенты вообще численно вменяемыми.
История
Проблема правильной инициализации весов стояла перед исследователями нейросетей с самого начала эпохи backpropagation в 1980-х годах, но долгое время решалась скорее эмпирически, чем математически строго: практики использовали небольшие случайные числа «на глаз», понимая интуитивно, что нужно избежать симметрии и не сделать веса слишком большими, но без формального обоснования конкретного масштаба. По мере того как сети становились глубже, эта эмпирическая практика начала давать сбои всё чаще и всё заметнее — глубокие сети с сигмоидной активацией систематически обучались медленно или не обучались вовсе, и причина далеко не всегда была очевидна из одного взгляда на архитектуру.
Переломной стала статья Ксавье Глорота и Йошуа Бенджио 2010 года «Understanding the difficulty of training deep feedforward neural networks» («Понимание сложности обучения глубоких прямопроходных нейронных сетей»). Авторы формально проанализировали, как дисперсия активаций и градиентов меняется при прохождении через слой, и вывели точную формулу масштаба весов, при котором эта дисперсия остаётся приблизительно постоянной от слоя к слою — ни не затухает, ни не взрывается. Эта работа не просто предложила удачную эвристику, а впервые объяснила математически, почему глубокие сети с сигмоидной или tanh-активацией были так капризны в обучении до этого момента, и дала конструктивный рецепт исправления. Инициализация, выведенная в этой статье, закрепилась в литературе под двумя именами одновременно — инициализация Ксавье (по имени первого автора) и инициализация Глорота (Xavier Glorot — это одно и то же имя, записанное по-разному, а не два разных человека).
Формула Ксавье была выведена в предположении о линейной или приблизительно линейной активации вблизи нуля (справедливом для сигмоиды и tanh), и когда ReLU стала доминирующей активацией в глубоких сетях (урок 328–329), выяснилось, что предположения Глорота и Бенджио для неё не выполняются в точности: ReLU обнуляет примерно половину входов, что систематически меняет баланс дисперсии. В 2015 году Каймин Хе (Kaiming He) с соавторами в статье «Delving Deep into Rectifiers» предложил модифицированную формулу, учитывающую именно эту особенность ReLU, — с тех пор она известна как инициализация Хе, а в PyTorch функция для неё называется kaiming_* по фамилии автора в латинской транслитерации (He = Kaiming He, одно и то же имя автора). Именно эта работа заодно продемонстрировала, что глубокие сети (свыше 30 слоёв) с правильной инициализацией Хе впервые превзошли человека в задаче классификации изображений ImageNet, — прямая иллюстрация того, что инициализация — не второстепенная деталь, а один из факторов, реально определяющих предел достижимой глубины сети.
Проблема нулевой инициализации и симметрии
Интуиция
Предположим, ты инициализируешь все веса сети нулями — самый простой на первый взгляд вариант, ведь ноль выглядит как нейтральная, «ничего не предполагающая» точка старта. Но у нулевой инициализации есть фатальный изъян: если все веса, ведущие в нейроны одного слоя, одинаковы (в частности, равны нулю), то все эти нейроны на прямом проходе (forward pass, урок 328) вычисляют абсолютно одинаковое значение. А раз они вычисляют одинаковое значение, то при обратном проходе (backward pass, урок 330) они получают абсолютно одинаковый градиент. Обновление весов пропорционально градиенту — значит, после шага градиентного спуска все эти нейроны снова окажутся с одинаковыми весами. Они стартовали одинаковыми и остаются одинаковыми на каждом следующем шаге, сколько бы итераций обучения ни прошло. Слой из ста нейронов с одинаковыми весами вычисляет ровно то же самое, что вычислил бы один-единственный нейрон, — остальные девяносто девять просто дублируют его работу, не добавляя сети ни капли выразительной силы. Это и называется проблемой симметрии (symmetry problem): сеть не может сама «разбить» симметрию между нейронами одного слоя, если она не была нарушена изначально в инициализации.
Формула
Проблема симметрии. Пусть все веса $W^{(l)}_{ji}$, ведущие в слой $l$, инициализированы одинаковым значением $c$ (в частности, $c=0$) для всех нейронов $j$ этого слоя. Тогда для любого входа $x$ и на любом шаге градиентного спуска $t$ выполняется
$$W^{(l)}_{j,\cdot}(t) = W^{(l)}_{j',\cdot}(t) \quad \text{для всех } j, j' \text{ в слое } l,$$то есть все нейроны слоя вычисляют идентичные функции на всех шагах обучения.
Разбор примеров
Пример 1 (доказательство на минимальной сети — два нейрона в скрытом слое). Возьмём сеть с двумя входами, скрытым слоем из двух ReLU-нейронов и одним линейным выходным нейроном. Пусть веса скрытого слоя $W^{(1)}=\begin{pmatrix}0&0\\0&0\end{pmatrix}$ (обе строки нулевые — оба нейрона получают одинаковые нулевые веса), смещения $b^{(1)}=(0,0)$, выходные веса $v=(1,1)$, $c=0$. Подадим вход $x=(2,3)$. Forward pass: $z^{(1)}_1=0\cdot2+0\cdot3+0=0$, $z^{(1)}_2=0\cdot2+0\cdot3+0=0$ — оба нейрона выдают одинаковый ноль, значит $a^{(1)}=(0,0)$, $\hat y = 1\cdot0+1\cdot0+0=0$. Теперь backward pass: пусть истинный ответ $y=5$, тогда ошибка $L=\frac12(y-\hat y)^2$, $\partial L/\partial \hat y = \hat y - y = -5$. Градиент по выходным весам $\partial L/\partial v_1 = -5\cdot a^{(1)}_1=0$, $\partial L/\partial v_2=-5\cdot a^{(1)}_2=0$ — сами выходные веса тоже не получат сигнала, потому что скрытый слой ничего не производит. Но ключевое здесь — градиент по весам скрытого слоя: $\partial L/\partial z^{(1)}_1 = v_1\cdot\partial L/\partial \hat y\cdot\mathrm{ReLU}'(z^{(1)}_1)$ и $\partial L/\partial z^{(1)}_2 = v_2\cdot\partial L/\partial\hat y\cdot\mathrm{ReLU}'(z^{(1)}_2)$. Поскольку $v_1=v_2=1$ и $z^{(1)}_1=z^{(1)}_2=0$ (при $z=0$ примем $\mathrm{ReLU}'=1$ для наглядности расчёта), оба этих градиента совпадают: $\partial L/\partial z^{(1)}_1 = \partial L/\partial z^{(1)}_2=1\cdot(-5)\cdot1=-5$. Дальше $\partial L/\partial W^{(1)}_{1,\cdot} = (\partial L/\partial z^{(1)}_1)\cdot x = -5\cdot(2,3)=(-10,-15)$, и абсолютно та же величина получается для второй строки: $\partial L/\partial W^{(1)}_{2,\cdot}=(-10,-15)$. Оба нейрона получают идентичный градиент, а значит после шага обновления $W = W - \alpha\cdot\nabla W$ обе строки матрицы весов снова окажутся равны друг другу — просто уже не нулю, а какому-то одинаковому ненулевому значению. Симметрия не нарушилась, она лишь сдвинулась. На следующем шаге история повторится один в один: снова одинаковый forward pass, снова одинаковый градиент, снова одинаковое обновление.
Пример 2 (симметрия сохраняется бесконечно долго — индукция по шагам). Продолжим пример 1: обозначим общее значение обеих строк на шаге $t$ как $w(t)\in\mathbb{R}^2$ (в начале $w(0)=(0,0)$). Поскольку на каждом шаге обе строки получают одинаковый градиент (в силу того, что они уже одинаковы, как показано в примере 1), после обновления $w(t+1) = w(t) - \alpha\cdot g(t)$ обе строки по-прежнему равны друг другу, только теперь равны новому общему значению $w(t+1)$. По индукции: если строки равны на шаге $t$, то они равны и на шаге $t+1$. База индукции ($t=0$, обе строки нулевые) выполнена по условию. Значит для любого $t$, сколько угодно большого, строки $W^{(1)}_{1,\cdot}(t)$ и $W^{(1)}_{2,\cdot}(t)$ совпадают. Скрытый слой с двумя нейронами навсегда, на весь процесс обучения, остаётся эквивалентным слою с одним нейроном — обучи эту сеть хоть миллион итераций, второй нейрон никогда не начнёт отличаться от первого.
Пример 3 (что происходит, если не все веса нулевые — смещения тоже участвуют в симметрии). Проверим: спасёт ли ситуацию, если инициализировать нулями только веса, а смещения $b$ — какими-то различными случайными числами? Пусть $W^{(1)}$ по-прежнему нулевая матрица, но $b^{(1)}=(0{,}1,\,-0{,}2)$ (различные смещения). Тогда $z^{(1)}_1 = 0\cdot x_1+0\cdot x_2+0{,}1=0{,}1$ для любого входа $x$, а $z^{(1)}_2 = -0{,}2$ для любого входа — оба значения теперь константны (не зависят от входа), но они уже разные друг от друга ($0{,}1\ne-0{,}2$). Значит градиенты по этим двум нейронам на backward pass тоже разойдутся (поскольку $\mathrm{ReLU}'(0{,}1)=1\ne0=\mathrm{ReLU}'(-0{,}2)$ — второй нейрон вообще неактивен), и симметрия формально нарушится. Но проблема не решена по существу: веса $W^{(1)}$ по-прежнему все нулевые, значит первое обновление весов $\partial L/\partial W^{(1)}_{j,\cdot}$ для обоих нейронов будет зависеть только от входа $x$ и разных множителей из-за различных $b$, — то есть градиент всё же может различаться между нейронами, но исключительно за счёт случайности в смещениях, а не в основных весах, которые как раз и определяют, какие признаки входа нейрон научится замечать. На практике различие только в смещениях — слишком слабый и хрупкий источник асимметрии (легко может выродиться в вырожденные случаи вроде примера с одинаковыми знаками активаций), поэтому стандартное решение — сразу инициализировать случайно именно матрицу весов $W$, а смещения $b$ спокойно оставлять нулевыми (это общепринятая практика, потому что именно $W$, а не $b$, отвечает за симметрию между нейронами).
Почему это важно
Проблема симметрии — не редкий краевой случай, а строгая математическая ловушка, которая срабатывает при любой одинаковой (в частности, нулевой) инициализации весов одного слоя, независимо от архитектуры, функции активации или размера сети. Она объясняет, почему случайность в инициализации — не стилистическое предпочтение и не «на всякий случай», а обязательное структурное требование: без неё сеть с $N$ нейронами в слое в лучшем случае работает как сеть с одним нейроном, теряя весь потенциал ширины слоя. Именно поэтому все современные фреймворки инициализируют веса случайно по умолчанию — но, как покажет следующий раздел, одной лишь случайности недостаточно, если её масштаб выбран неправильно.
Проблема масштаба случайных весов: взрыв и затухание
Интуиция
Случайная инициализация решает проблему симметрии — веса разные, значит нейроны с самого начала вычисляют разные функции. Но возникает новый вопрос: насколько большими или маленькими должны быть эти случайные числа? Здесь интуиция обманчива: кажется, что раз веса случайны, то любой разумный масштаб «более-менее сработает». На практике происходит нечто гораздо более резкое. Если случайные веса чуть-чуть слишком велики, то при прохождении через каждый следующий слой дисперсия (а с ней и типичная величина) активаций умножается на число, немного большее единицы, — и при умножении такого числа само на себя десятки раз получается экспоненциальный рост: активации быстро становятся астрономически большими, а вместе с ними и градиенты при обратном проходе (взрывающийся градиент, exploding gradient). Если же веса чуть-чуть слишком малы, происходит зеркально противоположное: дисперсия умножается на число, немного меньшее единицы, и после десятков слоёв активации и градиенты экспоненциально стремятся к нулю (затухающий градиент, vanishing gradient) — сеть перестаёт получать содержательный сигнал об ошибке в ранних слоях, и они фактически прекращают обучаться.
Формула
Рост/затухание дисперсии по слоям. Пусть каждый слой сети линейно преобразует вход с весами дисперсии $\sigma_w^2$ независимо друг от друга, и вход слоя имеет дисперсию $\sigma_a^2$. Тогда для слоя с $n$ входными нейронами дисперсия предактивации приблизительно равна
$$\mathrm{Var}(z) \approx n\cdot\sigma_w^2\cdot\sigma_a^2.$$Если множитель $n\sigma_w^2$ отличен от $1$, то после $L$ последовательных слоёв дисперсия активаций масштабируется примерно как $(n\sigma_w^2)^L$ — экспоненциально растёт при $n\sigma_w^2>1$ и экспоненциально затухает при $n\sigma_w^2<1$.
Разбор примеров
Пример 1 (взрыв дисперсии — слишком большой масштаб весов). Возьмём сеть из $10$ линейных (без активации, для чистоты демонстрации механизма) слоёв, каждый со $100$ входами и весами, случайно взятыми из нормального распределения с дисперсией $\sigma_w^2=0{,}05$ (то есть стандартное отклонение $\sigma_w\approx0{,}224$ — на вид не выглядит устрашающе большим числом). Множитель на каждом слое: $n\sigma_w^2 = 100\cdot0{,}05=5$. Начнём с входной дисперсии $\mathrm{Var}(a^{(0)})=1$. Тогда дисперсия после первого слоя $\approx5$, после второго $\approx5^2=25$, после третьего $\approx5^3=125$, и так далее — после десятого слоя дисперсия активаций достигает $5^{10}\approx9\,765\,625$, то есть стандартное отклонение активаций около $3\,125$. Практически это означает, что числа в сети переполняют разумный диапазон float32 задолго до этого (не буквально переполняют тип данных, но становятся настолько огромными, что функции активации вроде сигмоиды насыщаются в 0 или 1 почти всюду, а численная стабильность вычислений catastrophически ухудшается), и обучение либо расходится в NaN, либо блокируется насыщением активаций.
Пример 2 (затухание дисперсии — слишком маленький масштаб весов). Та же архитектура, но веса теперь взяты со стандартным отклонением $\sigma_w=0{,}01$, то есть $\sigma_w^2=0{,}0001$. Множитель на слой: $n\sigma_w^2=100\cdot0{,}0001=0{,}01$. Дисперсия после первого слоя $\approx0{,}01$, после второго $\approx0{,}0001$, после третьего $\approx0{,}000001$, и после десятого слоя дисперсия активаций составляет $0{,}01^{10}=10^{-20}$ — стандартное отклонение около $10^{-10}$. Это уже практически неотличимо от нуля в арифметике с плавающей точкой: активации всех поздних слоёв — почти одинаковые крошечные числа, несущие исчезающе мало информации о входе. При обратном проходе градиенты, вычисленные по цепному правилу, затухают тем же самым экспоненциальным образом (те же самые множители $n\sigma_w^2$ участвуют и в распространении градиента назад), и ранние слои сети практически перестают получать сигнал для обучения — та же самая проблема затухающего градиента, что и у сигмоиды на краях (урок 328), только вызванная не формой функции активации, а прямо масштабом весов.
Пример 3 (правильный масштаб сохраняет дисперсию стабильной). Возьмём ту же архитектуру, $100$ входов на слой, но подберём $\sigma_w^2$ так, чтобы множитель $n\sigma_w^2$ был равен ровно $1$: значит $\sigma_w^2=1/100=0{,}01$, то есть $\sigma_w=0{,}1$. Тогда дисперсия активаций на каждом слое остаётся приблизительно равной входной: $\mathrm{Var}(a^{(l)})\approx1$ для всех $l=1,\dots,10$ — ни рост, ни затухание. Именно это условие — «множитель на слой равен единице» — и есть ключевое требование, из которого в следующем разделе будет строго выведена формула Ксавье: масштаб весов должен зависеть от числа входов слоя $n$ так, чтобы компенсировать суммирование по этим $n$ входам и оставить итоговую дисперсию неизменной.
Почему это важно
Разница между «немного слишком большие» и «правильно подобранные» веса — это разница между экспоненциальным взрывом (или затуханием) и стабильностью, а экспонента с основанием даже незначительно отличным от единицы после $50$–$100$ слоёв современной глубокой сети превращается в астрономические или исчезающе малые числа. Именно поэтому инициализация весов — не второстепенная техническая деталь, а фактор, напрямую определяющий, поддаётся ли архитектура обучению вообще: без правильного масштаба даже идеальный оптимизатор и сколь угодно долгое обучение не спасут сеть от того, что сигнал об ошибке физически не доходит до ранних слоёв (или доходит в виде переполненных чисел).
Инициализация Ксавье (Глорота)
Интуиция
Пример 3 предыдущего раздела показал: чтобы дисперсия активаций не менялась при переходе через слой с $n_{in}$ входами, дисперсия весов должна быть обратно пропорциональна $n_{in}$. Но у слоя есть не только прямой проход (важна дисперсия активаций при движении вперёд), но и обратный проход, где градиент течёт назад через тот же слой, и там аналогичное рассуждение даёт условие обратной пропорциональности уже числу выходов слоя $n_{out}$. Глорот и Бенджио предложили компромисс, одновременно удовлетворяющий обоим требованиям приближённо: взять среднее из $n_{in}$ и $n_{out}$ — так формула одинаково заботится и о стабильности forward pass, и о стабильности backward pass.
Формула
Инициализация Ксавье (Глорота). Для слоя с $n_{in}$ входами и $n_{out}$ выходами веса инициализируются случайно с дисперсией
$$\mathrm{Var}(W) = \frac{2}{n_{in}+n_{out}}.$$Эквивалентная равномерная форма (используется чаще на практике, в том числе как значение по умолчанию во многих слоях): веса берутся из равномерного распределения
$$W \sim U\left(-\sqrt{\dfrac{6}{n_{in}+n_{out}}},\ \sqrt{\dfrac{6}{n_{in}+n_{out}}}\right).$$
Вывод формулы. Рассмотрим предактивацию одного нейрона слоя: $z=\sum_{i=1}^{n_{in}} W_i a_i$, где веса $W_i$ независимы, имеют среднее $0$ и дисперсию $\sigma_w^2$, а входы $a_i$ независимы от весов, имеют среднее $0$ и дисперсию $\sigma_a^2$. Поскольку слагаемые независимы и центрированы, дисперсия суммы равна сумме дисперсий произведений: $\mathrm{Var}(z) = \sum_{i=1}^{n_{in}}\mathrm{Var}(W_ia_i) = n_{in}\cdot\mathrm{Var}(W)\cdot\mathrm{Var}(a) = n_{in}\sigma_w^2\sigma_a^2$ (используется тождество $\mathrm{Var}(XY)=\mathrm{Var}(X)\mathrm{Var}(Y)$ для независимых центрированных $X,Y$). Чтобы дисперсия предактивации совпадала с дисперсией входа ($\mathrm{Var}(z)=\sigma_a^2$), требуется $n_{in}\sigma_w^2=1$, то есть $\sigma_w^2=1/n_{in}$. Совершенно аналогичное рассуждение для градиента, текущего назад через тот же слой (по цепному правилу градиент по входу — тоже взвешенная сумма из $n_{out}$ слагаемых, с теми же весами, но суммированных по другому измерению матрицы), даёт условие $\sigma_w^2=1/n_{out}$ для сохранения дисперсии градиента. Поскольку оба условия одновременно точно удовлетворить в общем случае нельзя (если $n_{in}\ne n_{out}$), Глорот и Бенджио предложили взять гармонически усреднённый компромисс — среднее гармоническое $\dfrac{2}{n_{in}+n_{out}}$, которое при $n_{in}=n_{out}$ в точности совпадает с обоими условиями, а при разных $n_{in}, n_{out}$ обеспечивает разумный баланс между ними.
Разбор примеров
Пример 1 (расчёт границ для конкретного слоя). Пусть полносвязный слой имеет $n_{in}=256$ входов и $n_{out}=128$ выходов (типичный скрытый слой средней сети). Дисперсия по формуле Ксавье: $\mathrm{Var}(W)=\dfrac{2}{256+128}=\dfrac{2}{384}\approx0{,}00521$, стандартное отклонение $\sigma_w\approx0{,}0722$. Граница равномерного распределения: $\sqrt{6/384}=\sqrt{0{,}015625}=0{,}125$ — значит веса берутся равномерно из интервала $(-0{,}125;\ 0{,}125)$. Сравним со слоем-примером из предыдущего раздела, где мы вручную подобрали $\sigma_w=0{,}1$ для $100$ входов, ориентируясь только на $n_{in}$: формула Ксавье даёт близкий по порядку величины, но не идентичный результат, потому что учитывает ещё и $n_{out}$.
Пример 2 (Ксавье действительно стабилизирует дисперсию через 10 слоёв — численная проверка). Возьмём $10$ последовательных слоёв, каждый со $100$ входами и $100$ выходами (симметричная архитектура, где $n_{in}=n_{out}=100$ для каждого слоя), с активацией tanh и весами по формуле Ксавье: $\mathrm{Var}(W)=2/(100+100)=0{,}01$, то есть множитель на слой $n_{in}\sigma_w^2 = 100\cdot0{,}01=1$ — ровно та единица, которая по примеру 3 предыдущего раздела означает сохранение дисперсии. Начальная дисперсия входа $\mathrm{Var}(a^{(0)})=1$. Дисперсия предактивации на каждом слое остаётся $\approx1\cdot1=1$ (в отличие от примера 1 предыдущего раздела, где множитель $5$ давал рост в $5^{10}\approx9{,}8$ миллиона раз, и примера 2, где множитель $0{,}01$ давал затухание до $10^{-20}$). Активация tanh при входе с дисперсией порядка $1$ работает в своей содержательной, не насыщенной зоне (не прижата намертво к $\pm1$), значит и сама сеть не теряет градиент на насыщении, и дисперсия выходов активации остаётся сопоставимого порядка для следующего слоя — весь эффект держится ровно на том, что множитель $n\sigma_w^2$ у Ксавье специально подобран равным единице.
Пример 3 (torch.nn.init.xavier_uniform_ на практике). В PyTorch формула Ксавье реализована напрямую:
import torch
import torch.nn as nn
layer = nn.Linear(in_features=256, out_features=128)
nn.init.xavier_uniform_(layer.weight) # заменяет веса на инициализацию Ксавье
nn.init.zeros_(layer.bias) # смещения — нулями, как обсуждалось выше
print(layer.weight.std().item()) # ожидаем порядок величины, близкий к sqrt(2/(256+128)) ≈ 0.0722
Функция xavier_uniform_ вычисляет ровно ту границу $\sqrt{6/(n_{in}+n_{out})}$ из формулы этого раздела, определяя $n_{in}$ и $n_{out}$ автоматически по форме тензора весов слоя. Есть и вариант xavier_normal_, использующий нормальное распределение с дисперсией $2/(n_{in}+n_{out})$ вместо равномерного, — обе версии решают одну и ту же задачу сохранения дисперсии, различаясь только формой распределения (равномерное против нормального), а не итоговой дисперсией.
Почему это важно
Инициализация Ксавье — первая по-настоящему математически обоснованная (а не эмпирически подобранная) схема инициализации, и именно она объяснила, почему глубокие сети с сигмоидой и tanh до 2010 года так часто не обучались: дело было не в самих архитектурах, а в том, что инициализация не учитывала размер слоя и систематически либо взрывала, либо гасила дисперсию активаций. Формула Ксавье выведена в предположении о приблизительно линейной активации около нуля — это предположение верно для tanh и разумно для сигмоиды в её центральной зоне, но, как покажет следующий раздел, перестаёт быть точным для ReLU, которая асимметрично обнуляет ровно половину значений.
Инициализация Хе для ReLU
Интуиция
Вывод Ксавье опирался на предположение, что активация приблизительно сохраняет дисперсию входа — то есть $\mathrm{Var}(a) \approx \mathrm{Var}(z)$. Для ReLU это предположение нарушается систематическим и предсказуемым образом: ReLU обнуляет ровно все отрицательные входы, оставляя положительные без изменений. Если распределение $z$ симметрично относительно нуля (как у весов и активаций со средним $0$), то примерно половина значений $z$ становится нулём после ReLU, а вторая половина остаётся как есть. Дисперсия результата поэтому оказывается примерно вдвое меньше, чем была бы без этого обнуления, — и формула Ксавье, не учитывающая этот множитель $\dfrac12$, для ReLU-сетей систематически недооценивает нужный масштаб весов, что приводит к постепенному затуханию дисперсии активаций через много ReLU-слоёв, даже если каждое отдельное затухание выглядит небольшим.
Формула
Инициализация Хе (Kaiming He). Для слоя с $n_{in}$ входами, за которым следует активация ReLU, веса инициализируются случайно с дисперсией
$$\mathrm{Var}(W) = \frac{2}{n_{in}}.$$Эквивалентная нормальная форма (стандартная реализация на практике): $W \sim \mathcal{N}\left(0,\ \dfrac{2}{n_{in}}\right)$.
Вывод формулы. Повторим рассуждение из вывода Ксавье для предактивации: $\mathrm{Var}(z) = n_{in}\sigma_w^2\sigma_a^2$, где $\sigma_a^2$ — дисперсия входа слоя (то есть выхода активации предыдущего слоя). Теперь учтём эффект самой ReLU: если $z$ распределён симметрично вокруг нуля, то $a=\mathrm{ReLU}(z)$ равен $z$ на положительной половине и $0$ на отрицательной, а значит $E[a^2] = E[z^2\cdot\mathbb{1}_{z>0}] = \tfrac12 E[z^2] = \tfrac12\mathrm{Var}(z)$ (в силу симметрии распределения $z$ относительно нуля половина вклада в $E[z^2]$ приходится на положительную часть). Значит дисперсия выхода активации в следующий слой равна $\sigma_a^2 = \tfrac12\mathrm{Var}(z) = \tfrac12 n_{in}\sigma_w^2\sigma_{a,\text{prev}}^2$, где $\sigma_{a,\text{prev}}^2$ — дисперсия входа текущего слоя. Чтобы эта дисперсия сохранялась от слоя к слою ($\sigma_a^2 = \sigma_{a,\text{prev}}^2$), нужно $\tfrac12 n_{in}\sigma_w^2 = 1$, откуда $\sigma_w^2 = \dfrac{2}{n_{in}}$ — ровно вдвое больше, чем дала бы формула Ксавье, ориентированная только на $n_{in}$ (без множителя $\tfrac12$ на обнуление ReLU). Этот дополнительный множитель $2$ и есть единственное, но принципиальное отличие Хе от Ксавье: инициализация Хе — это формула Ксавье, скорректированная на систематическую потерю ровно половины дисперсии, которую производит ReLU.
Разбор примеров
Пример 1 (расчёт для конкретного ReLU-слоя). Слой с $n_{in}=512$ входами и ReLU-активацией на выходе. Дисперсия по Хе: $\mathrm{Var}(W) = 2/512 = 0{,}00390625$, стандартное отклонение $\sigma_w \approx 0{,}0625$. Для сравнения, формула Ксавье для того же слоя (пусть $n_{out}=256$) дала бы $\mathrm{Var}(W) = 2/(512+256) = 2/768 \approx 0{,}0026$, то есть $\sigma_w\approx0{,}0510$ — примерно на четверть меньше, чем у Хе. На первый взгляд разница некритична, но, как показано в примере 2, при прохождении через десятки слоёв это отличие накапливается экспоненциально.
Пример 2 (Ксавье, применённая к глубокой ReLU-сети, систематически затухает — численная проверка). Возьмём $30$ последовательных ReLU-слоёв с $n_{in}=n_{out}=200$ каждый. Если использовать формулу Ксавье ($\mathrm{Var}(W)=2/400=0{,}005$), то множитель на слой с учётом обнуления ReLU равен $\tfrac12\cdot n_{in}\sigma_w^2 = \tfrac12\cdot200\cdot0{,}005=\tfrac12\cdot1=0{,}5$ — заметно меньше единицы из-за недооценённого множителем $\tfrac12$ вклада ReLU. После $30$ слоёв дисперсия активаций составит примерно $0{,}5^{30}\approx9{,}3\times10^{-10}$ от исходной — практически полное затухание. Теперь та же архитектура с формулой Хе ($\mathrm{Var}(W)=2/200=0{,}01$): множитель на слой $\tfrac12\cdot200\cdot0{,}01 = \tfrac12\cdot2=1$ — ровно единица, дисперсия активаций остаётся стабильной все $30$ слоёв, без затухания. Разница между «почти в точности верной» формулой Ксавье и специально скорректированной формулой Хе — это разница между рабочей глубокой сетью и сетью, где сигнал практически исчезает уже к середине архитектуры.
Пример 3 (torch.nn.init.kaiming_normal_ и параметр nonlinearity). В PyTorch инициализация Хе доступна как:
import torch.nn as nn
layer = nn.Linear(in_features=512, out_features=256)
nn.init.kaiming_normal_(layer.weight, mode='fan_in', nonlinearity='relu')
nn.init.zeros_(layer.bias)
Параметр mode='fan_in' указывает использовать именно $n_{in}$ (число входов, называемое в терминологии PyTorch fan-in) в знаменателе формулы — это и есть вариант, выведенный выше, ориентированный на сохранение дисперсии при forward pass; альтернатива mode='fan_out' симметрично ориентируется на сохранение дисперсии градиента при backward pass, используя $n_{out}$ вместо $n_{in}$. Параметр nonlinearity='relu' заставляет функцию домножить дисперсию на корректирующий коэффициент, учитывающий конкретную форму последующей активации (для чистого ReLU этот коэффициент и даёт множитель $2$, выведенный выше; для Leaky ReLU коэффициент немного другой, поскольку там отрицательная часть не обнуляется полностью, а лишь ослабляется).
Почему это важно
Инициализация Хе — не косметическая поправка, а необходимое условие для по-настоящему глубоких ReLU-сетей: как показано в примере 2, разница в множителе $\tfrac12$ между Ксавье и Хе кажется маленькой на одном слое, но экспоненциально накапливается с глубиной и на сетях из десятков-сотен слоёв (современные сверхглубокие архитектуры) превращается в разницу между рабочим и полностью нежизнеспособным обучением. Именно эта формула стояла за первыми успешными обучениями сетей глубиной в сотни слоёв и остаётся стандартом по умолчанию для ReLU-семейства активаций во всех современных фреймворках.
Практика: 30 заданий
Базовые задания (1–10)
Задание 1: Сеть с двумя ReLU-нейронами скрытого слоя, оба инициализированы весами $(0{,}5,\,0{,}5)$ (одинаковыми). Будут ли эти нейроны вычислять разные функции после одного шага обучения?
Задание 2: Дисперсия весов слоя $\sigma_w^2=0{,}02$, число входов $n=50$. Найди множитель роста/затухания дисперсии на этом слое $n\sigma_w^2$.
Задание 3: Слой имеет $n_{in}=100$, $n_{out}=100$. Найди дисперсию весов по формуле Ксавье.
Задание 4: Тот же слой, что в задании 3, но перед ReLU-активацией. Найди дисперсию весов по формуле Хе.
Задание 5 (машинное обучение): Почему смещения (bias) обычно инициализируют нулями, а веса $W$ — случайно, а не наоборот?
Задание 6: Слой с весами, взятыми из нормального распределения со стандартным отклонением $\sigma_w=0{,}3$, число входов $n=20$. Найди множитель $n\sigma_w^2$ и определи, взрывается или затухает дисперсия.
Задание 7: Для сети из $5$ слоёв с множителем дисперсии $n\sigma_w^2=0{,}5$ на каждом слое, во сколько раз дисперсия активаций уменьшится к выходу относительно входа?
Задание 8: Слой с $n_{in}=784$ входами (например, входной слой для MNIST) перед ReLU. Найди границы для xavier_uniform_, если считать $n_{out}=784$ (условно), и сравни с дисперсией Хе.
Задание 9 (машинное обучение): В чём принципиальное отличие формулы Хе от формулы Ксавье с точки зрения вывода?
Задание 10: Дана сеть из $3$ линейных слоёв по $50$ нейронов, все веса инициализированы одним и тем же числом $c=0{,}1$ (не нулём, но одинаковым для всех весов слоя). Сохранится ли проблема симметрии?
Средние задания (11–20)
Задание 11: Слой $2\to2$ с ReLU, оба нейрона имеют веса $(1,1)$ и $b=0$. Вход $x=(3,-1)$. Покажи, что оба нейрона выдают одинаковый выход.
Задание 12: Для сети из задания 1 этого блока (два одинаковых нейрона) выведи общую формулу: если оба нейрона на шаге $t$ имеют веса $w(t)$, покажи, что $w(t+1)$ тоже одинаковы для обоих.
Задание 13: Сеть из $8$ слоёв, множитель дисперсии на слой $n\sigma_w^2=1{,}3$. Во сколько раз возрастёт дисперсия активаций к выходу?
Задание 14 (машинное обучение): Почему для очень глубоких сетей (100+ слоёв) даже множитель $1{,}05$ на слой (всего на 5% больше единицы) опасен?
Задание 15: Слой с $n_{in}=300$, $n_{out}=100$ (сужающий слой) перед tanh. Найди дисперсию весов по Ксавье.
Задание 16: Тот же слой ($n_{in}=300$), но перед ReLU. Найди дисперсию по Хе и сравни с результатом задания 15.
Задание 17 (машинное обучение): Сеть с ReLU-слоями инициализирована формулой Ксавье вместо Хе. Через 40 слоёв дисперсия активаций упала практически до нуля. Объясни механизм этого затухания.
Задание 18: Дисперсия входа сети $\mathrm{Var}(a^{(0)})=4$. Слой с $n_{in}=64$, ReLU, инициализация по Хе. Найди ожидаемую дисперсию активации после слоя.
Задание 19: Приведи формулу Хе в режиме fan_out (ориентированную на сохранение дисперсии градиента, а не активаций) по аналогии с выводом в уроке.
Задание 20 (машинное обучение): В PyTorch слой создан как nn.Linear(128, 64), дальше идёт nn.ReLU(). Какой вызов инициализации правильно подобрать и почему?
Продвинутые задания (21–30)
Задание 21: Сеть из $20$ ReLU-слоёв по $256$ нейронов, инициализированных с $\sigma_w^2=0{,}003$ вместо правильных по Хе $2/256\approx0{,}00781$. Найди множитель на слой (с учётом ReLU) и итоговый коэффициент затухания дисперсии за 20 слоёв.
Задание 22 (машинное обучение): Почему инициализация Хе была предложена именно в 2015 году, а не одновременно с распространением ReLU (примерно 2010–2012)?
Задание 23: Слой $n_{in}=1000$, $n_{out}=10$ (сильно сужающий, характерно для выходного слоя классификатора) перед сигмоидой. Найди дисперсию весов по Ксавье и сравни с наивным вариантом $1/n_{in}$.
Задание 24: Ты обучаешь сеть и замечаешь: активации первого слоя имеют разумную дисперсию $\approx1$, но к 15-му слою дисперсия упала до $10^{-6}$. Опиши план диагностики с опорой на материал урока.
Задание 25 (машинное обучение): Почему инициализация нулями конкретно опасна для полносвязных (Linear) слоёв, но существенно менее (хотя тоже проблематична) для, например, смещений в батч-нормализации (урок 332)?
Задание 26: Сеть с $12$ слоями по $150$ нейронов, ReLU. Найди верную дисперсию весов по Хе и посчитай множитель на слой, чтобы убедиться, что он равен $1$.
Задание 27: Покажи алгебраически, что при $n_{in}=n_{out}=n$ формула Ксавье $\dfrac{2}{n_{in}+n_{out}}$ сводится к простому $1/n$.
Задание 28 (машинное обучение): Почему современные фреймворки (PyTorch, Keras) уже используют разумную инициализацию по умолчанию для стандартных слоёв, и означает ли это, что материал урока не нужен на практике?
Задание 29: Сеть из $6$ слоёв с сигмоидной активацией, инициализация по Хе (а не по Ксавье, как следовало бы). Множитель на слой без поправки на обнуление (сигмоида не обнуляет входы, как ReLU) окажется $n\sigma_w^2 = n\cdot(2/n) = 2$. К чему это приведёт за 6 слоёв?
Задание 30 (машинное обучение): Сформулируй общее правило выбора между Ксавье и Хе для произвольной новой архитектуры, опираясь на вывод обеих формул из этого урока.
Частые ошибки
-
Считают, что нулевая инициализация — безопасный «нейтральный» выбор. Как показано в разборе проблемы симметрии, нулевая (и вообще любая одинаковая) инициализация весов слоя навсегда фиксирует все нейроны этого слоя идентичными друг другу — сеть теряет всю выразительность ширины слоя, сколько бы шагов обучения ни прошло (задания 1, 10, 12).
-
Путают инициализацию весов $W$ и смещений $b$, считая, что оба нужно инициализировать одинаково случайно. Проблему симметрии создают именно веса $W$, комбинирующие вход; смещения $b$ принято инициализировать нулями без вреда для обучения (задание 5).
-
Используют формулу Ксавье для ReLU-сетей по инерции, не проверяя тип активации. Как показано в задании 17 и в примере с 30-слойной сетью, формула Ксавье систематически недооценивает нужный масштаб весов для ReLU примерно вдвое, что при достаточной глубине сети приводит к практически полному затуханию дисперсии активаций.
-
Считают, что раз современные фреймворки уже инициализируют веса «прилично», разбираться в формулах не нужно. Значения по умолчанию защищают от грубых ошибок в типовых слоях, но не спасают в кастомных архитектурах, необычных активациях или при диагностике проблем обучения — без понимания механизма невозможно понять, что именно пошло не так (задание 28).
-
Недооценивают, насколько небольшое отклонение множителя $n\sigma_w^2$ от единицы опасно на большой глубине. Как показано в задании 14, даже множитель $1{,}05$ (всего 5% превышения) даёт более чем стократный рост дисперсии на сотне слоёв — экспоненциальное накопление превращает малую погрешность в катастрофу именно на глубоких, а не на мелких сетях.
-
Применяют поправку Хе (множитель $2$) к активациям, которые не обнуляют часть входа, например к сигмоиде или tanh. Как показано в задании 29, лишний множитель Хе для таких активаций избыточен и приводит к завышенному масштабу весов и росту дисперсии активаций, а не к её сохранению.
Главное запомнить
-
Проблема симметрии: если все веса, ведущие в нейроны одного слоя, одинаковы (в частности, равны нулю), эти нейроны вычисляют идентичные функции на forward pass, получают идентичные градиенты на backward pass и остаются идентичными на любом шаге обучения — слой из $N$ нейронов вырождается в один нейрон.
-
Смещения $b$ можно инициализировать нулями без вреда — проблему симметрии создают именно веса $W$, комбинирующие несколько входов.
-
Дисперсия предактивации слоя приблизительно равна $\mathrm{Var}(z) \approx n\cdot\sigma_w^2\cdot\sigma_a^2$; если множитель $n\sigma_w^2$ отличен от $1$, дисперсия активаций масштабируется экспоненциально с числом слоёв $L$ как $(n\sigma_w^2)^L$.
-
Слишком большой масштаб случайных весов приводит к взрывающимся активациям и градиентам, слишком маленький — к затухающим; оба эффекта экспоненциальны по глубине сети.
-
Инициализация Ксавье (Глорота, 2010): $\mathrm{Var}(W) = \dfrac{2}{n_{in}+n_{out}}$, выведена из требования сохранения дисперсии активаций и градиентов одновременно; хорошо работает с сигмоидой и tanh.
-
Инициализация Хе (Kaiming He, 2015): $\mathrm{Var}(W) = \dfrac{2}{n_{in}}$, содержит дополнительный множитель $2$ относительно наивной формулы Ксавье по $n_{in}$, компенсирующий обнуление примерно половины входов активацией ReLU.
-
Формула Хе выведена как модификация Ксавье специально под ReLU-подобные активации; применение «не той» формулы к неподходящей активации систематически искажает масштаб весов (задания 17, 29).
-
Инициализация весов напрямую связана с проблемой затухающих и взрывающихся градиентов в глубоких сетях (урок 330) — оба явления имеют один и тот же математический механизм: экспоненциальное накопление множителя, отличного от единицы, по числу слоёв.
-
Современные фреймворки (PyTorch, TensorFlow, Keras) уже используют разумную инициализацию по умолчанию для стандартных слоёв, но понимание сути критично для диагностики проблем обучения и работы с нестандартными архитектурами и активациями.
-
torch.nn.init.xavier_uniform_иtorch.nn.init.kaiming_normal_— прямые программные реализации формул этого урока, различающиеся тем, какую активацию (и, соответственно, какой множитель) они предполагают.
Связь с темами курса
Этот урок напрямую продолжает урок 330 о backpropagation: там ты увидел, как градиент вычисляется по цепному правилу, проходя от выхода сети к каждому весу, а сегодня разобрал, почему стартовая точка этой цепочки вычислений — инициализация весов — определяет, будут ли эти градиенты вообще численно вменяемыми. Взрывающиеся и затухающие градиенты, о которых backpropagation лишь предупреждает как о потенциальной опасности, — это ровно то явление, которое сегодня разобрано с точной формулой и численным расчётом: экспоненциальное накопление множителя $n\sigma_w^2$ по числу слоёв.
Связь с уроком 328 про функции активации тоже прямая: сегодняшний разбор поведения сигмоиды, tanh и ReLU при инициализации опирается на их свойства, разобранные там (затухающий градиент сигмоиды на краях, умирающий ReLU), — просто теперь источник проблемы не только в форме самой функции активации, но и в масштабе весов, который в неё подаётся.
Следующий урок 332 о батч-нормализации (batch normalization) — прямое продолжение сегодняшней темы: батч-нормализация решает ту же самую задачу — контроль дисперсии активаций между слоями, — но не за счёт разового правильного выбора инициализации, а за счёт активной, постоянной нормализации активаций на каждом шаге обучения, что делает сеть значительно менее чувствительной к точному выбору начального масштаба весов.
Интересные факты
-
Статья Глорота и Бенджио 2010 года не только предложила формулу инициализации, но и впервые систематически показала на графиках, как именно дисперсия активаций и градиентов эволюционирует по слоям при неправильной инициализации, — эта визуализация распределения активаций по слоям до сих пор остаётся стандартным диагностическим инструментом при отладке глубоких сетей.
-
Название «инициализация Ксавье» и «инициализация Глорота» относятся к одному и тому же результату и одному и тому же человеку — Ксавье Глороту (Xavier Glorot), первому автору статьи 2010 года; путаница в литературе возникла просто потому, что одни ссылаются на имя, а другие на фамилию.
-
Инициализация Хе была впервые представлена не как самостоятельная тема, а как один из трёх факторов (наряду с новым вариантом ReLU под названием PReLU и более глубокой архитектурой), которые совместно впервые позволили нейросети превзойти человека на задаче классификации изображений ImageNet в 2015 году.
-
Несмотря на то что обе формулы выведены из достаточно упрощённых предположений (независимость весов и входов, приблизительная симметричность распределений), они остаются рабочим стандартом инициализации спустя более десяти лет после публикации и почти не изменились даже с появлением куда более сложных современных активаций вроде GELU и Swish.
Лайфхаки
-
Если глубокая сеть с ReLU не обучается и loss не сдвигается с первых эпох, в первую очередь проверь явно, какая формула инициализации используется в кастомных слоях: несоответствие Ксавье вместо Хе для ReLU — одна из самых частых и самых легко устранимых причин.
-
Быстрая диагностика в PyTorch: после создания модели пройди по всем слоям и выведи
layer.weight.std().item()для каждого — если стандартное отклонение заметно отличается от теоретического $\sqrt{2/n_{in}}$ (для ReLU) или $\sqrt{2/(n_{in}+n_{out})}$ (для tanh/сигмоиды), это сигнал проверить инициализацию отдельно. -
При проектировании кастомного слоя с нестандартной активацией сначала прикинь на бумаге (как в примерах этого урока), обнуляет ли активация часть входа и какую именно долю в среднем — это сразу подскажет, нужен ли поправочный множитель, аналогичный множителю $2$ у Хе, и какой именно.
-
Не полагайся на инициализацию по умолчанию вслепую при построении необычно глубоких сетей (существенно глубже типовых архитектур курса) — на такой глубине даже штатная инициализация фреймворка стоит перепроверить явным расчётом множителя $n\sigma_w^2$ по формулам этого урока.
-
При отладке взрывающихся или затухающих градиентов не забывай, что причина может быть не в оптимизаторе и не в learning rate, а именно в стартовом масштабе весов — прежде чем менять гиперпараметры обучения, проверь распределение активаций сразу после инициализации, ещё до первого шага градиентного спуска.
-
Если смешиваешь в одной сети слои с разными активациями (например, ReLU в скрытых слоях и сигмоиду на выходе), инициализируй каждый слой отдельной формулой, соответствующей именно следующей за ним активации, а не одной формулой на всю сеть сразу.
Сегодня ты разобрал то, что легко принять за формальность, а на деле оказывается одним из фундаментальных условий, при которых глубокая сеть вообще способна обучаться. Проблема симметрии показала, что случайность в весах — не опция, а строгая необходимость; а точный расчёт дисперсии по формулам Ксавье и Хе показал, что даже случайность должна быть правильно откалибрована, иначе сигнал попросту не дойдёт через десятки слоёв ни вперёд, ни назад. Ты теперь умеешь не просто вызвать xavier_uniform_ или kaiming_normal_ одной строкой, а объяснить, почему именно такая формула и почему множитель именно такой — а значит, сможешь диагностировать проблему инициализации в любой нестандартной архитектуре, где готового рецепта из коробки может не найтись. Следующий шаг — батч-нормализация, которая берёт ту же самую идею контроля дисперсии активаций и превращает её из разового решения при старте в постоянно работающий механизм на каждом шаге обучения.
Понял тему? Закрепи в боте! 🚀
Попрактикуйся на задачах и получи персональные рекомендации от AI
💪 Начать тренировку