Как нейросети обучаются на примерах
Мнение редакции может не совпадать с мнением автора
Редакция Nature включила в список 10 героев 2023 года Илью Суцкевера — одного из создателей ChatGPT. Чат-боту, который, по словам редакторов, может «открыть новую эру в науке», журнал отдал бонусное 11 место. В книге «Как устроен ChatGPT? Полное погружение в принципы работы и спектр возможностей самой известной нейросети в мире» (издательство «Манн, Иванов и Фербер»), переведенной на русский язык Еленой Быковой, математик Стивен Вольфрам рассказывает, что позволяет сервису, в основе которого лежит большая языковая модель, вести с пользователями беседы и генерировать тексты, которые вполне мог бы написать человек. Предлагаем вам ознакомиться с фрагментом о том, как обучаются нейронные сети.
Ранее мы говорили о нейронных сетях, которые «уже знают», как выполнять определенные задачи. Но что делает нейронные сети настолько полезными, так это способность не только выполнять всевозможные задачи, но и постепенно обучаться на различных примерах (в этом нейросети очень похожи на нас).
Когда мы создаем нейронную сеть, способную отличать кошек от собак, нам не нужно писать программу, которая, скажем, обнаруживает усы. Вместо этого мы просто показываем множество примеров того, что такое кошка и что такое собака, а затем заставляем сеть «учиться» на этих примерах.
Обученная сеть «обобщает» приметы кошек и собак, исходя из конкретных примеров, которые мы ей даем. Как мы видели выше, дело не просто в том, что сеть распознаёт конкретный пиксельный рисунок изображения кошки. Скорее, нейронная сеть как-то умудряется различать изображения на основе того, что мы, люди, считаем общими кошачьими приметами.
Итак, как же на самом деле происходит обучение нейронной сети? По сути, то, что мы пытаемся сделать, — это найти веса, которые позволят нейронной сети успешно воспроизводить примеры, которые мы ей дали. И затем нейронная сеть интерполирует (обобщает) эти примеры «разумным» способом.
Давайте рассмотрим простой пример. Наша задача — заставить нейронную сеть изучить эту функцию:
Для этой задачи нам понадобится сеть, которая имеет только один вход и один выход, как показано здесь:
Но какие веса мы должны использовать? При каждом весе нейронная сеть вычисляет некую функцию. Например, вот что она делает с несколькими случайно выбранными наборами весов:
Как мы видим, ни в одном из этих случаев сеть даже близко не воспроизводит нужную нам функцию. Итак, как нам найти веса, которые будут воспроизводить заданную функцию?
Основная идея состоит в том, чтобы предоставить множество примеров ввода/вывода, на которых можно «учиться», а затем попытаться найти веса, которые будут их воспроизводить. Вот результат, который мы получим, если будем постепенно увеличивать количество примеров для обучения сети:
На каждом этапе этого обучения веса в сети постепенно корректируются, и мы видим, что в итоге получается сеть, которая успешно воспроизводит нужную функцию. Итак, как нам отрегулировать вес? Основная идея заключается в том, чтобы на каждом этапе проверять, насколько мы далеки от получения желаемой функции, а затем обновлять веса таким образом, чтобы приблизиться к ней.
Для того чтобы выяснить, насколько далеко находимся от желаемой функции, мы вычисляем то, что обычно называется функцией потерь (или функцией стоимости). Здесь мы используем простую функцию потерь (L2), которая представляет собой сумму квадратов разностей между полученными и истинными значениями. Мы видим, что по мере продвижения процесса обучения функция потерь постепенно уменьшается (следуя кривой обучения, которая различается для разных задач), пока мы не достигнем точки, где сеть (по крайней мере, в хорошем приближении) успешно воспроизводит нужную нам функцию:
Последняя важная часть, которую необходимо объяснить, — это корректировка весов для уменьшения функции потерь. Как мы уже говорили, функция потерь дает нам «расстояние» между полученными и истинными значениями. Но полученные значения на каждом этапе определяются текущей версией нейронной сети и весами в ней. А теперь представьте, что веса являются переменными — скажем, wi. Мы хотим выяснить, как скорректировать значения этих переменных, чтобы минимизировать потери, которые от них зависят.
Например, предположим, что у нас есть только два веса: w1 и w2 (это очень упрощенная нейронная сеть по сравнению с теми, которые используются на практике). Тогда у нас могла бы быть потеря, которая в зависимости от w1 и w2 выглядит следующим образом:
Численный анализ предоставляет множество методов для нахождения минимума в подобных случаях. Но наиболее распространенный подход заключается в том, чтобы просто постепенно следовать по пути самого крутого спуска от любых предыдущих w1 и w2, которые у нас были:
Подобно воде, стекающей с горы, эта процедура закончится на некотором локальном минимуме (так сказать, в горном озере), и вполне возможно, что мы так и не достигнем глобального минимума.
Не всегда очевидно, где находится самый крутой спуск на подобном весовом ландшафте. Но здесь нам на помощь приходит математический анализ. Как уже упоминалось выше, мы можем представить нейронную сеть как вычисление математической функции, которая зависит от ее входных данных и их весов. Но теперь давайте рассмотрим дифференциацию в зависимости от этих весов. Оказывается, цепное правило математического анализа позволяет нам распутывать операции, выполняемые последовательными слоями нейронной сети. И в результате мы можем — по крайней мере в некотором локальном приближении — инвертировать работу нейронной сети и постепенно находить веса, которые минимизируют потери выходных данных.
На рисунке выше показан вид минимизации, который нам, возможно, потребуется выполнить в нереалистично простом случае всего с двумя весами. Но оказывается, что даже при гораздо большем количестве весов (ChatGPT использует 175 миллиардов) все еще возможно выполнить минимизацию, по крайней мере до некоторого уровня приближения. И на самом деле большой прорыв в «глубоком обучении», произошедший примерно в 2012 году, был связан с открытием того, что в каком-то смысле легче выполнить минимизацию (по крайней мере, приблизительно), когда задействовано много весов, чем когда их мало.
Другими словами — несколько нелогично, — с помощью нейронных сетей легче решать более сложные задачи, чем простые. И причина, по-видимому, заключается в том, что, когда мы имеем много весовых переменных, у нас есть многомерное пространство со множеством направлений, которые могут привести нас к минимуму, тогда как при меньшем количестве переменных легче застрять в локальном минимуме («горном озере») без возможности из него выбраться.
Стоит отметить, что в типичных случаях существует множество различных наборов весов, которые составляют нейронные сети почти с одинаковой производительностью. И обычно при практическом обучении нейронной сети составляется множество случайных наборов весов, которые приводят к разным, но эквивалентным решениям, подобным представленным ниже:
Однако каждое «другое решение» будет иметь немного иное поведение. И если мы попросим нейросеть, скажем, экстраполировать его за пределы области, в границах которой приводили обучающие примеры, то можем получить совершенно разные результаты:
Но какой из них «правильный»? На самом деле сказать сложно. Все эти результаты «согласуются с наблюдаемыми данными», но все соответствуют разным «врожденным» способам нейронной сети «думать о том», что значит выполнять задачу «нестандартно». И некоторые из них могут казаться нам, людям, «более разумными», чем другие.
Подробнее читайте:
Вольфрам, Стивен. Как устроен ChatGPT? Полное погружение в принципы работы и спектр возможностей самой известной нейросети в мире / Стивен Вольфрам ; пер. с англ. Елены Быковой ; науч. ред. А. Здоров. — Москва : МИФ, 2024. — 192 c. — (Цифровые технологии).