Головна / Статті

Від прогнозування наступного токену до виконання інструкцій: тонке налаштування моделі GPT

Як заздалегідь навчений GPT вчиться виконувати інструкції: форматування записів, зміна міток, маски заповнення, цикл навчання, обмеження оцінки та крок до уподобань DPO.

Видавець: REACTAPP.TOP9 хв читання2112 слів

Джерела: From Next-Token Prediction to ChatGPT <> Build an LLM From Scratch [6]

Попередня підготовка вже надає мовній моделі здатності писати. Однак їй бракує розуміння того, чого хоче досягти користувач. Налаштування за інструкціями заповнює цю прогалину. Якщо дати двом моделям однакове завдання — наприклад, пояснити рекурсію десятирічній дитині — різниця буде очевидною. Базова модель схильна просто повторювати запит та переходити до стандартного вступу про курси з інформатики. Вона зовсім не відповідає, а лише розтягує текст. Налаштована модель натомість пропонує образ: коробку, у якій знаходиться менша коробка, а в ній — ще менша, причому рекурсія описується як процес, коли проблема постійно передає собі меншу версію, поки найменша з них не стане простою для розв’язання.

По суті обидві моделі роблять одне й те саме — прогнозують наступний токен, проте їхня поведінка суттєво відрізняється. Продукти для чату роблять виконання інструкцій природним, що приховує цю різницю. На запитання даються відповіді, за запитами на код створюється код, а також складаються резюме. Усе це неможливо отримати безкоштовно лише шляхом читання величезних обсягів тексту. Попереднє навчання закладає щось більш базове: з урахуванням усього, що було до цього, який токен найімовірніший далі? У цьому немає жодних вказівок на те, що запит користувача має бути виконаний. Саме подолання цієї прогалини є темою цього тексту.

Етап 1: попереднє навчання вчить завершенню, а не послуху

Завдання попереднього навчання — це просто прогнозування наступного токена. Цього достатньо, щоб засвоїти граматику, факти, синтаксис коду, стилі письма та деякі дивовижно складні закономірності, але виконання інструкцій до них не належить. Надайте базовій моделі такий запит:

Explain why the sky appears blue.

і це може продовжуватися так:

Explain why the sky appears blue.
The following questions are commonly asked in introductory physics...

Це не обов’язково означає, що модель пошкоджена. Вона робить саме те, що вимагало попереднє навчання — продовжувати текст. Бажана поведінка виглядає більш-менш так:

The sky appears blue because Earth's atmosphere scatters
shorter wavelengths of sunlight more strongly than longer
wavelengths...

Основна модель залишається такою ж, але очікувана поведінка відрізняється. Питання змінюється на таке:

What text probably comes next?

до цього:

When the text looks like an instruction,
what kind of continuation should I produce?

Навчання моделі відповідати на те друге запитання — ось для чого існує тонке налаштування за інструкціями.

Етап 2: форматування даних інструкцій

Найпряміший спосіб навчити модель дотримуватися інструкцій — це показати їй багато інструкцій у поєднанні з хорошими відповідями, і все справді настільки просто. Запис тренування може виглядати так:

example = {
    "instruction": "Convert the following sentence to passive voice.",
    "input": "The developer fixed the bug.",
    "output": "The bug was fixed by the developer."
}

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

Below is an instruction that describes a task.

### Instruction:
Convert the following sentence to passive voice.

### Input:
The developer fixed the bug.

### Response:
The bug was fixed by the developer.

Форматування має значення, тому що модель постійно бачить одну й ту саму структуру:

instruction
    ↓
optional context
    ↓
response

Коротко кажучи, кожен запис спочатку перетворюється на форматований текст, потім — на токени, а далі — на доповнені пакети; ці пакети використовуються для деталізованої налаштування заздалегідь навченого моделі GPT.

Погляд на токени

Після токенізації приклад перетворюється на список ідентифікаторів, приблизно такий:

[21106, 318, 281, 12064, ... 4435, 257, 3126, ...]

Ці ідентифікатори токенів утворюють послідовність для навчання. Для авторегресивної моделі мітки є просто послідовністю, зсунутою на одну позицію:

Tokens:
[A, B, C, D, E]

Input:
[A, B, C, D]

Labels:
[B, C, D, E]

Отже, налаштування інструкцій не вносить жодних абсолютно нових цілей навчання. Модель все ще прогнозує наступний токен. Змінюється лише розподіл тексту, який від неї вимагають прогнозувати. Замість переважно звичайних документів вона тепер знову і знову бачить це мапування:

instruction → useful response

Це і є основна ідея.

Додатковий простір потребує особливого підходу

Приклади для навчання відрізняються за довжиною, проте пакети мають містити тензори з сумісними формами. Розглянемо два приклади:

Example 1:
[10, 20, 30, 40]

Example 2:
[11, 21]

Їх можна доповнити наповнювачем:

Example 1:
[10, 20, 30, 40]

Example 2:
[11, 21, PAD, PAD]

Токени заповнення не є значущими цілями. Модель не повинна отримувати винагороду за їх вивчення:

PAD → PAD → PAD → PAD

Тож ці позиції зазвичай замінюються на значення „ignore“:

ignore_index = -100

Функція втрати крос-ентропія в PyTorch ігнорує їх. Концептуально:

loss = cross_entropy(
    logits.reshape(-1, vocab_size),
    targets.reshape(-1),
    ignore_index=-100,
)

Деталі мають значення. Без маскування частина сигналу навчання витрачається на артефакти, створені через групування даних, а не на мову.

Етап 3: доробка поведінки

Сам цикл навчання тут не є чимось незвичайним, адже оптимізація моделі наступного токену вже є знайомою. Важливо те, які приклади подаються у цей цикл. У спрощеному вигляді:

for batch in train_loader:
    optimizer.zero_grad()

    input_ids = batch[:, :-1]
    targets = batch[:, 1:]

    logits = model(input_ids)

    loss = cross_entropy(
        logits.flatten(0, 1),
        targets.flatten(),
        ignore_index=-100,
    )

    loss.backward()
    optimizer.step()

У тому коді немає нічого, що б сказало щось подібне:

model.learn_to_be_helpful()

Поведінка походить з даних. Припустимо, тисячі прикладів виглядають так:

### Instruction:
Summarize this paragraph.

### Response:
<clear concise summary>

Оновлення градієнта постійно спрямовують модель на створення відповідей такої форми після запитів такої форми. Припустимо, інші приклади виглядають так:

### Instruction:
Write Python code that reverses a string.

### Response:
def reverse_string(s):
    return s[::-1]

Він вивчає інший зв’язок між шаблоном інструкції та відповідним продовженням. Якщо дивитися на рівні токенів, тонке налаштування інструкцій є менш чудодійним: контекст навколо прогнозів був навмисно змінений. Раніше:

The CPU cache is...

Після форматування інструкції:

### Instruction:
Explain CPU caching to a beginner.

### Response:
A CPU cache is...

Не було введено жодної мети на кшталт „розуміння користувачів“. Натомість розподіл навчального тексту змінився так, що корисні відповіді стали статистично більш ймовірними продовженнями після отримання інструкції. Саме ця зміна спричиняє нову поведінку. У наведеному прикладі заздалегідь навчений модель GPT-2-medium пройшов додаткову налаштування під конкретні інструкції, генерує відповіді та зберігає отриману модель.

Акт 4: оцінка стає складною

Класифікація забезпечувала просту схему оцінки. Для виявлення спаму:

Prediction: SPAM
Label:      SPAM

Correct.

Виконання інструкцій не дозволяє собі такої розкішшю. Розгляньмо прохання пояснити рекурсію просто. Одна з можливих відповідей:

Recursion is when a function solves a problem by calling
itself on a smaller version of the same problem.

Ще одне:

Recursion is a technique where a problem is reduced into
smaller instances of itself until a stopping condition is reached.

Обидва варіанти можуть бути правильними, і жоден з них не обов’язково має збігатися зі словом-орієнтиром слово в слово. Це робить точність збігу майже марною для відповідей відкритого типу.

Порівняння з орієнтиром

Одним із варіантів є надання орієнтира:

{
    "instruction": "Explain recursion simply.",
    "reference": "Recursion solves a problem by repeatedly reducing it...",
    "model_response": "A recursive function calls itself..."
}

і порівняти отриману відповідь із нею. Але схожість — це не якість, і модель може дати чудову відповідь абсолютно іншими словами. Це призводить до іншого підходу.

Запросити інший LLM для оцінки

Оцінювач отримує інструкцію, базову відповідь та відповідь, яку потрібно оцінити:

Instruction:
Explain recursion simply.

Reference answer:
...

Model answer:
...

Rate the model answer from 0 to 100 based on correctness,
relevance, and clarity.

Місцевий суддя може використовувати Ollama, що зручно, проте це створює нову проблему: сам суддя є моделлю. Його оцінка може залежати від запиту для оцінки, вибору оцінювача, порядку відповідей, рівня деталізації, стилістичних уподобань та власних помилок судді. Деякі приклади показують, що місцевий суддя може надавати дивовижно високі оцінки слабким відповідям базової моделі, що нагадує про те, що цифри, отримані за допомогою ШІ як судді, не є об’єктивною істиною.

Невеликий проект може складатися з трьох шарів:

1. Inspect representative outputs manually
2. Compare against reference answers where useful
3. Use an LLM judge for aggregate comparison

Жоден з цих показників сам по собі не є ідеальним. Разом вони дають більш чітке уявлення, ніж одна цифра, яка претендує на статус істини.

Етап 5: складніша проблема – уподобання

Налаштування інструкцій допомагає моделі зрозуміти, якою має бути розумна відповідь. Тепер порівняймо два варіанти відповіді. Відповідь А:

Recursion is when a function calls itself.

Відповідь B:

Recursion is a technique where a function solves a problem
by calling itself on a smaller version of that problem.
The process stops when it reaches a base case.

Обидва варіанти є дійсними, але може бути обраний варіант B. Сигнал навчання більше не є таким:

correct vs incorrect

Це ось що:

chosen vs rejected

Запис уподобань може виглядати так:

{
    "prompt": "Explain recursion simply.",
    "chosen": """
    Recursion solves a problem by repeatedly reducing it
    until reaching a base case.
    """,
    "rejected": """
    Recursion is when recursion happens recursively.
    """
}

Це інший тип нагляду. Замість того, щоб казати «ось відповідь, яку потрібно імітувати», тут кажуть «з цих двох відповідей оберіть цю». Саме тут використовуються такі техніки, як оптимізація прямої переваги (DPO). У загальних рисах:

Prompt
   ↓
Chosen response ─────┐
                     ├── preference objective
Rejected response ───┘
                     ↓
               model update

DPO заслуговує на окреме розглядання, тому його механізми не входять до цієї дискусії. Корисне посилання стосується загального прогресу:

Pretraining
    ↓
learn language patterns

------------------------------

Instruction fine-tuning
    ↓
learn instruction → response behavior

------------------------------

Preference tuning
    ↓
learn which acceptable responses we prefer

Створення наборів даних для налаштування переваг за допомогою Llama 3.1 через Ollama та реалізація методу DPO з нуля — це теми на пізніший час. Існує одне застереження: те, що DPO доступний як додатковий матеріал, не означає, що це правильний наступний крок для кожної моделі чи набору даних. Деякі експерименти показують обмеження його результатів, що саме є підставою для скептицизму під час налаштування переваг.

Що насправді змінилося

Вихідною точкою була заздалегідь навчена модель, яка вміла продовжувати текст. Архітектура трансформера не була замінена на спеціальну архітектуру асистента. Приклади, пов’язані з проблемою наступного токену, змінилися, що призвело до іншого початкового профілю поведінки. Тепер, коли модель бачить:

### Instruction:

Було достатньо випадків, коли продовженням не є інший абзац з Інтернету, а відповідь. Якщо дивитися так, логіку розвитку легше зрозуміти:

Pretraining:
What token should come next?

Instruction tuning:
What does a good answer look like after an instruction?

Preference tuning:
Of several reasonable answers, which behavior should we prefer?

Архітектура, оптимізатор та швидкість навчання — усе це має значення, але під час налаштування за інструкціями дані відіграють особливу роль, адже саме вони визначають поведінку, яку потрібно імітувати. Коли існує кілька прийнятних варіантів відповіді, правильний результат більше не є єдиною метою. Питання змінюється на те, яка з прийнятних відповідей заслуговує на більшу вагу, і саме це відкриває можливості методу DPO.

Попереднє навчання допомагає зрозуміти, який текст, як правило, йде далі. Налаштування за інструкціями змінює те, які продовження вважаються корисними відповідями на інструкції. Налаштування за пріоритетами робить наступний крок, визначаючи, які саме корисні відповіді варто віддавати перевагу.

Пов’язана література

  • Як Transformer прогнозує наступний токен: увага, резидуали та Softmax — простими словами розглядається Transformer у стилі GPT, від токенів та позиційних ембеддингів до каузальної уваги, шарів з передачею сигналу, логітів та Softmax.
  • Від прогнозування наступного токена до функціонального коду: як LLMи генерують Python — токени, Softmax, параметр температури, самоувага та шари з передачею сигналу пояснюються по порядку, із прикладом поетапної сортування та обмеженнями, що випливають з прогнозування.
  • Практичні нотатки: Як насправді працюють LLM: токени, трансформери та наступний токен — Детальний огляд Практичних нотаток: Як насправді працюють LLM: токени, трансформери та наступний токен, включаючи шаблони контрактів, перевірки та фрагменти коду для команд, які впроваджують цю модель.
  • Стратегії чанкінгу для RAG у продакшені: фіксованого розміру, семантичні та батьківсько-дочірні — Практичний огляд методів чанкінгу для RAG від фіксованого розміру та рекурсивного розділення до батьківсько-дочірніх структур, пропозицій, пізнього чанкінгу, технології RAPTOR, таблиць, коду та методів тестування.
  • Сандбокс рекурсивної мовної моделі: що заважало, що потребує перебудови — огляд платформи рекурсивних мовних моделей: шари ізоляції, брокери, CDR, обмеження трасування в користувацькому просторі, обмеження одного хоста та причини, чому саме стриманість була найважливішою.
  • Як працює LLM: токени, увага та прогнозування наступного токену — простий огляд архітектури LLM від токенів та ембеддингів через механізм уваги, каузальне маскування та генерацію, а також пояснення відмінностей між навчанням та інференсом.