Модуль: PyTorch. Теория: как обучается нейросеть


Операции, формы и broadcasting


Войдите на сайт, чтобы ответы сохранялись и баллы за тетрадь засчитывались.

Как из признаков получаются новые значения

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

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



В левом верхнем углу результата A * B находится число 5, потому что 1 · 5 = 5. В той же позиции результата A @ B стоит 19: мы вычислили 1 · 5 + 2 · 7. Число 22 справа от него получилось из той же строки первой матрицы и уже другого столбца второй: 1 · 6 + 2 · 8. Поэтому матричное умножение удобно для слоя, в котором каждый выход собирает собственную взвешенную сумму входов.

Пусть у четырёх объектов по три признака. Тогда форма X равна (4, 3). Если мы хотим вычислить по два новых значения для каждого объекта, в ручной записи X @ W нужна матрица W формы (3, 2). Совпадающее внутреннее число 3 указывает, сколько произведений нужно сложить. В результате останутся четыре объекта и два выхода, то есть форма (4, 2).



Все входы и веса здесь равны единице, поэтому каждый выход равен трём: в его вычислении участвовали три произведения 1 · 1. Количество объектов при этом не изменилось. Мы преобразовали признаки каждого объекта, а не смешали разные объекты между собой. Этот смысл форм пригодится, когда вместо единиц появятся реальные пиксели и обучаемые веса.

Как одно смещение применяется ко всем объектам

После взвешенной суммы обычно прибавляют смещение. У каждого выходного нейрона своё смещение, но для разных объектов используются одни и те же параметры слоя. Поэтому к таблице из нескольких строк хочется прибавить один вектор. PyTorch умеет делать это благодаря механизму broadcasting — согласованию форм при операции. Он позволяет трактовать вектор смещений так, будто тот повторён для каждой строки, без необходимости вручную составлять большую таблицу.



Первая строка превращается в [11, 22, 33], вторая — в [14, 25, 36]. В обоих случаях к первому столбцу прибавлено 10, ко второму 20, к третьему 30. Для проверки совместимости PyTorch сравнивает размеры осей справа налево. Они должны совпадать либо один из размеров должен равняться единице; недостающие слева оси мысленно имеют размер 1. Так формы (5, 1, 4) и (3, 4) совместимы и дают (5, 3, 4). Это правило говорит о возможности вычисления, но его осмысленность всё равно проверяет человек.

Иногда нам нужно двигаться в обратную сторону — заменить несколько чисел одним итогом. Например, найти сумму по каждому признаку или среднюю величину признаков одного объекта. Аргумент dim указывает ось, вдоль которой выполняется свёртка. В двумерной таблице dim=0 перебирает строки, поэтому итог остаётся для каждого столбца. При dim=1 перебираются столбцы, и итог получается для каждой строки.



Сумма по оси 0 равна [5, 7, 9]: в первом столбце сложены 1 и 4, во втором 2 и 5, в третьем 3 и 6. Средние по оси 1 равны [2, 5], по одному числу для каждой строки. Эти же правила позволяют вычесть из каждого признака его среднее по объектам: X - X.mean(dim=0). Сначала возникает вектор средних, затем broadcasting применяет его к каждой строке.

Сами оси тоже можно переорганизовать. Уже знакомый reshape меняет форму с сохранением порядка элементов при обходе массива, а flatten объединяет измерения. Транспонирование двумерной матрицы, записанное как A.T, меняет местами строки и столбцы. Это другое действие: оно переставляет роли осей. По этой причине одинаковый размер результата ещё не доказывает, что два преобразования сделали одно и то же.



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

Почему работающий код может считать не то

Особенно внимательно нужно сопоставлять предсказания и правильные ответы. Если три предсказания записаны столбцом формы (3, 1), а три ответа — вектором формы (3,), их разность допустима по правилам broadcasting. Однако результатом станет таблица (3, 3): каждое предсказание сравнилось с каждым ответом. Никакой ошибки выполнения не возникнет, хотя попарное сравнение, которое нам требовалось, не состоялось.



Команда y.reshape(-1, 1) превращает ответы в столбец. Число -1 просит библиотеку самой вычислить размер этой оси по общему количеству элементов. После преобразования формы совпадают, и разность состоит из трёх нулей: первый ответ сравнен с первым предсказанием и так далее. Проверка assert закрепляет это требование в коде. Привычка сначала объяснить формы, а уже потом доверять результату пригодится нам и при вычислении ошибки, и при обучении сети.

Проверим понимание

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


Чему равна форма суммы (5,1,4) + (3,4)?


В форме (8,4) строки — объекты. Как центрировать каждый признак: вычесть среднее его столбца?