Оглавление
В мире больших языковых моделей основное внимание обычно приковано к архитектурам, данным и оптимизации. Однако стратегии декодирования, такие как лучевой поиск, играют ключевую роль в генерации текста и часто остаются в тени, пишет Hugging Face.
Как работают LLM на самом деле
Распространенное заблуждение: языковые модели типа GPT-2 непосредственно генерируют текст. В реальности они вычисляют логиты — оценки для каждого возможного токена в их словаре. Токенизатор (чаще всего байт-парное кодирование) преобразует входной текст в идентификаторы токенов, модель предсказывает следующий наиболее вероятный токен, а затем генерирует логиты, которые преобразуются в вероятности через softmax-функцию.

Жадный поиск: простота ценой качества
Жадный поиск — метод декодирования, который на каждом шаге выбирает наиболее вероятный токен в качестве следующего в последовательности. Он сохраняет только самый вероятный токен на каждом этапе, отбрасывая все другие потенциальные варианты.
На примере фразы «I have a dream»:
- Шаг 1: Вход: «I have a dream» → Наиболее вероятный токен: » of»
- Шаг 2: Вход: «I have a dream of» → Наиболее вероятный токен: » being»
- Шаг 3: Вход: «I have a dream of being» → Наиболее вероятный токен: » a»
- Шаг 4: Вход: «I have a dream of being a» → Наиболее вероятный токен: » doctor»
- Шаг 5: Вход: «I have a dream of being a doctor» → Наиболее вероятный токен: «.»
Этот подход короткозоркий: он учитывает только наиболее вероятный токен на каждом шаге, не рассматривая общее влияние на последовательность. Это делает его быстрым и эффективным, но он может упускать лучшие последовательности, которые могли бы появиться с немного менее вероятными следующими токенами.
from transformers import GPT2LMHeadModel, GPT2Tokenizer import torch device = 'cuda' if torch.cuda.is_available() else 'cpu' model = GPT2LMHeadModel.from_pretrained('gpt2').to(device) tokenizer = GPT2Tokenizer.from_pretrained('gpt2') model.eval() text = "I have a dream" input_ids = tokenizer.encode(text, return_tensors='pt').to(device) outputs = model.generate(input_ids, max_length=len(input_ids.squeeze())+5) generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True) print(f"Generated text: {generated_text}")
Жадный поиск — это как шахматист, думающий только на один ход вперед. В мире генерации текста такая стратегия приводит к предсказуемым и часто банальным результатам. Именно поэтому современные продвинутые LLM используют более сложные методы вроде лучевого поиска или сэмплинга — они позволяют находить баланс между креативностью и осмысленностью текста.
Практическая реализация
Вот как выглядит реализация жадного поиска с использованием Graphviz и Networkx:
import matplotlib.pyplot as plt import networkx as nx import numpy as np import time def get_log_prob(logits, token_id): probabilities = torch.nn.functional.softmax(logits, dim=-1) log_probabilities = torch.log(probabilities) token_log_probability = log_probabilities[token_id].item() return token_log_probability def greedy_search(input_ids, node, length=5): if length == 0: return input_ids outputs = model(input_ids) predictions = outputs.logits logits = predictions[0, -1, :] token_id = torch.argmax(logits).unsqueeze(0) token_score = get_log_prob(logits, token_id) new_input_ids = torch.cat([input_ids, token_id.unsqueeze(0)], dim=-1) next_token = tokenizer.decode(token_id, skip_special_tokens=True) current_node = list(graph.successors(node))[0] graph.nodes[current_node]['tokenscore'] = np.exp(token_score) * 100 graph.nodes[current_node]['token'] = next_token + f"_{length}" input_ids = greedy_search(new_input_ids, current_node, length-1) return input_ids
Математическая основа
Авторегрессионные модели типа GPT предсказывают следующий токен в последовательности на основе предыдущих токенов. Для последовательности токенов $w = (w_1, w_2, \ldots, w_t)$ совместная вероятность этой последовательности $P(w)$ раскладывается как:
P(w)=P(w1)P(w2∣w1)P(w3∣w2,w1)…P(wt∣w1,…,wt−1)=∏i=1tP(wi∣w1,…,wi−1).
Для каждого токена $w_i$ в последовательности, $P(w_i | w_1, \ldots, w_{i-1})$ представляет условную вероятность $w_i$ при условии всех предыдущих токенов $(w_1, \ldots, w_{i-1})$. GPT-2 вычисляет эту условную вероятность для каждого из 50,257 токенов в своем словаре.
Оставить комментарий