Введение
Эта статья про мои эксперименты с языковыми моделями, в которых не используется машинное обучение и аппаратное ускорение. Чтобы избежать недопонимания поясню, что я имею ввиду под языковой моделью (ЯМ).
ЯМ это совокупность алгоритмов, структур данных и собственно данных для генерации связного текста в ответ на запрос. Каким образом ЯМ генерирует ответы определяется способом её реализации. В канонической реализации ЯМ используются методы машинного обучения и мощные аппаратные ускорители. В моей реализации ЯМ я хочу получать связный текст в ответ на запрос без машинного обучения и без аппаратного ускорения.
Если свериться с Википедией на английском и на русском языках, или с многочисленными публикациями про (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 должно быть больше длины максимального повтора в тексте. Максимальный повтор — среди повторяющихся фраз, предложений или абзацев — определяется на этапе предварительного сканирования исходных текстов.
Эксперимент, входные данные ЯМ и обсуждение результата
Для своего первого эксперимента я выбрал создание продолжения романа «Бесы» Ф.М.Достоевского.
В качестве исходных данных для ЯМ в рамках этого эксперимента я использовал два набора исходных текстов:
великое пятикнижие Ф.М.Достоевского «Преступление и наказание», «Идиот», «Бесы», «Подросток» и «Братья Карамазовы»;
15-томное собрание сочинений Ф.М.Достоевского, которое включает великое пятикнижие. Тексты из 15-томного набора были вручную разбиты на отдельные крупные произведения и были удалены комментарии к текстам.
Цель использование двух наборов данных — оценить эффективность выбранных структур данных и устойчивость работы алгоритмов ЯМ. Кратко статистика по наборам данных:
размер исходных текстов первого набора данных (source) 12246KB, размер структур данных ЯМ в RAM 150499KB, отношение RAM/source == 12.29;
размер исходных текстов второго набора данных (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. Также Б.Козак задал вопрос — как решить в рамках предлагаемой ЯМ проблему потери частоты для частых и редких вхождений слов при предсказании следующего слова. На последний вопрос я уже ответил в тексте выше. Поскольку этот вопрос часто задавали и другие читатели,то коротко повторю ответ здесь: моя ЯМ не использует частоты встречаемости слов из входных данных для генерации ответа на запрос.
Комментарии (16)

longtolik
27.05.2026 09:01Отличный подход.
Делаю трансформер на языке C, от самого простого до более сложного. Пока "полёт нормальный", то есть, он отлично генерирует следующие слова на основе предыдущих. Чтобы он правильно генерировал связный текст, нужно проводить массу экспериментов. И пока не всегда получается. Поэтому я тоже начал уже присматриваться к чему-то более логически прямолинейному, возможно, дополнить его векторными базами данных или чем-то еще.
Так что Вы - на правильном пути, удачи!

Shalundrive
27.05.2026 09:01Алексей, спасибо за статью! Эксперимент с детерминированными структурами данных для обработки текста,это отличная разминка для ума и прекрасная база для исследования производительности CPU (IPC, кэш-миссы, локальность данных). По сути, вы построили строгую n-грамную модель на пересечении множеств. Поскольку вы планируете масштабировать проект, наращивать объемы данных и исследовать профиль производительности (кэш-миссы, CPU конвейер), позвольте подкинуть несколько сугубо инженерных C++ хаков, которые помогут увести систему от неизбежного Memory Wall и спасут алгоритм от тупиков.
1. Хак по памяти: Полный отказ от строк (String Pool + Token ID)
Хранить
std::wstringв качестве ключей и элементов графа — главная точка отказа по памяти и скорости при масштабировании.std::wstringна Linux занимает 4 байта на символ, а на Windows — 2 байта, плюс оверхед на кучу. Как лучше: сделайте String Pool (один плотныйstd::vector<char>илиstd::vector<char32_t>, где все уникальные слова лежат через\0). Каждому уникальному слову присвойтеuint32_t TokenID.В результате: вся ваша логика, векторы
nextи функция пересечения начинают работать с обычными 32-битными числами. Граф связей сожмется в памяти в 4–8 раз, а сравнение чисел процессором происходит за 1 такт, вместо посимвольного сравнения строк.2. Хак по кэш-миссам: Замена
std::mapна Flat Map / Dense HashTablestd::map, это красно-черное дерево. Каждый узел, это отдельная аллокация в куче. При поиске словаstd::map::findпроцессор вынужден прыгать по указателям в случайные адреса RAM, что гарантирует тотальный вымыв CPU L1/L2 кэша (тот самыйcache miss, о котором вы писали). Как лучше: раз у вас слова стали числами (TokenID), используйте Flat Map (отсортированныйstd::vectorпар для бинарного поиска) или префиксное дерево (Trie), адаптированное под массивы. Если хочется хэш-таблицу, посмотрите наankerl::unordered_denseилиabsl::flat_hash_map. Локальность данных вырастет драматически.3. Алгоритмический хак: Введение мягкого контекста (Спасение от
goto DONE)Сейчас ваша модель страдает от жесткого детерминизма, как только пересечение
intersect_next_wordsвозвращает пустой массив (такой точной комбинации из 3-х слов в базе не нашлось), модель аварийно завершает работу. Из-за этого она может только дословно цитировать куски, а на незнакомой фразе упадет. Лучше: реализуйте алгоритм отката (Backoff), как в классическом сглаживании Кнесера-Нея. Если пересечение по трем словам (NEXT_MAX = 3) выдало пустое множество — не делайтеgoto DONE. Автоматически уменьшите контекст: отбросьте самое старое слово и ищите пересечение по двум последним словам (NEXT_MAX = 2). Если и там пусто — ищите продолжение по одному последнему слову. В результате: модель обретет плавучесть. Она перестанет обрываться и сможет генерировать новые, не существовавшие в исходном тексте комбинации, сохраняя связность на стыках фраз.4. Хак для IPC: Векторизация пересечений через SIMD
Раз ваши списки слов в
next[j]станут отсортированными массивамиuint32_t, операцияintersect_next_wordsпревращается в классическое пересечение двух упорядоченных массивов чисел.Лучше: эту операцию можно отлично векторизовать с помощью SIMD-инструкций (AVX2 / AVX-512). Процессор сможет сравнивать по 8 или 16 токенов за один цикл. Для исследования IPC и CPU pipeline — это идеальное поле для экспериментов.
С удовольствием понаблюдаю за развитием вашего проекта, если решите переписать его на плоские структуры данных. Оптимизация такого кастомного движка под кэш процессора, это самый сок системного программирования на C++!

Aleksei_R_Pax_et_Bonum Автор
27.05.2026 09:01Спасибо за подсказки, некоторые очень остроумные, обязательно воспользуюсь.
Пред-сортировка next[] уже была реализована. Не стал перегружать статью :)

coms20
27.05.2026 09:01Мне кажется, что продолжение текста по набору слов (не контексту) работает не правильно:
"оборвал он вдруг в бешенстве и, не оглядываясь, вышел из кельи.""Полная восторгом душа его жаждала свободы, места, широты."
Такие резкие перепады настроения у описываемого героя в 2 соседних строчках это уже патология. Без какого-то аналога векторизации контекста не обойтись.
ksbes
27.05.2026 09:01Так там уже по сути и есть векторизация - только очень малодетальная (на уровне слов, а не “слогов”-токенов), и очень малоразмерная. Как говориться - “вычисление весов вручную”
Если эту тему развивтать - получится просто сеть, тольок несколько иной архитектуры

coms20
27.05.2026 09:01так векторизация делается по блокам текста с перекрытием, не по словам или токенам - они не несут смысл без контекста. т.е. векторизовать нужно приличный кусок текста порядка абзаца или как минимум предложения.

Aleksei_R_Pax_et_Bonum Автор
27.05.2026 09:01мой замысел - обойтись без канонической векторизации. А значит без необходимости использовать операции над векторами с аппаратной поддержкой NVIDIA.

Aleksei_R_Pax_et_Bonum Автор
27.05.2026 09:01Про резкие перепады настроения на грани патологии абсолютно согласен :)). И конечно же Вы правы - надо работать над улучшением стиля сгенерированных текстов.
Кстати, тексты Достоевского использовались в обучении студентов по курсу психиатрии - именно из-за мастерского описания патологий
Kamil_GR
А подскажите цель проекта?
Генерализации эта концепция не предусматривает...
ENick
Цель работы Автор сформулировал: "Задаёшь вопрос и получаешь ответ". С вопросом понятно, а с ответом """тем «умнее» будут казаться ответы ЯМ """ ничего не понятно. Два ключевых слова, определяющих ответ ЯМ: "«умнее»" и "казаться". Два абсолютно не формализованных понятия отражают основной алгоритм формирования ответа??? Цель понятна, не понятен смысл проекта. Генерить квази литературные тексты? Повышать энтропию?
Aleksei_R_Pax_et_Bonum Автор
См. ответ выше.
Энтропию повысить увы не получится :). Чем больше повторов, тем энтропия меньше
Aleksei_R_Pax_et_Bonum Автор
Цели минимум проекта:
1) написать продолжение "Бесов" - как это мог бы сделать сам Федор Михайлович
2) спасти Анну Каренину "руками Льва Николаевича"
3) узнать у Антона Палыча, что он думает о "развесистом вишневом саде" в соц. сетях
Цели максимум: показать ненужность аппаратного ускорения в языковых моделях и лопнуть пузырь ИИ.
Генерализация возможна. Я же упоминал в статье, что можно использовать любые исходные тексты - например статьи с arXiv.org для "вопрос-ответ"
Kamil_GR
Попытки выстроить семантический компьютер, через графы или как-то ещё, все провалились. Но кто я такой, чтобы вас убеждать. Посмотрим.
Если не сложно, расскажите, как вы планируете или ожидаете, или представляете процесс генерализации в вашем случае.
Aleksei_R_Pax_et_Bonum Автор
Обязательно отвечу по результатам работы