惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Full Disclosure
Recorded Future
Recorded Future
T
Tenable Blog
S
Securelist
C
CERT Recently Published Vulnerability Notes
T
Threatpost
S
Schneier on Security
A
Arctic Wolf
The Hacker News
The Hacker News
C
CXSECURITY Database RSS Feed - CXSecurity.com
Know Your Adversary
Know Your Adversary
P
Privacy International News Feed
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
The Register - Security
The Register - Security
Cisco Talos Blog
Cisco Talos Blog
AWS News Blog
AWS News Blog
K
Kaspersky official blog
T
True Tiger Recordings
T
Threat Research - Cisco Blogs
V
Vulnerabilities – Threatpost
P
Palo Alto Networks Blog
T
The Exploit Database - CXSecurity.com
小众软件
小众软件
B
Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Azure Blog
Microsoft Azure Blog
Cyberwarzone
Cyberwarzone
C
Cybersecurity and Infrastructure Security Agency CISA
T
Tor Project blog
Spread Privacy
Spread Privacy
Malwarebytes
Malwarebytes
P
Proofpoint News Feed
F
Fox-IT International blog
F
Fortinet All Blogs
P
Privacy & Cybersecurity Law Blog
G
GRAHAM CLULEY
量子位
Latest news
Latest news
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 叶小钗
Project Zero
Project Zero
T
Tailwind CSS Blog
N
Netflix TechBlog - Medium
Martin Fowler
Martin Fowler
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
I
Intezer
博客园_首页
腾讯CDC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
D
Darknet – Hacking Tools, Hacker News & Cyber Security

Все публикации подряд на Хабре

Есть ли жизнь на фазе: откуда берёт энергию умный выключатель без подключённой нейтрали Go Computer. История удивительного планшета из 1992 года с графическим интерфейсом Экономия GPU-часов в 2,5 раза, уход ИИ в бэкенд и новые стандарты агентских систем: ML-дайджест Что скрывается за AI-стратегией SAP, Oracle и Palantir: зачем корпоративному ИИ семантическое ядро Почему RAG — фундамент любой AI-трансформации Персонализация как баг Одна на 9 команд: как я внедряла квартальное планирование в трайбе, который сопротивлялся переменам После ИИ писать код руками ощущается уже не как норма Обмен через интернет между мобильными приложениями ТСД и 1С От плановых ремонтов к предиктивному обслуживанию: дорожная карта для главного инженера Параллельный импорт техники закрыли или нет? Юридический разбор Резервное электрообеспечение для ЦОДов: патенты в мире и в России 256 зелёных тестов на нерабочем коде. Так выглядит «услужливый клерк» внутри нейросети Бизнес-аналитика для сети из 300 аптек: прогноз продаж и другие показатели Impact Analysis в дизайн-системе: как мы сделали CI осмысленнее, а review понятнее Топ-5 лучших нейросетей 2026 года: полный список на любой случай в SpeShu.AI Что делает сотрудников по-настоящему эффективными: процессы, знания или технологии Как за один вечер я написал сервис инвентаризации оргтехники для филиальной сети из 16 локаций Склад нанимает — и не может остановиться. Дефицит складских работников в 2026 году: причины и решения Шёл за утечкой памяти, нашёл утечку диска: SXSSFWorkbook без dispose() в Apache POI Штраф в размере 155 000 рублей получил владелец сайта по заявлению Роскомнадзора Индивидуальный план развития: от формальной процедуры к инструменту управления экспертизой команды Как понять, что вы не управляете финансами, а просто смотрите на цифры Водоросли и микропластик Масштабирование LLM: от одного чипа до ЦОДа. Глава 3. Траснформеры Бомба замедленного действия взорвалась: эпоха ИИ «бери сколько унесёшь» закончилась Стимпанк как часть жизни. История паровых двигателей и место, которое они занимали в мире в XIX-XX веках. Часть 2 288-ядерный Xeon 6+ и другие серверные CPU От OCR к смыслу: как мы научили модель понимать, кто кому отец, мать, жених и свидетель Насколько плох был Intel iAPX 432 — проверяем на практике Приручаем железо: внедряем DevOps в промышленной разработке Когда Reality не хватает: добавляем Hysteria2 + Salamander в iOS-мессенджер, и как всегда грабли по дороге (ч.2) Разработчики не экстрасенсы: как мы перестали приносить туман вместо ТЗ Дайджест C++: новости, полезные материалы и “свой язык” на десерт Ещё один репозиторий моделей для Archi 10 простых шагов, чтобы создать позиционирование для продукта Загадочная поэма древнего Китая, работающая как компьютер CLOUD Act, GDPR и ваш DNS: что на самом деле может ваш провайдер Ускоряем и оптимизируем numpy, pandas, scipy и sklearn Idempotency keys: 5 граблей, которые мы поймали на проде Gamedev. Парсинг данных из Google Sheets и Excel в json без привлечения программистов Nano Banana Google AI: как использовать Нано Банана для генерации и редактирования изображений Два игрока на весь российский рынок ИИ: что показал ЦИПР-2026 Менеджер ресурсов ЯНДЕКС 360 (YANDEX 360) промокоды июнь 2026: промокод Yandex 360 скидка 40% на годовые тарифы Open-Source инструмент для автоматического перевода книг Ищу ранних тестировщиков для Android-версии agent harnesses Не используйте LLM для текста Увеличиваем продажи без слез аналитика Оптимизация запросов к PostgreSQL: 5 неочевидных настроек для продакшена 45 лет тюрьмы за DROP TABLE и переход Карпатого в Anthropic Планирование движения для ровера на ходовой Ackerman'а Революция в изучении языков Java — быстрая. Ваш код может таким не быть Как я опоздал на конкурс OpenAi с новой архитектурой нейросети Быстрые интеграции в 1С: прощайте, бесконечные переделки Как получить субсидию 300 миллионов от Минпромторга? preIPO Anthropic, OpenAI, SpaceX. Разбираемся — стоит ли участвовать? Entaxy ION + OPC UA: два способа получить данные с промышленного оборудования Память на миллион, а толку ноль: как мы спасали ИИ-агента от «тупости» РСЯ, AdSense или myTarget: что на самом деле в 2026 приносит больше денег сайту и причем тут монетизаторы Практическое построение сервисов на Go под реальный трафик PostgreSQL и аналитика: что меняется, когда хранилище становится общим Codex за 5 месяцев 2026: мой топ-5 релизов, что не зашло и где OpenAI обогнал Anthropic Как создать короткое видео с помощью нейросетей: Полный гайд по Veo 3.1, Kling 3.0 и Happy Horse 1.0 Алгоритм проверок физлиц от экс сотрудника ФНС Как ИИ портит резюме студентам Системные вызовы в сфере ИТ в 2026: стратегический взгляд для ИТ-руководителей Вайбкодинг заканчивается на localhost: как я строю SaaS для цифровизации коттеджных поселков с Codex Производственные риски в небольшом кастомном производстве. С чем я сталкивалась и как научилась это учитывать Подключаем ИИ органы чувств: bash-демон, пайка и самосознание на Raspberry Pi Я хотел повторить Growing Neural CA за вечер. Ушёл месяц Промт для генерации текста без ИИ следа — как писать уникальные тексты через нейросеть От capabilities к AppArmor: что реально остановит атакующего в контейнере CactOS Вектора интересов: как находить настоящую мотивацию и усиливать команды Цена безопасности [Перевод] Цена безопасности “Рубик” от пет-проекта до прода или ITIL 4 для строительно-торговых центров Чего ждать (и не ждать) от ремейка AC4 Black Flag Архитектурный тупик корпоративного хранения: почему смена модели не снимает ограничений и что с этим делать Атаки через подрядчиков, дефицит кадров и квест с импортозамещением: главные вызовы ИБ в 2026 году Я не оставлю детям наследства Почему порты стали «дверями» в сервер, и кто решил, что SSH будет 22 Почему зарубежные разработчики чипов возвращаются на китайские фабрики Как у меня НЕ получился торговый бот на Polymarket Проектирование архитектуры в нотации ArchiMate с использованием ИИ. Часть 2 Как превратить домашнюю файлопомойку в умную AI-галерею на основе сборки из x99+Xeon и видеокарты за 2 тыс рублей Перспективы заселения нашей галактики Кризис менеджмент в ИТ Reactive Programming не спасёт вас. Если вы не решили эти 5 проблем — у вас просто медленный монолит с Flux Как я делаю DIY-контроллер для ПК: громкость, приложения, MIDI, OBS Миграция микросервисов на Python с помощью LLM: экономим месяцы для разработчиков Программирование микросхем GAL и им подобных Почему таск-трекер не заменяет ИСУП: из чего состоит полноценный контур управления проектами Всё об информационной безопасности. Кибербезопасность. DevOps, CI/CD. Хакеры. Алексей Федулаев Как импортировать базу клиентов в amoCRM и навести порядок в контактах Как мы четыре раза переписали Outbox Google предлагает единый «водяной знак» для изображений, видео и текста, созданных ИИ Сексизм в IT: данные вместо домыслов
Языковые модели без машинного обучения
Aleksei_R_Pa · 2026-05-27 · via Все публикации подряд на Хабре

Языковые модели без машинного обучения

Уровень сложностиСредний

Время на прочтение13 мин

Охват и читатели1.6K

Мнение

Введение

Эта статья про мои эксперименты с языковыми моделями, в которых не используется машинное обучение и аппаратное ускорение. Чтобы избежать недопонимания поясню, что я имею ввиду под языковой моделью (ЯМ).

ЯМ это совокупность алгоритмов, структур данных и собственно данных для генерации связного текста в ответ на запрос. Каким образом ЯМ генерирует ответы определяется способом её реализации. В канонической реализации ЯМ используются методы машинного обучения и мощные аппаратные ускорители. В моей реализации ЯМ я хочу получать связный текст в ответ на запрос без машинного обучения и без аппаратного ускорения.

Если свериться с Википедией на английском и на русском языках, или с многочисленными публикациями про (Large/Small) Language Models, то мои определение и понимание… несколько неканонические. Поскольку я экспериментирую для себя (я сам себе работодатель), то заранее соглашусь с любыми мнениями о неканоничности моего определения ЯМ.

Буду благодарен комментариям — если окажется, что подобное изложенному в этой статье уже было на просторах интернета. Как минимум такие подсказки избавят меня от хождения по тупикам. А как максимум, я надеюсь, позволят сделать мои дальнейшие эксперименты более успешными.

Последующий текст состоит из нескольких небольших частей. Сначала расскажу о своих мыслях, из которых возникли мои идеи для экспериментов. Далее, о своём текущем подходе к реализации ЯМ. Пока он совсем прост. Чем‑то напоминает классический подходы Markov chains и n‑grams, но без статистических и вероятностных методов.

Продолжу коротким изложением и анализом результатов экспериментов. И в заключение поделюсь планами на будущее.

Для понимания содержимого статьи достаточно знаний в объёме 3 курсов Университета ИТМО (кафедра КТ) или аналогичной учебной программы.

Мотивация

Я люблю читать русскую классику. И мне очень хочется с помощью ЯМ создать и прочесть продолжение «Бесов» Ф.М.Достоевского. Спасти Анну Каренину от Л.Н.Толстого. Попросить А.П.Чехова написать рассказ‑другой по темам из соцсетей. Да и много ещё чего в том же духе. Те, кто читал «Код Онегина» или продолжение рассказа «Штабс‑капитан Рыбников», поймут о чем я.

В мозге Достоевского, Толстого, Чехова, Куприна, Салтыкова‑Щедрина, Набокова не было умножения тензоров, градиентного спуска, ускорителей от Nvidia, AMD и пр. Писателям (были) не нужны мегаватты энергии и терабайты тренировочных текстов для создания свои гениальных произведений.

Как же писатели это делали и делают? Я задумался о концепции ЯМ, которая могла бы превратить мои желания в реальность. Одно из основных моих предположений: качественные и эффективные языковые модели возможно сделать на сравнительно небольшом объёме текстов русской классической литературы. А не на терабайтах данных со всего интернета.

Структуры данных и алгоритмы ЯМ

Моя ЯМ использует структуры данных и алгоритмы С++ STL и исполняется на обычном x86 компьютере без аппаратных ускорителей. В ЯМ нет никаких токенизаций, тензоров, градиентных спусков, квантизаций, имбеддингов, энкодеров, декодеров, скрытых слоёв, латентных голов, GeGLU — ничего из жаргона и канонических технологий LLM & ML. С++ STL достаточно функциональна и эффективна для компактного хранения текстов без потерь и для их последующей обработки в ЯМ. Компактное хранение без потерь означает, что сохранённый текст в структурах данных может занимать меньше места по сравнению с исходным объёмом текста. Чем более избыточны исходные тексты и чем их больше, тем более компактным будет их внутреннее представление относительно входных данных.

ЯМ в качестве запросов принимает фразы и предложения, взятые из произвольного места исходных текстов. В ответ на запрос генерируется связный текст в виде комбинации предложений из сохранённых исходных данных.

В текущей реализации ЯМ на C++ STL скорость доступа к сохраненным данным по заданному запросу аппроксимируется O(M*log2(N)), где M это количество слов в запросе, а N это размер словаря для всех сохранённых текстов. Под словами понимаются последовательности символов из исходного текста, разделённые пробелами. Скорость генерации ответа на запрос оценивается O(K), где К это обобщённое обозначение внутренних констант алгоритма. Скорость генерации текста теоретически не зависит от размера заданного запроса, от размера сгенерированного ответа и от объёма исходных текстов.

ЯМ использует два основных алгоритма: алгоритм (1) сохранения входных текстов во внутренних структурах данных и алгоритм (2) генерации связного текста в ответ на запрос.

Алгоритм (1) сканирует входной текст и для каждого слова собирает информацию о следующих за ним словах — какие слова и на каком расстоянии (через сколько слов) следуют за текущим. Расстояние между двумя словами определяется как количество слов между этими двумя словами.

Например, при обработке предложений из текста «Мы идём домой. Мы идём в магазин. Мы остались дома.» алгоритм сканирования обнаруживает, что за словом «Мы» на расстоянии 0 дважды следует слово «идём» и один раз следует слово «остались». Также за словом «Мы» на расстоянии 1 следуют слова «домой.», «в» и «дома.». А слово «магазин.» следует за словом «Мы» на расстоянии 2.

Собранная таким образом для каждого слова информация сохраняется в двумерном массиве. В элементах строки массива хранится идентификатор слова, следующего за текущим. Индекс строки массива соответствует расстоянию до слов, сохранённых в элементах этой строки. Так, для слова «Мы» содержимое строки с индексом 0 в массиве может быть представлено в псевдо‑нотации языка С как {next_word(«идём»), next_word(«остались»)}. Содержимое строки с индексом 1 в массиве — {next_word(«домой.»), next_word(«в»), next_word(«дома.»)}, содержимое строки с индексом 2 в массиве — {next_word(«магазин.»)}. Обозначение next_word(word) — это функция, которая возвращает ссылку на структуру данных для слова.

Таким образом, для слова «Мы» содержимое двумерного массива из трёх строк целиком будет выглядеть так:

{
	{next_word(«идём»), next_word(«остались»)},
	{next_word(«домой.»), next_word(«в»), next_word(«дома.»)},
	{next_word(«магазин.»)}
}

Строки двумерного массива имеют переменную длину и могут быть представлены типом std::vector<>.

Для слова «идём» содержимое массива из трёх строк будет выглядеть так:

{
	{next_word(«домой.»), next_word(«в»)},
	{next_word(«Мы»), next_word(«магазин.»)},
	{next_word(«идём»), next_word(«Мы»)}
}

Обобщая в терминах C++ STL, эту структуру данных можно определить так:

enum { NEXT_MAX = 3 }; // количество строк элементов в двумерном массиве

struct next_word_t;// тип ссылки на слово, см. определение типа ниже
struct dict_word_t {
	std::vector<next_word_t> next[NEXT_MAX];// переменное число элементов в строке
};

Алгоритм (1) сохраняет слова из текста и собранную для них информацию в структуре данных kv‑store, которая обеспечивает быстрый поиск по слову в качестве key. Такая структура данных может быть определена в терминах C++ STL как:

struct words_dict_t: std::map<std::wstring, dict_word_t>{
};

В этом определении std::wstring — это слово из исходного текста, оно используется как ключ (key) для поиска. Объект типа dict_word_t — это значение (value), которое соответствует конкретному ключу.

Теперь можно определить тип next_word_t, форвардная декларация которого дана выше:

struct next_word_t {
	words_dict_t::iterator it; //iterator returned by words_dict_t::find(wstring);
};

Псевдокод алгоритма (1) в терминах C++ STL:

vector<wstring> words;
words_dict_t words_dict;

for (i = 0; i < words.size(); ++i) {
	dict_word_t &dict_word = words_dict[words[i]];
	for (j = 0; i + 1 + j < words.size() && j < NEXT_MAX; ++j)
		push_if_unique(dict_word.next[j], words_dict.find(words[i + 1 + j]);
}

В этом коде dict_word содержит ссылку на значение (value) для ключа words[i].
Функция push_if_unique() заполняет строку массива next[j] уникальными значениями next_word_t. То есть, значение next_word_t добавляется только в том случае если оно отсутствует в строке массива next[j]. Метод std::map::find() описан в документации C++ STL.

Псевдокод подразумевает что алгоритм (1) двухпроходный. В первом проходе, который ввиду тривиальности опущен, исходный текст сканируется и разбивается на отдельные слова. Эти слова заносятся в массив words. Также каждое слово word из исходного текста помещается в словарь words_dict в результате вызова words_dict_t::operator []:

words_dict[word] = dict_word_t();

Алгоритм (2) ЯМ использует все определённые выше структуры данных для генерации связного текста в ответ на запрос. В текущей реализации запрос к ЯМ это фраза или фрагмент из любого места исходного текста.

Например, для запроса «Мы идём домой.» алгоритм (2) выполнит следующие шаги. Для каждого слова запроса будет выполнен поиск в words_dict среди отсканированных слов из исходных текстов.

В результате поиска для каждого слова будет найден двумерный массив. Как мы помним в этом массиве собрана информация о словах, следующих за данным словом на разных расстояниях.

Используя собранную информацию однозначно определяется слово, которое следует за «домой.». Это слово «Мы».

Запрос модифицируется — отбрасывается первое слово запроса, и добавляется найденное слово в конец запроса. Новый запрос будет «идём домой. Мы». Далее вышеописанные шаги повторяются для модифицированного запроса. Эффективность работы алгоритма (2) может быть повышена кэшированием результатов поиска.

Повторение шагов происходит до тех пор пока возможно найти следующее слово для запроса.

Псевдокод алгоритма (2) в терминах C++ STL:

next_word_t prompt[NEXT_MAX];// запрос как входной параметр
words_dict_t words_dict;// словарь заполненный алгоритмом (1)
int pi = NEXT_MAX — 1;// индексирование элементов в запросе с последнего слова
vector<next_word_t> result = prompt[pi].it→second.next[0];
// предсказание следующего слова сразу после запроса
if (result.size() == 0)
	goto DONE;// нет данных для предсказания (в конце текста)
for (i = 1; i < NEXT_MAX; ++i) {// по словам от конца запроса к началу
	--pi;// индекс предыдущего слова в запросе
	const vector<next_word_t> &b = prompt[pi].it→second.next[i];
	if (b.size() == 0)
		goto DONE;//нет данных для предсказания (в конце текста)
	const vector<next_word_t> a = result;
	intersect_next_words(result, a, b);
}
auto next_word = result.begin();// предсказанное слово после запроса
push_back(prompt, next_word);
DONE:// прыгаем сюда если не удалось предсказать следующее слово

Функция intersect_next_words() возвращает массив слов которые могут следовать за двумя последовательными словами [pi] и [pi — 1] в запросе. Функция intersect_next_words() не использует вычисление вероятностей или каких-либо арифметических операций. Она сравнивает содержимое двух массивов и находит в них общие элементы, которые помещает в возвращаемых массив. Возвращаемый массив result в свою очередь используется как аргумент для этой функции на следующей итерации цикла. По завершению цикла for() или раньше в массиве result останется один элемент, который и будет использован как продолжение запроса.

Функция push_back() добавляет предсказанное слово в конец запроса и отбрасывает первое слово запроса.

Длина запроса в алгоритме (2) эффективно ограничивается константой NEXT_MAX. То есть, для предсказания следующего слова используется NEXT_MAX или меньше последних слов запроса. Для однозначности предсказания в текущей реализации ЯМ значение NEXT_MAX должно быть больше длины максимального повтора в тексте. Максимальный повтор — среди повторяющихся фраз, предложений или абзацев — определяется на этапе предварительного сканирования исходных текстов.

Эксперимент, входные данные ЯМ и обсуждение результата

Для своего первого эксперимента я выбрал создание продолжения романа «Бесы» Ф.М.Достоевского.

В качестве исходных данных для ЯМ в рамках этого эксперимента я использовал два набора исходных текстов:

  1. великое пятикнижие Ф.М.Достоевского «Преступление и наказание», «Идиот», «Бесы», «Подросток» и «Братья Карамазовы»;

  2. 15-томное собрание сочинений Ф.М.Достоевского, которое включает великое пятикнижие. Тексты из 15-томного набора были вручную разбиты на отдельные крупные произведения и были удалены комментарии к текстам.

Цель использование двух наборов данных — оценить эффективность выбранных структур данных и устойчивость работы алгоритмов ЯМ. Кратко статистика по наборам данных:

  1. размер исходных текстов первого набора данных (source) 12246KB, размер структур данных ЯМ в RAM 150499KB, отношение RAM/source == 12.29;

  2. размер исходных текстов второго набора данных (source) 30767KB, размер структур данных ЯМ в RAM 345535KB, отношение RAM/source == 11.23.

Из приведённой статистики видно что с увеличением размера исходных текстов эффективность структур данных ЯМ улучшается. Также статистика показывает, что для сравнительно маленьких размеров входных данных их представление в RAM занимает существенное место.

Запросом для ЯМ в эксперименте послужила фраза из начала главы первой части первой романа «Бесы»: «Приступая к описанию недавних». Альтернативные допустимые и работающие варианты запросов в рамках этого эксперимента — любые другие фразы из романа «Бесы».

Напомню, роман «Бесы» заканчивается так:

Ставрогин даже задрожал от гнева и почти от испуга.

— Проклятый психолог! — оборвал он вдруг в бешенстве и, не оглядываясь, вышел из кельи.

ЯМ сгенерировала длинное продолжение, которое начинается со слов:

Он не остановился и на крылечке, но быстро сошёл вниз. Полная восторгом душа его жаждала свободы, места, широты. Над ним широко, необозримо опрокинулся небесный купол, полный тихих сияющих звёзд...

Многоточие здесь заменяет довольно длинный сгенерированный текст, который я не привожу из‑за ограничений на размер статьи.

Наблюдательный читатель в этом продолжении узнает фрагмент текста из романа «Братья Карамазовы». Такое функционирование ЯМ ожидаемо. ЯМ всего лишь комбинирует фрагменты исходных текстов для генерации ответа на запрос.

Разумеется, в качестве входных данных для ЯМ можно использовать какие угодно тексты. Например, тексты статей про AI/LLM с сайта arXiv.org. Либо дистилляцию вопросов и ответов любой доступной LLM. Либо использовать представление исходных данных в виде «вопрос — ответ». Затем, соответственно, задавать запросы по соответствующей тематике. ЯМ точно также будет комбинировать фрагменты исходных данных для генерации ответов на запросы.

Обобщая полученный результат: чем больше объем исходных данных для ЯМ, тем сложнее будет казаться сгенерированный текст. Тем труднее с человеческой точки зрения будет обнаружить происхождение фрагментов в сгенерированном тексте. А значит, тем сильнее будет желание очеловечить ЯМ — воспринять работу машинных алгоритмов как проявление (Artificial) Intelligence.

Сравнение с каноническими LLM

Моя экспериментальная ЯМ не использует методов Machine Learning, тензорных вычислений, вычислений вероятностей и не требует аппаратного ускорения. При значительном увеличении объёма исходных тестов практическая производительность ЯМ будет зависеть от объема RAM, от скорости доступа к памяти, от промахов в кэшах, от заполнения конвейеров процессора, от скорости memory paging and swapping, major page fault latencies, etc.

М оя ЯМ работает в терминах слов и словосочетаний (n-grams), то есть предсказывает следующее слово на основе предыдущих NEXT_MAX n-grams. Примерно так же, с точностью до реализации, как работают Markov chains.

Алгоритмы ЯМ делают её функционирование объяснимым (explainable) без привлечения дополнительных сущностей — Intelligence, reasoning, emergent properties, and so on.
Из‑за отсутствия тензорных вычислений над слоями коэффициентов и отсутствия необходимости сжатия коэффициентов ЯМ не подвержена галлюцинациям в смысле канонических LLM. Однако ЯМ все же может генерировать несвязный текст, поскольку она лишь комбинирует фрагменты текстов из входных данных большого объёма. В использованной реализации ЯМ несвязности в тексте могут быть отлажены. То есть, ввиду сравнительной простоты используемых алгоритмов и структур данных, возможно обнаружить какие именно исходные тексты приводят к несвязности сгенерированного текста. И соответственно изменить внутренние параметры ЯМ для получения более связного или более «разумного» ответа на запрос.

В ЯМ отсутствует понятие длины контекста. Запрос большого размера сканируется алгоритмом (1) также как и любой входной текст, в реальном времени. В результате все слова и и отношения следования слов из такого запроса будут помещены во внутренние структуры данных ЯМ. После чего ЯМ генерирует ответ на запрос.

Для генерации ответа на запрос не требуется огромная дополнительная память, то есть не требуется аналога «kv‑cache».

Заключение и планы на ближайшее будущее

Моя ЯМ использует эффективную реализацию идей цепей Маркова и n-grams в терминах STL C++. ЯМ сначала определяет зависимости каждого слова от предшествующих слов во входных текстах. Вычисления вероятностей при этом не требуется. Затем, на основе этой информации исходя из содержимого запроса (prompt) ЯМ предсказывает следующее слово и таким образом генерирует ответ на запрос. Цепи Маркова и n-grams достаточно хорошо описаны в Википедии и других источниках.

Это достаточно простые алгоритмы для обработки исходных текстов и для генерирования ответа на запрос. Причина простоты алгоритмов — их реализация на традиционной x86/ARM платформе, где есть строки переменной длины, массивы переменного размера, деревья, указатели и пр. Если те же самые алгоритмы переложить на аппаратный ускоритель, то... потребуется токенизация и представление слов в виде векторов, поскольку в ускорителях нет строк переменной длины. Потребуются тензоры и операции с ними, поскольку в ускорителях нет указателей и деревьев. Потребуется умножение векторов поскольку в ускорителях нельзя сравнить поэлементно два массива переменной длины. И тому подобное. И, как следствие, возникает необходимость в тяжеловесных машинном обучении и инференсе.

«Магия» моей ЯМ не в алгоритмах, а в исходных данных. Чем больше исходных данных и чем более они релевантны к предметной области (предполагаемым запросам), тем «умнее» будут казаться ответы ЯМ. Поэтому в моих планах прежде всего увеличение объёма исходных данных. Хочется практически оценить объем RAM в зависимости от объёма исходных данных, производительность ЯМ в IPC (Instructions per Cycle), CPU cache misses, etc. Убедиться, что с увеличением объёма хранимых и обрабатываемых данных все работает как задумано. Найти узкие места в алгоритмах и реализовать их более эффективно, насколько это возможно.

Следующий серьёзный шаг — сделать запросы нечёткими, то есть использовать достаточно произвольно составленную фразу для генерации продолжения этой фразы по сохраненным в ЯМ текстам.

Ну и наконец, я приложу максимум усилий для ответов на идеи, комментарии и вопросы читателей — в частности от «добровольных» рецензентов из следующего параграфа.

Благодарности

Большое спасибо всем согласившимся прочитать черновик этой статьи. В особенности я благодарен следующим людям за ценные комментарии, вопросы и идеи:

  • А.Дмитриев предложил повысить эффективность структур данных заменив 64-битные указатели на 32-битные индексы. Это будет очень актуально для огромных наборов входных данных;

  • П.Кринов подсказал, что желательно добавить подробностей о сходстве и отличиях между предлагаемым подходом и цепями Маркова (n‑grams). Также для научной статьи (не для Habr) необходимы более формальная постановка проблемы, детальное сравнение с другими методами, анализ качества текста (типа BLEU‑score), кода или репозитория для повторения экспериментов;

  • Б.Козак заметил, что NEXT_MAX может рассматриваться в определённом смысле как длина контекста, а алгоритм (1) ЯМ все равно можно считать вариантом ML. Также Б.Козак задал вопрос — как решить в рамках предлагаемой ЯМ проблему потери частоты для частых и редких вхождений слов при предсказании следующего слова. На последний вопрос я уже ответил в тексте выше. Поскольку этот вопрос часто задавали и другие читатели,то коротко повторю ответ здесь: моя ЯМ не использует частоты встречаемости слов из входных данных для генерации ответа на запрос.