Тензор — это обобщение векторов и матриц до nразмерностей. Понимание того, как они взаимодействуют друг с другом, имеет основополагающее значение для машинного обучения.

Обзор

Хотя тензоры кажутся сложными объектами, их можно понимать как набор векторов и матриц. Понимание векторов и матриц необходимо для понимания тензоров.

Вектор представляет собой одномерный список элементов:

Матрица представляет собой двумерный список векторов:

Нижний индекс указывает (строка, столбец). Другой способ представить матрицу — это вектор, элементами которого являются векторы. Обратите внимание, что они обычно обозначаются заглавными буквами.

Трехмерный тензор можно рассматривать как трехмерный список матриц:

Другой способ представить трехмерный тензор — это вектор с матрицами в качестве его элементов. Обратите внимание, что в этой статье они отмечены каллиграфическими заглавными буквами.

Четырехмерный тензор можно рассматривать как четырехмерный список трехмерных тензоров:

Другой способ представить четырехмерный тензор — это вектор с трехмерными тензорами в качестве его элементов.

Они могут становиться все более и более сложными, но именно в таком объеме необходимо перейти к выполнению операций с тензорами.

Векторные операции

Предположим, что это векторы одинаковой длины, i.

Последующие операции в основном поэлементные. Это означает, что соответствующие элементы в каждом векторе обрабатываются вместе.

Дополнение

import torch

x = torch.tensor([1, 3, 5])
y = torch.tensor([3, 7, 4])

x + y
tensor([ 4, 10,  9])

Вычитание

x = torch.tensor([1, 3, 5])
y = torch.tensor([3, 7, 4])

x - y
tensor([-2, -4,  1])

Скалярный продукт (умножение)

Это также можно записать суммированием:

x = torch.tensor([1, 3, 5])
y = torch.tensor([3, 7, 4])

torch.dot(x, y) # 1*3 + 3*7 + 5*4 = 3 + 21 + 20 = 44
tensor(44)

Это также можно сделать с помощью x @ y. Выход скалярного произведения является скаляром. Он не возвращает вектор.

Произведение Адамара (умножение)

Произведение Адамара используется для поэлементного умножения и возвращает вектор.

x = torch.tensor([1, 3, 5])
y = torch.tensor([3, 7, 4])

x * y
tensor([ 3, 21, 20])

Скалярное умножение

k — это скаляр, который в большинстве случаев является действительным числом.

k = 5
x = torch.tensor([1, 3, 5])

k * x
tensor([ 5, 15, 25])

Поскольку kможет быть дробью, это также можно рассматривать как скалярное деление.

Умножение матриц

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

Предположим следующее, где X и Yимеют форму (4,3 ):

Дополнение

X = torch.tensor([[1, 3, 5],
                  [3, 6, 1],
                  [6, 8, 5],
                  [7, 3, 2]])

Y = torch.tensor([[6, 3, 2],
                  [8, 5, 4],
                  [3, 1, 7],
                  [1, 8, 3]])

X + Y
tensor([[ 7,  6,  7],
        [11, 11,  5],
        [ 9,  9, 12],
        [ 8, 11,  5]])

Вычитание

X = torch.tensor([[1, 3, 5],
                  [3, 6, 1],
                  [6, 8, 5],
                  [7, 3, 2]])

Y = torch.tensor([[6, 3, 2],
                  [8, 5, 4],
                  [3, 1, 7],
                  [1, 8, 3]])

X - Y
tensor([[-5,  0,  3],
        [-5,  1, -3],
        [ 3,  7, -2],
        [ 6, -5, -1]])

Скалярное произведение (умножение матриц)

При выполнении матричного умножения важно, чтобы матрицы рассматривались как составленные из векторов. С этой точки зрения ясно, как скалярное произведение выполняется по матрицам. Умножение возможно только в том случае, если количество строк в первой матрице совпадает с количеством столбцов во второй. Это приводит к:

  • (m, n) x (n, r) = (m, r)

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

На изображении выше видно, что каждый вектор или строка в левой матрице умножается на каждый вектор или столбец во второй матрице. Таким образом, в этом примере каждый вектор в A должен быть умножен на каждый вектор в B, в результате чего Выполняется 16 точечных произведений.

X = torch.tensor([[1, 3, 5],
                  [3, 6, 1],
                  [6, 8, 5],
                  [7, 3, 2]])

Y = torch.tensor([[6, 3, 2],
                  [8, 5, 4],
                  [3, 1, 7],
                  [1, 8, 3]])

X.matmul(Y.T) # X @ Y.T
tensor([[ 25,  43,  41,  40],
        [ 38,  58,  22,  54],
        [ 70, 108,  61,  85],
        [ 55,  79,  38,  37]])

Произведение Адамара (умножение матриц)

Произведение Адамара — это поэлементное умножение, поэтому оно выполняется так же, как сложение и вычитание.

X = torch.tensor([[1, 3, 5],
                  [3, 6, 1],
                  [6, 8, 5],
                  [7, 3, 2]])

Y = torch.tensor([[6, 3, 2],
                  [8, 5, 4],
                  [3, 1, 7],
                  [1, 8, 3]])

X * Y
tensor([[ 6,  9, 10],
        [24, 30,  4],
        [18,  8, 35],
        [ 7, 24,  6]])

Скалярное умножение

k = 5
X = torch.tensor([[1, 3, 5],
                  [3, 6, 1],
                  [6, 8, 5],
                  [7, 3, 2]])

k * X
tensor([[ 5, 15, 25],
        [15, 30,  5],
        [30, 40, 25],
        [35, 15, 10]])

Тензорные операции в трех измерениях

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

Для поэлементных операций в этом разделе предположим, что оба тензора имеют форму (3, 3, 2). Это означает, что оба тензора содержат три (3,2) матрицы. Это можно увидеть ниже:

import torch

gen = torch.Generator().manual_seed(2147483647)

X = torch.randint(0, 10, (3, 3, 2), generator=gen)
Y = torch.randint(0, 10, (3, 3, 2), generator=gen)
X = tensor([[[1, 4],
             [9, 2],
             [3, 0]],

            [[4, 6],
             [7, 7],
             [1, 5]],

            [[6, 8],
             [1, 4],
             [4, 9]]])

Y = tensor([[[8, 0],
             [3, 6],
             [6, 0]],

            [[9, 1],
             [0, 0],
             [2, 2]],

            [[7, 1],
             [8, 1],
             [9, 0]]])

Дополнение

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

X + Y
tensor([[[ 9,  4],
         [12,  8],
         [ 9,  0]],

        [[13,  7],
         [ 7,  7],
         [ 3,  7]],

        [[13,  9],
         [ 9,  5],
         [13,  9]]])

Вычитание

Вычитание также является поэлементным и работает так, как ожидалось.

X - Y
tensor([[[-7,  4],
         [ 6, -4],
         [-3,  0]],

        [[-5,  5],
         [ 7,  7],
         [-1,  3]],

        [[-1,  7],
         [-7,  3],
         [-5,  9]]])

Скалярное произведение (тензорное умножение)

Тензорное умножение немного сложнее, чем в двух измерениях. Раньше умножение матриц могло происходить только при выполнении следующего условия:

  • (m, n) x (n, r) = (m, r)

В трех измерениях это все еще требование. Однако первые оси должны быть одинаковыми:

  • (z, m, n) x (z, n, r) = (z, m, r)

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

Изображение выше должно помочь объяснить это. Это может помочь думать об обоих трехмерных тензорах как о векторах матриц. Поскольку скалярное произведение выполняется путем поэлементного умножения, а затем суммирования, первое, что происходит, — это умножение каждой матрицы на соответствующую ей матрицу. Когда это происходит, умножение матриц приводит к тому, что каждый вектор в матрицах выполняет скалярное произведение с другими. В некотором смысле это похоже на вложенный точечный продукт.

Чтобы 𝓧 и 𝓨 умножались друг на друга, необходимо поменять местами вторую и третью оси 𝓨. 𝓧 и 𝓨 оба имеют размер (3, 3, 2). Это означает, что 𝓨 должно стать (3, 2, 3). Этого можно добиться с помощью Y.permute(0, 2, 1), который меняет местами вторую и третью оси. В качестве альтернативы можно использовать Y.transpose(1,2).

print(Y.transpose(1,2))
print(Y.transpose(1,2).shape) # Y.permute(0, 2, 1)
tensor([[[8, 3, 6],
         [0, 6, 0]],

        [[9, 0, 2],
         [1, 0, 2]],

        [[7, 8, 9],
         [1, 1, 0]]])

torch.Size([3, 2, 3])

При соответствующих размерах тензорное умножение теперь можно выполнять с помощью matmul или @. Выходные данные должны иметь форму (3, 3, 2) x (3, 2, 3) = (3, 3, 3).

X.matmul(Y.transpose(1,2)) # X @ Y.transpose(1,2)
tensor([[[ 8, 27,  6],
         [72, 39, 54],
         [24,  9, 18]],

        [[42,  0, 20],
         [70,  0, 28],
         [14,  0, 12]],

        [[50, 56, 54],
         [11, 12,  9],
         [37, 41, 36]]])

Произведение Адамара (тензорное умножение)

Продукт Адамара работает так, как ожидалось, и поэлементно умножает матрицы в трехмерном тензоре.

X * Y
tensor([[[ 8,  0],
         [27, 12],
         [18,  0]],

        [[36,  6],
         [ 0,  0],
         [ 2, 10]],

        [[42,  8],
         [ 8,  4],
         [36,  0]]])

Скалярное умножение

Скалярное умножение также работает должным образом.

k = 5
k*X
tensor([[[ 5, 20],
         [45, 10],
         [15,  0]],

        [[20, 30],
         [35, 35],
         [ 5, 25]],

        [[30, 40],
         [ 5, 20],
         [20, 45]]])

Тензорные операции в четырех измерениях

Тензорные операции в четырех измерениях по-прежнему требуют, чтобы оба тензора имели одинаковый размер.

Для этого раздела предположим, что 𝓧 и 𝓨 имеют форму (2, 3, 3, 2). Это означает, что оба четырехмерных тензора содержат два трехмерных тензора, и каждый из них содержит три матрицы (3,2). Это можно увидеть ниже:

import torch

gen = torch.Generator().manual_seed(2147483647)

X = torch.randint(0, 10, (2, 3, 3, 2), generator=gen)
Y = torch.randint(0, 10, (2, 3, 3, 2), generator=gen)
X
# 4d tensor
tensor([
# 3d tensor
        [
         # matrix 1
         [[1, 4],
          [9, 2],
          [3, 0]],
         # matrix 2
         [[4, 6],
          [7, 7],
          [1, 5]],
         # matrix 3
         [[6, 8],
          [1, 4],
          [4, 9]]],

# 3d tensor
        [
         # matrix 1
         [[8, 0],
          [3, 6],
          [6, 0]],
         # matrix 2
         [[9, 1],
          [0, 0],
          [2, 2]],
         # matrix 3
         [[7, 1],
          [8, 1],
          [9, 0]]]])
Y
# 4d tensor
tensor([
# 3d tensor
        [
         # matrix 1 
         [[6, 3],
          [6, 4],
          [5, 7]],
         # matrix 2
         [[3, 7],
          [2, 0],
          [5, 1]],
         # matrix 3
         [[0, 4],
          [0, 8],
          [0, 6]]],

# 3d tensor
        [
         # matrix 1
         [[0, 5],
          [8, 6],
          [1, 0]],
         # matrix 2
         [[5, 1],
          [1, 6],
          [1, 2]],
         # matrix 3
         [[6, 0],
          [2, 6],
          [1, 5]]]])

Дополнение

Сложение, вычитание и произведение Адамара по-прежнему выполняются поэлементно, как и ожидалось.

X + Y
tensor([[[[ 7,  7],
          [15,  6],
          [ 8,  7]],

         [[ 7, 13],
          [ 9,  7],
          [ 6,  6]],

         [[ 6, 12],
          [ 1, 12],
          [ 4, 15]]],


        [[[ 8,  5],
          [11, 12],
          [ 7,  0]],

         [[14,  2],
          [ 1,  6],
          [ 3,  4]],

         [[13,  1],
          [10,  7],
          [10,  5]]]])

Вычитание

X - Y
tensor([[[[-5,  1],
          [ 3, -2],
          [-2, -7]],

         [[ 1, -1],
          [ 5,  7],
          [-4,  4]],

         [[ 6,  4],
          [ 1, -4],
          [ 4,  3]]],


        [[[ 8, -5],
          [-5,  0],
          [ 5,  0]],

         [[ 4,  0],
          [-1, -6],
          [ 1,  0]],

         [[ 1,  1],
          [ 6, -5],
          [ 8, -5]]]])

Скалярное произведение (тензорное умножение)

В четырех измерениях тензорное умножение будет иметь те же требования, что и в трех и двух измерениях. Также потребуется, чтобы первая и вторая оси совпадали для обоих тензоров:

  • (c, z, m, n) x (c, z, n, r) = (c,z,m,r)

В трех измерениях выполнялось матричное умножение, за которым следовало скалярное произведение между векторами. Те же шаги будут выполняться в четырех измерениях, но они начнутся с умножения каждого трехмерного тензора на соответствующий ему трехмерный тензор. Затем каждая из их матриц будет умножаться друг на друга. Наконец, их векторы будут производить скалярные произведения друг на друга. Это видно на изображении выше.

В этом примере 𝓧 и 𝓨 имеют размер (2, 3, 3, 2). Чтобы произошло умножение, третья и четвертая оси 𝓨 должны быть переставлены. Это можно сделать так же, как и раньше, используя Y.permute(0, 1, 3, 2) или Y.transpose(2,3 ). Это транспонирует 𝓨, чтобы иметь форму (2, 3, 2, 3).

Результат должен иметь вид (2, 3, 3, 2) x (2, 3, 2, 3) = (2,3,3,3) . Это означает, что будет два трехмерных тензора, и каждый из них будет содержать три (3,3) матрицы. Этот результат можно получить с помощью matmul или @.

X.matmul(Y.transpose(2,3)) # X @ Y.transpose(2,3)
tensor([[[[18, 22, 33],
          [60, 62, 59],
          [18, 18, 15]],

         [[54,  8, 26],
          [70, 14, 42],
          [38,  2, 10]],

         [[32, 64, 48],
          [16, 32, 24],
          [36, 72, 54]]],


        [[[ 0, 64,  8],
          [30, 60,  3],
          [ 0, 48,  6]],

         [[46, 15, 11],
          [ 0,  0,  0],
          [12, 14,  6]],

         [[42, 20, 12],
          [48, 22, 13],
          [54, 18,  9]]]])

Произведение Адамара (тензорное умножение)

X * Y
tensor([[[[ 6, 12],
          [54,  8],
          [15,  0]],

         [[12, 42],
          [14,  0],
          [ 5,  5]],

         [[ 0, 32],
          [ 0, 32],
          [ 0, 54]]],


        [[[ 0,  0],
          [24, 36],
          [ 6,  0]],

         [[45,  1],
          [ 0,  0],
          [ 2,  4]],

         [[42,  0],
          [16,  6],
          [ 9,  0]]]])

Скалярное умножение

k = 5
k * X
tensor([[[[ 5, 20],
          [45, 10],
          [15,  0]],

         [[20, 30],
          [35, 35],
          [ 5, 25]],

         [[30, 40],
          [ 5, 20],
          [20, 45]]],


        [[[40,  0],
          [15, 30],
          [30,  0]],

         [[45,  5],
          [ 0,  0],
          [10, 10]],

         [[35,  5],
          [40,  5],
          [45,  0]]]])

Пожалуйста, не забудьте поставить лайк и подписаться, чтобы узнать больше! :)

Рекомендации

  1. 3D-матричное умножение GeeksForGeeks в NumPy