Матрично-векторные произведения через оператор @
Содержание курса
Правило согласования внутренних размеров
Прежде чем запускать @, полезно уметь предсказать результат только по форме операндов — без вычислений.
В этом уроке мы работаем с одно- и двумерными массивами, и для них правило звучит так: последняя ось левого операнда должна совпадать с предпоследней (или единственной, если правый операнд — вектор) осью правого. Именно эти два числа называют «внутренними размерами» — они как бы смотрят друг на друга в записи (m, k) @ (k, n). Если они равны, операция пройдёт. Если нет — ValueError.
Shape результата определяется «внешними» размерами — теми, что остались после сокращения внутренних:
(m, k) @ (k, n)→(m, n)— внутренний размерk«схлопывается», остаётся(m, n)(m, k) @ (k,)→(m,)— вектор shape(k,)не имеет второго измерения, поэтому результат одномерный(n,) @ (n,)→ скаляр shape()— оба измерения «схлопываются», ничего не остаётся
Чтобы проверить совместимость до запуска, достаточно выписать оба shape и мысленно поставить их рядом:
(2, 3) @ (3, 4) → внутренние: 3 == 3 ✓ → результат (2, 4) (2, 3) @ (3,) → внутренние: 3 == 3 ✓ → результат (2,) (2, 3) @ (2, 3) → внутренние: 3 ≠ 2 ✗ → ValueError
Обратите внимание: @ — не поэлементная операция и не broadcasting в том смысле, который мы разбирали в прошлом уроке. Правило внутренних размеров работает независимо от того, насколько похожи формы массивов в целом. Матрицы (2, 3) и (2, 3) имеют одинаковый shape — но перемножить их через @ нельзя, потому что внутренние размеры 3 и 2 не совпадают.
Примечание. Для трёхмерных и выше массивов
np.matmulприменяет то же правило к двум последним осям каждого операнда, а ведущие («пакетные») измерения согласуются по правилам broadcasting. Например,(5, 2, 3) @ (5, 3, 4)корректно даёт(5, 2, 4). В этом уроке мы не углубляемся в пакетное умножение — достаточно знать, что оно существует и работает согласованно с изученным правилом.
