Тензор (tensor) представляет многомерный массив - структуру данных, которая может хранить и представлять данные в структурированном виде. В PyTorch тензоры применяются для кодирования входных и выходных данных модели, а также ее параметров. Тензоры являются обобщением скаляров (0-мерных), векторов (1-мерных) и матриц (2-мерных) на более высокие размерности. Можно ассоциировать тензоры с массивами за тем исключением, что тензоры могут работать на графических процессорах или других аппаратных ускорителях.
В глубоком обучении данные часто представляются именно в виде тензоров, а модели нейронных сетей состоят из слоев, которые принимают тензоры на входе и выдают тензоры на выходе. Тензоры хранят входные данные, параметры модели (веса и смещения), промежуточные активации и градиенты во время обучения.
Рассмотрим основные характеристики тензоров:
Размерность: количество индексов, необходимых для уникальной идентификации и доступа к определенному элементу тензора. По сути, она описывает "структуру" или "форму" тензора (как в массивах). Тензоры могут иметь произвольные размерности. Число размерностей тензора также называется его рангом или порядком. Например:
Скаляр: 0-мерный тензор
Вектор: 1-мерный тензор
Матрица: 2-мерный тензор
Тензор более высокой размерности может иметь три или более измерений.
[7, 2, 9, 10] имеет форму (4, ), так как вектор - одномерный тензор, и в данном случае имеет 4 элемента. В
Pytorch описывается выражением shape(4,). А матрица 2x3 имеет форму (2, 3), что означает две строки и три столбца (shape(2, 3)).
Тензоры можно создавать непосредственно из данных с помощью функции torch.tensor(), которой передаются сами данные:
import torch data = [[1, 2],[3, 4]] my_tensor = torch.tensor(data) print(my_tensor)
Здесь на основании массива data создается двухмерный тензор. Тип данных тензора определяется автоматически. И консоль нам выведет содержимое тензора:
tensor([[1, 2],
[3, 4]])
Кроме того, PyTorch предоставляет ряд специальных функций для создания векторов по определенному шаблону, например, все единицы или все нули и т.д.:
Почти все эти функции (кроме randint()) в качестве первого параметра принимают размер тензора. Применение некоторых их этих функций:
import torch
shape = (2,3,) # кортеж, который определяет размер создаваемых векторов - 2 строки по 3 столбца
zeros_tensor = torch.zeros(shape) # тензор, заполненный нулями
print(f"zeros_tensor: \n {zeros_tensor} \n")
ones_tensor = torch.ones(shape) # тензор, заполненный единицами
print(f"ones_tensor: \n {ones_tensor} \n")
rand_tensor = torch.rand(shape) # тензор, заполненный случайными числами
print(f"rand_tensor: \n {rand_tensor} \n")
randint_tensor = torch.randint(5, 9, shape) # тензор, заполненный случайными числами от 5 до 9
print(f"randint_tensor: \n {randint_tensor} \n")
empty_tensor = torch.empty(shape) # неинициализированный тензор
print(f"empty_tensor: \n {empty_tensor} \n")
full_tensor = torch.full(shape, fill_value=2) # тензор, заполненный сопределенным значением
print(f"full_tensor: \n {full_tensor} \n")
Консольный вывод:
zeros_tensor:
tensor([[0., 0., 0.],
[0., 0., 0.]])
ones_tensor:
tensor([[1., 1., 1.],
[1., 1., 1.]])
rand_tensor:
tensor([[0.5144, 0.2868, 0.2153],
[0.4840, 0.8548, 0.4075]])
randint_tensor:
tensor([[6, 8, 6],
[5, 6, 6]])
empty_tensor:
tensor([[5.8592e-11, 0.0000e+00, 0.0000e+00],
[0.0000e+00, 0.0000e+00, 0.0000e+00]])
full_tensor:
tensor([[2, 2, 2],
[2, 2, 2]])
Тензор также можно создать на основании старого тензора. При этом новый тензор сохраняет свойства (форму, тип данных) старого тензора (если только они явно не переопределены). Для этого предназначен ряд функций, рассмотрим некоторые из них:
В качестве первого параметра эти функции принимают входной тензор, на основании которого надо создать новый. Пример применения некоторых из этих функций:
import torch
my_tensor = torch.tensor([[1, 2],[3, 4]])
zeros_tensor = torch.zeros_like(my_tensor) # тензор, заполненный нулями
print(f"zeros_tensor: \n {zeros_tensor} \n")
ones_tensor = torch.ones_like(my_tensor) # тензор, заполненный единицами
print(f"ones_tensor: \n {ones_tensor} \n")
rand_tensor = torch.rand_like(my_tensor, dtype=torch.float) # тензор, заполненный случайными числами с изменением типа данных
print(f"rand_tensor: \n {rand_tensor} \n")
empty_tensor = torch.empty_like(my_tensor) # неинициализированный тензор
print(f"empty_tensor: \n {empty_tensor} \n")
full_tensor = torch.full_like(my_tensor, fill_value=2) # тензор, заполненный сопределенным значением
print(f"full_tensor: \n {full_tensor} \n")
Консольный вывод:
zeros_tensor:
tensor([[0, 0],
[0, 0]])
ones_tensor:
tensor([[1, 1],
[1, 1]])
rand_tensor:
tensor([[0.3657, 0.9211],
[0.4143, 0.3728]])
empty_tensor:
tensor([[ 509746093, 0],
[ 178, 4600386960198991872]])
full_tensor:
tensor([[2, 2],
[2, 2]])
Атрибуты тензора описывают их форму, тип данных и устройство, на котором тензор хранится, и представлены свойствами:
shape: форма (размер) тензора
dtype: тип данных
device: устройство
Получение атрибутов:
import torch
tensor = torch.rand(3,4)
print(f"Форма тензора: {tensor.shape}")
print(f"Тип данных тензора: {tensor.dtype}")
print(f"Устройство хранения тензора: {tensor.device}")
ПРимер консольного вывода:
Форма тензора: torch.Size([3, 4]) Тип данных тензора: torch.float32 Устройство хранения тензора: cpu