Управление параметрами ====================== Выбрав архитектуру и задав гиперпараметры, мы переходим к циклу обучения, где наша цель — найти такие значения параметров, которые минимизируют функцию потерь. После обучения нам понадобятся эти параметры для будущих предсказаний. Кроме того, иногда возникает необходимость извлечь параметры, например, чтобы использовать их в другом контексте, сохранить модель на диск для выполнения в другом программном обеспечении или для анализа с целью получения научных знаний. В большинстве случаев нам не придется вдаваться в тонкости объявления и манипулирования параметрами, поскольку мы можем положиться на фреймворки глубокого обучения для выполнения основной работы. Однако при отходе от стандартных архитектур со слоями нам иногда приходится погружаться в детали объявления и манипулирования параметрами. В этом разделе мы рассмотрим следующее: - Доступ к параметрам для отладки, диагностики и визуализации. - Объединение параметров между различными компонентами модели. .. raw:: latex \diilbookstyleinputcell .. code:: python import torch from torch import nn Сначала мы сосредоточимся на многослойном перцептроне с одним скрытым слоем. .. raw:: latex \diilbookstyleinputcell .. code:: python net = nn.Sequential(nn.LazyLinear(8), nn.ReLU(), nn.LazyLinear(1)) X = torch.rand(size=(2, 4)) net(X).shape .. _subsec_param-access: Доступ к параметрам ------------------- Начнем с того, как получить доступ к параметрам в уже известных вам моделях. Когда модель определена с помощью класса ``Sequential``, мы можем получить доступ к любому слою, обращаясь к модели по индексу, как к списку. Параметры каждого слоя удобно доступны через его атрибут. Мы можем изучить параметры второго полносвязного слоя следующим образом. .. raw:: latex \diilbookstyleinputcell .. code:: python net[2].state_dict() Мы видим, что этот полносвязный слой содержит два параметра, соответствующих весам и смещениям этого слоя соответственно. Целевые параметры ~~~~~~~~~~~~~~~~~ Обратите внимание, что каждый параметр представлен как объект класса параметра. Чтобы выполнять какие-либо полезные действия с параметрами, нам сначала необходимо получить доступ к их базовым числовым значениям. Существует несколько способов сделать это. Некоторые из них проще, другие — более универсальны. Приведённый ниже код извлекает смещение из второго слоя нейронной сети, который возвращает объект класса параметра, а затем получает доступ к значению этого параметра. .. raw:: latex \diilbookstyleinputcell .. code:: python type(net[2].bias), net[2].bias.data Параметры — это сложные объекты, содержащие значения, градиенты и дополнительную информацию. Именно поэтому нам необходимо явно запросить значение. В дополнение к значению, каждый параметр также позволяет получить доступ к градиенту. Поскольку мы ещё не вызывали обратное распространение ошибки для этой сети, она находится в своём начальном состоянии. .. raw:: latex \diilbookstyleinputcell .. code:: python net[2].weight.grad == None Все параметры одновременно ~~~~~~~~~~~~~~~~~~~~~~~~~~ Когда требуется выполнять операции со всеми параметрами, доступ к ним по одному может стать утомительным. Эта ситуация особенно усложняется при работе со сложными, например вложенными, модулями, так как в таком случае потребуется рекурсивный обход всего дерева для извлечения параметров каждого подмодуля. Ниже демонстрируется доступ к параметрам всех слоёв. .. raw:: latex \diilbookstyleinputcell .. code:: python [(name, param.shape) for name, param in net.named_parameters()] Связанные параметры ------------------- Часто мы хотим разделять параметры между несколькими слоями. Давайте посмотрим, как сделать это элегантно. В приведённом ниже примере мы создаем полносвязный слой, а затем используем его параметры для задания параметров другого слоя. Для этого нам необходимо выполнить прямое распространение ``net(X)`` перед обращением к параметрам. .. raw:: latex \diilbookstyleinputcell .. code:: python # 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]) Этот пример показывает, что параметры второго и третьего слоёв связаны. Они не просто равны, а представлены одним и тем же тензором. Таким образом, если мы изменим один из параметров, изменится и другой. Возникает вопрос: что происходит с градиентами, когда параметры связаны? Поскольку параметры модели содержат градиенты, градиенты второго скрытого слоя и третьего скрытого слоя суммируются во время обратного распространения ошибки. Итог ---- Мы рассмотрели несколько способов доступа к параметрам модели и их связывания. Упражнения ---------- 1. Используйте модель ``NestMLP``, определённую в :numref:`sec_model_construction`, и получите доступ к параметрам различных слоёв. 2. Создайте многослойный перцептрон (MLP), содержащий слой с общими параметрами, и обучите его. В процессе обучения наблюдайте за параметрами модели и градиентами каждого слоя. 3. Почему разделение параметров — хорошая идея? `Обсуждения `__