Как я создал генератор Haiku для работы на блокчейне

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

Существующие генеративные NFT

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

Art Blocks — одна из крупнейших платформ для генеративных NFT. Художники создают скрипт (часто с помощью p5js), который может взять число и превратить его в произведение искусства. Каждое число будет производить другой результат. Этот скрипт сохраняется в виде текста в блокчейне Ethereum. Когда вы создаете NFT на Art Blocks, транзакция сохраняет случайное начальное число на ваш адрес Ethereum. Чтобы просмотреть искусство, ваш компьютер извлекает скрипт из блокчейна, извлекает начальное число, а затем ваш компьютер запускает сценарий на этом начальном значении. Все вычисления происходят на компьютерах, просматривающих искусство; Блокчейн — это просто книга для отслеживания сценария и того, кто какими семенами владеет.

Другой подход заключается в создании произведений искусства по запросу, но путем вызова API вне блокчейна. Это известно как оракул. Оракулы часто используются для доступа к внешним источникам данных, таким как обменные курсы для финансового приложения. Но их также можно использовать для вызова API, который генерирует текст с использованием GPT-3, или дерево пиксельной графики, которое представляет выбросы углерода в вашей блокчейне. В этом случае искусство генерируется черным ящиком, и вы не знаете, как вы получили тот результат, который сделали. Результат также хранится вне сети, поэтому блокчейн не дает вам никаких гарантий неизменности.

И еще один — просто создавать искусство заранее. Например, с помощью Обработки сгенерировать 100 случайных изображений в формате jpg, а затем отчеканить эти изображения как NFT на OpenSea. Эти изображения будут храниться вне блокчейна с использованием чего-то вроде IPFS, а NFT в блокчейне будет ссылаться на это изображение.

Есть действительно удивительные художники, создающие потрясающие и новые произведения искусства в качестве NFT. У меня нет претензий к качеству арта. Но с технической точки зрения я нахожу эти подходы неудовлетворительными, потому что все они имеют одну общую черту: они переносят вычислительную сложность создания произведений искусства с блокчейна на какой-то другой компьютер, будь то ваш компьютер, API в облаке, или компьютер художника. NFT используются просто как доказательство права собственности и не являются неотъемлемой частью самого искусства.

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

Учитывая, насколько плоха эта идея, именно это я и собирался сделать.

Идея

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

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

Почему это плохая идея

Блокчейны по своей природе имеют временные и пространственные ограничения. Блокчейны работают путем дублирования вычислений и хранения на многих компьютерах.

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

Эта стоимость отражается в потребности в газе для выполнения транзакций. Желтая бумага Эфириума описывает стоимость различных операций, таких как вычисления, хранение или загрузка байтов. Хранение 1 МБ будет стоить 640 миллионов газа, что составляет примерно 64 ETH или 170 000 долларов США по сегодняшней цене на газ и обменному курсу. Это просто хранилище и не влияет на стоимость вычислений.

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

Имея в виду цель, следующим вопросом было как создать хайку на блокчейне. Проект, на который я ссылался выше, использует повторяющуюся модель глубокого обучения, которая занимает 140 МБ на диске и требует больших вычислительных ресурсов для запуска.

Модели цепи Маркова

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

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

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

Каждое слово связано с другими словами вероятностью того, что это слово следует за предыдущим. Чтобы сгенерировать текст из этого, если бы мы начали с «однажды», в 100% случаев мы выбирали бы слово «после», а оттуда мы всегда выбирали бы «а». В этот момент у нас есть несколько слов, которые могут последовать. Каждый раз, когда мы генерируем предложение, содержащее «а», мы можем получить другое слово после «птица» или «колбаса».

Эти вероятности исходят из тренировочного процесса. Обучение осуществляется путем обработки набора текста (известного как корпус) и отслеживания каждого перехода между словами.

В этом случае «после» всегда следует за «однажды», поэтому в нашей модели оно будет следовать за ним со 100% вероятностью. В то время как четыре слова идут после «а», каждое равное количество раз, поэтому каждое из них имеет равный 25%-й шанс.

Это становится намного сложнее по мере роста корпуса, но идея остается той же: частота, с которой пара слов встречается в корпусе, дает модели вероятность генерации этой пары.

Создание генератора блокчейна Haiku

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

Блокчейн потока

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

Рассмотрев несколько вариантов, остановился на Flow. Flow — относительный новичок, наиболее известный благодаря NBA Top Shot, но с растущей экосистемой приложений. Flow использует алгоритм консенсуса PoS, который разделен на несколько разных типов узлов. В результате выполнение происходит на относительно небольшом количестве компьютеров по сравнению с большинством блокчейнов. Трудно оценить вычислительное/энергетическое/углеродное воздействие выполнения сложных транзакций в блокчейне Flow, поскольку в настоящее время все транзакции облагаются фиксированной ставкой, эквивалентной менее чем одной сотой копейки, но наверняка это на порядки ниже, чем при использовании блокчейн, такой как Ethereum.

Что подтолкнуло меня к Flow по сравнению с другими блокчейнами PoS, так это его язык программирования Cadence и экосистема разработчиков. Cadence имеет простой и понятный интерфейс для программирования смарт-контрактов, особенно для новичков в программировании смарт-контрактов, таких как я. Есть хорошие туториалы с онлайн-площадкой для начала работы и понятной справочной документацией по API. Flow и Cadence все еще находятся в стадии активной разработки, поэтому я столкнулся с некоторыми местами, где документация устарела, а некоторые части экосистемы разработчиков все еще находятся на ранней стадии разработки, например, библиотеки JavaScript, но в целом у меня был хороший опыт разработки на Flow.

Построение марковской модели, генерирующей хайку

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

когда-то колбаса вступила в товарищество и мышь с мышью с мышью...

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

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

Я обработал каждое «хайку», чтобы каталогизировать переходы от состояния (номер строки, текущее слово и предыдущее слово) к следующему слову. После этого шага у меня было около 6,5 миллионов переходов.

В следующем примере показаны эти переходы от текущего слова (the) к каждому слову, которое следует за «the», и сколько раз это произошло.

the, world, 644
the, night, 474
…
the, sudden, 2
the, change, 1

При этом вы можете рассчитать вероятность перехода из одного состояния в слово. Если бы эти четыре слова были единственными четырьмя словами, которые следуют за «the» в нашем корпусе, «мир» встречается в 57,4% случаев, «ночь» встречается в 42,3% случаев, а «изменение» встречается менее чем в 0,1% случаев. время. Это означает, что когда я использую эту модель для создания хайку, в 57,4% случаев, когда текущим словом является «the», следующим сгенерированным словом будет «world», в то время как «change» будет очень редко.

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

  • Первая модель использует номер строки, текущее слово и предыдущее слово для генерации следующего слова.
  • Вторая модель использует номер строки и только текущее слово для генерации следующего слова. Эта модель является запасным вариантом, когда текущее состояние не существует в первой модели. Например, это тот случай, когда мы находимся в начале хайку и у нас еще нет двух слов, или если генерируется необычная пара слов, такая как «изменение».
  • Последняя модель специально моделирует концы хайку. Проблема, с которой я сталкивался ранее при создании хайку, заключается в том, что, поскольку хайку ограничены по размеру (лишь ограниченное количество строк и слогов), у вас часто остается незаконченная мысль в конце стихотворения. Я обращаюсь к этому, создавая модель состояний, которые приходят в конце хайку в обучающих данных. Если это состояние встречается приблизительно к концу создания поэмы, мы выбираем этот вариант и завершаем поэму, вместо того чтобы продолжать генерацию.

Полный код для обработки обучающих данных и построения моделей можно найти здесь.

Портирование на поток

После обучения моделей мне пришлось заставить модели работать на блокчейне Flow. Это повлекло за собой перенос моего кода Python на смарт-контракт Cadence. Cadence — это «ресурсоориентированный» язык программирования, который позволяет очень легко и безопасно выполнять все части блокчейна — чеканить NFT, хранить их в правильном аккаунте и обменивать средства. Но хотя Cadence и завершена по Тьюрингу, она гораздо более ограничена, чем такой язык, как Python, из-за чего перенос кода, генерирующего хайку, стал более сложной задачей.

Уменьшение моей модели

Но самая большая проблема заключалась в том, чтобы найти поддерживаемое Cadence представление модели, достаточно маленькое, чтобы хранить его в блокчейне. Мой практический предел составлял от 1 до 2 МБ для каждой из трех моделей, исходя из ограничения размера транзакции 4 МБ Flow.

Чтобы перейти от сотен МБ обучающих данных и 6,5 миллионов переходов состояний к нескольким МБ, я сделал следующее:

  • Сократите словарь слов до 1000 самых распространенных слов. Размер конечной модели растет экспоненциально по мере увеличения количества слов в словаре из-за множества взаимосвязей между новым словом и другими словами. Я обнаружил, что 1000 — это хороший баланс между размером модели и разнообразием сгенерированных хайку.
  • Сократите нечастые переходы между оставшимися словами. Это также происходит за счет уменьшения разнообразия продукции. Возьмем приведенный выше пример: хотя «the» и «change» включены в словарь из 1000 слов, «the change» не включен в качестве перехода состояния. Это не только экономит место, но и помогает предотвратить грамматически неправильные переходы. В то время как «изменение» может быть правильным, когда «изменение» — это существительное, как в «дайте мне сдачу», обычно «изменение» — это глагол. Модель не знает, в какой части речи использовалось слово, поэтому «изменение» обычно интерпретируется как глагол, за которым следуют такие слова, как «мой» и «твой».
  • Сожмите слова в более мелкие представления. Моя схема сжатия заключалась в том, чтобы заменить слова уникальными буквенно-цифровыми кодами, давая самые короткие коды наиболее распространенным словам.

Получение точного количества слов и порога для нечастых переходов было итеративным процессом, поскольку я создавал модели и тестировал их в Flow. Flow/Cadence также все еще находится на ранней стадии, и новые версии среды выполнения Cadence заставляли меня несколько раз корректировать размер моих моделей.

Вот фрагмент из словаря для обратного сжатия:

{
  "a":"END",
  "b":"START",
  "c":"\n",
  "d":"the",
  "e":"I",
  "f":"to",
  "g":"and",
  "h":"a",
  "i":"of",
  …,
  "pg":"walking",
  "ph":"lonely",
  "pi":"thousand"
}

«НАЧАЛО» и «КОНЕЦ» — это символы, которые я использовал для обозначения начала и конца хайку. После этого чаще всего используется «\n» (перевод строки), за которым следуют «the» и «I». «Тысяча» по совпадению является наименее частым из 1000 слов в словаре, и, как вы можете видеть, его можно сжать всего до двух символов («пи»).

Вот как выглядит модель:

{
  "d":{
    0:{"c":8,"aw":9,…,"i6":34,"d7":35},
    1:{"c":7,"bB":8,…,"gm":46,"aj":47},
    2:{"cP":1,"bG":2,…,"k9":51,"mc":52}
  }
}

Это модель слов, которые следуют за словом «d», которое переводится как «the». Внутри есть три словаря, по одному на каждую из трех строк хайку. В первой строке чаще всего после «the» следует слово «c» («\n»), во второй — «aw» («только»), а в последней — «d7» («господин»). Максимальное число — 35, поэтому, чтобы сгенерировать слово, следующее за «the» в первой строке хайку, выберите случайное число от 1 до 35 и выберите первое слово, значение которого меньше или равно этому числу. 5 переводится как «\n», а 9 как «только». В переводе на проценты для данного конкретного случая это означает, что примерно в 23% случаев разрыв строки следует за «the», в то время как вероятность каждого другого слова составляет 3%.

Портирование кода генерации в Cadence

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

Основная идея состоит в том, чтобы взять случайное слово из модели, а затем использовать это слово для случайного выбора следующего. Во время генерации, если в первой строке 5 или более слогов или 7 или более во второй строке, то в качестве следующего «слова» вставляется разрыв строки. А в последней строке, если слогов 4 и более, то мы пытаемся тянуть из модели окончания, описанной выше.

Хотя я говорил о выборе «случайных» слов, на самом деле нам нужно псевдослучайное слово — что-то, что кажется случайным, но ведет себя повторяемым образом. Одним из преимуществ, которые мы получаем от создания этого на блокчейне, является явное происхождение хайку. Мы можем знать не только историю владения, как в случае с другими NFT, но и как именно она была создана. Предполагая, что у нас есть семя, мы всегда можем вернуться назад, проследить код и понять, что произошло, чтобы создать то или иное хайку.

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

* Можно заранее узнать, в какой блок будет включена ваша транзакция, если вы достаточно быстры, но на практике это непредсказуемо.

Полный код смарт-контрактов, включая модели и код генерации, можно найти здесь.

Полученные результаты

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

Да, последний состоит всего из двух слов. Как я упоминал ранее, одна из замечательных особенностей использования блокчейна заключается в том, что вы можете точно определить, что произошло, учитывая начальное число случайных чисел. (Я оставлю это читателю в качестве упражнения; здесь — транзакция, которая породила хайку № 221.)

Вы можете прочитать больше о проекте, а также найти весь исходный код по адресу: https://github.com/docmarionum1/bitku

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

Джереми Нейман совершает такие же бессмысленные действия на своем веб-сайте: http://jeremyneiman.com/

Спасибо Эбигейл Поуп-Брукс за редактирование и отзыв.

Все изображения в этой статье созданы автором, если не указано иное.

[1] Приложение: Состояние машинного обучения в блокчейне

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

Я смог найти только один другой пример исходного кода, который реализует машинное обучение в смарт-контрактах: Децентрализованный и совместный ИИ на блокчейне Microsoft Research (также известный как Совместное использование обновляемых моделей (SUM) на блокчейне) .

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

Проект был реализован на Ethereum и показал работу с использованием локального эмулятора. Я не могу найти никаких указаний на то, что он был развернут в основной сети, и его использование сейчас было бы непомерно дорогим. Но я видел, как этот подход работает на блокчейне PoS.

Помимо этого, я не смог найти никаких реализаций машинного обучения на блокчейне.

  • Есть бумага, в которой предлагается схема использования блокчейна для стимулирования создания эффективных моделей (вспомните Kaggle, но на блокчейне), но, насколько я могу судить, это всего лишь теория.
  • Существуют исследования в области блокчейнов, специально предназначенные для облегчения машинного обучения, такие как предлагаемая LearningChain, но это совершенно другой зверь — он использует блокчейн для координации и защиты распределенного машинного обучения — он не запускает машинное обучение в смарт-контракте.