Несреднюю статью можно найти на blog.datasloth.io.

Во-первых, это не учебник по машинному обучению,
это учебник по pytorch, поэтому вы можете манипулировать его
структурами данных и в полной мере использовать возможности JIT
скомпилированного графического процессора pytorch в любой ваш числовой код!

Недавно я начал писать книгу
[Создай свой собственный Shazzam!](https://leanpub.com/build-your-own-shazzam-python)
В приложении I будет предоставлять некоторые указатели для использования pytorch и numpy.
Вот пример учебника Pytorch.

Основы Pytorch

Почему бы просто не использовать списки Python для вычислений
вместо того, чтобы перенести все это в библиотеку?

Списки Python очень общие.
Они могут содержать объекты любого типа.
Они динамически типизированы.
Они не поддерживают математические функции, такие как матричное
умножение точек и т. д.

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

Тензоры Pytorch эффективно используют память и имеют общее двоичное
представление, позволяющее без затрат использовать уже существующие данные numpy
.
Из-за статической типизации быстрая реализация
математических такие функции, как умножение и сложение
тензоров Pytorch, могут быть реализованы на скомпилированном
языке (используются C и Fortran, а также некоторые специфические функции на основе графического процессора
, что позволяет нам использовать все, от
CUDA, OpenCL и SYCL).
Оптимизация размещения памяти также позволяет выполнять числовые
вычисления параллельно данным (SIMD и т. д.)
Теперь давайте оценим простоту разработка при прохождении
Pytorch Primer.
[Примечание!]: в некоторых ссылках на документацию предоставляется версия numpy, учитывая, что она
значительно лучше объясняет удобство использования некоторых функций.

Начните с установки и импорта библиотеки pytorch.

Установка

# CUDA 10.0 install
pip install torch==1.2.0 torchvision==0.4.0 -f https://download.pytorch.org/whl/torch_stable.html
# CUDA 9.2
pip install torch==1.2.0+cu92 torchvision==0.4.0+cu92 -f https://download.pytorch.org/whl/torch_stable.html
# CPU only install
pip install torch==1.2.0+cpu torchvision==0.4.0+cpu -f https://download.pytorch.org/whl/torch_stable.html

Инициализация

import torch

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

Создайте неинициализированный тензор

>>> a = torch.empty(2, 4)
[Out]: tensor([[ 0.0000e+00,  2.0000e+00, -1.8032e-07,  4.6577e-10],
               [ 8.4078e-45,  1.1210e-44,  4.2039e-45,  0.0000e+00]])

Или нулевой инициализированный тензор

>>> a = torch.empty(5, 6)
[Out]: tensor([[0., 0., 0., 0., 0., 0.],
 [0., 0., 0., 0., 0., 0.],
 [0., 0., 0., 0., 0., 0.],
 [0., 0., 0., 0., 0., 0.],
 [0., 0., 0., 0., 0., 0.]])

Создание тензора: аргументом функции массива является список Python

>>> a = torch.empty(5, 6)
[Out]: tensor([[0., 0., 0., 0., 0., 0.],
 [0., 0., 0., 0., 0., 0.],
 [0., 0., 0., 0., 0., 0.],
 [0., 0., 0., 0., 0., 0.],
 [0., 0., 0., 0., 0., 0.]])

Создание тензора: аргументом функции массива является список Python

>>> v = torch.Tensor([1.1, 2, 3, 4])
[Out]: tensor([1.1000, 2.0000, 3.0000, 4.0000])

Создание многомерного тензора (матрицы):
аргументом функции массива является вложенный список Python.

>>> M = torch.Tensor([[1, 2], [3, 4]])
[Out]: tensor([[1., 2.],
 [3., 4.]])

Объекты v и M относятся к типу torch.Tensor, который предоставляет модуль pytorch.
Мы можем проверить это так же, как и любой другой объект Python.

>>> type(v), type(M)
[Out]: (torch.Tensor, torch.Tensor)

Разница между массивами v и M заключается только в их форме.
Мы можем получить информацию о форме массива, используя
свойство Tensor.shape.

>>> print( f”v: {v.shape} ; M: {M.shape}”)
[Out]: v: torch.Size([4]) ; M: torch.Size([2, 2])

Количество элементов в массиве доступно через
метод Tensor.size:

>> print( f”v: {v.size()} ; M: {M.size()}”)
[Out]: v: torch.Size([4]) ; M: torch.Size([2, 2])

Используя свойство dtype (тип данных) тензора,
мы можем увидеть, какой тип имеют данные тензора:

>>> print( f”v: {v.dtype} ; M: {M.dtype}”)
[Out]: v: torch.float32 ; M: torch.float32

Используя метод elemetn_size тензора, мы можем увидеть байты на элемент тензора:

>>> print( f”v: {v.element_size()} ; M: {M.element_size()}”)
[Out]: v: 4 ; M: 4

Используя метод element_size тензора и метод flatten
, мы можем увидеть количество байтов в тензоре:

>>> print(f”v: {v.element_size() * v.flatten().shape[0]};\
 M: {M.element_size() * M.flatten().shape[0]}”)
[Out]: v: 16 ; M: 16

Вы также можете проверить структуру памяти
В настоящее время поддерживается torch.strided (плотные тензоры)
и есть экспериментальная поддержка torch.sparse_coo (разреженные тензоры COO).

>>> print(f”v: {v.layout} M: {M.layout}”)
[Out]: v: torch.strided M: torch.strided

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

>>> print( f”v: {v.ndim} ; M: {M.ndim}”)
[Out]: v: 1 ; M: 2

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

>>> M[0,0] = “hello”
[Out]: TypeError: cant assign a str to a torch.FloatTensor

Мы можем явно определить тип тензора
с помощью аргумента ключевого слова dtype:
[ПРИМЕЧАНИЕ!]: в отличие от numpy квантованные и сложные типы еще не поддерживаются в pytorch

>>> float_tensor = torch.ones(11, dtype=torch.float)
[Out]: tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])

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

Создайте тензор на основе диапазона

>>> x = torch.arange(0, 10, 1) # arguments: start, stop, step
[Out]: tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

Создайте тензор на основе диапазона значений с плавающей запятой

>>> x = torch.arange(-1, 1, 0.1)
[Out]: tensor([-1.0000, -0.9000, -0.8000, -0.7000, -0.6000, -0.5000, -0.4000, -0.3000,
 -0.2000, -0.1000, 0.0000, 0.1000, 0.2000, 0.3000, 0.4000, 0.5000,
 0.6000, 0.7000, 0.8000, 0.9000])

Используя [linspace](https://docs.scipy.org/doc/numpy/reference/generated/numpy.linspace.html),
включены обе конечные точки

>>> torch.linspace(0, 10, 25)
[Out]: tensor([ 0.0000, 0.4167, 0.8333, 1.2500, 1.6667, 2.0833, 2.5000, 2.9167,
 3.3333, 3.7500, 4.1667, 4.5833, 5.0000, 5.4167, 5.8333, 6.2500,
 6.6667, 7.0833, 7.5000, 7.9167, 8.3333, 8.7500, 9.1667, 9.5833,
 10.0000])

Использование [logspace](https://docs.scipy.org/doc/numpy/reference/generated/numpy.logspace.html)

>>> torch.logspace(0, 10, 10, base=np.e)
[Out]: tensor([1.0000e+00, 3.0377e+00, 9.2278e+00, 2.8032e+01, 8.5153e+01, 2.5867e+02,
 7.8577e+02, 2.3870e+03, 7.2510e+03, 2.2026e+04])

Использование [meshgrid](https://docs.scipy.org/doc/numpy/reference/generated/numpy.meshgrid.html)

>>> x, y = torch.meshgrid([torch.arange(0,5), torch.arange(0,5)]) 
# similar to meshgrid in MATLAB
>>> x
[Out]: tensor([[0, 0, 0, 0, 0],
 [1, 1, 1, 1, 1],
 [2, 2, 2, 2, 2],
 [3, 3, 3, 3, 3],
 [4, 4, 4, 4, 4]])
>>> y
[Out]: tensor([[0, 1, 2, 3, 4],
 [0, 1, 2, 3, 4],
 [0, 1, 2, 3, 4],
 [0, 1, 2, 3, 4],
 [0, 1, 2, 3, 4]])

Создавайте тензоры с хорошей поддержкой случайных чисел

Равномерные случайные числа в [0,1]

>>> torch.rand(5,5)
[Out]: tensor([[0.8045, 0.6434, 0.6919, 0.1928, 0.1206],
 [0.6650, 0.9219, 0.7604, 0.3623, 0.7129],
 [0.2362, 0.8861, 0.2842, 0.6565, 0.4014],
 [0.8429, 0.3326, 0.2073, 0.2165, 0.7568],
 [0.4814, 0.4796, 0.5633, 0.3096, 0.7262]])

Стандартные нормально распределенные случайные числа

>>> torch.randn(5,5)
[Out]: tensor([[ 0.7389, -0.0692, -0.4417, 0.2532, -0.6249],
 [-0.7023, 0.2570, 0.1416, -1.7092, -1.1454],
 [-0.5858, -1.7136, -2.0907, 0.0318, -1.0332],
 [ 0.6930, 0.9322, 1.3171, -0.4396, 1.9546],
 [ 0.1334, -1.5349, 0.7378, -0.5799, -0.8226]])

Диагональная матрица

>>> torch.diag(torch.arange(1,5))
[Out]: tensor([[1, 0, 0, 0],
 [0, 2, 0, 0],
 [0, 0, 3, 0],
 [0, 0, 0, 4]])

Диагональ со смещением от главной диагонали

>>> torch.diag(torch.arange(1,5),1)
[Out]: tensor([[0, 1, 0, 0, 0],
 [0, 0, 2, 0, 0],
 [0, 0, 0, 3, 0],
 [0, 0, 0, 0, 4],
 [0, 0, 0, 0, 0]])

Создайте тензоры с нулями

>>> torch.zeros((3,3))
[Out]: tensor([[0., 0., 0.],
 [0., 0., 0.],
 [0., 0., 0.]])

Создавайте тензоры с единицами

>>> torch.ones((3,3))
[Out]: tensor([[1., 1., 1.],
 [1., 1., 1.],
 [1., 1., 1.]])

Упорство

Сохраните тензор в файл

>>> torch.save(M, ‘tst.csv’)

Загрузить тензоры
учитывая гетерогенную вычислительную природу pytorch
, мы можем загружать их по-разному

Загрузите все тензоры в ЦП

>>> torch.load(‘tst.csv’) 
[Out]: tensor([[1., 2.],
               [3., 4.]])

Загрузите все тензоры в ЦП, используя функцию

>>> torch.load(‘tst.csv’, map_location=torch.device(‘cpu’)) 
[Out]: tensor([[1., 2.],
               [3., 4.]])

Проверьте, доступна ли cuda

>>> torch.cuda.is_available()
[Out]: True/False

Загрузите тензор на GPU cuda, иначе cpu

if torch.cuda.is_available()
 map_location=lambda storage, loc: storage.cuda()
else:
 map_location=’cpu’

Загрузите все тензоры в GPU 1

>>> torch.load(‘tst.csv’, map_location=lambda storage, loc: storage) 
[Out]: tensor([[1., 2.],
               [3., 4.]])

Сопоставьте тензоры от GPU 1 до GPU 0

>>> torch.load(‘tst.csv’, map_location={‘cuda:1’:’cuda:0'}) 
[Out]: tensor([[1., 2.],
               [3., 4.]])

сохранить в объект BytesIO

>>> import io
>>> buffer = io.BytesIO()
>>> torch.save(M, buffer)
>>> buffer.seek(0)
[Out]: <_io.BytesIO at 0x11ea80cb0>

Загрузить тензоры из объекта BytesIO