Главная страница
Навигация по странице:

  • Глубокое обучение с PyTorch

  • Элементы PyTorch: Model, Layer, Optimizer и Loss

  • Реализация строительных блоков нейронной сети с использованием PyTorch: DenseLayer

  • Пример: моделирование цен на жилье в Бостоне в PyTorch

  • Элементы PyTorch: Trainer

  • Хитрости для оптимизации обучения в PyTorch Из главы 4 мы знаем четыре таких хитрости:y импульс;y дропаут; 242

  • Сверточные нейронные сети в PyTorch

  • Курсовая работа. Глубокое обучение


    Скачать 4.97 Mb.
    НазваниеГлубокое обучение
    АнкорКурсовая работа
    Дата26.06.2022
    Размер4.97 Mb.
    Формат файлаpdf
    Имя файлаVeydman_S_Glubokoe_obuchenie_Legkaya_razrabotka_proektov_na_Pyth.pdf
    ТипДокументы
    #615357
    страница20 из 22
    1   ...   14   15   16   17   18   19   20   21   22
    233
    print(a.grad)
    tensor([[35., 35.],
    [35., 35.]], dtype=torch.float64)
    Эта особенность PyTorch позволяет нам определять модели, задавая прямой проход, вычисляя потерю и вызывая функцию
    .backward
    , чтобы автоматически вычислить производную каждого из параметров относи- тельно этой потери. В частности, не нужно думать о повторном использо- вании одного и того же количества в прямом проходе (что ранее не давала делать структура класса
    Operation
    , которую мы использовали в первых нескольких главах). Как показывает этот простой пример, градиенты сами начнут вычисляться правильно, как только мы вызовем результаты наших вычислений в обратном направлении.
    В следующих нескольких разделах мы покажем, как фреймворк обучения, который мы рассмотрели ранее в книге, реализуется с помощью типов данных PyTorch.
    Глубокое обучение с PyTorch
    Как мы уже видели, у моделей глубокого обучения есть несколько эле- ментов, которые совокупно создают обученную модель:
    y
    Model
    (модель), которая содержит
    Layers
    (слои).
    y
    Optimizer
    (оптимизатор).
    y
    Loss
    (потери).
    y
    Trainer
    (учитель).
    Оказывается, что
    Optimizer и
    Loss реализуются в PyTorch одной строкой кода, а с
    Model и
    Layer все чуть сложнее. Давайте рассмотрим каждый из этих элементов по очереди.
    Элементы PyTorch: Model, Layer, Optimizer и Loss
    Ключевой особенностью PyTorch является возможность определять моде- ли и слои как простые в использовании объекты, которые автоматически отправляют градиенты назад и сохраняют параметры, просто наследуя

    234
    Глава 7. Библиотека PyTorch их от класса torch.nn.Module
    . Позже в этой главе вы увидите, как эти части собираются вместе. Сейчас просто знайте, что слой
    PyTorchLayer записывается так:
    from torch import nn, Tensor class PyTorchLayer(nn.Module):
    def __init__(self) -> None:
    super().__init__()
    def forward(self, x: Tensor, inference: bool = False) -> Tensor:
    raise NotImplementedError()
    а
    PyTorchModel можно записать так:
    class PyTorchModel(nn.Module):
    def __init__(self) -> None:
    super().__init__()
    def forward(self, x: Tensor, inference: bool = False) -> Tensor:
    raise NotImplementedError()
    Иными словами, каждый подкласс
    PyTorchLayer или
    PyTorchModel просто должен реализовать методы
    __init__
    и forward
    , что позволит нам исполь- зовать их интуитивно понятными способами
    1
    Флаг вывода
    Как мы видели в главе 4, из-за отсева данных нужна возможность под- страивать поведение нашей модели в зависимости от того, работает ли она в режиме обучения или в режиме вывода. В PyTorch мы можем пере- ключать модель или слой из режима обучения (поведение по умолчанию) в режим вывода, запустив функцию m.eval на модели или слое (любой
    1
    Написание слоев и моделей таким способом с использованием PyTorch не реко- мендуется и не применяется. Здесь мы пишем так только для целей иллюстрации понятий, которые рассмотрели до сих пор. Более распространенный способ постро- ения блоков нейронной сети с помощью PyTorch приведен во вводном руководстве из официальной документации.

    Глубокое обучение с PyTorch
    235
    объект, который наследуется от nn.Module
    ). Кроме того, в PyTorch есть элегантный способ быстро изменять поведение всех подклассов слоя с помощью функции apply
    . Если мы определим:
    def inference_mode(m: nn.Module):
    m.eval()
    тогда мы можем включить следующее:
    if inference:
    self.apply(inference_mode)
    в метод forward каждого подкласса
    PyTorchModel или
    PyTorchLayer
    , который мы определяем, получая желаемый флаг.
    Давайте посмотрим, как все это соединить.
    Реализация строительных блоков нейронной сети с использованием
    PyTorch: DenseLayer
    Теперь у нас есть все предпосылки для того, чтобы начать реализовывать слои, которые мы видели ранее, но с применением операций PyTorch.
    Слой
    DenseLayer описывается следующим образом:
    class DenseLayer(PyTorchLayer):
    def __init__(self, input_size: int, neurons: int, dropout: float = 1.0, activation: nn.Module = None) -> None:
    super().__init__()
    self.linear = nn.Linear(input_size, neurons)
    self.activation = activation if dropout < 1.0:
    self.dropout = nn.Dropout(1 — dropout)
    def forward(self, x: Tensor, inference: bool = False) -> Tensor:
    if inference:
    self.apply(inference_mode)
    x = self.linear(x) # does weight multiplication + bias

    236
    Глава 7. Библиотека PyTorch if self.activation:
    x = self.activation(x)
    if hasattr(self, "dropout"):
    x = self.dropout(x)
    return x
    С помощью функции nn
    Linear мы увидели наш первый пример операции
    PyTorch, которая автоматически выполняет обратное распространение.
    Этот объект не только реализует умножение веса и добавление члена смещения в прямом проходе, но также вызывает накопление градиен- тов x
    , поэтому производные потери по параметрам в обратном проходе вычисляются правильно. Также обратите внимание, что поскольку все операции PyTorch наследуются от nn.Module
    , мы можем вызывать их как математические функции: например, в предыдущем случае мы пи- шем self.linear
    (x)
    , а не self.lin ear.forward
    (x)
    . Это также относится и к самому
    DenseLayer
    , как мы увидим, когда будем использовать его в будущей модели.
    Пример: моделирование цен на жилье в Бостоне в PyTorch
    Используя этот слой в качестве строительного блока, мы можем реали- зовать уже знакомую модель цен на жилье, которую упоминали в главах
    2 и 3. Напомним, что в этой модели был один скрытый слой с сигмовид- ной функцией активации. В главе 3 мы реализовали это в нашей объек- тно-ориентированной среде, в которой были класс для слоев и модель, а в качестве атрибута слоев был список длины 2. Точно так же мы можем определить класс
    HousePricesModel
    , который наследуется от
    PyTorchModel
    :
    class HousePricesModel(PyTorchModel):
    def __init__(self, hidden_size: int = 13, hidden_dropout: float = 1.0):
    super().__init__()
    self.dense1 = DenseLayer(13, hidden_size, activation=nn.Sigmoid(), dropout = hidden_dropout)
    self.dense2 = DenseLayer(hidden_size, 1)

    Глубокое обучение с PyTorch
    237
    def forward(self, x: Tensor) -> Tensor:
    assert_dim(x, 2)
    assert x.shape[1] == 13
    x = self.dense1(x)
    return self.dense2(x)
    Теперь создаем экземпляр:
    pytorch_boston_model = HousePricesModel (hidden_size = 13)
    Обратите внимание, что в моделях
    PyTorch писать отдельный класс
    Layer не принято. Чаще всего просто определяют модели с точки зрения от- дельных выполняемых операций, используя что-то вроде такого:
    class HousePricesModel(PyTorchModel):
    def __init__(self, hidden_size: int = 13):
    super().__init__()
    self.fc1 = nn.Linear(13, hidden_size)
    self.fc2 = nn.Linear(hidden_size, 1)
    def forward(self, x: Tensor) -> Tensor:
    assert_dim(x, 2)
    assert x.shape[1] == 13
    x = self.fc1(x)
    x = torch.sigmoid(x)
    return self.fc2(x)
    При создании своих моделей PyTorch вы, возможно, будете писать свой код именно так, а не создавать отдельный класс
    Layer
    . При чтении кода других пользователей вы почти всегда увидите что-то похожее на по- казанный выше код.
    Слои и модели реализуются сложнее, чем оптимизаторы и потери, о ко- торых мы расскажем далее.

    238
    Глава 7. Библиотека PyTorch
    Элементы PyTorch: Optimizer и Loss
    Оптимизаторы и потери реализованы в PyTorch одной строкой кода. На- пример, потеря
    SGDMomentum
    , которую мы рассмотрели в главе 4, пишется так:
    import torch.optim as optim optimizer = optim.SGD(pytorch_boston_model.parameters(), lr=0.001)
    В PyTorch модели передаются в оптимизатор в качестве аргумента. Та- кой способ гарантирует, что оптимизатор «указывает» на правильные параметры модели, поэтому знает, что обновлять на каждой итерации
    (ранее мы делали это с помощью класса
    Trainer
    ).
    Кроме того, среднеквадратическую потерю, которую мы видели в главе 2, и
    SoftmaxCrossEntropyLoss
    , которая обсуждалась в главе 4, тоже можно записать просто:
    mean_squared_error_loss = nn.MSELoss ()
    softmax_cross_entropy_loss = nn.CrossEntropyLoss ()
    Как и слои, они наследуются от nn.Module
    , поэтому их можно вызывать так же, как слои.
    Обратите внимание: в названии класса nn.CrossEntropyLoss отсут- ствует слово softmax
    , но сама операция softmax там выполняется, так что мы можем передавать «сырой» вывод нейронной сети, не реализуя softmax вручную.
    Этот вариант
    Loss наследуется от nn.Module
    , как и
    Layer из примера выше, поэтому их можно вызывать одинаково, например с помощью loss(x)
    вместо loss.forward
    (x)
    Элементы PyTorch: Trainer
    Trainer
    (учитель) объединяет все эти элементы. Какие к нему предъявляются требования? Мы знаем, что он должен реализовать общую модель обучения нейронных сетей, которая уже неоднократно встречалась в этой книге:

    Глубокое обучение с PyTorch
    239
    1) пакет данных передается через модель;
    2) результаты и целевые значения передаются в функцию потерь, чтобы вычислить значение потерь;
    3) вычисляется градиент потерь по всем параметрам;
    4) оптимизатор обновляет параметры согласно некоторому правилу.
    В PyTorch все это работает точно так же, за исключением двух небольших моментов:
    y по умолчанию оптимизаторы сохраняют градиенты параметров (
    param_
    grads
    ) после каждой итерации обновления параметров. Чтобы очистить эти градиенты перед следующим обновлением параметра, нужно вы- зывать функцию self.optim.zero_grad
    ;
    y как было показано ранее в простом примере с автоматическим диф- ференцированием, чтобы начать обратное распространение, нужно вызвать функцию loss.backward после вычисления значения потерь.
    Таким образом мы получаем следующий код, который приводится в курсах по PyTorch и фактически будет использоваться в классе
    PyTorchTrainer
    Как и класс
    Trainer из предыдущих глав,
    PyTorchTrainer принимает на вход оптимизатор,
    PyTorchModel и потери (либо nn.MSELoss
    , либо nn.CrossEntropyLoss)
    для пакета данных
    (X_batch,
    y_batch)
    . Имея объ- екты как self.optim
    , self.model и self.loss
    , запускаем обучение модели следующим кодом:
    # Сначала обнуляем градиенты self.optim.zero_grad()
    # пропускаем X_batch через модель output = self.model(X_batch)
    # вычисляем потери loss = self.loss(output, y_batch)
    # выполняем обратное распространение на потерях loss.backward()
    # вызываем функцию self.optim.step() (как и раньше), чтобы обновить
    # параметры self.optim.step()

    240
    Глава 7. Библиотека PyTorch
    Это самые важные строки. Остальной код для PyTorch
    Trainer в основ- ном похож на код для
    Trainer
    , который мы видели в предыдущих главах:
    class PyTorchTrainer(object):
    def __init__(self, model: PyTorchModel, optim: Optimizer, criterion: _Loss):
    self.model = model self.optim = optim self.loss = criterion self._check_optim_net_aligned()
    def _check_optim_net_aligned(self):
    assert self.optim.param_groups[0]['params']\
    == list(self.model.parameters())
    def _generate_batches(self,
    X: Tensor, y: Tensor, size: int = 32) -> Tuple[Tensor]:
    N = X.shape[0]
    for ii in range(0, N, size):
    X_batch, y_batch = X[ii:ii+size], y[ii:ii+size]
    yield X_batch, y_batch def fit(self, X_train: Tensor, y_train: Tensor,
    X_test: Tensor, y_test: Tensor, epochs: int=100, eval_every: int=10, batch_size: int=32):
    for e in range(epochs):
    X_train, y_train = permute_data(X_train, y_train)
    batch_generator = self._generate_batches(X_train, y_train, batch_size)
    for ii, (X_batch, y_batch) in enumerate(batch_generator):

    Глубокое обучение с PyTorch
    241
    self.optim.zero_grad()
    output = self.model(X_batch)
    loss = self.loss(output, y_batch)
    loss.backward()
    self.optim.step()
    output = self.model(X_test)
    loss = self.loss(output, y_test)
    print(e, loss)
    Поскольку мы передаем
    Model
    ,
    Optimizer и
    Loss в
    Trainer
    , то долж- ны проверить, что параметры, на которые ссылается
    Optimizer
    , фактически совпадают с параметрами модели. Это делает функция
    _check_optim_net_aligned
    Теперь обучить модель проще простого:
    net = HousePricesModel()
    optimizer = optim.SGD(net.parameters(), lr=0.001)
    criterion = nn.MSELoss()
    trainer = PyTorchTrainer(net, optimizer, criterion)
    trainer.fit(X_train, y_train, X_test, y_test, epochs=10, eval_every=1)
    Этот код практически идентичен коду, который мы использовали для обу чения моделей в структуре, созданной в первых трех главах. Неважно, что мы используем — PyTorch, TensorFlow или Theano, — основные шаги обучения модели глубокого обучения остаются неизменными!
    Далее мы рассмотрим более продвинутые возможности PyTorch и пока- жем пару трюков для улучшения обучения, которое мы видели в главе 4.
    Хитрости для оптимизации обучения в PyTorch
    Из главы 4 мы знаем четыре таких хитрости:
    y импульс;
    y дропаут;

    242
    Глава 7. Библиотека PyTorch y
    инициализация веса;
    y снижение скорости обучения.
    В PyTorch это все легко реализовать. Например, чтобы включить в оп- тимизатор импульс, достаточно лишь добавить соответствующее слово в
    SGD
    , получая:
    optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
    Отсев данных тоже реализуется легко. В PyTorch есть встроенный мо- дуль nn.Linear
    (n_in, n_out)
    , который вычисляет операции плотного слоя. Аналогично модуль nn.Dropout
    (dropout_prob)
    реализует операцию
    Dropout
    , с той лишь разницей, что в аргумент передается вероятность ис-
    ключения (дропаута) нейрона, а не его сохранения, как это было в нашей реализации ранее.
    Об инициализации весов думать вообще не надо: в большинстве операций
    PyTorch с параметрами, включая nn.Linear
    , веса автоматически масшта- бируются в зависимости от размера слоя.
    Наконец, в
    PyTorch есть класс lr_scheduler
    , который можно использо- вать для снижения скорости обучения. Нужно выполнить импорт from torch.optim import lr_scheduler
    1
    . Теперь вы можете легко использовать эти методы в любом будущем проекте глубокого обучения, над которым вы работаете!
    Сверточные нейронные сети в PyTorch
    В главе 5 мы говорили о том, как работают сверточные нейронные сети, уделяя особое внимание операции многоканальной свертки. Мы видели, что операция преобразует пиксели входных изображений в слои нейронов, организованных в карты признаков, где каждый нейрон говорит, при- сутствует ли данный визуальный элемент (определенный в сверточном фильтре) в данном месте на изображении. Операция многоканальной свертки для двух входов и выходов имеет следующие формы:
    1
    В репозитории GitHub книги, oreil.ly/301qxRk
    , вы можете найти пример кода, кото- рый реализует экспоненциальное снижение скорости обучения как часть PyTorch
    Trainer. Документацию по используемому там классу
    ExponentialLR
    можно найти на веб-сайте PyTorch (
    oreil.ly/2Mj9IhH
    ).

    Сверточные нейронные сети в PyTorch
    243
    y форма ввода данных
    [batch_size,
    in_channels,
    image_height,
    image_
    width]
    ;
    y форма ввода параметров
    [in_channels,
    out_channels,
    filter_size,
    filter_size]
    ;
    y форма вывода
    [batch_size,
    out_channels,
    image_height,
    image_width]
    Тогда операция многоканальной свертки в PyTorch:
    nn.Conv2d (in_channels, out_channels, filter_size)
    С этим определением можно легко обернуть
    ConvLayer вокруг этой опе- рации:
    class ConvLayer(PyTorchLayer):
    def __init__(self, in_channels: int, out_channels: int, filter_size: int, activation: nn.Module = None, flatten: bool = False, dropout: float = 1.0) -> None:
    super().__init__()
    # основная операция слоя self.conv = nn.Conv2d(in_channels, out_channels, filter_size, padding=filter_size // 2)
    # те же операции "activation" и "flatten", что и ранее self.activation = activation self.flatten = flatten if dropout < 1.0:
    self.dropout = nn.Dropout(1 — dropout)
    def forward(self, x: Tensor) -> Tensor:
    # всегда выполняется операция свертки x = self.conv(x)
    # свертка выполняется опционально if self.activation:
    x = self.activation(x)

    244
    Глава 7. Библиотека PyTorch if self.flatten:
    x = x.view(x.shape[0], x.shape[1] * x.shape[2] * x.shape[3])
    if hasattr(self, "dropout"):
    x = self.dropout(x)
    return x
    В главе 5 мы автоматически добавляли выходные данные в зависи- мости от размера фильтра, чтобы размер выходного изображения соответствовал размеру входного изображения. PyTorch этого не де- лает. Чтобы добиться того же поведения, что и раньше, мы добавляем аргумент в параметр операции nn.Conv2d padding
    = filter_size
    //
    2
    Теперь осталось лишь определить
    PyTorchModel с его операциями в функ- ции
    __init__
    и последовательность операций в функции forward
    , после чего можно начать обучение. Далее следует простая архитектура, которую можно использовать в наборе данных
    MNIST
    , использующемся в главах 4 и 5. В ней есть:
    y сверточный слой, который преобразует входной сигнал из 1 «канала» в 16 каналов;
    y другой слой, который преобразует эти 16 каналов в 8 (каждый канал по-прежнему содержит 28
    × 28 нейронов);
    y два полносвязных слоя.
    Схема нескольких сверточных слоев, за которыми следует меньшее коли- чество полносвязных слоев, довольно обычна для сверточных архитектур.
    Здесь используется каждый по две штуки:
    class MNIST_ConvNet(PyTorchModel):
    def __init__(self):
    super().__init__()
    self.conv1 = ConvLayer(1, 16, 5, activation=nn.Tanh(), dropout=0.8)
    self.conv2 = ConvLayer(16, 8, 5, activation=nn.Tanh(), flatten=True, dropout=0.8)
    self.dense1 = DenseLayer(28 * 28 * 8, 32, activation=nn.Tanh(), dropout=0.8)
    self.dense2 = DenseLayer(32, 10)

    Сверточные нейронные сети в PyTorch
    245
    def forward(self, x: Tensor) -> Tensor:
    assert_dim(x, 4)
    x = self.conv1(x)
    x = self.conv2(x)
    x = self.dense1(x)
    x = self.dense2(x)
    return x
    Далее обучим эту модель так же, как обучали
    HousePricesModel
    :
    model = MNIST_ConvNet ()
    criterion = nn.CrossEntropyLoss ()
    optimizer = optim.SGD (model.parameters (), lr = 0,01, momentum = 0,9)
    trainer = PyTorchTrainer (model, optimizer, criterion)
    trainer.fit (X_train, y_train,
    X_test, y_test, epochs = 5, eval_every = 1)
    В отношении класса nn.CrossEntropyLoss есть важный момент. Напомним, что в нашей структуре из предыдущих глав класс
    Loss ожидал ввод той же формы, что и целевые данные. Для этого мы закодировали 10 различных целевых значений в данных
    MNIST
    , чтобы у каждой партии данных цель имела форму
    [batch_size,
    10]
    В классе PyTorch nn.CrossEntropyLoss
    , который работает точно так же, как и предыдущий
    SoftmaxCrossEntropyLoss
    , этого делать не нужно. Эта функция потерь ожидает два объекта
    Tensor
    :
    y
    Tensor предсказания размера
    [batch_size,
    num_classes]
    , похожий на наш класс
    Softmax
    CrossEntropyLoss y
    Целевой
    Tensor размера
    [batch_size]
    с различными значениями num_classes
    Таким образом, в предыдущем примере y_train
    — это массив размера
    [60000]
    (количество наблюдений в обучающем наборе
    MNIST)
    , а y_test имеет размер
    [10000]
    (количество наблюдений в тестовом наборе).

    1   ...   14   15   16   17   18   19   20   21   22


    написать администратору сайта