Вещание происходит, когда меньший тензор «растягивается», чтобы иметь совместимую форму с большим тензором для выполнения операции.

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

Согласно PyTorch, тензор является «транслируемым», если:

Каждый тензор имеет хотя бы одно измерение

При переборе размеров размеров, начиная с конечного размера, размеры размеров должны быть либо равными, либо один из них равен 1, либо один из них не существует.

Конечный размер — это самое правое число при сравнении фигур.

На изображении выше можно увидеть общий процесс:

1. Определите, совместимы ли крайние правые размеры

  • Каждый ли тензор имеет хотя бы одно измерение?
  • Размеры одинаковые? Один из них один? Одного не существует?

2. Растяните размер до нужного размера

3. Повторите предыдущие шаги для следующего измерения.

Эти шаги можно увидеть в следующих примерах.

Элементарные операции

Все поэлементные операции требуют, чтобы тензоры имели одинаковую форму.

Векторный и скалярный пример

import torch
a = torch.tensor([1, 2, 3])
b = 2 # becomes ([2, 2, 2])

a * b
tensor([2, 4, 6])

В этом примере скаляр имеет форму (1,), а вектор имеет форму (3,). Как показано на изображении, b транслируется в форму (3,), и произведение Адамара выполняется так, как ожидалось.

Матрица и вектор, пример 1

В этом примере A имеет форму (3, 3), а bимеет форму ( 3,).

Когда происходит умножение, вектор растягивается по строкам для создания матрицы, которую можно увидеть на изображении выше. Теперь и A, и b имеют форму (3, 3).

Это можно увидеть ниже.

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

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

A * b
tensor([[ 1,  4,  9],
        [ 4, 10, 18],
        [ 7, 16, 27]])

Матрица и вектор, пример 2

В этом примере Aимеет форму (3, 3), а bимеет форму ( 3, 1).

Когда происходит умножение, вектор растягивается по столбцам, чтобы создать два дополнительных столбца, которые можно увидеть на изображении выше. Теперь и A, и b имеют форму (3, 3).

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

b = torch.tensor([[1], 
                  [2], 
                  [3]])
A * b
tensor([[ 1,  2,  3],
        [ 8, 10, 12],
        [21, 24, 27]])

Пример тензора и вектора

В этом примере A — это тензор формы (2, 3, 3), а b представляет собой вектор-столбец формы (3, 1).

A = (2, 3, 3)
b = ( , 3, 1)

Начиная с крайнего правого измерения, каждый элемент растягивается по столбцам для создания матрицы (3, 3). Средние размеры равны. На данный момент b — это просто матрица. Крайнего левого измерения не существует, поэтому необходимо добавить измерение. Затем матрица должна быть передана для создания размера (2, 3, 3). Теперь есть две (3, 3) матрицы, которые можно увидеть на изображении выше.

Это позволяет вычислить произведение Адамара и создать матрицу (2, 3, 3):

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

                  [[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]]])

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

A * b
tensor([[[ 1,  2,  3],
         [ 8, 10, 12],
         [21, 24, 27]],

        [[ 1,  2,  3],
         [ 8, 10, 12],
         [21, 24, 27]]])

Пример тензора и матрицы

В этом примере A — это тензор формы (2, 3, 3), а B является матрицей формы (3, 3).

A = (2, 3, 3)
B = ( , 3, 3)

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

При вычислении произведения Адамара результатом является (2, 3, 3).

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

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

A * B
tensor([[[ 1,  4,  9],
         [ 4, 10, 18],
         [ 7, 16, 27]],

        [[ 1,  4,  9],
         [ 4, 10, 18],
         [ 7, 16, 27]]])

Матричное и тензорное умножение с скалярным произведением

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

Для матричного умножения:

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

Для трехмерного тензорного умножения:

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

Для четырехмерного тензорного умножения:

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

Пример

В этом примере 𝓐 имеет форму (2, 3, 3), а Bимеет форму (3, 2). На данный момент последние два измерения подходят для умножения скалярного произведения. К B необходимо добавить измерение, а матрицу (3, 2) необходимо распространить по этому измерению, чтобы создать форму (2, 3, 2).

Результатом этого тензорного умножения будет (2, 3, 3) x (2, 3, 2) = (2, 3, 2).

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

B = torch.tensor([[1, 2], 
                  [1, 2], 
                  [1, 2]])

A @ B # A.matmul(B)
tensor([[[ 6, 12],
         [15, 30],
         [24, 48]],

        [[ 6, 12],
         [15, 30],
         [24, 48]]])

Дополнительную информацию о трансляции можно найти по ссылкам ниже. Подробнее о тензорах и их операциях можно прочитать здесь.

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

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

  1. NumPy-трансляция
  2. Трансляция PyTorch