Генерация текста
Модели вроде GPT пишут текст. Устроено это проще, чем кажется: модель умеет только одно — предсказывать следующий токен.
Шаг за шагом
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
tok = AutoTokenizer.from_pretrained("openai-community/gpt2")
model = AutoModelForCausalLM.from_pretrained("openai-community/gpt2")
ids = tok("The best thing about Python is")["input_ids"]
for _ in range(10):
with torch.no_grad():
logits = model(torch.tensor([ids])).logits[0, -1] # оценки следующего токена
ids.append(int(logits.argmax())) # самый вероятный
print(tok.decode(ids))
logits[0, -1]— логиты последней позиции: оценки каждого токена словаря на роль следующего;- выбрали токен — дописали — повторили. Это жадная генерация;
- модель может выбрать токен конца текста (
tok.eos_token_id) — тогда ответ закончен.
model.generate
В настоящих программах цикл не пишут — для этого есть generate:
enc = tok("The best thing about Python is", return_tensors="pt")
out = model.generate(**enc, max_new_tokens=30, do_sample=True, temperature=0.8, top_k=50)
print(tok.decode(out[0], skip_special_tokens=True))
max_new_tokens ограничивает длину, do_sample=True включает случайный выбор вместо жадного.
Температура
Жадная генерация часто скучна и зацикливается. Поэтому следующий токен выбирают случайно по вероятностям, а их «остроту» регулируют температурой:
probs = torch.softmax(logits / temperature, dim=-1)
token = torch.multinomial(probs, 1)
Температура меньше 1 усиливает разницу между логитами (текст предсказуемее), больше 1 — сглаживает (текст разнообразнее и безумнее).
Top-k
Чтобы случайный выбор не взял совсем неподходящий токен, оставляют только k лучших:
values, idx = logits.topk(k)
filtered = torch.full_like(logits, float("-inf"))
filtered[idx] = values
probs = torch.softmax(filtered, dim=-1) # у остальных токенов вероятность 0
-inf после softmax превращается в ноль. Похожий способ — top-p: оставить самые вероятные токены, пока их суммарная вероятность не достигнет p.
Итог
- языковая модель предсказывает следующий токен по
logits[0, -1]; - жадная генерация, остановка на
eos,max_new_tokens; model.generate(…, do_sample=True, temperature=…, top_k=…);- температура делит логиты, top-k обнуляет хвост через
-inf.