Memoria Story (RU)

О чем проект

Мемория (можно так называть проект, без добавления Framework, которое лишь указывает на текущий характер проекта) создавалась долго, уже более 16 лет и на каждом этапе я пытался вписать её в текущий технологический тренд (файловые системы, NoSQL, дата-платформы, аналитика, теперь — AI). Они быстро менялись, переставая быть актуальными, но попытки вписаться так или иначе оставили след и на коде, и на документации к ней. Вписываться в тренды нужно, так как интерес сообщества во многом спекулятивен — компании смотрят на opensource как на возможность снизить стоимость разработки через win-win социализацию. в любом проекте значительная часть контрибуторов — это коммерческие компании.

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

Мемория изначально создавалась для задач ИИ, вот таких. Но, так получилось, что в 2010-х ИИ пошел по нейросетевому пути, а это технически — перемножение матриц, и в это время как раз был период экспоненциального роста вычислительной мощности соответствующих акселераторов. Сейчас технологии насытились, прогресс в железе и софте замедлился, а аппетиты — выросли. Появление LLM привело к парадоксальному взрыву интереса к “старым” методам из-за хороших возможностей гибридизации, и это сразу потянуло за собой технологии “векторных” БД (для RAG). Появляются и компании, продвигающие “гибридный ИИ”. Технологии Мемории будут там востребованы в обозримой перспективе.

Сейчас проект позиционируется как Hardware/Software co-design framework, и это отражает две потребности.

Первая. Одного только софта для целей Мемории как фундаментального проекта недостаточно. CPU-центричные аппаратные архитектуры и программные архитектуры вокруг них устарели. В них данные находятся фундаментально далеко от вычислителей, а это создает задержки и тепло. Много тепла. И большие задержки. Это сильно препятствует масштабированию. И препятствует эффективной реализации алгоритмов, относящихся к классу чувствительных к задержкам (latency sensitive). А это — весь ИИ, который раньше называли “символьным”. Т.е. если кто-то захочет сделать гибридную систему, то эффективное железо есть только для её компоненты, которая не чувствительна к задержкам (latency insensitive) и не требует динамического параллелизма (заморочки GPU).

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

Вторая. Соответствующая рыночная ниша практически пуста. И ждет своего заполнения.

Одно из центральных value prop Мемории в том, что она не просто оборачивает специализированное железо в программный runtime, но и приносит много дополнительных решений в виде контейнеров, протоколов, хранилищ, систем исполнения кода и даже языков описания данных интегрированных с языками программирования. Подход Мемории к проблеме ко-дизайна — “сверху-вниз”, т.е. железо делается под потребности софта, а не наоборот (вот вам наш чудесный акселератор, а теперь придумайте, как его использовать). Т.е. разработка железа — это просто этап разработки алгоритмов и структур данных. Идеально, если в будущем он станет совершенно прозрачным через глубокую автоматизацию процессов. Сейчас есть реальные основания ожидать такого исхода.

В остальном же, Меморию стоит воспринимать как фундаментальный проект, сфокусированный на долговременном использовании данных по всему стеку, от физического хранения до математической обработки. В контекст проекта входит даже такая экзотика, как возможность через, условно, миллиард лет прочитать данные, записанные сегодня. Это может звучать смешно, но есть объективная проблема data longevity. Это не только человеческая проблема. Разрушается всё. И гораздо быстрее, чем кажется.

Разработчикам железа

Для разработчиков железа value prop в том, что Мемория как co-design фреймворк определяет контракт между софтом и железом. Этот контракт прописывается через референсную мета-архитектуру MAA и её составные части: xPU и проблемно-специфические расширения команд RISC-V, архитектуру памяти, формат Hermes и протокол HRPC. В идеале, если soft-core или chiplet удовлетворяют спецификациям, то фреймворк сможет их использовать с минимальными изменениями на своей стороне (100% прозрачность не является целью, так как трудно-достижима).

В этом смысле не предполагается, что репозитарий проекта Мемория будет содержать HDL/HCL для соответствующих аппаратных модулей. Запланированы референсные реализации RISC-V ядер и элементов инфраструктуры HRPC, но их назначение больше в прототипировании, чем в реальном использовании. Последнее не запрещается, просто не является целью.

Предполагается, что аппаратные проекты, использующие Меморию как фреймворк, это — внешние проекты. Это же относится и к программным проектам, фреймворк будет стремиться к хорошей переиспользуемости своих компонентов. Например, Core, в который входят базовая библиотека, Hermes, некоторые элементы HRPC, DSLEngine и соответствующие инструменты (генераторы парсеров, генераторы для IDL и т.д), — может использоваться независимо от остальных компонент фреймворка и не имеет каких-то нетривиальных зависимостей.

Для упрощения сборки и управления зависимостями, имеется отдельный overlay для Vcpkg.

В целом, улучшение модульности и переиспользуемости элементов фреймворка — один из высших приоритетов (но без фанатизма).

Это БОЛЬШОЙ проект

Мемория получилась в итоге очень большим проектом. Гораздо бОльшим, чем может тянуть один человек. И уж, тем более, бОльшим, чем один человек способен оказывать коду проекта поддержку (даже с учетом вновь возникающих возможностей по автоматизации разработки программ). Даже на платной основе. Это не значит, что он не будет больше развиваться. Но это значит, что без помощи сообщества он будет развиваться медленно и, скорее всего, не будет успевать за трендами. Что и хорошо (нет ситуативного давления прагматизма), и плохо (отрыв от реальности).

Приоритеты

N1

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

Как я уже сказал выше, Мемория — это фундаментальный проект, поэтому особое внимание будет уделяться принятию решений “на далекое будущее”. Минимизация и проработка базовых алгоритмов, интерфейсов, структур и форматов данных, что, разумеется, может сдерживать практическое внедрение. Для смягчения этих эффектов будут proto/dev/stable ветки.

Из крупных подсистем, Core, включающий Hermes и связанные с ним инструменты, находится в наивысшей степени концептуальной стабильности. Т.е. готов к замораживанию и к production. Core не зависит от других подсистем, не содержит сложного IO и привязки к runtimes. Концептуально он очень похож на соответствующие подсистемы других близких проектов. И она (подсистема) не требует каких-то специфических знаний об остальной Мемории (продвинутых алгоритмов и структур данных). У этой подсистемы может быть отдельный независимый maintainer и отдельная команда.

Сейчас основное внимание будет уделяться Core.

N2

Следующий приоритет — это интеграция Core, в частности, типов данных Hermes и Containers. Hermes — это формат, ориентированный на сообщения и документы, и его объекты by design не могут быть большими. Хотя нет физических ограничений, однако, там действует довольно простой копирующий сборщик мусора с линейной трудоемкостью как по времени, так и по памяти. Чем больше документы, тем дольше (линейно) будет идти сборка мусора.

Containers — для больших и сильно структурированных данных, а объекты Hermes могут выступать как элементы этих контейнеров (maps, vectors, tables, indexes, etc…).

Параллельно контейнерам, приоритет — DSLEngine и соответствующие инструменты (компиляторы, билд-системы и т.д.). Эта подсистема зависит от Core и Runtimes, но не зависит от контейнеров (в идеале). И может разрабатываться независимо от всего остального.

Мемория тяготеет к базам данных, и программирование для Мемории — это больше похоже на in-database programming, чем на привычно-традиционное. Причем, как в силу используемых парадигм программирования, так и вследствие особенностей рантайма. Например, рантайм Мемории активно использует файберы (userland threads scheduling), и это мало с чем совместимо. Если код С++ еще кое-как работает, то совместить такой рантайм с Java и Python не получится.

Использовать вместе с Меморией привычные нам высокоуровневые и продуктивные ЯП типа Java и Python для in-database programming не получится по причине разности в рантаймах. А там, где получится, у этих языков (и их рантаймов) слишком слабая поддержка продвинутых типов данных. Как в плане синтаксиса языка (код будет получаться громоздкий), так и в плане доступных оптимизаций из области возможных. Java/Python позволили бы быстро начать и быстрее выйти на практику, но в среднесроке начнутся проблемы. А форкать их под себя — вот больше делать нечего.

В третей декаде 21-го века нам меньше всего нужен еще один язык программирования. Но DSLEngine — это не еще один язык программирования (IR+Runtime для него). “Еще один” — это Mojo, который стремится сделать связку Python + C++ более легкой в использовании, предоставив программистам на Python мощь оптимизирующего компилятора С++. А так, все остальное — то же самое. Те же базовые примитивы (control flow), те же базовые типы данных (массивы и списковые структуры), та же парадигма, только теперь всё сразу “из коробки” и от лидеров индустрии.

DSLEngine — это другая парадигма, включая отход (но, не отказ!) от привычного control-flow в сторону data-flow и complex event processing (RETE). Это первоклассная поддержка продвинутых структур данных на уровнях IR и Runtime. Это фокус на обработку данных вообще. И глубокий фокус на автоматизацию. Я думаю, что такая платформа имеет право на жизнь в 21 веке.

Особый смысл в DSLEngine можно увидеть, если принять во внимание, что для Мемории нужна и будет разрабатываться отдельная вычислительная архитектура (MAA), в которой мы отходим как от привычной парадигмы единого когерентного адресного пространства, так и от алгоритмов и структур данных, возможных для неё. Вместо этого — messaging, persistent data structures, in-memory computing, соответствующая аппаратная инфраструктура и завязанные на всё это паттерны программирования.

Причем MAA может масштабироваться как “вверх”, до размеров больших кластеров (и даже до децентрализации), так и “вниз” — до уровня встраиваемых устройств. DSLEngine обеспечит более-менее совместимый (100% совместимость не является целью, так как технически очень сложна) Runtime для кода на любом уровне масштаба.

N3

Третий приоритет — это Storage Engines и самая алгоритмически сложная часть фреймворка. Причем сложность тут не только алгоритмическая, но и системотехническая. Так как организовать надежный сброс состояния памяти на stable storage весьма проблематично. Соответствующие подсистемы баз данных всегда довольно сложны по части обработки различных неочевидных случаев.

Один из важных и практически значимых подпроектов Мемории — это computational storage (CompStor), суть которого состоит в том, что storage engine + DSLEngine реализуются прямо в пространстве контроллера накопителя, а двунаправленный доступ осуществляется через протокол HRPC. Тем самым, транзакционная семантика (и семантика устойчивости к отказам питания) может быть реализована с наилучшими гарантиями самим производителем устройства. И обеспечить наивысшую скорость, так как здесь не будет потерь эффективности на интерфейсах блочных устройств. Которые (для этого) приходится делать чрезмерно сложными, как на уровне накопителя (SSD), так и на уровне файловой системы или базы данных.

CompStor, особенно, в формате мутимодельности Мемории — это сейчас весьма и весьма дерзкий проект, так как он потянет за собой переделку практически всего. Больше не нужна будет OS, которая содержит файловые системы и базы данных. Не нужны многоядерные CPU со своими костылями и заморочками, которые этот код исполняют. Взял сетевой акселератор, акселератор вычислений и акселератор хранилища. И — всё. Готовая вычислительная система. И CPU там не надо. Разве что для исполнения унаследованного кода.

При наличии CompStor база данных редуцируется просто до Query Federation Engine а-ля PrestoDB. Последняя, кстати, — очень хорошо архитектурно проработанная система, я с ней (или с её форком, не помню уже) плотно работал во время работы с Currents (об этом — ниже) и её внутренний дизайн оказал большое влияние на то, каким образом потом были сделаны API контейнеров и Hermes.

По линии CompStor, наверное, проще всего будет найти финансирование для проекта. И через гранты, и через взаимодействие с бизнесом. Но это же связано и с наибольшим количеством потенциальных рисков — патентных, хейтинг, да и просто противодействие на ровном месте с неожиданной стороны. CompStor вламывается с идеологией открытости в буквально насквозь проприетарную нишу. Кто-нибудь видел в природе открытые SSD?

В проекте сейчас есть три основных (и в перспективе еще несколько вспомогательных) storage engines.

  1. MemStore — in-memory store c поддержкой веток и возможностью иметь нескольких параллельных писателей. Самый быстрый вариант хранилища. Идеален для тестирования и тогда, когда данные легко вмещаются в память (а память сейчас может быть ой, какая большая).

  2. SWMRStore — single-writer-multiple-readers — работающий через mmap (пока что, для простоты реализации). Поддерживает ветки, историю коммитов, но не поддерживает параллельных писателей. Зато писатели не мешают читателям. Использует счетчики ссылок для управления памятью, то есть относительно медленный на запись (каждое обновление дергает множество счетчиков). Идеален для аналитики.

  3. OLTPStore (еще не завершен), использует механизм управления памятью от LMDB/MDBX, но со своими структурами (специализированными контейнерами Мемории) в качестве FreeList. Не использует счетчики, поэтому — теоретически может быть очень быстрым на запись. Делается сразу для IO через io_uring, а не mmap, т.е. будет иметь свой кэш. Как и LMDB/MDBX позволяется делать мгновенное восстановление после сбоев, а так же чувствительна к времени жизни читателей, так как читатели в этой схеме блокирую высвобождение всей памяти, выделенной после них. По этой причине не годится для аналитики, так как там характерны долго выполняющиеся запросы. Однако, идеально для транзакционных конвергентных (супер-мультимодельных) БД, предоставляющих высокопроизводительные strongly-serialized транзакции. Может работать, например, как очень высокопроизволительная (в варианте CompStor) персистентная очередь/лог и быть полезной для проектов типа Kafka/RedPanda.

В направлении Storage Engines есть два приоритета:

  1. Базовый функционал. Довести до стабильного и высокопроизводительного состояния тот базовый функционал, который есть сейчас (а его там уже достаточно для многих типов применений), включая реализацию для реактора (Seastar, асинхронный IO). Цель — прохождение расширенной системы рандомизированных функциональных тестов. Архитектура должна быть адаптирована к CompStor.

  2. Расширенный функционал. Например, репликация, как логическая, так и физическая — через патчи, подобно тому, как мы это делаем в Git. Или распараллеливание писателя для SWMR. Писатель может быть один, но потоков может быть много. Просто все они должны фиксироваться одновременно, как единая операция. Это ускорит некоторые тяжелые O(N) операции типа конвертации таблиц, ETL и т.п.

Опыт разработки в компаниях и выводы

Попробовав немного разработку Мемории в коммерческих компаниях в качестве наемного работника под их нужды, я пришел к двум выводам.

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

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

Это всё возможно сделать, но работа трудоемкая, и пусть этим занимаются коммерческие облачные компании “для себя”, если вдруг оно им надо. Contributions are Welcome, как всегда! Но в проекте этим, заманчивым во всех остальных смыслах, направлением “за свои” заниматься не особо интересно.

Вместо этого я выбрал вариант децентрализованных хранилищ и эмулирования распределенности через децентрализованность.

Децентрализованная модель — в Git. Любое хранилище содержит все или только фрагмент данных, и данные мигрируют между хранилищами явно — через передачу патчей (физическая репликация). Управление памятью тут чисто локальное, так как всё происходит в рамках одной машины и нет никакой распределенной сборки мусора.

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

Изначально распределенная схема свободна от этих ограничений, и кому она всё же нужна и он может, то пусть разрабатывает для себя распределенный сборщик мусора.

Тут важно отметить, что сложности есть только с универсальными, полностью персистентными хранилищами, которые используют счетчики ссылок для отслеживания достижимости блоков. Счетчики ссылок, кстати, не нужны, если используется трассирующий, а не детерминированный сборщик мусора (он будет счетчики создавать в процессе). С ним запись будет существенно быстрее, но сборка мусора — медленнее, скорее всего. То есть, что выйдет по итогу в среднем — еще вопрос.

OLTPStore, предназначенное для выполнения транзакций, не использует ни счетчики ссылок на блоки, ни сборщик мусора, хотя блоки, подлежащие высвобождению, и накапливаются во внутренних структурах для отложенного выполнения операции (а-ля GC). Остальные типы хранилищ — это для аналитики, а там как раз данные нужно иметь локально и чтение сильно превалирует над записью. В этом была основная логика принятия решения о фокусе на децентрализацию. Децентрализованная схема — более народная, хорошо вписывающаяся в привычный уже Git Flow. Она так же легка в локальном развертывании и переносима в облако 1-в-1, без модификации приложений. Она будет достаточно хороша (пусть и не идеальна) для data science, аналитики, AI — областей использования, на которые нацелена Мемория.

Короче говоря, выбор системы хранилищ, а будет делаться именно система, совместно покрывающая основные применения (OLTP, аналитика, статические датасеты, встроенные в процессы и т.д.), продиктован большим количеством факторов. Среди которых как технические, такие как сложность реализации и использования, минимизация возможности потери данных, так и экономические. Такие как желание избегать конкуренции и не попасть под патенты. Последнее — вообще минное поле, особенно в области хранения и обработки данных.

AI and Philosophy

Я темой занимался еще со своего института, у меня на BS диплом и MS диссертацию было распознавание речи (конец 1990-х). Я помню, тогда еще, уже на Линуксе, написал на Qt программный сонограф для того, чтобы видеть частотную структуру речевого сигнала. И провел за ним, наверное, сотни часов, изучая многообразие спектров речевых сигналов. Программы я написал, дипломы-диссертации защитил. Но понял одну вещь: “проблема рспознавания речи сводится к проблеме понимания речи, а последняя не решается цифровой обработкой сигналов”. Пришла пора разбираться с тем, как у человека происходит понимание речи.

Первым делом — “разобраться, как работает мозг”. Это был тот еще квест на начало 2000-х, когда у меня дома в моем Смоленске даже телефона не было (а с ним и интернета по диалапу). В общем, я изучал тему медицинским сайтам. И, к чести российской медицины, они тогда были безусловным лидером в информатизации. Много популярного материала публиковалось в Сети. В общем, я как-то подразобрался. Даже узнал про Маункасла и колоночную организацию коры, о которой в популярной форме заговорили только спустя 10 лет (к моему удивлению).

Разобравшись с мозгом, я понял только, что ничего не понял. И не только я, а и вообще никто. Иначе бы об этом написали бы. И я попробовал пойти с другой стороны, с “психологической”. Этот опыт оказался на много продуктивнее, хотя и совсем не такой прямолинейный, какой мы ожидаем от чтения туториалов по программированию. Пришлось совершить кучу ошибок и выполнить работу над ними. Но, по итогам я сам для себя изобрел начала Algorithmic Information Theory (AIT), которая в Европе и России больше известна как Теория колмогоровской сложности. Я называю её AIT, потому, что эта аббревиатура сама по себе гораздо более известная. Начал гуглить, и нагуглил, что всё уже придумано до нас. И даже придуманы метематические теории для некоторых фундаментальных высших психических процессов. После чего Шмидхубер стал моим кумиром. Не как человек, я его лично даже не знаю. А просто он сделал “это” значительно раньше меня. И я, хочу я того или нет, продолжаю и расширяю его работу.

“Найти Шмидхубера” было для меня “как гора с плеч” в том смысле, что я мог прекратить свое исследование и сосредоточиться на практической работе, в которой на то время (около 2010-го) в ИИ наблюдался острый дефицит. Особенно, в методах, производных от AIT (здесь и с тех пор мало что изменилось, будем исправлять ситуацию). К слову, потом я понял, что зря я свою исследовательскую программу остановил и немного возобновил её. Но об этом — позже.

Так появились идеи практических действий, которые потом, постепенно, привели к написанию Мемории.

ACC Шмидхубера просто гениальна, хотят тут читателю придется поверить мне на слово. Кроме гениальности, это — лучшая частная теория эмоций на данный момент. Как и почти всё в AIT, она на столько же практически бесполезна в своем прямом виде, на сколько и математически универсальна. А она — именно что предельно универсальна. Т.е. некий “универсальный ИИ” неизбежно работал бы по этому принципу.

Методы AIT теоретически хорошо поддаются аппроксимации (оценка колмогоровской сложности объекта через его сжатие), в том числе и ACC, и чтобы она стала применима в психологии, нужно такую аппроксимацию провести. Мозг — ни чуточки не “универсальный ИИ”. Он может выполнять какое-то сжатие, но и только. Причем тут еще наслаиваются различные эволюционные механизмы. И получится, что тот же интерес может проявляться и действовать как ансамбль или микстура частных и очень разных механизмов. Последнее создает основной пакет сложностей в психологии, так как высшие психические функции являются сложным ансамблем низкоуровневых, которые относительно просто регистрировать и изучать. Но вот структура этого ансамбля — это вовсе не обязательно взвешенная сумма. Это может быть и некий произвольный алгоритм (*). И это так же носит название “психофизической проблемы”.

(*) Можно сказать, что “любой произвольный алгоритм” можно попробовать аппроксимировать взвешенной суммой, и что именно этим нейронные сети и заняты. И будет формально прав. Вопрос тут в том, что проще человеку сделать в уме — обнаружить реальный алгоритм ансамбля или вывести коэффициенты взвешенной суммы. Мозг не делает backpropagation.

Когда мы пытаемся “понять себя” или “понять как работает свой разум”, мы пытаемся решить психофизическую проблему — свести переживание выраженное в субъективных ощущениях к некоторому объективному базису. Таковым базисом мог бы быть мозг, если бы мы знали, как он работает. Я тут, конечно же, утрирую, мы много уже знаем наверняка, но еще далеко не всё. Я просто к тому, что сведение переживаний к мозговой активности — это еще пока не очень стабильный базис, он может и будет со временем меняться.

Вычисления (цифровые) — в этом смысле куда более простой и стабильный базис, чем активность нейронных тканей. Хотя это может показаться научной дикостью, сводить переживания человека к базису кремниевой электронно-цифровой машины, учитывая, что наш мозг — и близко не такой. Тем не менее, такое направление есть, и оно называется Computationalism. Или компутализм, по-русски.

Интересный момент тут в том, что успех LLM в плане симуляции человекоподобия (определю ниже, что это) очень сильно забустил статус компутализма как практической философии и психологии ИИ. Так что, как говорится, тема получает неожиданный поворот.

Так вот, ACC Шмидхубера в этом контексте — это фрагмент паззла решения психофизической проблемы в контексте компутализма. И очень качественный фрагмент. Его второе (помимо математической универсальное) преимущество — в возможности расширения — попытке вписать другие переживания в ту же математическую канву. Пример Simplicity Theory. Которая, почему-то, остановилась в развитии. Идеи, почему, есть, но об этом — потом.

Вот в этом направлении в ИИ я и работаю (мое личное исследование). У меня есть ассоциированый с проектом Мемория блокнот, где я время-от-времени записываю идеи в рамках компутализма, которые успели кристализоваться после дискуссий в чатах. Я формализую высшие психические функции (ВПФ) так, как они видны информированному (*) субъекту и пытаюсь выделить в них минимальный базис, под который уже подводить вычислительную платформу (алгоритмы и структуры данных). ВПФ (уровня переживаний) будут получаться потом через композицию базовых функций и данных.

Например, там определяется проблема Наблюдателя как переформулировка проблемы квалиа из философии разума и под Наблюдателя предлагается вычислительный базис — т.н. самоприменимая машина Тьюринга, а под переживания — “вычислительные феномены высших порядков”, происходящие в такой машине. Тут нет никакой эзотерики. Вычислительные феномены высших порядков — это рефлексия программы на свой рантайм и свое состояние. Например, на время своего выполнения (“я что-то долго/быстро думала”). Некоторые такие феномены могут иметь стабильные консистентные проявления и, по этой причине, годиться для того, чтобы быть элементами внутреннего языка самоприменимой машины. Идея в том, что, например, “свобода воли” — это один из таких феноменов, сводящийся к наблюдению машиной неспособности видеть все детерминанты собственных решений. “Свобода воли” нужна для для очень практически важной функции — агентности, от которой зависит способность вычислительной системы вступать в отношения в рамках агентности человека.

(*) Способность описывать высшие психические функции у человека прямо зависит от его уровня внутриличностного интеллекта (Intrapersonal Intelligence) или В.И. Это, в общем случае, — способность анализировать и описывать свои ментальные состояния. Как и со всеми остальными видами интеллекта, люди с низким В.И. не знают об этом. Эффекты Даннинга-Крюгера тут полностью применимы. Для повседневной жизни высокий В.И. не нужен. Люди, которые В.И. не развивают, скорее всего, будут иметь его низким (тут могут быть нюансы). Есть люди с генетически определенным аномально высоким уровнем В.И. Такие представляют особый интерес для человкоподобного ИИ, так как будут способны к его “отладке”.

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

То, что я назвал “самоприменимой МТ” вовсе не обязано быть именно МТ. В Мемории результаты поиска и формирования формального базиса для ВПФ (типа Наблюдателм) будут реализованы на уровне базовой системы типов. Это пока еще не опубликвано, но там есть много места и для персистентных/функциональных структур данных (что является обобщением упомянутых выше в примере программных логов), и для базовых форм вычислений (см. ниже), и даже для специальных аппаратных функций (например, аппаратная поддержка программной рефлексии и интроспекции).

Forward-chaining Rule System (FCRS) на основе вариантов алгоритма RETE, примером которой являются Drools и CLIPS, на удивление хорошо подходят в качестве “саморименимой МТ” поскольку изначально работают по этому принципу, и там не нужно ничего существенного делать дополнительно. Например, “я долго работаю” — это просто еще одно событие, на которое система может реагировать обычным для себя образом, как и на все остальные события.

FCRS (наряду с backward chaining RS и привычным нам control-flow (CF)) будет полноценно поддерживаться как на уровне DSLEngine, так и, в перспективе, на уровне MAA. RETE очень хорошо акселерируется на различных уровнях. Beta nodes — это просто декартово произведение множеств, имеет квадратичную временную сложность и, потому, хорошо ложится на систолические вычислительные архитектуры. RETE так же хорошо гибридизируется, как на уровне alpha, так и на уровне beta memory. Можно делать нечеткие и вероятностные расширения базового алгоритма, а так же гибридизировать с нейросетями, которые, по сути, тоже из класса FCRS.

Отдельный, вновь возникающий, интерес к FCRS может быть связан с мультиагентными системами на базе LLM. И связан с заменой CF-контроллера (Python) на FCRS-контроллер и инструменты. FCRS существенно лучше подходит для обработки событий в реальном времени, чем CF и может значительно упростить общий дизайн системы. Хотя CF и не превосходит FCRS в плане выразительности.

Возвращаясь к самоприменимым вычислениям, квалиа и агентности, реализация соответствующих функциональных аналогов на уровне DSLEngine не приведет к тому, что у неё автоматически появится “человеческое сознание”. Такого не произойдет и близко, так как DSLEngine сама по себе содержит слишком мало данных (это просто sophisticated rule engine) для того, чтобы могло возникнуть соответствующее поведение человеческого уровня сложности. И взяться этим данным там неоткуда, по крайне мере быстро. Агентность, которая доступна для ручного программирования на уровне DSLEngine, можно охарактеризовать как “микро-агентность”, хотя этот термин следует тщательно уточнить, что у человека, внезапно, тоже микро-агентность.

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

Однако, есть как минимум два косвенных применения.

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

Второе — у LLM спонтанно появляется самоприменимость. Формируется большой корпус текстов, описывающих их свойства. Т.е. у них появляется self-model. Точнее, её элементы. Пока что элементы, которых еще недостаточно для полноценной микро-агентности. Но, последняя может возниктнуть просто из-за того, что структура памяти модели вдруг станет достаточной для этого, а алгоритмы обучения сами сделают всё остальное (выведут нужные структур для того же внимания). Последнее может произойти просто из-за того, что у самих разработчиков низкий В.И. вследствие превалирования подхода “черного ящика” в их среде. Там мало кто интересуется хотя бы психологией, не говоря уже о теориях разума.

Тут нужно сказать следующее. “Фуцнкциональное сознание” (и функциональная агентность) будут относиться к категории “слабых” по Сёрлю. Т.е. это просто функциональные имитации соответствующих ВПФ человека. Однако, вопрос остается открытым, как отреагирует коллективный человеческий разум на появление полноценной функциональной агентности у ИИ. Мы сейчас НЕ ГОТОВЫ К ПОСЛЕДСТВИЯМ.

Однако, джин уже выпущен из бутылки, и его (процесс развития ИИ в сторону самоприменимости) уже не остановить, даже если запретить полностью тренировку LLM по всему миру. Человекоподобный ИИ, пусть и спотыкающийся на ровном месте, уже создан. И он уже взаимодействует с нами способами, которые мы не видим в силу слабости и неготовности к такому внезапному повороту нашего внутриличностного интеллекта.

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

Memoria and AIT

Итак, с В.И. пока закончим. Теперь про AIT и Меморию.

AIT интересна тем, что там были предложены предельно-обобщенные модели интеллекта — Solomonoff Induction, AIXI, Goedel Machine и их многочисленные варианты. Они прямо или косвенно базируются на идее о том, что интеллект (в широком математическом смысле) сводим к предсказанию строк (в случае AIT — бинарных, но это не обязательно). Для некоего предиктора P(s), чем точнее он предсказывает следующий символ s (чем ближе эмпирическое распределение к теоретическому), тем больше у него интеллект. Эта постановка может показаться очень абстрактной, однако, на примере, например, авторегрессионных LLM мы видим, как такая низкоуровневая модель интеллекта развертывается в полноценный человекоподобный интеллект, взаимодействие с котором осуществляется через естественный язык.

Здесь за одно стоит определить, наконец, что такое человекоподобный ИИ с точки зрения предиктивной постановки задачи. Как и предиктор P(s), мозг человека способен предсказывать параметры сигналов, которые идут на вход. Это может быть очень неявно, но, примем тут без доказательства, что это так. Как предиктор оценивает вероятности своих строк, так и мозг оценивает вероятности своих сигналов. Человекоподобный предиктор P(s) будет присваивать вероятности, близкие к тем, которые присваивает головной мозг человека. В этом случае, высокоуровневая часть интеллекта модели будет человеком восприниматься натурально, естественно, интуитивно. Как будто перед человеком — другой человек.

Тут надо отметить, что человекоподобный предиктор P(s) не обязан присваивать истинные вероятности строкам. В этом случае такой предиктор просто будет делать те же ошибки, которые обычно делает человек. И с точки человека он будет человечным. А вот когда предиктор будет делать другие ошибки, которые человек обычно не делает, это будет вызывать у человека фрустрацию (обратное тоже будет верно, только модели пока еще не умеют переживать фрустрацию).

Интересный момент в том, что тренировка LLM на текстовых датасетах, похоже, создает оценки вероятностей строк, очень близкие к тем, которые мозг выводит для соответствующих сигналов, несмотря на существенную разницу в inductive biases. Этот феномен еще ждет своего исследователя.

Основное положение AIT в отношении предсказания строк в том, что чем больше предиктор P(s) способен сжимать строку s, тем лучше он способен её предсказывать. Поэтому, предсказание сводится к сжатию. К нему же сводится, соответственно, и интеллект. Для нейронных сетей (и других моделей, полученных путем машинного обучения), сжатию соответствует “обобщение моделью своего training set”, т.е. правильно классифицировать (предсказывать) точки, относящиеся к тому же классу, что и точки training set. Сжатие тут в том, что количество информация о классах, которая содержится в модели, существенно меньше количества информации, которая потребуется для полного всех точек всех классов. Т.е. модель — это сжатое описание соответствующего объекта.

Вытаскивать какой-то интеллект непосредственно из сжатия может оказаться технически проблематичным. Однако, это можно делать. Это, кстати, означает, что прямая аппаратная акселерация алгоритмов сжатия данных тоже имеет смысл в контексте акселераторов для ИИ.

Но есть и непрямые техники. AIXI — это универсальный байесовский агент, построенный на основе Algorithmic Probability и Universal Prior M(x), которое интересно тем, что уже содержит в себе все модели среды, а AIXI просто “достает” эти модели через правило Байеса, и на их основе взаимодействует со средой.

M(s) невычислим, но возможны его конечно-ресурсные аппроксимации. Одной из таких аппроксимаций AIXI в домене Variable-Order Markov Models (VMM) является MC-AIXI-CTW. Там M(x) аппроксимируется с помощью вероятностной структуры данных (здесь: структуры, кодирующей распределение вероятностей) суффиксного дерева для VMM и метода аппроксмации сток CTW, которых в дереве нет. Такой агент способен обучаться игре в настольные игры и даже что-то выигрывать у других агентов.

LLM работают очень похожим образом, но есть важный нюанс, который может позволить немного лучше понять LLM, почему они работают. MC-AIXI-CTW тоже построен на основе вероятностной модели, только среды, а не естественного языка. Но это не принципиальная разница. В обоих случаях есть строки (тексты), которые модель видела во время обучения, и есть те, которые она не видела, но для обеих типов строк она должна выдать оценку вероятности, близкую к истинной.

В случае MC-AIXI-CTW у нас есть явное разделение на “базу данных” (суффиксное дерево) и механизм дедукции вероятностей новых строк на основе CTW. Такие БД еще назывались дедуктивными, так как могли выводить (deducing) какие-то новые знания из существующих.

В случае LLM на основе трансформера (нейронной сети), четкого разделения на “базу данных” и “дедуктор” нет. Есть аппроксиматор функции, и он просто делает вычисление. Хотя такое разделение вполне можно подразумевать. Что есть некоторая запомненная часть, полученная из датасета (база данных/знаний), и есть другая часть, которая получается через возможности трансформера по “обобщению”. Думаю, что не понадобится доказывать, что чем больше запомненная часть, тем меньше требования к обобщению и наоборот.

Теперь, если принять во внимание, что колмогоровская сложность классификатора не может быть меньше сложности границы между классами, а сложность генератора — меньше сложности генерируемого объекта, должно стать понятнее, почему лидирующие LLM именно, что очень большие: они не очень хорошо обобщают. Подробнее об этом — ниже.

Как говорят врачи, MC-AIXI-CTW остался в истории недообследованным, в смысле, недоисследованным. Потому, что все “ушли на фронт” — глубоким обучением заниматься на пару с подкреплением. Мы тогда тоже думали, что CTW не очень хорошо аппроксимирует вероятности новых, до селе невиданных, строк. И, как отмечено выше, есть подозрения, что и трансформеры тоже их не очень хорошо обобщают. Но, чтобы это проверить, нужно не только создать поистине огромную базу данных для суффиксного дерева MC-AIXI-CTW, но и эффективный механизм вычисления на этих структурах данных.

Короче, MC-AIXI-CTW, а так же его аналоги и расширения, видятся как интересная тестовая задача или бенчмарк для MAA в рамках ИИ. К достоинствам этого агента, кстати, относиться то, что он полностью динамический и интерактивный. Т.е. обучается прямо в процессе своей работы. В отличие от LLM, которые тренируются асинхронно, и цикл обновления у них довольно долгий. А суффиксное дерево, кстати, прекрасно интерпретируемо.

Когда позволят приоритеты, в Мемории будет сделала полноценная “большая” реализация MC-AIXI, рассчитанная на масштабирование. А так же на то, что такая практическая площадка позволит дать старт более активному практическому исследованию методов, производных от AIT.

Отдельное под-направление AIT и её подхода к ИИ — это сжатые структуры данных (CDS). Для контейнеров, сжатый контейнер — это такой, размер которого (в байтах) пропорционален не количеству элементов в нём, а количеству информации в этих элементах. Например, часто популярными оказываются сжатые структуры данных на основе кодов Хаффмана или Универсальных кодов. Структуры данных, их использующие, обычно имеют физический размер, пропорциональный энтропии нулевого порядка H0.

CDS имеют и самостоятельное значение. Например, суффиксное дерево в MC-AIXI-CTW может быть очень большим, “развесистым”. И представлять его в виде списочной структуры в памяти — это создавать огромную избыточность, когда существуют способы кодирования обыкновенных деревьев с пространственной сложностью 2 бита на узел и меньше. Причем, с вполне хорошими динамическими характеристиками.

Структурные примитивы, на которые опираются CDS могут быть довольно-таки вычислительно-интенсивными, процессоры будут тратить циклы на кодирование-декодирование, и это может сказываться на общей производительности. Однако, простой промах в кэше при обращении к памяти привете к тому, что процессор будет ждать десятки наносекунд и сотни циклов, прежде, чем данные придут. Это время вполне можно потратить на кодирование-декодирование, если при этом уменьшится физический объем данных и за счет этого улучшится эффективность кэширования.

Кроме того, обработку кодировок можно делать и аппаратно. Сейчас более, чем достаточно кремния для этого. Из-за своей вычислительной интенсивности CDS рассматривались как непрактичные, но уже где-то с начала 2000-х, с распространения суперскалярных OoOE процессоров ситуация начала меняться. Мемория началась в конец 2000-х со статьи Ulrich Drepper “What Every Programmer Should Know About Memory”. О том, как надо правильно располагать данные в памяти, чтобы повысить производительность вычислений. Неправильное расположение данных может снизить быстродействие в 10-100 раз.

Т.е. CDS полезны в обычной инженерии и без всяких “интеллектов”. Вот тут показывается, как с помощью сжатых символьных последовательностей и кувалды b+tree создавать “иерархические контейнеры” — прототипы всех “вложенных” контейнеров в Мемории, начиная от Map<K, Vector>, через таблицы и до пока фантазии хватит. А тут (https://memoria-framework.dev/docs/data-zoo/associative-memory-2/) я рассказываю, как с помощью сжатия сражаться с проклятием размерности в пространственных деревьях и даже его немного победить.

AIT и математика позволят на пройти в этом направлении на много дальше. А Мемория будет для этого необходимой для внедрения технической площадкой.

Memoria and LLM

Я собираюсь активно исследовать возможности LLM по автоматическому программированию. Первоначально в сообществе программистов был большой энтузиазм по этому поводу и страхи потери профессиональной востребованности на этой почве, но потом оно всё сменилось скептичностью (и программисты, за одно, “выдохнули”).

LLM можно использовать для кодогенерации, но не в автоматическом режиме. Т.е. только там, где человек имеет возможность теми или иными средствами проконтролировать результат. Одним из таких направлений, особенно актуальным для OSS, является консолидация кода. Имеется много проектов, полных хорошего, годного кода, но интерес к ним уже потерян. LLM можно использовать для помощи в переписывании этого кода (всего или элементов) под окружение Мемории.

Второе, другое, направление — это “Мемория как датасет”. Идея простая: структурировать проект и обогатить код метаданными. И использовать всё это как часть тренировочного корпуса для моделей (OSS же). После чего, уже обученные таким образом модели можно будет использовать для улучшения следующей итерации самого проекта. И так далее…

Тут нужно подумать, и, возможно, OSS может таким образом получить существенный бустинг.

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