Что такое PyTorch ?

Глубокое обучение - это раздел Машинного обучения, где разрабатываются алгоритмы, имитирующие работу человеческого мозга. Наиболее часто используемые библиотеки в глубоком обучении - это Tensorflow и PyTorch. Pytorch - это открытая платформа глубокого обучения, доступная с интерфейсами Python и C++. PyTorch находится внутри модуля torch. В PyTorch данные для обработки подаются в виде тензора.

Оглавление

Как установить Pytorch?

Если у вас установлен менеджер пакетов Python Anaconda, тогда, используя следующую команду в терминале, вы можете установить PyTorch:

conda install pytorch torchvision cpuonly -c pytorch

Эта команда установит последнюю стабильную версию PyTorch. Стабильная версия представляет собой наиболее полно протестированную и поддерживаемую версию PyTorch. Последняя стабильная версия Pytorch - 1.12.1. Если вы хотите использовать PyTorch, не устанавливая его явно на вашем локальном компьютере, вы можете использовать Google Colab.

Как работает PyTorch?

Вот обзор того, как работает PyTorch:

Тензоры: В основе PyTorch лежит класс torch.Tensor, который представляет собой многомерный массив, похожий на массивы NumPy.

import torch  # Импорт библиотеки PyTorch

x = torch.tensor([1, 2, 3])  # Создание тензора из списка

Динамические Вычислительные Графы: В PyTorch граф строится по мере выполнения операций, что позволяет динамически изменять его во время выполнения. Это контрастирует со статическими вычислительными графами, используемыми некоторыми другими фреймворками глубокого обучения.

# Динамическое вычисление
y = x + 2  # Вычисление y как результат сложения x и 2
z = y * 3  # Вычисление z как результат умножения y на 3

Автоград (Autograd): Он автоматически вычисляет градиенты тензоров по отношению к какому-либо скалярному значению. Это имеет решающее значение для обучения нейронных сетей с использованием алгоритмов оптимизации на основе градиента.

# Вычисление градиентов
z.backward()

# Доступ к градиентам
print(x.grad)

Нейронно Сетевой Модуль (Neural Network Module): PyTorch предлагает модуль torch.nn, который включает в себя предопределенные слои, функции потерь и другие компоненты для построения нейронных сетей. Пользователи также могут определять собственные архитектуры нейронных сетей, создавая подклассы класса torch.nn.Module

import torch.nn as nn  # Импорт модуля для создания нейронных сетей

# Определение простой нейронной сети
class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        self.fc = nn.Linear(10, 5)  # Определение полносвязного слоя с входным размером 10 и выходным размером 5

    def forward(self, x):
        return self.fc(x)  # Прямой проход: применение полносвязного слоя к входным данным

Тензоры PyTorch

Pytorch используется для обработки тензоров. Тензоры являются многомерными массивами, подобными n-мерному массиву NumPy. Однако, в отличие от массивов NumPy, тензоры также могут использоваться в GPU, что ускоряет научные вычисления с тензорами, поскольку в PyTorch есть различные встроенные функции.

Вектор является одномерным тензором, а матрица - двумерным тензором. Одно из существенных отличий между тензором и многомерным массивом, используемым в C, C++ и Java, заключается в том, что в тензорах все размеры столбцов должны быть одинаковыми во всех измерениях. Также тензоры могут содержать только числовые типы данных.

Два фундаментальных атрибута тензора это:

  • Форма: относится к размерности массива или матрицы

  • Ранг: обозначает количество измерений тензора

Пример 1:

# Импорт библиотеки PyTorch
import torch

# Создание тензоров
t1 = torch.tensor([1, 2, 3, 4])  # Одномерный тензор
t2 = torch.tensor([[1, 2, 3, 4],
                   [5, 6, 7, 8],
                   [9, 10, 11, 12]])  # Двумерный тензор

# Вывод тензоров
print("Tensor t1: \n", t1)
print("\nTensor t2: \n", t2)

# Ранг тензоров
print("\nRank of t1: ", len(t1.shape))  # Ранг одномерного тензора
print("Rank of t2: ", len(t2.shape))    # Ранг двумерного тензора

# Форма тензоров
print("\nShape of t1: ", t1.shape)  # Форма одномерного тензора
print("Shape of t2: ", t2.shape)    # Форма двумерного тензора

Создание тензора в PyTorch

В PyTorch существует несколько способов создания тензоров. Тензор может содержать элементы только одного типа данных. Создать тензор можно, используя список Python или массив NumPy. В Torch есть 10 вариантов тензоров как для GPU, так и для CPU. Ниже приведены различные способы определения тензора.

  • torch.Tensor() : Копирует данные и создает тензор. Является псевдонимом для torch.FloatTensor.

  • torch.tensor() : Также копирует данные для создания тензора, однако определяет тип данных автоматически.

  • torch.as_tensor() : В этом случае данные не копируются, а используются общие, при создании тензора, и метод принимает массив любого типа для создания тензора.

  • torch.from_numpy() : Это аналог tensor.as_tensor(), однако принимает только массивы numpy.

Пример 2:

# Импорт модуля torch
import torch
import numpy as np  # Импорт модуля numpy

# Список значений для создания тензоров
data1 = [1, 2, 3, 4, 5, 6]  # Список целых чисел
data2 = np.array([1.5, 3.4, 6.8, 9.3, 7.0, 2.8])  # Массив numpy с плавающей точкой

# Создание тензоров и вывод
t1 = torch.tensor(data1)  # Создание тензора из списка с использованием функции torch.tensor
t2 = torch.Tensor(data1)  # Создание тензора из списка с использованием конструктора torch.Tensor
t3 = torch.as_tensor(data2)  # Создание тензора из массива numpy с использованием функции torch.as_tensor
t4 = torch.from_numpy(data2)  # Создание тензора из массива numpy с использованием функции torch.from_numpy

# Вывод тензоров и их типов данных
print("Tensor: ", t1, "Data type: ", t1.dtype, "\n")  # Вывод и тип данных тензора t1
print("Tensor: ", t2, "Data type: ", t2.dtype, "\n")  # Вывод и тип данных тензора t2
print("Tensor: ", t3, "Data type: ", t3.dtype, "\n")  # Вывод и тип данных тензора t3
print("Tensor: ", t4, "Data type: ", t4.dtype, "\n")  # Вывод и тип данных тензора t4

Реструктуризация тензоров в Pytorch

Мы можем изменять форму и размер тензора по желанию в PyTorch. Также мы можем создать транспонирование n-мерного тензора. Ниже приведены три распространенных способа изменения структуры вашего тензора по желанию:

.reshape(a, b) : возвращает новый тензор размера a,b

.resize(a, b) : возвращает тот же тензор размера a,b

.transpose(a, b) : возвращает транспонированный тензор по измерениям a и b

Матрица 2*3 была преобразована и транспонирована в 3*2. Мы можем визуализировать изменение расположения элементов в тензоре в обоих случаях.

Пример 3:

# Импорт модуля torch
import torch

# Определение тензора
t = torch.tensor([[1, 2, 3, 4],
                  [5, 6, 7, 8],
                  [9, 10, 11, 12]])

# Изменение формы тензора
print("Изменение формы")
print(t.reshape(6, 2))  # Изменение формы на 6x2

# Изменение размера тензора
print("\nИзменение размера")
print(t.resize(2, 6))  # Изменение размера на 2x6

# Транспонирование тензора
print("\nТранспонирование")
print(t.transpose(1, 0))  # Транспонирование (перестановка осей)

Математические операции с тензорами в PyTorch

Мы можем выполнять различные математические операции с тензорами, используя Pytorch. Код для выполнения математических операций такой же, как и в случае с массивами NumPy. Ниже приведен код для выполнения четырех основных операций с тензорами.

Пример 4:

Python3

# Импорт модуля torch
import torch

# Определение двух тензоров
t1 = torch.tensor([1, 2, 3, 4])
t2 = torch.tensor([5, 6, 7, 8])

# Сложение двух тензоров
print("tensor2 + tensor1")
print(torch.add(t2, t1))

# Вычитание двух тензоров
print("\ntensor2 - tensor1")
print(torch.sub(t2, t1))

# Умножение двух тензоров
print("\ntensor2 * tensor1")
print(torch.mul(t2, t1))

# Деление двух тензоров
print("\ntensor2 / tensor1")
print(torch.div(t2, t1))

Для того чтобы более глубоко понять умножение матриц с использованием Pytorch, вы можете обратиться к этой статье –

Python – Matrix multiplication using Pytorch

Модули Pytorch

Библиотека PyTorch и её модули необходимы для создания и обучения нейронных сетей. Три основных модуля библиотеки – это Autograd, Optim и nn.

1. Модуль Autograd: Autograd предоставляет функциональность легкого расчета градиентов без необходимости вручную реализовывать прямой и обратный проход для всех слоев.

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

Пример 5:

# Импорт модуля torch
import torch

# Создание тензоров и указание на необходимость вычисления градиентов
t1 = torch.tensor(1.0, requires_grad=True)
t2 = torch.tensor(2.0, requires_grad=True)

# Вычисление функции z = 100 * t1 * t2
z = 100 * t1 * t2

# Вычисление градиентов
z.backward()

# Вывод значений градиентов
print("dz/dt1 : ", t1.grad.data)  # Градиент по t1
print("dz/dt2 : ", t2.grad.data)  # Градиент по t2

2. Модуль Optim: Модуль PyTorch Optim, который помогает в реализации различных алгоритмов оптимизации. Этот пакет содержит наиболее часто используемые алгоритмы, такие как Adam, SGD и RMS-Prop. Для использования torch.optim сначала нужно создать объект Optimizer, который будет хранить параметры и обновлять их соответственно. Сначала мы определяем Optimizer, указав алгоритм оптимизации, который хотим использовать. Мы устанавливаем градиенты в ноль перед обратным распространением. Затем для обновления параметров вызывается optimizer.step().

optimizer = torch.optim.Adam(model.parameters(), lr=0.01) # определение оптимизатора

optimizer.zero_grad() # обнуление градиентов

optimizer.step() # обновление параметров

3. Модуль nn: Этот пакет помогает в построении нейронных сетей. Он используется для создания слоев.

Для создания модели с одним слоем мы можем просто определить её, используя nn.Sequential().

model = nn.Sequential( nn.Linear(in, out), nn.Sigmoid(), nn.Linear(_in, _out), nn.Sigmoid() )

Для реализации модели, которая не представляет собой единую последовательность, мы определяем модель путем наследования класса nn.Module.

Пример 6:

import torch.nn as nn  # Импорт модуля для создания нейронных сетей

class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.linear = torch.nn.Linear(1, 1)  # Определение линейного слоя с одним входом и одним выходом

    def forward(self, x):
        y_pred = self.linear(x)  # Прямой проход: применение линейного слоя к входным данным
        return y_pred

Набор данных PyTorch и загрузчик данных

Класс torch.utils.data.Dataset содержит все пользовательские наборы данных. Для создания собственного класса набора данных нам необходимо реализовать два метода: __len__() и __get_item__(). Загрузчик данных PyTorch обладает удивительной функцией параллельной загрузки набора данных с автоматической пакетной обработкой. Это значительно сокращает время, необходимое для последовательной загрузки набора данных, тем самым увеличивая скорость.

Syntax: DataLoader(dataset, shuffle=True, sampler=None, batch_sampler=None, batch_size=32)

PyTorch DataLoader поддерживает два типа наборов данных:

  • Map-style datasets (Наборы данных в стиле карты): Элементы данных сопоставляются с индексами. В этих наборах данных метод __get_item__() используется для получения индекса каждого элемента.

  • Iterable-style datasets (Наборы данных в стиле итерируемых объектов): В этих наборах данных реализован протокол __iter__(). Образцы данных извлекаются последовательно.

Пожалуйста, ознакомьтесь со статьей о использовании DataLoader в PyTorch, чтобы узнать больше.

Создание нейронной сети с помощью PyTorch

Мы увидим это в поэтапной реализации:

  1. Подготовка набора данных: Поскольку в PyTorch все представлено в форме тензоров, прежде всего мы должны представить данные в виде тензоров.

  2. Построение модели: Для создания нейронной сети сначала мы определяем количество входных, скрытых и выходных слоев. Также необходимо определить начальные веса. Значения матриц весов выбираются случайным образом с использованием torch.randn(). Torch.randn() возвращает тензор, состоящий из случайных чисел, следуя стандартному нормальному распределению.

  3. Прямое распространение: Данные подаются на нейронную сеть, и выполняется матричное умножение между весами и входом. Это можно легко сделать с помощью torch.

  4. Вычисление потерь: Функции PyTorch.nn включают в себя множество функций потерь. Функции потерь используются для измерения ошибки между предсказанным и целевым значениями.

  5. Обратное распространение: Используется для оптимизации весов. Веса изменяются таким образом, чтобы минимизировать потери.

Давайте создадим нейронную сеть с нуля:

Пример 7:

# Импорт модуля torch
import torch

# Определение входных (X) и выходных (y) данных для обучения
X = torch.Tensor([[1], [2], [3], [4], [5], [6]])
y = torch.Tensor([[5], [10], [15], [20], [25], [30]])

# Определение модели
class Model(torch.nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.linear = torch.nn.Linear(1, 1)  # Определение однослойной линейной нейронной сети

    def forward(self, x):
        y_pred = self.linear(x)  # Прямой проход: применение линейного слоя к входным данным
        return y_pred

model = Model()  # Создание экземпляра модели

# Определение функции потерь и оптимизатора
loss_fn = torch.nn.L1Loss()  # Функция потерь L1
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)  # Оптимизатор Adam с learning rate 0.01

# Цикл обучения модели
for epoch in range(1000):
    y_pred = model(X)  # Получение прогнозов модели

    loss = loss_fn(y_pred, y)  # Вычисление потерь

    loss.backward()  # Обратное распространение ошибки

    optimizer.step()  # Обновление параметров модели

    optimizer.zero_grad()  # Обнуление градиентов

# Тестирование на новых данных
X_test = torch.Tensor([[7], [8]])  # Новые данные для тестирования
predicted = model(X_test)  # Получение прогнозов
print(predicted)  # Вывод прогнозов

Last updated