Магарето никога не удря два пъти главата си в един и същи камък. И изглежда това е нещо общо, което ChatGPT и магаретата имат: ChatGPT не е глупак, той не винаги прави една и съща грешка. Вместо това прави различна грешка всеки път. хубаво? Опитайте се да го принудите винаги да прави една и съща грешка. Гадно: това просто не е възможно.

Наблюдаваме, че Generative API-извикваемите модели на OpenAI (DALL-E, ChatGPT, …) не могат да бъдат контролирани да действат детерминистично. С други думи: те дават противоречиви резултати, дори когато температурата им, параметърът, който контролира тяхната „креативност“, е набрана на нула. Повече информация за temperature можете да намерите в документацията за OpenAI API. Вместо да предлага решения, тази публикация в блога цели да обясни това поведение. Защото знанието е сила, нали?

Но колко уместно е това наистина? Този въпрос възниква ли редовно? Очевидно; да В момента той оглавява списъка на списъка с често задавани въпроси на OpenAI GPT.

Вероятно, ако изграждате приложение, което разчита на изхода на GPT-модел, вие (поне във фаза на тестване) искате да можете да накарате модела да се държи детерминистично, така че да можете да разчитате на възпроизводимо поведение за някои степен. Например:

  • (Генеративен език) Контекст на GPT:
    искате да покажете на шефа си, че вашият „управляван генератор на Angular код“доставя правилния блок код за определена заявка в 100% от времето.
  • (Generative Vision) Контекст на DALL-E:
    искате да покажете на колегите си, че вашата подкана предоставя точно същото прекрасно изображение на „плодов сок в купа за супа“както направи вчера, когато вие работехте по маркетинга на щанда за лимонада на вашия син.

Но достатъчно въведение, тъй като ценим както структурата, така и прекомерното раздуване на нещата, сега ще анализираме конкретно поведението на GPT моделите, като ви преведем от наблюдениепрез разбиране къмобяснение. Тук трябва да навлезем в доста детайли, но чрез опростена визуализация се надяваме да облекчим нуждата от каквото и да е знание за сложни математически концепции. Ура за опростяванията!

Наблюдението

За да обобщим отново, въпросът, на който ще отговорим тук, се свежда до следното:

„защо не получавам постоянно едни и същи отговори от повикване към всеки OpenAI Generative API, когато температурата е 0?

Обърнете внимание, че докато могат да бъдат намерени подходящи дискусии и ресурси по тази тема;

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

Разбирането

„Трудно е да се разбере как точно работи системата за черна кутия. Но ако черната кутия е еволюирала от кутии, които са, знаете, по-малко черни и по-прозрачни, тогава все още могат да се направят някои предположения за качество.”
- някой, в даден момент от времето, вероятно

Както става ясно от фалшивия цитат по-горе: не можем да знаем точно как LLMs със затворен код (големи езикови модели) ChatGPT или GPT-4 работят под капака (напр. хартиен GPT-4). Но от техните по-прозрачни предшественици (напр. „хартия GPT-2“ [2] и „код“ с отворен код) и конкуренти с отворен код (напр. „хартия LLaMA“), ние знаем същността на съответната архитектура, базирана на трансформатор.

По-долу увеличаваме частите от архитектурата, които смятаме за най-подходящи за наблюдение на недетерминирано поведение. Чувствайте се свободни бързо да прегледате това и да преминете към секцията „Обяснение“, ако сте запознати с основите на архитектурата на текстовите генериращи модели.

Как моделът доставя изходен текст?

Първо; едно изводно преминаване напред през мрежата на LLM доставя единичен „токен“, който представлява „най-подробната единица текст, която моделът разбира“ (може да се разглежда като сричка, но може също толкова добре да представлява дума като цяло). В името на тълкуемостта, ние считаме, че всеки „токен“ в нашата история представлява цяла дума. Това опростяване не оказва влияние върху по-нататъшните заключения.

Като се има предвид това, LLM мрежата има речник от токени и чрез своето привидно магическо разбиране на въведения текст, тя е много добра в посочването кои токени от нейния речник е най-вероятно да следват дадения вход. Тази индикация се осъществява чрез (вижте чертежа по-горе) присвояване на вероятности. Например P(token_0) представлява изчислената вероятност думата дъвчене (представена от token_0) да следва дадената последователност от входни токени ( the cow is …). Вероятността за думата боулинг(представена от token_50.256) се надяваме, че е по-ниска от тази за думата дъвченеили паша в този контекст.

Подчертаваме, че за да може LLM да генерира пълна поредица от текст, той трябва итеративно да премине през мрежата няколко пъти: всяко преминаване напред служи за избиране на точно един токен, който от своя страна допринася за определянето на следващия токен.

Решаващата част от пъзела сега идва от това как само един изходен токен е избран с помощта на този списък с вероятности за токени. По-долу се потапяме накратко в света на пробата. За по-разширено разбиране на методите за вземане на проби препоръчваме да прочетете тази публикация в блога на Hugging Face.

Вземане на проби от най-висок клас: Вземане на проби от най-висок клас

Съвременните LLM използват (вариант на) вземане на проби от най-високо ниво (т.е. вземане на проби от ядра, въведено в тази документация от 2018 г.) за вземане на проби от отговора. Този метод разглежда само токените, чиято кумулативна вероятност надвишава вероятността p и след това преразпределя вероятностната маса между останалите символи, така че сумата от вероятностите да е 1. Ако сега си мислите „чакайте какво“, поздравления, вие не сте статистик! Чувствайте се свободни да прочетете отново това изречение и след това преминете към по-разбираемото визуално обяснение по-долу:

Кажете, че сме задали p=0.92. При първото преминаване, започвайки само от думата "the”, имаме нужда от 6 токена, за да надхвърлим тази вероятност от 92% (сумата им е 94%). Можем да вземем извадка от токен от тези шест думи, като вземем предвид техните преразпределени вероятности (където думата nice ще има най-голям шанс да бъде избрана). За следващото преминаване откриваме, че 3-те най-вероятни токена заедно вече лесно надхвърлят прага от 92% и по този начин евентуалният токен се взема извадка само от тези три.

Хубавото е, че количеството токени за динамично вземане на проби зависи от нивото на „несигурност“ на модела. Ако моделът прецени, че малко подмножество от токени е най-уместно (например защото входните токени се състоят от "the", "car", което ограничава контекста), той ще взема проби само от тях.

Уместен анекдот: преди няколко години в ML6 създадохме основен „резюме за условия и условия“, който случайно генерира думата „мляко“ в резюме и напълно се измести към говорене за храна, само защото не не използвайте вземане на проби от ядра.

Тогава какво е контрол на температурата?

Добре, толкова хубаво, вече разбираме за какво се отнася параметърът top_p от документацията на OpenAI API. Обърнете внимание, че по подразбиране този параметър задава p=100%, което означава, че всички изходни токени се вземат предвид. Ако от друга страна p=0%, винаги ще бъде избран първият токен за проверка, който алгоритмично е този с най-висока вероятност, тъй като незабавно превишава супер ниския праг сам по себе си.

Добре, но каква роля играе параметърът temperature?

Представете си, че имате набор от изходни токени (вероятно с преразпределена вероятност, ако играете с параметъра top_p), за да вземете проби от:

Това, което прави температурата е: тя контролира относителните тегла във вероятностното разпределение. Контролира степента, до която разликите във вероятностите играят роля в извадката. Вземете примера по-горе: за входната последователност на токени "The” бихме (по подразбиране) очаквали думата nice да има 75% шанс да бъде избрана P(“nice”)=75%. Това се случва при температура t=1. Този параметър може да се избира между 0 и 2.

При температура t=0 тази техника за вземане на проби се превръща в това, което наричаме алчно търсене/аргмакс вземане на пробикъдето винаги се избира токенът с най-висока вероятност(тук: P(“nice”)=100% ).

При температура t=2 разликата между по-вероятните и по-малко вероятните токени се намалява по време на пробното време. За примера вляво по-горе това ще доведе до: P("nice")=58% , P("dog")=32% , P("car")=10%.

За тези, които се интересуват, формулата за изчисляване на вероятностите за вземане на проби, повлияни от температурата t, е добавена по-долу (където K представлява общото количество токени, взети предвид при вземането на проби):

Заключение: тайните са изчезнали

Вече можете да се смятате за истински воин на Generative APIs на OpenAI, защото извлечението по-долу вече няма тайни за вас.
Обърнете внимание на изявлението „като цяло препоръчваме да промените това или top_p/temperature, но не и двете“. И това е само предложение да запазите промените си повече или по-малко интерпретируеми, докато си играете със стойностите. Задаването на която и да е от тези стойности на техните детерминистични граници (т.е. p=0 или top_p=0) има същия ефект.

Помним, че: по подразбиране вземането на проби се извършва в целия речник на токена (top_p=1) и вероятностното разпределение остава незасегнато (temperature=1).

Обяснението

Разполагайки със знанията по-горе, ние знаем точно какво трябва да се случи, ако поправим temperature=0. А именно: ще бъде избран един токен с най-вероятна вероятност.

Но какво ще стане, ако в даден момент по време на генерирането светкавица удари ⚡ и два токена получат точно същата вероятност?

Може да удари мълния: ненулев шанс

Този случай на поне два токена с еднаква вероятност може да изглежда малко вероятен, но има някои фактори, които допринасят за неговата не толкова малка вероятност:

  • Несигурност на модела: в случаите, когато моделът далеч не е сигурен, че един токен е идеалният избор за следващия токен, шансовете токените, които са сред предпочитаните, да имат подобни вероятности, са по-високи.
  • Ограничена точност: шансовете две вероятности да бъдат абсолютно еднакви намаляват с количеството битове, които се използват за представянето им. Ако имате: 1 бит = 2 възможни числа, 2 бита = 4 възможни числа, 8 бита = 256 възможни числа. Ако имате само 8 бита, за да представите число в мрежа (което е резултат от сбор от умножения от други 8-битови числа), шансовете резултатите да бъдат абсолютно еднакви са по-големи, отколкото когато имате 32 бита на всяка стъпка по пътя. Отбелязваме, че ако се правят избори на квантуване, за да се оптимизира скоростта и цената на извода, прецизността на представените числа е допълнително ограничена.
  • Forward Pass Bonanza: с количеството жетони, обикновено необходими за конструиране на подходящ отговор, шансът за удар от мълния непрекъснато нараства. Ако Pᵢ е вероятността това да се случи за едно преминаване напредi, тогава общият шанс това да се случи е сумата от тази вероятност за всички преминавания напред, необходими за генериране на общия отговор. Като опростен пример, представете си фиксирани шансове за удряне на мълния P_i=0.0001%, тогава за отговор, който се нуждае от 200 преминавания през мрежата, шансовете за удряне на мълния за целия отговор ще бъдат P=0.02%, което не е твърде малко.

И разбира се отбелязваме, че мълнията трябва да удари само веднъж, за да промени цялото генеративно поведение; ако друг токен бъде избран веднъж, тогава вероятността за следване на напредващи преминавания ще бъде пряко засегната, което ще доведе до различен „път на отговор“. Можете да си представите, че получаването на думата „мляко“ веднъж води до напълно различно резюме на правилата и условията.

Добре, значи мълнията може да удари ⚡. Но какво ще стане, ако стане?

Тогава очевидният следващ въпрос е: ако два токена наистина имат точно една и съща вероятност, какво се случва след това?

Е, когато компютрите трябва да направят избор между набор от еднакво валидни/вероятни опции, решаващата сила за „хвърляне на монета“ се предава на семена. Семена контролира стойност на генератор на псевдослучайни числа. По-интуитивно опростяване е показано по-долу.

Следователно очакваме тези семена да повлияят на начина, по който се обработват ⚡-ситуации. Обикновено, когато хоствате свой собствен алгоритъм/модел, можете да поправите това начало, така че случайните решения за „хвърляне на монета“ винаги да са едни и същи.

Без контрол на семената, без контрол на реколтата

Някога един мъдър фермер можеше да каже:

„ако не контролирате това, което сеете, тогава как можете да контролирате това, което жънете?“
— хипотетичен фермер, вероятно

И да не би този хипотетичен фермер да удари пословичния пирон на главата. Ако не можете да коригирате семето, което се използва за определяне на решенията за „хвърляне на монета“ във вашата система, тогава пълният контрол е недостижим.

Затова обяснихме защо детерминизмът остава недостъпен при работа с най-популярните API на OpenAI.

Quod erat demonstrandum?

Но защо? Защо нещата са такива, каквито са?

Добре, значи семена. Голям вик. Не е толкова изненадващо. Въпросът, който остава:
Защо не можете да подадете семена? Както каза този човек в Twitter:

„донякъде е лудост, че API на OpenAI няма параметър „случайно начално начало“. Очакваното поведение е да получите резултати, които никога не можете да възпроизведете.
— Саша Ръш (доцент в Cornell Tech и изследовател на прегръщане на лица)

Така че нека да разгледаме някои възможни причини за избора на дизайн, направен да не позволява преминаване на фиксирано семе:

  • Може би количеството вуду магия, необходимо за задаване на дефинирано от потребителя семе в потенциално множество графични процесори, е твърде много за справяне?
    Искрите на изкуствения общ интелект“: разбира се.
    Но „Проблясъци на детерминистично поведение“: мечтайте (намирайте Aerosmith).
  • Може би различни комбинации от софтуер и хардуер (GPU), които се грижат за изчисленията с плаваща запетая, въвеждат степен на произволност, която не може да бъде напълно контролирана чрез коригиране на семето? И следователно даването на опцията на потребителя да коригира семето би поставило грешни очаквания?
  • Може би нашите приятели от OpenAI (и други доставчици на API) не искат да можете да детерминистично вземете проба от поведението на модел, тъй като това потенциално може да ви даде по-добър начин да надникнете под капака на днешните модели със затворен код?

Увийте го

В това пътуване предложихме прозрения за:

  • Как вероятностите за токени се доставят от LLM мрежа
  • Как се вземат проби от токените на всяка стъпка от генерирането на отговор и как параметрите temperature и top_p влияят върху това вземане на проби
  • Защо точно равните вероятности на жетони (⚡) не са толкова необичайни, колкото бихте очаквали
  • Ролята, която семето обикновено играе в ситуации на удар от мълния

По причини, които не са ни известни непосредствено, OpenAI не ни позволява да зададем семето, което има убедителна сила, когато светкавица удари по време на генериране на отговор чрез символи.

Може да не знаем защо детерминизмът и следователно възпроизводимостта са възпрепятствани до известна степен. Но поне поведението вече е по-ясно. И това ни кара да се чувстваме малко по-добре.
Нали?