Что такое PyTorch?
PyTorch - это Python пакет для научных вычислений, предназначенный для двух целей:
- В качестве замены NumPy для использования преимуществ GPU
- В качестве платформы для разработки программ глубого обучения, которая предоставляет максимальную гибкость и скорость.

Тензоры (Tensors) в PyTorch
Тензоры схожи с ndarrays в NumPy, с добавлением того, что тензоры могут быть использованы на GPU для ускорения вычислений. Импортируем torch и рассмотрим несколько примеров:
from future import print_function
import torch
Контруируем 5x3 матрицу, не инициализированную:
x = torch.empty(5, 3)
print(x)
Вывод:
tensor([[1.3440e-19, 4.5673e-41, 8.3430e-18],
[4.5673e-41, 2.5431e+30, 5.5073e+11],
[5.2563e+05, 5.5123e+11, 1.6669e+35],
[2.1541e+09, 3.7906e+22, 4.1644e+34],
[7.3002e-12, 3.9694e+28, 9.4759e+21]])
print(x)
Конструируем матрицу, инициализированную случайными значениями:
x = torch.rand(5, 3)
print(x)
Вывод:
tensor([[0.4163, 0.1625, 0.9454],
[0.8632, 0.3480, 0.1602],
[0.3037, 0.3912, 0.3449],
[0.3911, 0.5578, 0.7367],
[0.6628, 0.3991, 0.3471]])
print(x)
Создадим матрицу, наполненную нулями и dtype long:
x = torch.zeros(5, 3, dtype=torch.long)
print(x)
Вывод:
tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
Создадим тензор напрямую из данных:
x = torch.tensor([5.5, 3])
print(x)
Вывод:
tensor([5.5000, 3.0000])
Или создадим тензор, основанный на существующем тензоре. Этот метод будет повторно использовать свойства вводного тензора, например dtype, если новые значения не переданы пользователем
# new_* методы принимают размеры
x = x.new_ones(5, 3, dtype=torch.double)
print(x)
# переопределяем dtype!
x = torch.randn_like(x, dtype=torch.float)
# результат имеет тот же размер
print(x)
Вывод:
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=torch.float64)
tensor([[-0.6714, 0.7803, -1.0026],
[-1.1583, 1.7177, 2.7201],
[-0.1254, -0.4324, -0.6761],
[-2.1195, -0.7945, 0.6865],
[ 0.1464, -0.3747, -0.8441]])
Возьмем его размер:
print(x.size())
Вывод:
torch.Size([5, 3])
Примечание
torch.Size по факту является tuple, поэтому он поддерживает все tuple операции.
Операции с тензорами
Существует несколько вариантов синтаксиса для операций. В следующем примере мы рассмотрим операцию сложения.
Сложение: синтаксис 1
y = torch.rand(5, 3)
print(x + y)
Вывод:
tensor([[ 0.0732, 0.9384, -0.2489],
[-0.6905, 2.1267, 3.0045],
[ 0.6199, 0.4936, -0.0398],
[-2.0623, -0.5140, 1.6162],
[ 0.3189, -0.0327, -0.5353]])
Сложение: синтаксис 2
print(torch.add(x, y))
Вывод:
tensor([[ 0.0732, 0.9384, -0.2489],
[-0.6905, 2.1267, 3.0045],
[ 0.6199, 0.4936, -0.0398],
[-2.0623, -0.5140, 1.6162],
[ 0.3189, -0.0327, -0.5353]])
Сложение: предоставление тензора вывода как аргумента
result = torch.empty(5, 3)
torch.add(x, y, out=result)
print(result)
Вывод:
tensor([[ 0.0732, 0.9384, -0.2489],
[-0.6905, 2.1267, 3.0045],
[ 0.6199, 0.4936, -0.0398],
[-2.0623, -0.5140, 1.6162],
[ 0.3189, -0.0327, -0.5353]])
Сложение: на месте (in-place)
# добавляем x к y
y.add_(x)
print(y)
Вывод:
tensor([[ 0.0732, 0.9384, -0.2489],
[-0.6905, 2.1267, 3.0045],
[ 0.6199, 0.4936, -0.0398],
[-2.0623, -0.5140, 1.6162],
[ 0.3189, -0.0327, -0.5353]])
Примечание
Любая операция, которая изменяет тензор на месте имеет постфикс _. Например: x.copy_(y), x.t_(), будут изменять x.
Вы можете использовать стандартное (как в NumPy) индексирование:
print(x[:, 1])
Вывод:
tensor([ 0.7803, 1.7177, -0.4324, -0.7945, -0.3747])
Изменение размера: если вы хотите изменить размер/форму тензора, вы можете использовать torch.view:
x = torch.randn(4, 4)
y = x.view(16)
# размер -1 выведен из других измерений
z = x.view(-1, 8)
print(x.size(), y.size(), z.size())
Вывод:
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
Если у вас есть одноэлементный тензор, используйте .item() для получения значения как Python числа
x = torch.randn(1)
print(x)
print(x.item())
Вывод:
tensor([0.1550])
0.15495021641254425
NumPy мост
Преобразование Torch тензора в NumPy массив и обратно выполняется легко.
Torch тензор и NumPy массив будут иметь общие подлежащие занятые области памяти, и изменение одного из них будет изменять другой.
Преобразование Torch тензора в NumPy массив
a = torch.ones(5)
print(a)
Вывод:
tensor([1., 1., 1., 1., 1.])
b = a.numpy()
print(b)
Вывод:
[1. 1. 1. 1. 1.]
Посмотрим как изменится значение в numpy массиве.
a.add_(1)
print(a)
print(b)
Вывод:
tensor([2., 2., 2., 2., 2.])
[2. 2. 2. 2. 2.]
Преобразование NumPy массива в Torch тензор
Рассмотрим как изменяется NumPy массив, преобразованный в Torch тензор автоматически
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
Вывод:
[2. 2. 2. 2. 2.]
tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
Все тензоры на CPU, исключая CharTensor, поддерживают преобразование в NumPy и обратно.
CUDA тензоры
Тензоры могут быть перемещены на любое устройство, используя .to метод.
# выполняем этот скрипт, только если CUDA доступно
# Мы будем использовать ``torch.device`` объекты
# чтобы перемещать тензор на GPU и обратно
if torch.cuda.is_available():
# объект CUDA устройства
device = torch.device("cuda")
# напрямую создаем тензор на GPU
y = torch.ones_like(x, device=device)
# или просто используем строки ``.to("cuda")``
x = x.to(device)
z = x + y
print(z)
# ``.to`` может также одновременно изменять dtype!
print(z.to("cpu", torch.double))
Вывод:
tensor([1.1550], device='cuda:0')
tensor([1.1550], dtype=torch.float64)
Читайте также другие статьи в блоге:
TensorFlow: базовая классификация