Пользовательские слои ===================== Одним из факторов успеха глубокого обучения является наличие широкого спектра слоёв, которые можно комбинировать творческими способами для проектирования архитектур, подходящих для самых разных задач. Например, исследователи разработали специализированные слои для обработки изображений, текста, обхода последовательных данных и выполнения динамического программирования. В какой-то момент вам может понадобиться слой, которого ещё нет во фреймворке глубокого обучения. В таких случаях необходимо создать собственный слой. В этом разделе мы покажем, как это сделать. .. raw:: latex \diilbookstyleinputcell .. code:: python import torch from torch import nn from torch.nn import functional as F from d2l import torch as d2l Слои без параметров ------------------- Для начала создадим пользовательский слой, не имеющий собственных параметров. Если вы помните наше введение в модули из :numref:`sec_model_construction`, этот подход должен показаться вам знакомым. Приведённый ниже ``CenteredLayer`` класс просто вычитает среднее значение из входных данных. Для его реализации достаточно наследоваться от базового класса слоя и реализовать функцию прямого распространения. .. raw:: latex \diilbookstyleinputcell .. code:: python class CenteredLayer(nn.Module): def __init__(self): super().__init__() def forward(self, X): return X - X.mean() Давайте проверим, что наш слой работает так, как задумано, пропустив через него некоторые данные. .. raw:: latex \diilbookstyleinputcell .. code:: python layer = CenteredLayer() layer(torch.tensor([1.0, 2, 3, 4, 5])) Теперь мы можем **использовать наш слой в качестве компонента при построении более сложных моделей.** .. raw:: latex \diilbookstyleinputcell .. code:: python net = nn.Sequential(nn.LazyLinear(128), CenteredLayer()) В качестве дополнительной проверки мы можем пропустить через сеть случайные данные и убедиться, что среднее значение действительно равно нулю. Поскольку мы работаем с числами с плавающей запятой, из-за квантования может наблюдаться очень малое ненулевое значение. .. raw:: latex \diilbookstyleinputcell .. code:: python Y = net(torch.rand(4, 8)) Y.mean() Слои с параметрами ------------------ Теперь, когда мы знаем, как определять простые слои, перейдём к определению слоёв с параметрами, которые можно настраивать в процессе обучения. Мы можем использовать встроенные функции для создания параметров, которые обеспечивают базовые функции управления. В частности, они регулируют доступ, инициализацию, разделение, сохранение и загрузку параметров модели. Таким образом, среди прочих преимуществ, нам не придётся писать пользовательские процедуры сериализации для каждого пользовательского слоя. Теперь реализуем собственную версию полносвязного слоя. Напомним, что этот слой требует два параметра: один для веса, а другой — для смещения. В данной реализации в качестве функции активации по умолчанию используется ReLU. Этот слой принимает два входных аргумента: ``in_units`` и ``units``, которые обозначают количество входов и выходов соответственно. .. raw:: latex \diilbookstyleinputcell .. code:: python class MyLinear(nn.Module): def __init__(self, in_units, units): super().__init__() self.weight = nn.Parameter(torch.randn(in_units, units)) self.bias = nn.Parameter(torch.randn(units,)) def forward(self, X): linear = torch.matmul(X, self.weight.data) + self.bias.data return F.relu(linear) Далее мы создаём экземпляр класса ``MyLinear`` и обращаемся к его параметрам модели. .. raw:: latex \diilbookstyleinputcell .. code:: python linear = MyLinear(5, 3) linear.weight Мы можем выполнять прямое распространение непосредственно с помощью пользовательских слоёв. .. raw:: latex \diilbookstyleinputcell .. code:: python linear(torch.rand(2, 5)) Мы также можем **создавать модели с использованием пользовательских слоёв.** После этого мы можем использовать их так же, как встроенный полносвязный слой. .. raw:: latex \diilbookstyleinputcell .. code:: python net = nn.Sequential(MyLinear(64, 8), MyLinear(8, 1)) net(torch.rand(2, 64)) Итог ---- Мы можем создавать пользовательские слои с помощью базового класса слоя. Это позволяет определять гибкие новые слои, поведение которых отличается от поведения любых существующих слоёв в библиотеке. После определения такие слои можно использовать в любых контекстах и архитектурах. Слои могут содержать локальные параметры, которые создаются с помощью встроенных функций. Упражнения ---------- 1. Спроектируйте слой, который принимает входные данные и вычисляет тензорное свёртывание, то есть возвращает :math:`y_k = \sum_{i, j} W_{ijk} x_i x_j`. 2. Спроектируйте слой, который возвращает первую половину коэффициентов Фурье данных. `Обсуждения `__