Автор оригинала: Pankaj Kumar.
Знание того, как инициализировать веса моделей, является важной темой в глубоком обучении . Начальные веса влияют на множество факторов – градиенты, выходное подпространство и т. Д. В этой статье мы узнаем о некоторых наиболее важных и широко используемых методах инициализации веса и о том, как их реализовать с помощью PyTorch . В этой статье ожидается, что пользователь будет знаком с PyTorch на начальном уровне.
Почему важно инициализировать веса модели?
Цель обучения любой модели глубокого обучения-найти оптимальный набор весов для модели, которая дает нам желаемые результаты. Методы обучения, используемые в глубоком обучении, как правило, носят итеративный характер и требуют, чтобы мы предоставили исходный набор весов, который необходимо обновлять с течением времени.
Начальные веса играют огромную роль в определении окончательного результата тренировки. Неправильная инициализация весов может привести к исчезновению или взрыву градиентов, что, очевидно, нежелательно. Поэтому мы используем некоторые стандартные методы инициализации слоев, которые мы обсудим в этой статье.
Общее эмпирическое правило
Эмпирическое правило состоит в том, что “начальные веса модели должны быть близки к нулю, но не нулю” . Наивной идеей было бы выбрать выборку из распределения, которое сколь угодно близко к 0.
Например, вы можете выбрать заполнение веса значениями, выбранными из U(-0.01, 0.01) или N(0, 0.01).
Оказывается, вышеприведенная идея вовсе не так наивна, большинство стандартных методов основаны на выборке из равномерного и нормального распределения.
Но настоящая хитрость заключается в установлении граничных условий для этих распределений. Одним из обычно используемых граничных условий является 1/sqrt(n), где n – количество входов в слой.
В Pitch мы можем установить веса слоя, который будет выбран из равномерного или нормального распределения , используя функции uniform_
и normal_|/. Вот простой пример
uniform_() и
normal_() в действии.
# Linear Dense Layer layer_1 = nn.Linear(5, 2) print("Initial Weight of layer 1:") print(layer_1.weight) # Initialization with uniform distribution nn.init.uniform_(layer_1.weight, -1/sqrt(5), 1/sqrt(5)) print("\nWeight after sampling from Uniform Distribution:\n") print(layer_1.weight) # Initialization with normal distribution nn.init.normal_(layer_1.weight, 0, 1/sqrt(5)) print("\nWeight after sampling from Normal Distribution:\n") print(layer_1.weight)
Выход:
Initial Weight of layer 1: Parameter containing: tensor([[-0.0871, -0.0804, 0.2327, -0.1453, -0.1019], [-0.1338, -0.2465, 0.3257, -0.2669, -0.1537]], requires_grad=True) Weight after sampling from Uniform Distribution: Parameter containing: tensor([[ 0.4370, -0.4110, 0.2631, -0.3564, 0.0707], [-0.0009, 0.3716, -0.3596, 0.3667, 0.2465]], requires_grad=True) Weight after sampling from Normal Distribution: Parameter containing: tensor([[-0.2148, 0.1156, 0.7121, 0.2840, -0.4302], [-0.2647, 0.2148, -0.0852, -0.3813, 0.6983]], requires_grad=True)
Но у этого метода есть и некоторые ограничения. Эти методы слишком обобщены и, как правило, немного проблематичны для слоев, имеющих нелинейные функции активации, такие как Сигмоид
, Tanh
и ReLU
активации, где существует высокая вероятность исчезновения и взрыва градиентов.
Поэтому в следующем разделе мы рассмотрим некоторые из передовых методов, которые были предложены для решения этой проблемы.
Инициализация слоев с нелинейной активацией
Существует два стандартных метода весовой инициализации слоев с нелинейной активацией – инициализация Ксавье(Glorot) и инициализация Кайминга.
Мы не будем углубляться в математические выражения и доказательства, а сосредоточимся больше на том, где их использовать и как их применять. Это абсолютно не приглашение пропустить математическую подготовку.
1. Инициализация Ксавье
Инициализация Xavier используется для слоев, имеющих функции активации Sigmoid
и Tanh
. Существует две разные версии инициализации Ксавье. Разница заключается в распределении, из которого мы отбираем данные – Равномерное распределение и Нормальное распределение. Вот краткий обзор этих двух вариантов:
2. Равномерное распределение Ксавье
В этом методе тензор веса заполняется значениями, выбранными из равномерного распределения U(-a, a), где,
input_dim
и output_dim
являются выходным и входным измерением или, более явно, измерениями предыдущего и предыдущего слоя, а коэффициент усиления
– это просто коэффициент масштабирования.
Пример:
# The convolution layer conv_layer = nn.Conv2d(1, 4, (2,2)) # Initiliazing with Xavier Uniform nn.init.xavier_uniform_(conv_layer.weight)
3. Нормальное распределение Ксавье
Этот метод аналогичен предыдущему, за исключением того, что значения отбираются из нормального распределения, где,
и input_dim
и output_dim
являются выходным и входным измерением или, более явно, измерениями предыдущего и предыдущего слоя.
Пример:
# The convolution layer conv_layer = nn.Conv2d(1, 4, (2,2)) # Initiliazing with Xavier Normal nn.init.xavier_normal_(conv_layer.weight)
Инициализация Кайминга
До сих пор мы обсуждали, как инициализировать веса, когда слой имеет функцию активации sigmoid
и Tanh
. Мы еще не обсуждали ReLU
.
Слои с функцией активации ReLU
были однажды инициализированы с помощью метода Ксавье, пока Каймин не предложил свой метод инициализации слоев ReLU
функций активации. Кай мин немного отличается от инициализации Ксавье только в математической формуле для граничных условий.
Реализация PyTorch Kaming имеет дело не только с ReLU, но и с LeakyReLU. PyTorch предлагает два различных режима для инициализации кайминга – режим fan_in и режим fan_out. Использование режима fan_in гарантирует, что данные будут сохранены от взрыва или взрыва. Аналогично режим fan_out будет пытаться сохранить градиенты при обратном распространении.
1. Равномерное распределение Кайминга
Тензор веса заполняется значениями, выбранными из равномерного распределения U(-a, a), где,
Для режима fan_in используются входные размеры, в то время как для режима fan_out используются выходные размеры. Коэффициент усиления для ReLU равен √2, а для LeakyReLU равен √(1/a^2 +1).
О выигрыше обычно заботятся функции kaiming_uniform_()
и kaiming_normal_ ()
, где нам нужно указать только тип нелинейности, с которой мы имеем дело.
Пример:
conv_layer = nn.Conv2d(1, 4, (2,2)) nn.init.kaiming_uniform_(conv_layer.weight, mode='fan_in', nonlinearity='relu')
2. Нормальное распределение Кайминга
Веса слоев отбираются из нормального распределения, где,
и input_dim и output_market размер вывода и ввода и выбираются при выборе режима работы.
Пример:
conv_layer = nn.Conv2d(1, 4, (2,2)) nn.init.kaiming_normal_(conv_layer.weight, mode='fan_in', nonlinearity='relu')
Интеграция правил инициализации в модель PyTorch
Теперь, когда мы знакомы с тем, как мы можем инициализировать отдельные слои с помощью шага, мы можем попытаться инициализировать слои реальных моделей PyTorch. Мы можем выполнить эту инициализацию в определении модели или применить эти методы после определения модели.
1. Инициализация при определении модели
import torch.nn as nn import torch.nn.functional as F class Net(nn.Module): def __init__(self): # Layer definitions super().__init__() self.conv1 = nn.Conv2d(3, 6, 5) self.pool = nn.MaxPool2d(2, 2) self.conv2 = nn.Conv2d(6, 16, 5) self.fc1 = nn.Linear(16 * 5 * 5, 120) self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) # Initialization nn.init.kaiming_normal_(self.fc1.weight, mode='fan_in', nonlinearity='relu') nn.init.kaiming_normal_(self.fc2.weight, mode='fan_in', nonlinearity='relu') nn.init.xavier_normal_(self.fc3.weight) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = x.view(-1, 16 * 5 * 5) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) x = nn.sigmoid(x) return x # Every time you create a new mode, it will have a weight initialized model net = Net()
2. Инициализация после создания модели
Вы всегда можете изменить веса после создания модели, вы можете сделать это, определив правило для определенного типа слоев и применив его ко всей модели или просто инициализировав один слой.
# Defining a method for initialization of linear weights # The initialization will be applied to all linear layers # irrespective of their activation function def init_weights(m): if type(m) == nn.Linear: torch.nn.init.xavier_uniform(m.weight) # Applying it to our net net.apply(init_weights)
# Create the model net = Net() # Apply the Xavier normal method to the last layer nn.init.xavier_normal_(self.fc3.weight)
Вывод
Это подводит нас к концу этой статьи об инициализации веса. Оставайтесь с нами, чтобы узнать больше таких статей о глубоком обучении и питче.