Представление информации для нейронок



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





💻 Биты и байты

Основной формат представления любой информации в компьютерах.

Бит = 0 или 1. Байт = 8 бит (но это не точно, тут большая история и контекст).



Есть современные модели, которые оперируют напрямую байтами:

Beyond Language Models: Byte Models are Digital World Simulators

MEGABYTE: Predicting Million-byte Sequences with Multiscale Transformers

ByT5: Towards a token-free future with pre-trained byte-to-byte models



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





🔤 Текст / Символы

Юникод — это стандарт, который пронумеровывает все существующие символы в письменности человечества. Всего описывает около 150к символов, но может до 1.1кк. Конкретные кодировки описывают каждый символ с помощью от 1 до 4 байтов. UTF-8 и UTF-16 — кодировки переменной длины, то есть разные символы могут занимать разное число байтов.



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



Современные модели такого типа довольно редки, см. например CANINE: Pre-training an Efficient Tokenization-Free Encoder for Language Representation. Кроме игрушечных примеров и исторической ценности, символы как входы полезны в узких задачах, типа расстановки ударений или генерации названий и имён. И как альтернативный вариант там, где токены найти не удалось.





🔤 Текст / Слова

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



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





🔤 Текст / Токены

Мы можем соединять символы в n-граммы и нумеровать уже эти n-граммы. Теперь задача такая: минимизировать среднюю длину закодированных текстов при фиксированном размере словаря. Есть несколько основных алгоритмов, которые делают это для заданного набора текстов: BPE, Unigram, SentencePiece. Какой из них использовать — зависит от специфики языков.



Чуть подробнее почитать можно тут.



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





🖼️ Картинки / Пиксели

Если упрощенно, то картинка — это двумерный набор пикселей, чаще всего трёхканальных 8-битных чисел. Самое важное слово тут — “двумерный”, что и отличает картинки от текстов.



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





🖼️ Картинки / Патчи

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



Это основной формат, которым оперируют энкодеры типа ViT.





🖼️ Картинки / Латенты

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



Это основной формат, которым оперирует Stable Diffusion.





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