Текст книги "Как устроен ChatGPT? Полное погружение в принципы работы и спектр возможностей самой известной нейросети в мире"
Автор книги: Стивен Вольфрам
Жанр: Программы, Компьютеры
Возрастные ограничения: +16
сообщить о неприемлемом содержимом
Текущая страница: 2 (всего у книги 7 страниц) [доступный отрывок для чтения: 2 страниц]
Что такое модель?
Предположим, что вы (подобно Галилею в конце 1500-х годов) хотите знать, сколько времени будет падать пушечное ядро, если сбросить его поочередно со всех этажей Пизанской башни. Вы можете просто замерить время в каждом конкретном случае и составить таблицу результатов. Или сделать то, что является сутью теоретической науки: создать модель, которая позволит вам вычислить ответ, вместо того чтобы проводить серию экспериментов и получать данные эмпирическим путем.
Давайте представим, что у нас есть (несколько усредненные) данные о том, сколько времени требуется пушечному ядру, чтобы долететь до земли при падении с разных этажей:
Как мы можем выяснить, сколько времени потребуется ядру, чтобы долететь до земли при падении с конкретного этажа, если не проводили эксперимент? В этом случае мы можем использовать известные законы физики. Но, допустим, все, что у нас есть, – это экспериментальные данные, и мы не знаем, какие основополагающие физические законы управляют движением ядра. Тогда мы могли бы сделать математическое предположение, например, что, возможно, нам следует использовать в качестве модели прямую линию:
Можно было бы провести разные прямые линии. Но эта линия в среднем ближе всего к полученным нами данным. И по этой прямой мы можем оценить время падения ядра с любого этажа.
Как мы поняли, что нужно провести прямую линию? Это следует из самых основ математики. Мы привыкли к тому, что множество эмпирически полученных данных хорошо описываются с помощью простых математических формул. Мы могли бы попробовать что-нибудь математически более сложное, скажем: a + bx + cx2, и тогда у нас получится следующее:
Однако результат может быть и не таким, как нам надо. Вот, например, что выйдет, если мы используем формулу a + b: x + c × sin(x):
Нужно понимать, что не существует модели без модели. То есть любая модель, которую вы используете, имеет определенную базовую структуру и набор параметров, которые вы можете установить и которые соответствуют вашим данным. И в случае с ChatGPT тоже используется множество параметров (на самом деле их 175 миллиардов).
Примечательно, что лежащая в основе ChatGPT структура (с таким «небольшим» количеством параметров) способна создавать модель, которая вычисляет вероятности следующего слова достаточно хорошо, чтобы у нас получились фрагменты текста размером с настоящее эссе.
Модели для человеческих задач
Пример, который мы привели выше, предполагает создание модели числовых данных, которая, по сути, основана на простой физике и старой доброй прикладной математике. Но для ChatGPT мы должны создать модель текста, который будет подобен тому, что написал бы человек. И для этого у нас нет (по крайней мере, пока) ничего похожего на базовую прикладную математику. Итак, что же это за модель?
Прежде чем мы поговорим о языке, давайте обсудим другую сугубо человеческую задачу – распознавание образов. И в качестве простого примера предлагаю рассмотреть изображения цифр (это классический пример машинного обучения):
Мы можем взять ряд изображений каждой цифры:
Затем, чтобы выяснить, соответствует ли изображение, полученное нами в качестве входных данных, определенной цифре, мы могли бы сравнить его с имеющимися у нас образцами пиксель за пикселем. Но мы, люди, выполняем эту задачу намного лучше, потому что способны распознать цифры, даже если они написаны от руки и имеют всевозможные модификации и искажения:
Создавая описанную выше модель для наших числовых данных, мы взяли определенное числовое значение x и просто вычислили a + bx для конкретных a и b. В данном случае, если мы определим цвет каждого пикселя как некую переменную xi, есть ли какая-то функция всех этих переменных, которая – при вычислении – скажет нам, какая цифра изображена в этом случае? Оказывается, такую функцию можно построить. Однако это не так-то просто. И типичный пример может включать в себя, возможно, полмиллиона математических операций.
Если мы введем весь набор значений пикселей в эту функцию, то на выходе появится число, указывающее, какая цифра изображена на рисунке. Далее мы поговорим о том, как можно сконструировать такую функцию, и о самом принципе работы нейронных сетей. Но пока давайте рассмотрим функцию как черный ящик, куда мы вводим изображения, скажем, рукописных цифр (в виде массивов значений пикселей), чтобы на выходе получить числа, которым они соответствуют:
In[]:= NetModel[][{}]
Out[]= {7, 0, 9, 7, 8, 2, 4, 1, 1, 1}
Но что на самом деле тут происходит? Допустим, мы постепенно начнем размывать изображение цифры (в нашем примере – цифры 2). Некоторое время наша функция все еще будет распознавать ее. Но вскоре функция начнет выдавать «неправильный» результат:
In[]:= NetModel[][{}]
Out[]= {2, 2, 2, 1, 1, 1, 1, 1, 1}
Но почему мы рассматриваем этот результат как неправильный? В данном случае мы знаем, что получили изображения, просто размыв цифру 2. Но если наша цель состоит в том, чтобы создать модель того, как люди распознают изображения, то нужно задать следующий вопрос: что сделал бы человек, не знающий, откуда взялись эти размытые изображения?
Наша модель может считаться хорошей, если результаты, которые выдает наша функция, совпадают с ответами человека. И мы знаем, как создавать функции для распознавания изображений, подобные этой.
Можем ли мы математически доказать, что эти модели работают? В целом – нет. Потому что для этого у нас должно быть математическое описание того, что делаем мы, люди. Возьмите изображение цифры 2 и измените в нем несколько пикселей. Мы можем представить, что с несколькими пикселями не на своих местах мы все равно сумеем считать изображение. Но как долго мы сможем передвигать пиксели и при этом распознавать изображение? Это вопрос зрительного восприятия человека. Ответ, без сомнения, был бы другим для пчел или осьминогов – и совершенно отличался для гипотетических инопланетян.
Нейронные сети
Итак, как же на самом деле работают типичные модели распознавания изображений? В настоящее время самый популярный – и успешный – подход задействует нейронные сети. Изобретенные в 1940-х годах (хотя их форма до сих пор очень близка к современной) нейронные сети можно рассматривать как упрощенное представление того, как, по-видимому, работает наш мозг.
В человеческом мозге находится около 100 миллиардов нейронов (нервных клеток), каждый из которых способен генерировать электрический импульс, возможно, до тысячи раз в секунду. Нейроны соединены в сложную сеть, причем каждый имеет древовидные отростки, позволяющие ему передавать электрические сигналы тысячам других нейронов. Электронный импульс зависит от того, какие импульсы данный нейрон получил от других, при этом разные связи имеют разный вес.
Когда мы видим некое изображение, происходит следующее: фотоны света, отразившиеся от изображения, попадают на особые клетки – фоторецепторы – в задней части глаза, после чего эти клетки передают импульс в виде электрического сигнала нервным клеткам. Эти нервные клетки соединены с другими нейронами, так что в итоге сигналы проходят через целый их ряд. Именно во время этого процесса распознается изображение, и в завершение формируется мысль о том, что мы видим цифру 2 (и, возможно, в конце мы произносим слово «два» вслух).
«Черный ящик» из предыдущего раздела является «математизированной» версией такой нейронной сети. Оказывается, она имеет одиннадцать слоев (четыре из которых считаются основными):
В этой нейронной сети нет ничего теоретически выведенного; все в 1998 году было сконструировано как часть инженерной разработки и оказалось работоспособным. (Это не сильно отличается от ситуации, когда мы описываем мозг как нечто созданное в ходе биологической эволюции.)
Хорошо, но как подобная нейронная сеть распознаёт изображения? Ключевым моментом является понятие аттрактора. Представьте, что у нас есть изображения рукописных цифр 1 и 2:
Мы как бы хотим, чтобы все единицы «притянулись» в одно место, а все двойки – в другое. Иными словами, если изображение больше похоже на единицу, чем на двойку, мы хотим, чтобы оно оказалось единицей, и наоборот. Эти «зоны притяжения» и называются аттракторами (от англ. attract – привлекать, притягивать).
В качестве простой аналогии предположим, что есть определенные позиции на плоскости, отмеченные точками (в реальной жизни это могут быть кафе, обозначенные на карте). Предположим, что, двигаясь из любого места, мы хотим оказаться в ближайшей к нам точке, то есть в ближайшем кафе. Мы можем представить эту плоскость разделенной на области – зоны аттракторов, разграниченные чем-то вроде водоразделов:
Это можно рассматривать как своего рода задачу на распознавание, где мы не пытаемся понять, на какую цифру похоже изображение, а стараемся увидеть, к какой точке определенная точка находится ближе всего.
(Диаграмма Вороного, которую мы здесь построили, разделяет точки в двумерном евклидовом пространстве; задачу распознавания цифр можно рассматривать как нечто очень похожее, но в 784-мерном пространстве, сформированном из уровней серого всех пикселей на каждом изображении.)
Итак, как мы можем заставить нейронную сеть «распознать» что-то? Давайте рассмотрим такой случай:
Наша цель состоит в том, чтобы получить входные данные, соответствующие позиции {x, y}, а затем «распознать» их, то есть отнести к той из трех точек, к которой они находятся ближе всего. Или, другими словами, мы хотим, чтобы нейронная сеть вычисляла функцию от {x, y} следующим образом:
Как же мы можем это сделать? В конечном счете нейронная сеть представляет собой связанную совокупность нейронов, обычно расположенных слоями. Простой пример выглядит так:
Каждый «нейрон» производит вычисление простой числовой функции. Чтобы задействовать всю сеть, мы просто вводим числа (например, наши координаты x и y) на самом верхнем слое, затем заставляем нейроны каждого следующего слоя вычислять простую числовую функцию и передавать результаты вычисления дальше по сети и в итоге в самом низу получаем:
В традиционной (вдохновленной биологией) установке каждый нейрон фактически имеет определенный набор входящих соединений от нейронов предыдущего уровня, причем каждому соединению присваивается вес, который может быть выражен положительным или отрицательным числом. Значение конкретного нейрона определяется путем умножения значений предыдущих нейронов на их веса, затем сложения результатов, далее добавления константы и, наконец, применения функции порогового значения (или активации). В математических терминах: если у нейрона есть входные данные x = {x1, x2 …}, то мы вычисляем f[wx + b], где обычно вес w и константа b выбираются по-разному для каждого нейрона в сети, а функция f не меняется.
Вычисление wx + b – это всего лишь вопрос умножения и сложения матриц. Функция активации f вводит нелинейность, и в конечном счете именно это приводит к нетривиальному поведению. Обычно используются различные функции активации (на иллюстрации ниже – их примеры). Здесь мы просто применим Ramp (или ReLU):
Для каждой задачи, которую нейронная сеть должна выполнить (или, что эквивалентно, для каждой общей функции, которую мы хотим вычислить), у нас будут разные варианты весов. И, как мы обсудим позже, эти веса обычно определяются путем «обучения» нейронной сети на примерах нужных нам выходных данных.
В конечном счете каждая нейронная сеть просто соответствует некоей общей математической функции (хотя ее может быть сложно записать). Для приведенного выше примера это была бы следующая запись:
Нейронная сеть ChatGPT так же просто реализует математическую функцию, подобную этой, но с миллиардами данных.
Однако давайте вернемся к отдельным нейронам. Вот несколько примеров функций, которые нейрон с двумя входными данными (представляющими координаты x и y) может вычислять при различных вариантах весов и констант (и Ramp в качестве функции активации):
Но как насчет более крупной сети сверху? Вот что у нас получается:
Это не совсем правильно, но близко к функции ближайшей точки, которую мы описали выше.
Давайте посмотрим, что происходит с некоторыми другими нейронными сетями. Как вы узнаете позднее, в каждом случае мы используем машинное обучение, чтобы найти наилучший выбор весов. Здесь мы можем увидеть, что вычисляет нейронная сеть с этими заданными весами:
Крупные сети, как правило, лучше выполняют эту функцию, и в центре каждого аттрактора мы обычно получаем именно тот ответ, который хотим. Но на границах – там, где нейронной сети «трудно принять решение», – ситуация может быть еще более запутанной.
При помощи простой с математической точки зрения задачи на распознавание мы получаем «правильный» ответ. Но в задаче на распознавание рукописных цифр все не так однозначно. Что, если кто-то написал цифру 2 так плохо, что она выглядит как 7? Тем не менее мы можем задаться вопросом, как нейронная сеть различает цифры, и вот как это может выглядеть:
Можем ли мы сказать, что сеть вычисляет различия математически? Не совсем. Математические вычисления – это то, что лежит в основе работы нейронной сети. Но оказывается, что способ того, как нейронная сеть находит различия, очень схож с тем, как это делаем мы, люди.
Давайте возьмем более сложный пример. Допустим, у нас есть изображения кошек и собак и нейронная сеть, которая была обучена различать их. Вот что сеть могла бы сделать с этими изображениями:
Теперь стало еще непонятнее, какой ответ правильный. А что насчет собаки, одетой в кошачий костюм? Какие бы входные данные ни вводились, нейронная сеть генерирует ответ. И, как выясняется, она делает это таким образом, что ее ответ очень похож на тот, который мог бы дать человек. Как уже упоминалось выше, мы не можем логически вывести этот факт из теоретических положений. Это просто то, что эмпирически было признано верным, по крайней мере в определенных областях. Но это ключевая причина, по которой нейронные сети полезны: они каким-то образом воспроизводят человеческие действия.
Возьмите фотографию кошки и спросите самого себя: «Почему это кошка?» Возможно, вы начнете так: «Ну, я вижу заостренные уши», – и так далее. Не очень-то легко объяснить, как вы распознали на изображении кошку. Просто ваш мозг каким-то образом догадался об этом. Но у нас нет возможности (по крайней мере, пока) заглянуть внутрь мозга и понять, как он это сделал. Как насчет искусственной нейронной сети? Что ж, несложно увидеть, что делает каждый нейрон, когда вы загружаете в сеть фотографию кошки. Но получить даже базовую визуализацию уже очень сложно.
В сети выше, которую мы использовали для нахождения ближайшей точки, насчитывается 17 нейронов. В сети для распознавания рукописных цифр 2190 нейронов. А в сети, которую мы используем для распознавания кошек и собак, их 60 650. В обычной жизни было бы довольно сложно визуализировать то, что составляет 60650-мерное пространство. Но поскольку эта сеть создана для работы с изображениями, то многие из слоев нейронов организованы в массивы, подобные массивам пикселей, которые сеть визуализирует.
Возьмем типичное изображение кошки:
Мы можем представить состояние нейронов на первом слое с помощью набора производных изображений, многие из которых легко интерпретировать как «кошка без фона» или «контур кошки»:
На десятом слое уже довольно тяжело интерпретировать картинку:
Но в целом мы могли бы сказать, что нейронная сеть «выделяет некоторые черты» (возможно, среди них есть и заостренные уши) и использует их для определения того, что находится на изображении. Однако можно спросить, те же ли это черты, которые выделяем мы, люди? По большей части нет.
Использует ли наш мозг аналогичные функции? Мы этого не знаем. Но примечательно, что первые несколько слоев нейронной сети, подобной той, которую мы показываем здесь, похоже, выделяют аспекты изображений (например, края объектов), которые кажутся похожими на те, которые, как известно, наш мозг выделяет первыми при обработке визуальной информации.
Но давайте предположим, что нам нужно создать «теорию распознавания кошек» нейронными сетями. Мы можем сказать: «Смотрите, целая отдельная сеть только распознает кошек», – и это дает нам некоторое представление о том, насколько проблема сложная (и, например, о том, сколько нейронов или их слоев может потребоваться). Но – по крайней мере на данный момент – мы не можем дать словесного описания того, что именно делает сеть. Вероятно, причина заключается в том, что это действительно невозможно определить и нет другого способа узнать, что делает сеть, кроме как просто проследить за каждым этапом ее работы. Или, может быть, дело в том, что мы еще не разобрались, как работают нейросети, и не определили те законы, которые ими управляют.
Мы столкнемся с такими же проблемами, когда будем говорить о создании языка с помощью ChatGPT. И снова неясно, существуют ли способы обобщить то, что делает сеть. Но богатство и детализация языка (и наш опыт работы с ним) могут позволить нам продвинуться дальше, чем у нас это получилось с изображениями.
Машинное обучение нейронных сетей
Ранее мы говорили о нейронных сетях, которые «уже знают», как выполнять определенные задачи. Но что делает нейронные сети настолько полезными, так это способность не только выполнять всевозможные задачи, но и постепенно обучаться на различных примерах (в этом нейросети очень похожи на нас).
Когда мы создаем нейронную сеть, способную отличать кошек от собак, нам не нужно писать программу, которая, скажем, обнаруживает усы. Вместо этого мы просто показываем множество примеров того, что такое кошка и что такое собака, а затем заставляем сеть «учиться» на этих примерах.
Обученная сеть «обобщает» приметы кошек и собак, исходя из конкретных примеров, которые мы ей даем. Как мы видели выше, дело не просто в том, что сеть распознаёт конкретный пиксельный рисунок изображения кошки. Скорее, нейронная сеть как-то умудряется различать изображения на основе того, что мы, люди, считаем общими кошачьими приметами.
Итак, как же на самом деле происходит обучение нейронной сети? По сути, то, что мы пытаемся сделать, – это найти веса, которые позволят нейронной сети успешно воспроизводить примеры, которые мы ей дали. И затем нейронная сеть интерполирует (обобщает) эти примеры «разумным» способом.
Давайте рассмотрим простой пример. Наша задача – заставить нейронную сеть изучить эту функцию:
Для этой задачи нам понадобится сеть, которая имеет только один вход и один выход, как показано здесь:
Но какие веса мы должны использовать? При каждом весе нейронная сеть вычисляет некую функцию. Например, вот что она делает с несколькими случайно выбранными наборами весов:
Как мы видим, ни в одном из этих случаев сеть даже близко не воспроизводит нужную нам функцию. Итак, как нам найти веса, которые будут воспроизводить заданную функцию?
Основная идея состоит в том, чтобы предоставить множество примеров ввода/вывода, на которых можно «учиться», а затем попытаться найти веса, которые будут их воспроизводить. Вот результат, который мы получим, если будем постепенно увеличивать количество примеров для обучения сети:
На каждом этапе этого обучения веса в сети постепенно корректируются, и мы видим, что в итоге получается сеть, которая успешно воспроизводит нужную функцию. Итак, как нам отрегулировать вес? Основная идея заключается в том, чтобы на каждом этапе проверять, насколько мы далеки от получения желаемой функции, а затем обновлять веса таким образом, чтобы приблизиться к ней.
Для того чтобы выяснить, насколько далеко находимся от желаемой функции, мы вычисляем то, что обычно называется функцией потерь (или функцией стоимости). Здесь мы используем простую функцию потерь (L2), которая представляет собой сумму квадратов разностей между полученными и истинными значениями. Мы видим, что по мере продвижения процесса обучения функция потерь постепенно уменьшается (следуя кривой обучения, которая различается для разных задач), пока мы не достигнем точки, где сеть (по крайней мере, в хорошем приближении) успешно воспроизводит нужную нам функцию:
Последняя важная часть, которую необходимо объяснить, – это корректировка весов для уменьшения функции потерь. Как мы уже говорили, функция потерь дает нам «расстояние» между полученными и истинными значениями. Но полученные значения на каждом этапе определяются текущей версией нейронной сети и весами в ней. А теперь представьте, что веса являются переменными – скажем, wi. Мы хотим выяснить, как скорректировать значения этих переменных, чтобы минимизировать потери, которые от них зависят.
Например, предположим, что у нас есть только два веса: w1 и w2 (это очень упрощенная нейронная сеть по сравнению с теми, которые используются на практике). Тогда у нас могла бы быть потеря, которая в зависимости от w1 и w2 выглядит следующим образом:
Численный анализ предоставляет множество методов для нахождения минимума в подобных случаях. Но наиболее распространенный подход заключается в том, чтобы просто постепенно следовать по пути самого крутого спуска от любых предыдущих w1 и w2, которые у нас были:
Подобно воде, стекающей с горы, эта процедура закончится на некотором локальном минимуме (так сказать, в горном озере), и вполне возможно, что мы так и не достигнем глобального минимума.
Не всегда очевидно, где находится самый крутой спуск на подобном весовом ландшафте. Но здесь нам на помощь приходит математический анализ. Как уже упоминалось выше, мы можем представить нейронную сеть как вычисление математической функции, которая зависит от ее входных данных и их весов. Но теперь давайте рассмотрим дифференциацию в зависимости от этих весов. Оказывается, цепное правило математического анализа позволяет нам распутывать операции, выполняемые последовательными слоями нейронной сети. И в результате мы можем – по крайней мере в некотором локальном приближении – инвертировать работу нейронной сети и постепенно находить веса, которые минимизируют потери выходных данных.
На рисунке выше показан вид минимизации, который нам, возможно, потребуется выполнить в нереалистично простом случае всего с двумя весами. Но оказывается, что даже при гораздо большем количестве весов (ChatGPT использует 175 миллиардов) все еще возможно выполнить минимизацию, по крайней мере до некоторого уровня приближения. И на самом деле большой прорыв в «глубоком обучении», произошедший примерно в 2012 году, был связан с открытием того, что в каком-то смысле легче выполнить минимизацию (по крайней мере, приблизительно), когда задействовано много весов, чем когда их мало.
Другими словами – несколько нелогично, – с помощью нейронных сетей легче решать более сложные задачи, чем простые. И причина, по-видимому, заключается в том, что, когда мы имеем много весовых переменных, у нас есть многомерное пространство со множеством направлений, которые могут привести нас к минимуму, тогда как при меньшем количестве переменных легче застрять в локальном минимуме («горном озере») без возможности из него выбраться.
Стоит отметить, что в типичных случаях существует множество различных наборов весов, которые составляют нейронные сети почти с одинаковой производительностью. И обычно при практическом обучении нейронной сети составляется множество случайных наборов весов, которые приводят к разным, но эквивалентным решениям, подобным представленным ниже:
Однако каждое «другое решение» будет иметь немного иное поведение. И если мы попросим нейросеть, скажем, экстраполировать его за пределы области, в границах которой приводили обучающие примеры, то можем получить совершенно разные результаты:
Но какой из них «правильный»? На самом деле сказать сложно. Все эти результаты «согласуются с наблюдаемыми данными», но все соответствуют разным «врожденным» способам нейронной сети «думать о том», что значит выполнять задачу «нестандартно». И некоторые из них могут казаться нам, людям, «более разумными», чем другие.
Внимание! Это не конец книги.
Если начало книги вам понравилось, то полную версию можно приобрести у нашего партнёра - распространителя легального контента. Поддержите автора!Правообладателям!
Данное произведение размещено по согласованию с ООО "ЛитРес" (20% исходного текста). Если размещение книги нарушает чьи-либо права, то сообщите об этом.Читателям!
Оплатили, но не знаете что делать дальше?