Практическое руководство по глубокому обучению 5.3 PyTorch Пользовательский слой

глубокое обучение PyTorch

Примите участие в 20-м дне Ноябрьского испытания обновлений и узнайте подробности события:Вызов последнего обновления 2021 г.


В предыдущем разделе говорилось о том, как настроить параметры инициализации.Практическое руководство по глубокому обучению 5.2. Инициализация параметров PyTorch — самородки (juejin.cn)

В этом разделе рассматривается, как настраивать слои.

Таким образом, вы можете подумать о том, каким был предыдущий этаж. Напримерnn.Linear,nn.ReLUЖдать. Их роль заключается в том, чтобы выступать в качестве слоя обработки. Разница между ними заключается в том, что у первого есть параметры, а у второго нет списка параметров. Теперь давайте также реализуем некоторые операции со слоями со списками параметров и без них.

import torch
import torch.nn.functional as F
from torch import nn

Слой без параметров

class CenteredLayer(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, X):
        return X - X.mean()

Нам также нужно только определить прямое распространение. Функция этого самостоятельно построенного слоя состоит в том, чтобы вычесть его среднее значение из каждого количества признаков.

layer = CenteredLayer()
X = torch.arange(5)*0.1
print(layer(X))
>>
tensor([-0.2000, -0.1000,  0.0000,  0.1000,  0.2000])

После тестирования мы видим, что этот слой полностью эффективен.

Что, если вы поместите это в сложную модель.

net = nn.Sequential(nn.Linear(8, 128), CenteredLayer())

Y = torch.rand(10, 8)
print(net(Y).mean().data)
>>
tensor(7.8231e-09)

Ну, эта модель на самом деле не такая уж сложная, в ней всего два слоя. Первый — линейный слой. Второй — наш пользовательский слой.

Сгенерируйте случайный набор тестовых данных Y. Затем используйте построенную нами сеть для выполнения внешних вычислений и выведите среднее значение ее результатов.

Неудивительно, что результат должен быть 0. Хотя здесь не отображается 0. Это связано с точностью хранения чисел с плавающей запятой, и вы, конечно, можете думать об этом чрезвычайно маленьком числе примерно как о 0.

Что касается того, почему не получается результат, то это математическая проблема, и вы можете решить ее, самостоятельно перечислив несколько чисел.

слой с параметрами

class MyLinear(nn.Module):
    def __init__(self, in_units, units):
        super().__init__()
        self.weight = nn.Parameter(torch.ones(in_units, units))
        self.bias = nn.Parameter(torch.zeros(units,))
    def forward(self, X):
        linear = torch.matmul(X, self.weight.data) + self.bias.data
        return F.relu(linear)

Этот уровень аренды является пользовательской реализацией полностью связанного уровня. Параметры в этом слое должны использовать веса и смещения и, наконец, возвращаться к функции активации ReLU после вычисления.

linear = MyLinear(5, 3)
print(linear.weight.data)
>>
tensor([[ 1.0599,  0.3885,  1.2025],
        [-1.8313,  0.2097, -1.6529],
        [ 1.4119,  0.2675, -0.4148],
        [ 0.2596, -0.0319,  1.9548],
        [-1.2874,  1.0776,  0.5804]])

Взгляните на вывод его веса, он действительно может генерировать весовую матрицу 5×3.

X = torch.rand(2, 5)
linear(X)
>>
tensor([[2.3819, 2.3819, 2.3819],
        [1.8295, 1.8295, 1.8295]])

Результаты однослойного теста также в порядке.

net = nn.Sequential(MyLinear(64, 8), MyLinear(8, 1))
net(torch.rand(2, 64))
>>
tensor([[0.4589],
        [0.0000]])

Выложить в сеть оказалось не проблема.

Теперь позвольте мне привести код сравнения, то есть как слой, который мы написали, и слой, написанный pytorch, могут выполнять одну и ту же функцию.

net1 = nn.Sequential(MyLinear(64, 8), MyLinear(8, 1))
net2 = nn.Sequential(nn.Linear(64,8),
                     nn.ReLU(),
                     nn.Linear(8,1),
                     nn.ReLU())

def init(m):
    if type(m)==nn.Linear:
        nn.init.ones_(m.weight)
        nn.init.zeros_(m.bias)
net2.apply(init)

Y = torch.rand(4, 64)


print(net1(Y).data)
print(net2(Y).data)

>>
tensor([[270.5055],
        [253.7892],
        [238.7834],
        [258.4998]])
tensor([[270.5055],
        [253.7892],
        [238.7834],
        [258.4998]])

Итак, на первый взгляд, два результата не совсем одинаковы.

По сравнению с реализацией, поставляемой с pytorch, вам не нужно писать процесс взвешивания или добавлять слой ReLU.

Это выглядит просто, но на практике не рекомендуется реализовывать функции, которые уже есть в pytorch, самостоятельно. Потому что эффективнее использовать чужие методы.


  1. Подробнее о серии «Практическое глубокое обучение» см. здесь:Колонка «Практическое глубокое обучение» (juejin.cn)

  2. Примечания Адрес Github:DeepLearningNotes/d2l(github.com)

Все еще в процессе обновления......