Практические заметки: Создание LLM, часть 1 — Обучение: прогнозирование следующего токена
Пошаговое руководство по практическим заметкам: создание LLM, часть 1 — обучение: прогнозирование следующего токена: контракты, проверки и слоты для вставки кода для команд, использующих эту схему.
Используйте это как переработанную версию идей из статьи «Создание LLM, часть 1 — Обучение: прогнозирование следующего токена», ориентированную на операторов: четкие этапы, упорядоченные блоки кода и записи о восстановлении, сохраняющиеся при передаче задачи. Этап Обзора работает наилучшим образом, если рассматривать его как измеримую основу. Сначала зафиксируйте один идеальный пример работы, один случай сбоя и записи о возврате к предыдущему состоянию, прежде чем расширять объем работ. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отображение стоимости на ранних этапах предотвращает неожиданные счета при переходе от демо-версии к общим средам.
Почему сначала Vision Transformer?
Для этапа Vision Transformer необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг, используя известную точку контроля, без необходимости угадывать скрытое состояние. Конфигурацию следует хранить отдельно от кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. При следующем шаге, представляющем собой код или вызов инструмента, следует отдавать предпочтение структурированным выводам с проверкой схемы перед свободным текстом.
Основная идея: прогнозирование следующего токена
На этапе планирования необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед внесением изменений в код. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Необходимо одновременно задокументировать успешный сценарий выполнения и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не этапом последующей доработки. При следующем шаге, представляющем собой код или вызов инструмента, следует отдавать предпочтение структурированным выводам с проверкой по шаблону перед свободным текстовым описанием.
logits, _ = model(ids) # ids = the tokens so far, shape (1, T)
probs = F.softmax(logits[0, -1], dim=-1) # one probability per vocabulary token
Текст → токены: почему нам пришлось создать собственный токенизатор
Что касается токенов текста, то перед изменением кода необходимо определить этапы обработки, входные данные, ответственного за выполнение шага и критерии завершения. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Лучше использовать небольшие, тестируемые единицы кода вместо обширных скриптов. При сбое шага он должен указывать на конкретную причину, а не на сложную структуру обработки данных. При следующем шаге, представляющем собой код или вызов инструмента, лучше использовать структурированные результаты с проверкой соответствия шаблону вместо свободного текста. Что касается токенов текста, то перед изменением кода необходимо определить этапы обработки, входные данные, ответственного за выполнение шага и критерии завершения. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Регистрируйте время выполнения и стоимость обработки токенов или запросов вместе с функциональными результатами. Отображение затрат на раннем этапе предотвращает неожиданные расходы при переходе с демо-среды в общедоступные среды.
import glob
from tokenizers import Tokenizer, models, trainers, pre_tokenizers
from llm_transformer.prep_tales import strip_gutenberg, RAW_DIR
# read every raw .txt book and strip its Project Gutenberg header/footer,
# leaving just the story text - one big string per book
tales_texts = [strip_gutenberg(open(p, encoding="utf-8", errors="ignore").read())
for p in sorted(glob.glob(f"{RAW_DIR}/*.txt"))] # 12 books, ~809k words
tok = Tokenizer(models.BPE())
tok.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) # start from bytes
trainer = trainers.BpeTrainer(vocab_size=8192, special_tokens=["<|endoftext|>"],
initial_alphabet=pre_tokenizers.ByteLevel.alphabet())
tok.train_from_iterator(tales_texts, trainer) # learn the 7,935 merges
tok.save("tales_bpe.json")
tok = Tokenizer.from_file("tales_bpe.json") # reload the trained tokenizer
ids = tok.encode("Once upon a time").ids # -> [412, 987, 15, 733] (integers)
idx = torch.tensor(ids).unsqueeze(0) # (1, 4) — a batch of one sequence
vocab_size = tok.get_vocab_size() # 8192 - sets the NUMBER OF ROWS below
Токен → вектор: поиск, а не вычисления
При работе с этапом поиска вектора токена сначала опишите требования: необходимые входные данные, сигнал успешного завершения и действия при частичной неудаче. Такой список поможет избежать ошибок при последующих изменениях кода. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Храните в кэше стабильные системные инструкции и схемы инструментов. Пересылка одинаковых преамбул является распространенной причиной ресурсозатрат.
self.token_embed = nn.Embedding(vocab_size, n_embed) # the 8,192 x 256 table
# .weight IS a learnable (8192, 256) parameter tensor — 2.1M weights, trained by backprop;
# each id's row is nudged only on steps where that token appears in the batch
...
tok_emb = self.token_embed(idx) # idx (B, T) -> vectors (B, T, 256), one row per id
Исключение: маска причинности
При работе над этапом обработки исключений запишите сначала описание требований: необходимые входные данные, сигнал успешного завершения и действия при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Документируйте одновременно путь успешного выполнения и путь восстановления. Повторные попытки, проверки со стороны оператора и обработка некорректных сообщений являются частью продукта, а не элементами последующей доработки. Храните в кэше стабильные инструкции системы и схемы инструментов. Пересылка одинаковых заголовков — распространенная причина избыточных ресурсов.
# tril = torch.tril(torch.ones(T, T)) — a lower-triangular matrix of 1s, made once
attn = q @ k.transpose(-2, -1) / math.sqrt(head_size) # scores, (B, T, T)
attn = attn.masked_fill(self.tril[:T, :T] == 0, float('-inf')) # blank out the future
attn = F.softmax(attn, dim=-1) # -inf -> weight 0
out = attn @ v
Один проход, все контексты сразу
При работе с одним прохождением каждой стадии контекста сначала запишите условия взаимодействия: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список помогает сохранять честность при последующих изменениях кода. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Если какой-то шаг не сработает, причина должна быть связана с конкретной функцией, а не с запутанной цепочкой операций. Храните в кэше стабильные инструкции системы и схемы инструментов. Повторная отправка одинаковых данных — распространённая причина избыточных затрат. При работе с одним прохождением каждой стадии контекста сначала запишите условия взаимодействия: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список помогает сохранять честность при последующих изменениях кода. Регистрируйте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные расходы при переходе с демо-среды в общедоступные среды.
Внутри одной итерации: что на самом деле вычисляет attn @ V
При рассмотрении этапа «Внутри одной итерации» как измеримой величины наилучшим подходом является сбор одного идеального примера работы, одного случая сбоя и записи о возврате к предыдущему состоянию перед расширением объёма работ. Храните конфигурацию вне кода приложения: файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь граф зависимостей. Установите лимиты на количество токенов за ход и за сессию — инструменты агентного типа активно расширяют контекст, и жёсткие ограничения предотвращают появление неожиданных счетов.
Одна обработка, множество уроков: прогнозы T и потери T
Этап «один проход, множество уроков» работает наилучшим образом, если рассматривать его как измеримую поверхность. Зафиксируйте один идеальный пример выполнения, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Документируйте одновременно успешный и восстановительный пути выполнения. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не последующими доработками. Установите лимиты на количество токенов за один проход и за сессию. Инструменты агентов активно расширяют объем контекста; строгие ограничения предотвращают появление неожиданных счетов при демонстрациях.
logits = self.lm_head(x) # (B, T, vocab)
B, T, C = logits.shape
loss = F.cross_entropy(logits.reshape(B*T, C), # every position ...
targets.reshape(B*T)) # ... vs the token that actually followed
Каждая потеря представляет собой классификацию словаря (как у ViT, но 8 192 классов)
Метод «Каждая потеря — это этап» работает наилучшим образом, когда его рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ. Предпочитайте небольшие, тестируемые единицы вместо обширных скриптов. Когда какой-то шаг терпит неудачу, причина сбоя должна указывать на конкретный ответственный элемент, а не на запутанную цепочку операций. Установите лимиты на количество токенов за ход и за сессию. Инструменты агентного типа активно расширяют объём контекста; жесткие ограничения предотвращают появление неожиданных счетов. Метод «Каждая потеря — это этап» работает наилучшим образом, когда его рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-версии к общим средам.
Как создаётся пакет обработки — и как формируется его единственная потеря
Чтобы определить этапы обработки пакета, необходимо заранее указать входные данные, ответственного за выполнение шага и критерии завершения перед внесением изменений в код. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Конфигурацию следует хранить отдельно от кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. При следующем шаге, представляющем собой выполнение кода или вызов инструмента, предпочтительнее использовать структурированные выходные данные с проверкой соответствия шаблону, а не свободный текст.
Обучение: наблюдение за снижением показателя потерь
Для этапа отслеживания потерь в процессе обучения необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Необходимо одновременно задокументировать успешный сценарий выполнения и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не этапом последующей доработки. При следующем шаге, представляющем собой код или вызов инструмента, следует отдавать предпочтение структурированным выводам с проверкой по схеме перед свободным текстовым описанием.
for step in range(train_steps):
xb, yb = get_batch(train_data) # random (context, next-token) windows
_, loss = model(xb, yb) # forward: T predictions -> one mean loss
opt.zero_grad(); loss.backward() # backprop the loss into all 9M parameters
opt.step() # nudge them downhill
Что мы создали — и что будет дальше
Для разделов «Что мы создали» и «Этапы» необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед внесением изменений в код. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Лучше использовать небольшие, тестируемые единицы кода вместо обширных скриптов. При сбое шага причина должна быть связана с конкретной функцией, а не с запутанной структурой всего процесса. При следующем шаге, представляющем собой код или вызов инструмента, лучше использовать структурированные результаты с проверкой соответствия шаблону вместо свободного текста. Для разделов «Что мы создали» и «Этапы» необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед внесением изменений в код. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рядом с функциональными результатами следует записывать время выполнения, а также стоимость токенов или запросов. Отображение затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-среды к общедоступным средам.
Чек-лист операционной работы
На этапе чек-листа операционной работы сначала запишите условия контракта: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой чек-лист помогает сохранять честность последующих изменений в коде.
Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Дайте названия всем элементам, определите критерии успешности и не допускайте молчаливого частичного выполнения задачи.
Храните в кэше стабильные инструкции системы и схемы инструментов. Пересылка одинаковых данных является распространенной причиной лишних ресурсозатрат.
Сделайте процесс генерации результатов максимально экономичным и откладывайте ресурсоемкие операции на этап мемоизации только после проведения измерений. Преждевременная мемоизация может скрыть ошибки, связанные с устаревшими данными.
Каждый раз, когда это позволяют бюджетные ограничения, добавляйте тест на базовую работоспособность, который проверяет критически важные этапы в рамках CI с использованием фикстчеров, а не реальных платных API.
Документируйте одновременно путь успешной работы и путь восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не последующим доработкам.
Перед тем как переводить стек на более высокий уровень, заморозьте версии, сохраните эталонный отчет для критического пути и уточните шаги отката. В совместных средах необходимы ограничения по частоте запросов, проверки принадлежности и четко определенный ответственный за обновление секретов. Лучше предпочесть простую надежность умным одноразовым демонстрациям.
Примечание для пакета 44c72473e486: не храните ключи поставщика в репозитории, установите лимит токенов на сессию и сохраняйте отчеты рядом с фикстурами для оценки, чтобы последующие замены моделей оставались сопоставимыми.
Для этапа 0 записки по укреплению безопасности необходимо определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Укажите названия результатов работы, определите критерии успеха и не допускайте молчаливого частичного завершения задачи.
Подробности укрепления безопасности 0/729: измерьте время выполнения, класс ошибок и расход токенов для данной записки, затем решите, следует ли сохранять изменения, опираясь на заранее установленный набор критериев, а не на субъективные оценки.
При работе над первым этапом записки по усилению безопасности сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Храните конфигурацию отдельно от кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код.
Подробность усиления безопасности 1/729: измерьте время выполнения, класс ошибки и расход токенов для данной записки, затем решите, следует ли сохранять изменение, опираясь на установленный набор критериев, а не на случайные наблюдения.
Второй этап записки по усилению безопасности лучше всего работает, если рассматривать его как измеримую область. Соберите один эталонный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Предпочитайте небольшие, тестируемые единицы кода большим скриптам. Когда какой-то шаг терпит неудачу, причина должна быть связана с конкретной функцией, а не с запутанной цепочкой операций.
Подробности усиления безопасности 2/729: измерьте время выполнения, класс ошибки и расход токенов для этой записи, затем решите, следует ли сохранить изменения на основе фиксированного набора вопросов, а не на основе единичных примеров.
На третьем этапе работы над усилением безопасности определите входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отображение стоимости заранее предотвращает неожиданные счета при переходе с демо-среды в общедоступные среды.
Подробности усиления безопасности 3/729: измерьте время выполнения, класс ошибки и расход токенов для этой записи, затем решите, следует ли сохранить изменения на основе фиксированного набора вопросов, а не на основе единичных примеров.
При работе над четвертым этапом записки по укреплению безопасности сначала запишите условия соглашения: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список поможет сохранять честность при последующих изменениях кода. Документируйте одновременно успешный сценарий работы и сценарий восстановления. Повторные попытки, проверки со стороны людей и обработка некорректных сообщений являются частью продукта, а не элементами последующей доработки.
Подробности укрепления безопасности 4/729: измерьте время выполнения, класс ошибки и количество использованных токенов для данной записки, затем решите, следует ли сохранять изменение на основе фиксированного набора критериев, а не на основе устных замечаний.
Четвертый этап записки по укреплению безопасности работает наилучшим образом, когда его рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Рассматривайте этот этап как соглашение между входными данными и проверенными выходными результатами. Дайте названия соответствующим элементам, определите критерии успеха и не допускайте молчаливого частичного завершения работы.
Подробности усиления безопасности 5/729: измерьте время выполнения, класс ошибки и расход токенов для этой записи, затем решите, следует ли сохранить изменения на основе фиксированного набора критериев, а не на основе единичных примеров.
На этапе 6 записи о усилении безопасности определите входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Храните конфигурацию вне кода приложения: файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, которое операторы могут проверять, не читая весь код.
Подробности усиления безопасности 6/729: измерьте время выполнения, класс ошибки и расход токенов для этой записи, затем решите, следует ли сохранить изменения на основе фиксированного набора критериев, а не на основе единичных примеров.
При работе над этапом 7 записки по усилению безопасности сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Лучше использовать небольшие, тестируемые модули вместо обширных скриптов. Если какой-то шаг не сработает, причина неудачи должна указывать на конкретную ответственность, а не на запутанную цепочку операций.
Деталь усиления безопасности 7/729: измерьте время выполнения, класс ошибки и расход токенов для этой записки, затем решите, следует ли сохранять изменение, опираясь на заранее определенный набор критериев, а не на устные оценки.
Этап 8 записки по усилению безопасности работает лучше всего, когда его рассматривают как измеримую область. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Записывайте временные показатели и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные расходы при переходе с демо-среды в общедоступные среды.
Подробности усиления безопасности 8/729: измерьте время выполнения, класс ошибки и расход токенов для этой записи, затем решите, следует ли сохранить изменение на основе фиксированного набора вопросов, а не на основе единичных случаев.
На этапе 9 записи о усилении безопасности определите входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Документируйте как успешный путь, так и путь восстановления одновременно. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не последующими улучшениями.
Подробности усиления безопасности 9/729: измерьте время выполнения, класс ошибки и расход токенов для этой записи, затем решите, следует ли сохранить изменение на основе фиксированного набора вопросов, а не на основе единичных случаев.
При работе над этапом усиления безопасности №10 сначала запишите контракт: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Дайте названия соответствующим элементам, определите критерии успешности и не допускайте молчаливого частичного выполнения задач.
Подробности усиления безопасности 10/729: измерьте время выполнения, класс ошибки и расход токенов для данного этапа, затем решите, следует ли сохранять изменение на основе фиксированного набора критериев, а не на основе единичных примеров.
Этап усиления безопасности №11 будет работать наилучшим образом, если рассматривать его как измеримую поверхность. Соберите один эталонный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, которое операторы могут проверять, не читая весь код.
Подробности усиления безопасности 11/729: измерьте время обработки стены, класс ошибки и расход токенов для этой записи, затем решите, следует ли сохранять изменения на основе фиксированного набора вопросов, а не на основе единичных примеров.