Тензор PyTorch

Тензор — это многомерный массив, который может быть скаляром, вектором, матрицей или структурой данных большей размерности.

В PyTorch тензор — это основное представление данных, аналогичное многомерным массивам NumPy, но с более мощными возможностями, такими как поддержка ускорения на GPU и автоматическое вычисление градиентов.

Тензоры поддерживают несколько типов данных (целочисленный, с плавающей запятой, логический и т. д.).

Тензоры могут храниться на CPU или GPU; тензоры GPU могут значительно ускорить вычисления.

На следующем рисунке показано, как представляются тензоры разных размерностей в PyTorch:

Пояснение:

  • 1D-тензор / Вектор (одномерный тензор/вектор):Самая базовая форма тензора, которую можно рассматривать как массив. В примере на рисунке представлен вектор, содержащий 10 элементов.
  • 2D-тензор / Матрица (двумерный тензор/матрица):Двумерный массив, обычно используемый для представления матрицы. В примере на рисунке показана матрица 4x5, содержащая 20 элементов.
  • 3D-тензор / Куб (трёхмерный тензор/куб):Трёхмерный массив, который можно рассматривать как куб, образованный путём наложения нескольких матриц. В примере на рисунке показан куб 3x4x5, где каждая матрица размера 5x5 представляет "слой" куба.
  • 4D-тензор / Вектор кубов (четырёхмерный тензор/вектор кубов):Четырёхмерный массив, который можно рассматривать как вектор, состоящий из нескольких кубов. В примере на рисунке нет конкретных значений, но его можно понимать как набор, содержащий несколько 3D-тензоров.
  • 5D-тензор / Матрица кубов (пятимерный тензор/матрица кубов):Пятимерный массив, который можно рассматривать как матрицу, состоящую из нескольких 4D-тензоров. В примере на рисунке также нет конкретных значений, но его можно понимать как набор, содержащий несколько 4D-тензоров.

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

Существует несколько способов создания тензоров:

МетодОписаниеПример кода
torch.tensor(data)Создать тензор из списка Python или массива NumPy.x = torch.tensor([[1, 2], [3, 4]])
torch.zeros(size)Создать тензор, заполненный нулями.x = torch.zeros((2, 3))
torch.ones(size)Создать тензор, заполненный единицами.x = torch.ones((2, 3))
torch.empty(size)Создать неинициализированный тензор.x = torch.empty((2, 3))
torch.rand(size)Создать случайный тензор, подчиняющийся равномерному распределению, со значениями в[0, 1)。x = torch.rand((2, 3))
torch.randn(size)Создать случайный тензор, подчиняющийся нормальному распределению, со средним 0 и стандартным отклонением 1.x = torch.randn((2, 3))
torch.arange(start, end, step)Создать одномерный тензор-последовательность, аналогичный таковому в Pythonrange。x = torch.arange(0, 10, 2)
torch.linspace(start, end, steps)Создать тензор-последовательность с равными интервалами в заданном диапазоне.x = torch.linspace(0, 1, 5)
torch.eye(size)Создать единичную матрицу (на диагонали 1, остальные 0).x = torch.eye(3)
torch.from_numpy(ndarray)Преобразовать массив NumPy в тензор.x = torch.from_numpy(np.array([1, 2, 3]))

Используйте функциюtorch.tensor(), чтобы преобразовать список или массив в тензор:

Пример

import torch

tensor = torch.tensor([1, 2, 3])
print(tensor)

Вывод следующий:

tensor([1, 2, 3])

Если у вас есть массив NumPy, вы можете использовать torch.from_numpy() для преобразования его в тензор:

Пример

import numpy as np

np_array = np.array([1, 2, 3])
tensor = torch.from_numpy(np_array)
print(tensor)

Вывод следующий:

tensor([1, 2, 3])

Создание двумерного тензора (матрицы):

Пример

import torch

tensor_2d = torch.tensor([
    [-9, 4, 2, 5, 7],
    [3, 0, 12, 8, 6],
    [1, 23, -6, 45, 2],
    [22, 3, -1, 72, 6]
])
print("2D тензор (матрица):\n", tensor_2d)
print("Форма:", tensor_2d.shape)  # shape

Вывод следующий:

2D Tensor (Matrix):
 tensor([[-9,  4,  2,  5,  7],
        [ 3,  0, 12,  8,  6],
        [ 1, 23, -6, 45,  2],
        [22,  3, -1, 72,  6]])
Shape: torch.Size([4, 5])

Создание других размерностей:

# 创建 3D 张量(立方体)
tensor_3d = torch.stack([tensor_2d, tensor_2d + 10, tensor_2d - 5])  # 堆叠 3 个 2D 张量
print("3D Tensor (Cube):\n", tensor_3d)
print("Shape:", tensor_3d.shape)  # 形状

# 创建 4D 张量(向量的立方体)
tensor_4d = torch.stack([tensor_3d, tensor_3d + 100])  # 堆叠 2 个 3D 张量
print("4D Tensor (Vector of Cubes):\n", tensor_4d)
print("Shape:", tensor_4d.shape)  # 形状

# 创建 5D 张量(矩阵的立方体)
tensor_5d = torch.stack([tensor_4d, tensor_4d + 1000])  # 堆叠 2 个 4D 张量
print("5D Tensor (Matrix of Cubes):\n", tensor_5d)
print("Shape:", tensor_5d.shape)  # 形状

Атрибуты тензора

Атрибуты тензора следующие:

AttributeОписаниеПример
.shapeПолучить форму тензораtensor.shape
.size()Получить форму тензораtensor.size()
.dtypeПолучить тип данных тензораtensor.dtype
.deviceПросмотреть устройство (CPU/GPU), на котором находится тензорtensor.device
.dim()Получить число измерений тензораtensor.dim()
.requires_gradВключено ли вычисление градиентаtensor.requires_grad
.numel()Получить общее число элементов в тензореtensor.numel()
.is_cudaПроверить, находится ли тензор на GPUtensor.is_cuda
.TПолучить транспонирование тензора (применимо к 2D-тензорам)tensor.T
.item()Получить значение одноэлементного тензораtensor.item()
.is_contiguous()Проверить, хранится ли тензор непрерывноtensor.is_contiguous()

Пример

import torch

# Создать 2D-тензор
tensor = torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.float32)

# Атрибуты тензора
print("Тензор:\n", tensor)
print("Форма:", tensor.shape)  # Получить форму
print("Размер:", tensor.size())  # Получить размер (другой метод)
print("Тип данных:", tensor.dtype)  # Тип данных
print("Устройство:", tensor.device)  # Устройство
print("Размерности:", tensor.dim())  # Количество измерений
print("Всего элементов:", tensor.numel())  # Общее количество элементов
print("Требуется градиент:", tensor.requires_grad)  # Включён ли градиент
print("Использует CUDA:", tensor.is_cuda)  # Находится ли на GPU
print("Непрерывный:", tensor.is_contiguous())  # Является ли хранилище непрерывным

# Получить значение одного элемента
single_value = torch.tensor(42)
print("Значение одного элемента:", single_value.item())

# Транспонирование тензора
tensor_T = tensor.T
print("Транспонированный тензор:\n", tensor_T)

Результат вывода:

Tensor:
 tensor([[1., 2., 3.],
         [4., 5., 6.]])
Shape: torch.Size([2, 3])
Size: torch.Size([2, 3])
Data Type: torch.float32
Device: cpu
Dimensions: 2
Total Elements: 6
Requires Grad: False
Is CUDA: False
Is Contiguous: True
Single Element Value: 42
Transposed Tensor:
 tensor([[1., 4.],
         [2., 5.],
         [3., 6.]])

Операции с тензорами

Методы операций с тензорами описаны ниже.

Базовые операции:

Действие Описание Пример кода
+, -, *, / Поэлементное сложение, вычитание, умножение и деление. z = x + y
torch.matmul(x, y) Умножение матриц. z = torch.matmul(x, y)
torch.dot(x, y) Скалярное произведение векторов (только для одномерных тензоров). z = torch.dot(x, y)
torch.sum(x) Сумма. z = torch.sum(x)
torch.mean(x) Среднее. z = torch.mean(x)
torch.max(x) Максимум. z = torch.max(x)
torch.min(x) Минимум. z = torch.min(x)
torch.argmax(x, dim) Вернуть индекс максимального значения (вдоль указанного измерения). z = torch.argmax(x, dim=1)
torch.softmax(x, dim) Вычислить softmax (вдоль указанного измерения). z = torch.softmax(x, dim=1)

Операции с формой

Действие Описание Пример кода
x.view(shape) Изменить форму тензора (без изменения данных). z = x.view(3, 4)
x.reshape(shape) Похоже наview, но более гибкий. z = x.reshape(3, 4)
x.t() Транспонировать матрицу. z = x.t()
x.unsqueeze(dim) Добавить измерение в указанной размерности. z = x.unsqueeze(0)
x.squeeze(dim) Удалить измерение размера 1 в указанной размерности. z = x.squeeze(0)
torch.cat((x, y), dim) Конкатенировать несколько тензоров вдоль указанной размерности. z = torch.cat((x, y), dim=1)

Пример

import torch

# Создать 2D-тензор
tensor = torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.float32)
print("Исходный тензор:\n", tensor)

# 1. **Операции индексирования и среза**
print("\n[Индексация и срезы]")
print("Получить первую строку:", tensor[0])  # Получить первую строку
print("Получить элемент в первой строке и первом столбце:", tensor[0, 0])  # Получить конкретный элемент
print("Получить все элементы во втором столбце:", tensor[:, 1])  # Получить все элементы во втором столбце

# 2. **Операции преобразования формы**
print("\n[Преобразование формы]")
reshaped = tensor.view(3, 2)  # Изменить форму тензора на 3x2
print("Тензор после изменения формы:\n", reshaped)
flattened = tensor.flatten()  # Развернуть тензор в одно измерение
print("Развёрнутый тензор:\n", flattened)

# 3. **Математические операции**
print("\n[Математические операции]")
tensor_add = tensor + 10  # Сложение тензоров
print("Тензор плюс 10:\n", tensor_add)
tensor_mul = tensor * 2  # Умножение тензоров
print("Тензор, умноженный на 2:\n", tensor_mul)
tensor_sum = tensor.sum()  # Вычислить сумму всех элементов
print("Сумма элементов тензора:", tensor_sum.item())

# 4. **Операции с другими тензорами**
print("\n[Операции с другими тензорами]")
tensor2 = torch.tensor([[1, 1, 1], [1, 1, 1]], dtype=torch.float32)
print("Другой тензор:\n", tensor2)
tensor_dot = torch.matmul(tensor, tensor2.T)  # Матричное умножение тензоров
print("Результат матричного умножения:\n", tensor_dot)

# 5. **Условные проверки и фильтрация**
print("\n[Условные проверки и фильтрация]")
mask = tensor > 3  # Создать булеву маску
print("Булева маска элементов, больших 3:\n", mask)
filtered_tensor = tensor[tensor > 3]  # Отфильтровать элементы, удовлетворяющие условию
print("Элементы, большие 3:\n", filtered_tensor)

Результат вывода:

原始张量:
 tensor([[1., 2., 3.],
         [4., 5., 6.]])

【索引和切片】
获取第一行: tensor([1., 2., 3.])
获取第一行第一列的元素: tensor(1.)
获取第二列的所有元素: tensor([2., 5.])

【形状变换】
改变形状后的张量:
 tensor([[1., 2.],
         [3., 4.],
         [5., 6.]])
展平后的张量:
 tensor([1., 2., 3., 4., 5., 6.])

【数学运算】
张量加 10:
 tensor([[11., 12., 13.],
         [14., 15., 16.]])
张量乘 2:
 tensor([[ 2.,  4.,  6.],
         [ 8., 10., 12.]])
张量元素的和: 21.0

【与其他张量操作】
另一个张量:
 tensor([[1., 1., 1.],
         [1., 1., 1.]])
矩阵乘法结果:
 tensor([[ 6.,  6.],
         [15., 15.]])

【条件判断和筛选】
大于 3 的元素的布尔掩码:
 tensor([[False, False, False],
         [ True,  True,  True]])
大于 3 的元素:
 tensor([4., 5., 6.])

Ускорение тензоров на GPU

Перенос тензора на GPU:

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
x = torch.tensor([1.0, 2.0, 3.0], device=device)

Проверить, доступен ли GPU:

torch.cuda.is_available()  # 返回 True или  False

Взаимодействие между тензорами и NumPy

Взаимодействие между тензорами и NumPy показано в следующей таблице:

Действие Описание Пример кода
torch.from_numpy(ndarray) Преобразовать массив NumPy в тензор. x = torch.from_numpy(np_array)
x.numpy() Преобразовать тензор в массив NumPy (только для тензоров на CPU). np_array = x.numpy()

Пример

import torch
import numpy as np

# 1. Преобразование массива NumPy в тензор PyTorch
print("1. Преобразование NumPy в тензор PyTorch")
numpy_array = np.array([[1, 2, 3], [4, 5, 6]])
print("Массив NumPy:\n", numpy_array)

# Используйте torch.from_numpy() для преобразования массива NumPy в тензор
tensor_from_numpy = torch.from_numpy(numpy_array)
print(Преобразованный тензор PyTorch:\n", tensor_from_numpy)

# Измените массив NumPy и посмотрите, как изменяется тензор (общая память)
numpy_array[0, 0] = 100
print(Изменённый массив NumPy:\n", numpy_array)
print(Тензор PyTorch также изменяется соответственно:\n", tensor_from_numpy)

# 2. Преобразование тензора PyTorch в массив NumPy
print("\n2. Преобразование тензора PyTorch в массив NumPy)
tensor = torch.tensor([[7, 8, 9], [10, 11, 12]], dtype=torch.float32)
print(Тензор PyTorch:\n", tensor)

# Используйте tensor.numpy() для преобразования тензора в массив NumPy
numpy_from_tensor = tensor.numpy()
print(Преобразованный массив NumPy:\n", numpy_from_tensor)

# Измените тензор и проследите за изменением в массиве NumPy (общая память)
tensor[0, 0] = 77
print(Изменённый тензор PyTorch:\n", tensor)
print(Массив NumPy также изменяется соответственно:\n", numpy_from_tensor)

# 3. Примечание: случаи, когда память не разделяется (нужно скопировать данные)
print("\n3. Используйте clone(), чтобы обеспечить независимые данные)
tensor_independent = torch.tensor([[13, 14, 15], [16, 17, 18]], dtype=torch.float32)
numpy_independent = tensor_independent.clone().numpy()  # Используйте clone для копирования данных
print(Исходный тензор:\n", tensor_independent)
tensor_independent[0, 0] = 0  # Изменить данные тензора
print(Изменённый тензор:\n", tensor_independent)
print(Массив NumPy (не изменится соответствующим образом):\n", numpy_independent)

Вывод:

1. NumPy 转为 PyTorch 张量
NumPy 数组:
 [[1 2 3]
 [4 5 6]]
转换后的 PyTorch 张量:
 tensor([[1, 2, 3],
         [4, 5, 6]])

修改后的 NumPy 数组:
 [[100   2   3]
 [  4   5   6]]
PyTorch 张量也会同步变化:
 tensor([[100,   2,   3],
         [  4,   5,   6]])

2. PyTorch 张量转为 NumPy 数组
PyTorch 张量:
 tensor([[ 7.,  8.,  9.],
         [10., 11., 12.]])
转换后的 NumPy 数组:
 [[ 7.  8.  9.]
 [10. 11. 12.]]

修改后的 PyTorch 张量:
 tensor([[77.,  8.,  9.],
         [10., 11., 12.]])
NumPy 数组也会同步变化:
 [[77.  8.  9.]
 [10. 11. 12.]]

3. 使用 clone() 保证独立数据
原始张量:
 tensor([[13., 14., 15.],
         [16., 17., 18.]])
修改后的张量:
 tensor([[ 0., 14., 15.],
         [16., 17., 18.]])
NumPy 数组(不会同步变化):
 [[13. 14. 15.]
 [16. 17. 18.]]
Другие расширения