6.2. Управление параметрами¶
Выбрав архитектуру и задав гиперпараметры, мы переходим к циклу обучения, где наша цель — найти такие значения параметров, которые минимизируют функцию потерь. После обучения нам понадобятся эти параметры для будущих предсказаний. Кроме того, иногда возникает необходимость извлечь параметры, например, чтобы использовать их в другом контексте, сохранить модель на диск для выполнения в другом программном обеспечении или для анализа с целью получения научных знаний.
В большинстве случаев нам не придется вдаваться в тонкости объявления и манипулирования параметрами, поскольку мы можем положиться на фреймворки глубокого обучения для выполнения основной работы. Однако при отходе от стандартных архитектур со слоями нам иногда приходится погружаться в детали объявления и манипулирования параметрами. В этом разделе мы рассмотрим следующее:
Доступ к параметрам для отладки, диагностики и визуализации.
Объединение параметров между различными компонентами модели.
import torch
from torch import nn
Сначала мы сосредоточимся на многослойном перцептроне с одним скрытым слоем.
net = nn.Sequential(nn.LazyLinear(8),
nn.ReLU(),
nn.LazyLinear(1))
X = torch.rand(size=(2, 4))
net(X).shape
6.2.1. Доступ к параметрам¶
Начнем с того, как получить доступ к параметрам в уже известных вам моделях.
Когда модель определена с помощью класса Sequential, мы можем
получить доступ к любому слою, обращаясь к модели по индексу, как к
списку. Параметры каждого слоя удобно доступны через его атрибут.
Мы можем изучить параметры второго полносвязного слоя следующим образом.
net[2].state_dict()
Мы видим, что этот полносвязный слой содержит два параметра, соответствующих весам и смещениям этого слоя соответственно.
6.2.1.1. Целевые параметры¶
Обратите внимание, что каждый параметр представлен как объект класса параметра. Чтобы выполнять какие-либо полезные действия с параметрами, нам сначала необходимо получить доступ к их базовым числовым значениям. Существует несколько способов сделать это. Некоторые из них проще, другие — более универсальны. Приведённый ниже код извлекает смещение из второго слоя нейронной сети, который возвращает объект класса параметра, а затем получает доступ к значению этого параметра.
type(net[2].bias), net[2].bias.data
Параметры — это сложные объекты, содержащие значения, градиенты и дополнительную информацию. Именно поэтому нам необходимо явно запросить значение.
В дополнение к значению, каждый параметр также позволяет получить доступ к градиенту. Поскольку мы ещё не вызывали обратное распространение ошибки для этой сети, она находится в своём начальном состоянии.
net[2].weight.grad == None
6.2.1.2. Все параметры одновременно¶
Когда требуется выполнять операции со всеми параметрами, доступ к ним по одному может стать утомительным. Эта ситуация особенно усложняется при работе со сложными, например вложенными, модулями, так как в таком случае потребуется рекурсивный обход всего дерева для извлечения параметров каждого подмодуля. Ниже демонстрируется доступ к параметрам всех слоёв.
[(name, param.shape) for name, param in net.named_parameters()]
6.2.2. Связанные параметры¶
Часто мы хотим разделять параметры между несколькими слоями. Давайте
посмотрим, как сделать это элегантно. В приведённом ниже примере мы
создаем полносвязный слой, а затем используем его параметры для задания
параметров другого слоя. Для этого нам необходимо выполнить прямое
распространение net(X) перед обращением к параметрам.
# We need to give the shared layer a name so that we can refer to its
# parameters
shared = nn.LazyLinear(8)
net = nn.Sequential(nn.LazyLinear(8), nn.ReLU(),
shared, nn.ReLU(),
shared, nn.ReLU(),
nn.LazyLinear(1))
net(X)
# Check whether the parameters are the same
print(net[2].weight.data[0] == net[4].weight.data[0])
net[2].weight.data[0, 0] = 100
# Make sure that they are actually the same object rather than just having the
# same value
print(net[2].weight.data[0] == net[4].weight.data[0])
Этот пример показывает, что параметры второго и третьего слоёв связаны. Они не просто равны, а представлены одним и тем же тензором. Таким образом, если мы изменим один из параметров, изменится и другой.
Возникает вопрос: что происходит с градиентами, когда параметры связаны? Поскольку параметры модели содержат градиенты, градиенты второго скрытого слоя и третьего скрытого слоя суммируются во время обратного распространения ошибки.
6.2.3. Итог¶
Мы рассмотрели несколько способов доступа к параметрам модели и их связывания.
6.2.4. Упражнения¶
Используйте модель
NestMLP, определённую в Section 6.1, и получите доступ к параметрам различных слоёв.Создайте многослойный перцептрон (MLP), содержащий слой с общими параметрами, и обучите его. В процессе обучения наблюдайте за параметрами модели и градиентами каждого слоя.
Почему разделение параметров — хорошая идея?