Все, что вам нужно знать для вашего первого проекта в PyTorch!

Для экстремальных новичков - от новичков!

Предварительные требования:

Добро пожаловать, изучающие глубокое обучение! Эта статья станет началом вашего первого в истории проекта глубокого обучения на pytorch.

Чтобы получить право читать эту историю, убедитесь, что любой из этих пунктов лучше всего описывает вас:

  1. Вы должны быть тем, у кого есть «DL Enthusiast» в вашем профиле LinkedIn, но вы строите модели только с помощью keras! Поздравляю! эта статья полностью посвящена вам!
  2. Вам, должно быть, было трудно понять сеансы, переменные, классы и т. Д. В тензорном потоке и вы планировали перейти на pytorch. Ага! Вы находитесь в нужном месте!
  3. Вы тот, кто построил достаточно сложные модели в pytorch и ищет некоторые подробные вещи. Пока-пока! вы можете перейти к последнему разделу!

Фактический старт!

Если вы это читаете, поздравляем! вы полностью готовы к дальнейшим действиям!

Первый вопрос:

Что такое pytorch и чем он отличается от keras?

Как новичок, довольно легко построить нейронную сеть, добавив плотные слои и некоторые выпадения с помощью этих двух команд:

from keras.models import Sequential 
from keras.layers import Dense, Dropout

Это так же просто, как сказать….

import Andrew as ng !

Если вам нужно иметь дело с тензорами, строить достаточно сложные модели, создавать какие-то собственные функции потерь или понимать, что именно происходит внутри каждого отдельного слоя, pytorch спасает вас! Это идеальный инструмент для n-мерных данных! Он имеет упрощенный край keras-i в сочетании с множеством полезной документации.

Это удобно для новичков!

Pytorch известен своими возможностями отладки, отличной поддержкой сообщества и низкоуровневой абстракцией. Более быстрые реализации лучше выполнять с помощью pytorch, поскольку он не требует тяжелого вычислительного мусора, как в keras.

Погрузитесь в мир!

Шаг 1: Настройка оборудования. Модели глубокого обучения всегда сопровождаются большим количеством данных. Очевидно, нужен графический процессор. для настройки cuda и nvidia: обратитесь к этой замечательной статье.

Шаг 2: Установка: Pytorch устанавливается в течение нескольких секунд с помощью одной строки ctrl + C - ctrl + V со своего официального сайта. Перейдите на их веб-сайт, прокрутите вниз, выберите параметры настройки, скопируйте ссылку и вставьте ее в свой терминал! Выполнено! готов к использованию! Также установите tensorboardX для визуализации результатов. Обратитесь к этому репозиторию github для инструкций по установке.

Шаг 3: Основы: есть отличные курсы по udemy, в которых обсуждаются базовый синтаксис, использование и функции. Поверьте мне! pytorch не требует особых усилий! Он очень похож на Numpy и имеет множество предопределенных функций. Вы можете открывать для себя что-то, как только начнете кодировать.

Самое интересное!

Шаг 3: Импорт необходимого:

import torch
import torch.nn as nn
from torch.utils import data
import torch.nn.functional as F
from torch.autograd import Variable as V
import torch.optim as optim
from tqdm import tqdm
from tensorboardX import SummaryWriter 

Это библиотеки, необходимые для любой модели глубокого обучения. В модуле nn есть все необходимые функции потерь, слои, последовательные модели, функции активации и т. д. nn.functional - это особый сегмент, используемый для функций активации. Остальные обсуждаются по мере того, как вы продвигаетесь дальше.

Второй вопрос:

В чем разница между TorchTensor и переменной?

Вы, должно быть, заметили, что мы импортировали библиотеку переменных из torch.autograd. Тензоры - это просто nd-массивы. Для таких функций, как обратное распространение, тензоры должны быть связаны с соответствующим им градиентом. То же самое и с переменной torch. Это тензор с соответствующим градиентом, что значительно упрощает все тензорные операции! Взгляните на это вопросы и ответы, чтобы узнать подробности.

Имея все это основание, давайте приступим к построению нашей модели!

Первый этап: класс сети:

шаг 1: Наследование:. Чтобы построить архитектуру нейронной сети, необходимо создать класс, унаследованный от nn.Module. nn.Module дает структуру для создания нашей сети.

class Network(nn.Module):
      def __init__(self):
          super(Network, self).__init__()

шаг 2: Слои: различные типы слоев, такие как линейный, LSTM, выпадающий и т. д., непосредственно присутствуют в модуле nn. Если вы привыкли к настройке последовательной модели keras, то nn.sequential точно такой же. Лично я предлагаю не использовать последовательный, поскольку он не раскрывает истинную цель использования pytorch. Лучший способ добавить слои к вашей модели:

  1. Создайте один слой с nn и назначьте его частному члену вашего сетевого класса.

Выглядит это примерно так:

self.linear = nn.linear(input dim, output dim)

Объявите все ваши слои как переменные класса в init вашего сетевого класса.

Шаг 3. Функция пересылки. Это сердце и душа вашей сети. Каждый раз, когда вы вызываете свою архитектуру для обучения или прогнозирования, выполняются шаги, которые вы записываете в функции пересылки. Здесь мы перезаписываем функцию пересылки из класса nn.Module, который точно сообщает модели, что делать. Если вы укажете какие-либо параметры для своей функции forward, кроме self, они должны передаваться каждый раз при вызове модели.

Например ,

def forward(self,x): 
     out =  self.linear1(x)
     out = self.linear2(out)
return out

Здесь вы можете заметить, что связь между двумя слоями устанавливается путем передачи выходных данных в виде тензоров факела или переменных.

Шаг 4: Дополнительные функции:. Все действия, описанные выше, готовы! Иногда, когда ваша модель имеет слои LSTM, требуется функция инициализации скрытых слоев. Аналогичным образом, если вы пытаетесь построить сеть машин Больцмана, требуется выборка скрытых и видимых узлов. поэтому можно создавать и использовать новые функции-члены нашего сетевого класса.

Шаг 5. Параметры вашего класса. При построении сети с классом убедитесь, что вы используете минимальные значения или их отсутствие. Скорость обучения, размеры скрытых слоев и т. Д. Могут быть переданы при создании экземпляра вашего класса.

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

Поздравляю! 100/100 на вашем первом этапе !!

Поскольку этот этап был достаточно длинным, давайте посмотрим на небольшой, но важный!

Вторая веха: пользовательский загрузчик данных:

Вы когда-нибудь делали тестовое разделение поездов, разделение поездов val, разделение размеров пакетов, перемешивание и т. Д. Для ваших данных с нуля? У Keras есть параметр «размер партии», который заботится о нестандартных размерах партий. Но, если вам нужно сделать это в pytorch, это потребует довольно много усилий.

Не волнуйся! пользовательский DataLoader уже здесь!

DataLoader - это термин, используемый для создания данных для обучения, тестирования и проверки данных из ваших данных с такими функциями, как размер пакета, перемешивание и количество рабочих.

pytorch имеет класс загрузчика данных по умолчанию, который можно импортировать с помощью torch.utils.data.dataloader. Вы можете напрямую подготовить свою модель данных!

Вместо использования загрузчика данных по умолчанию довольно легко создать собственный загрузчик данных в соответствии с вашими требованиями. Посмотрим, как это сделать!

Вы помните, как импортировали данные из torch.utils? Надеюсь, да!

Создать собственный загрузчик данных так же просто, как выполнить следующие шаги:

Шаг 1. Наследование:. Подобно тому, как мы унаследовали nn.Module для нашего сетевого класса, мы наследуем класс data.Dataset для нашего DataLoader. Вам не нужно вызывать конструктор инициализации, как это было раньше.

Что-то вроде этого :

class dataset(data.Dataset):

Шаг 2. Последовательности и метки: класс data.Dataset имеет члены, называемые последовательностями, которые относятся к данным X или обучающим данным, а метки относятся к y. Вы можете создать параметр, называемый разделом, который будет возвращать соответствующие данные.

Например,

class dataset(data.Dataset):
     def __init__(self, partition):
         if partition==’train’:
            self.sequences = X_train
            self.labels = y_train

Вы можете убедиться, что ваши данные относятся к типу torch.tensor, преобразовав их изначально.

 self.sequences = torch.tensor(self.sequences)

Шаг 3: метод len: __len __ () - это метод класса data.Dataset, который необходимо перезаписать, чтобы наш загрузчик данных работал. Просто верните длину сгенерированных последовательностей этим методом.

Шаг 4: метод getitem: __getitem__ (self, index) - это метод, который возвращает последовательности и метки по заданному индексу. Это должно быть перезаписано, чтобы сделать загрузчик данных полностью функциональным.

Шаг 5: генераторы и параметр dict:. С помощью описанных выше шагов создание пользовательского класса загрузчика данных завершено. Пришло время использовать это!

Данные, которые отправляются загрузчиком данных, используются в виде генераторов. Итак, необходимо создать параметр dict, на основе которого будут генерироваться данные. этот dict содержит ключи: batch_size, shuffle, num_workers. объект для класса загрузчика данных будет создан и передан генератору вместе с параметром dict:

params= {
‘batch_size’ : 10, 
‘shuffle’ : True,
‘num_workers’ : 20}
training_set = dataset(X, y, ‘train')
training_generator = torch.utils.data.dataloader(training_set, **params)

Дополнительные параметры смотрите в официальной документации здесь.

Получил ваши данные довольно легко ?! Если да,

🎊Престиж !! Еще 100/100 на втором этапе! 👏

Теперь, когда у нас есть и архитектура, и данные, наша модель готова к работе! Итак, перейдем к нашему третьему этапу!

Третья веха: функция поезда:

Теперь у вас есть 2 класса: один для архитектуры, а другой для данных. Наша функция поезда - это то, что объединяет и то, и другое, и позволяет нашей модели учиться.

Шаг 1. Параметры:. Первый и самый важный параметр нашей функции train - это объект нашего класса Network. Далее идут обучающий генератор и генератор проверки из загрузчика данных. После этих обязательных параметров можно передать количество эпох, скорость обучения, размер пакета, клип, потерю и т. Д. Как уже упоминалось, не жестко кодируйте значения. Вместо этого передайте их как параметры.

Шаг 2: Инициализация. Считаем «сеть» объектом нашего сетевого класса. Чтобы начать обучение, его необходимо установить в режим обучения. Делается это командой:

net.train()

Функции потерь и оптимизаторы должны быть назначены с помощью модуля nn.

Например :

criterion = nn.MSELoss() 
optimizer = torch.optim.Adam(net.parameters(), lr=lr)

Теперь, когда мы инициализировали значения, модель готова к обучению.

шаг 3: цикл эпох: запускает цикл, который повторяется n раз, где n означает количество эпох. В конце цикла выведите потери (как для обучения, так и для проверки), соответствующие этой эпохе.

Шаг 4: цикл tqdm: Циклы могут работать бесконечно! Специально для моделей глубокого обучения с большим количеством данных! Разобраться, что происходит внутри и сколько времени потребуется, чтобы закончить, довольно сложно. tqdm уже здесь! Это индикатор выполнения для каждой итерации. Посмотрите его официальную документацию здесь. Итератор должен быть назначен tqdm и использоваться в цикле.

Для каждой эпохи наша функция выполняет итерацию по размеру пакета. Итак, наш итератор - это обучающий генератор.

Циклы tqdm выглядят примерно так:

t = tqdm(iter(training_generator), leave=False, total=len(training_generator))
for i, batch in enumerate(t): 
 x_batch, y_batch = next(iter(training_generator))

Шаг 5: доступность графического процессора. Переменные, объекты и т. д. могут быть перенесены в графический процессор с помощью одной единственной команды pytorch.

Включите одну строку:

torch.cuda.set_ device(0)

в начале вашего кода. 0 - это номер используемого графического процессора.

Когда вы чувствуете необходимость передать некоторую переменную в cuda,

сделать: X = X.cuda ()

Однако наш код должен работать независимо от базового оборудования. Если графического процессора не существует, вы не можете передавать переменные в cuda. Код показывает ошибку в этой строке. Чтобы избавиться от этих зависимостей, рассмотрим переменную, которая содержит логическое значение доступности графического процессора.

Ваш код можно просто изменить как:

if gpu_available:
    X= X.cuda()

Шаг 6. Процедура обучения:. После настройки начинается обучение с использованием объекта класса архитектуры как:

output = net(x) 

Здесь передаются параметры, указанные в функции forward.

После получения результатов потери рассчитываются как:

loss = criterion(output, targets)

Обратное распространение осуществляется с помощью:

loss.backward()
optimizer.step()

Optimizer.step () используется для обновления параметров (весов и смещений) на основе потерь, которые распространяются обратно.

Вы можете распечатать прогресс потери с помощью итератора tqdm как:

t.set_postfix(loss=train_loss)

Шаг 7. Оценка. После обучения можно выполнить оценку, для которой модель должна быть переведена в режим оценки:

net.eval()

В конце оценки убедитесь, что вы вернули режим обучения с помощью net.train ().

шаг 8: сохранение модели и state_dict:. После успешного завершения обучения модели необходимо сохранить ее для использования в будущем. Есть 2 основных способа сохранения обученной модели в pytorch.

  1. torch.save (): этот метод сохраняет всю модель вместе со структурой каталогов. Его можно использовать с двумя строками кода:
torch.save(net, path)       #saving
net = torch.load(path)      #loading

2. model.state_dict (): функция state_dict сохраняет только параметры вашей модели (веса, смещения и т. Д.) Вместо сохранения всей модели. Для использования сохраненной модели необходимо создать объект класса архитектуры и назначить соответствующие параметры.

torch.save(net.state_dict(), path)       #saving
net = Network(*args, **kwargs)           #loading
net.load_state_dict(torch.load(path))

Третий вопрос:

Когда использовать torch.save (), а когда - model.state_dict ()?

Как упоминалось выше, torch.save сохраняет всю модель. Чтобы загрузить его, вам не нужно создавать экземпляр класса Network. В случаях, когда ваша модель должна работать на совершенно другой платформе независимо от базового кода, torch.save () очень подходит.

Напротив, если вы проводите эксперименты, state_dict () очень удобен, поскольку он просто сохраняет параметры вашей модели и является гибким для любых дальнейших модификаций. это относительно дружественно к памяти.

Посмотрите эти ответы stackoverflow для более подробной информации.

Поздравляю! если вы здесь, вы почти построили свою модель до совершенства! Чтобы упорядочить свой код и провести эксперименты, давайте взглянем на одну последнюю веху. Кстати,

A 100/100 и для этой вехи !! 🎊

Заключительный этап: организация

Поскольку многочисленные эксперименты, настройки параметров часто выполняются на модели глубокого обучения, очень важно хранить их в правильной структуре каталогов. Вот несколько шагов, которые необходимо выполнить:

Шаг 1. Файл конфигурации: такие параметры, как скорость обучения, функция потерь, количество эпох, всегда меняются. Чтобы отслеживать все эти параметры, создайте файл конфигурации и упомяните все те параметры, с которыми можно поиграть. Вместо того, чтобы упоминать значения при создании экземпляра класса или вызове функции, вы можете импортировать эти переменные как:

from config import * 

и пользуйся. Когда вам нужно использовать различные методы проб и ошибок, достаточно изменить файл конфигурации.

Шаг 2. Tensorboard: Помните, как импортировать SummaryWriter из tensorboardX? Как упоминалось ранее, визуализацию потерь, точности и т. Д. Можно выполнить с помощью тензорной доски.

Чтобы включить тензорную доску, просто добавьте одну строку перед функцией поезда:

 writer = SummaryWriter(path)

В цикл, который продолжается для каждой эпохи, включают:

writer.add_scalar(‘loss’, loss, epoch_number)
writer.add_scalar('accuracy', accuracy, epoch_number)

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

В конце обучения близкий писатель с:

writer.close()

Не забудьте изменить путь последующих записей тензорной доски, поскольку графики могут быть перезаписаны или перекрыты.

Шаг 3: файл требований: Может быть слишком банальным, чтобы упоминать его, но рекомендуется иметь файл требований, содержащий все библиотеки с их используемыми версиями. Одна команда справится со всеми вашими зависимостями.

Посмотрите эту ссылку, чтобы узнать, как заморозить все свои требования.

Шаг 4: ознакомительные сведения: После всей тяжелой работы ваше право хвастаться своей работой и направлять людей по использованию вашего кода! Ридми делает то же самое. Завершите свой проект, добавив качественный и количественный ридми!

Готово !!

Наконец-то !!! Поздравляем с успешным прохождением всех четырех этапов! Вы получите еще 100/100 за последний этап и в целом:

🎊 Награда «Лучший новичок в pytorch» !! 🎉

Дополнительно: проведение нескольких экспериментов - трюк с JSON!

Для крупномасштабных экспериментов требуется много человеческого вмешательства для изменения файла конфигурации каждый раз, когда вы запускаете эксперимент. Чтобы минимизировать это, один набор параметров конфигурации может быть преобразован в один объект json.

Учитывая, что ваш файл конфигурации выглядит так:

lr = 0.01

эпох = 100

……

Код ниже преобразует весь текст в объект json.

import json
data = dict(zip(parameter, value))   #create a dictionary
json.dumps(data)    #json object

Можно создать несколько объектов JSON, каждый из которых представляет отдельный эксперимент. Они сформируют массив объектов JSON, по которым можно рекурсивно перемещаться, передав в main только один раз!

Лучшее заключение!

Давайте быстро посмотрим на полную схему структуры нашего проекта:

Надеюсь, структура вашего проекта выглядит так же! Не стесняйтесь комментировать любые сомнения!

Конец статьи! Сделайте перерыв, создайте сеть! 😬

P.S: Я благодарю А.Маноджа Гухана и Нияти Чхая за то, что они наставляли меня на всем пути, исправляли мои глупые ошибки и придали мне уверенности в теме!