- PVSM.RU - https://www.pvsm.ru -

Меня долгое время интересовал запуск больших языковых моделей на пользовательских устройствах: есть что‑то в том, чтобы запустить одну из лучших языковых моделей на обычном домашнем компьютере или на мобильном телефоне, помещающемся в карман.
В этом посте я расскажу о своём пет‑проекте AQLM.rs [1]. Я написал инференс модели Llama 3.1 8B, работающий в браузере на WebAssembly без использования GPU, с помощью алгоритма сжатия, разработанного нашей лабораторией [2].
Попробовать можно на сайте проекта [1].
Запуск языковых моделей на пользовательском девайсе — далеко не новая идея. Например, такие модели, как Llama 3.2 1B и Llama 3.2 3B, изначально создавались с целью запуска на маломощных устройствах.
Модели, имеющие 8 млрд параметров, идеально подходят для демонстрации того, что может быть помещено в браузер с помощью продвинутых алгоритмов сжатия.
В разжатом виде на каждый параметр приходится по 16 бит, и, как следствие, модель 8B весит 16 ГБ. Используя стандартные 4-битные методы сжатия, такие как nf4, можно сжать её до 4 ГБ. В этом проекте я использую экстремальное сжатие в 2 бита, сжимающее тело модели в 8 раз. Для слоёв головы и эмбеддингов я всё ещё использую 4-битное и 8-битное сжатие, поэтому модель получается размером в районе 2,5 ГБ.
Плюс экстремального сжатия заключается в том, что с уменьшением размера сама модель ускоряется, поскольку скорость вычисления такого рода сильно упирается в работу с памятью. Меньше памяти — значит, больше скорость.
Отдельно хочется упомянуть, что Llama 3.1 8B, сжатая до 2 бит нашим алгоритмом, всё ещё лучше, чем Llama 3.2 3B в несжатом виде, потому что занимает в 2 раза меньше места.
Большие языковые модели состоят из матриц. Основная вычислительная нагрузка при работе модели — это обыкновенное умножение матрицы на вектор. Оптимизацией именно этой части занимаются методы сжатия. Они пытаются уменьшить размер матриц, меняя их представление на более компактное, минимизируя потери качества.
В мае 2024 года наша команда из Yandex Research вместе с коллегами из университетов IST Austria и KAUST опубликовала исследование [3], в котором мы описали алгоритм PV‑Tuning для улучшения методов сжатия больших языковых моделей без изменения формата сжатых весов (я писал [4] про неё на «Хабре»).
В моём проекте в качестве базового метода, улучшаемого PV‑Tuning, я использую AQLM [5]. В этом методе сжатым представлением является аддитивная векторная квантизация. Для 2-битной квантизации (это когда на один параметр приходится всего 2 бита, а не 16, как у изначальной модели, то есть в 8 раз меньше) каждая строчка матрицы собирается из маленьких кусков по восемь чисел. Каждый такой кусок — это сумма двух векторов из словарей по 256 элементов каждый. Получается, что для хранения значения восьми элементов матрицы надо потратить 2 раза по 8 бит на индексы. Отсюда и берётся 2 бита на параметр.

Благодаря развитию WebAssembly программы для браузера стало можно писать почти на любом языке. Несколько лет назад я прошёл курс по Rust в ШАД [6], влюбился в язык, но никак не мог найти ему применение в своих пет‑проектах. Я не мог упустить этот шанс и реализовал весь инференс на нём.
Приятным сюрпризом было то, что на Rust написано очень много фундаментальных библиотек для инфраструктуры вокруг LLM.
Например, у Hugging Face есть формат под названием safetensors. Оказалось, что его реализация полностью написана на Rust! Каждый раз, когда кто‑нибудь в своём коде на Python использует safetensors‑модель с Hugging Face, он использует Rust.
На Rust также написан токенайзер под названием tiktoken от OpenAI, который используется в новых «ламах».
Чтобы ускорить работу модели, я реализовал многопоточность с помощью веб‑воркеров. Они поддерживают двунаправленную связь между тредами через передачу сообщений. Моё решение основано на model‑parallel‑подходе: все матрицы разделяются по размерности выхода, и каждый воркер получает свой кусок каждой матрицы.
Самая сложная часть заключалась в организации взаимодействия между воркерами и основным тредом. Для этого я написал кастомный RPC‑стек для воркеров с интеропом между Rust и JavaScript.
Когда главному треду нужно умножить вектор на матрицу, он составляет запрос к каждому воркеру, сериализует его и отправляет в JavaScript‑рантайм. Затем JavaScript пересылает его воркеру, который десериализует, обрабатывает запрос и сериализует результат перед отправкой обратно. После этого JavaScript отправляет результат в главный тред, где тот десериализуется.
Этот подход позволил увеличить производительность примерно в 2 раза.
Если не хочется ждать загрузки модели, посмотрите видео [7]. А чтобы поиграться на своём компьютере, зайдите на демо [1].
При первом обращении дождитесь окончания загрузки модели, это может занять несколько минут. Рекомендую общаться с ней на английском языке — так она будет существенно умнее.
Исходный код проекта загружен на GitHub [8]. Буду рад критике и предложениям.
Автор: galqiwi
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/yandeks/404629
Ссылки в тексте:
[1] AQLM.rs: https://galqiwi.github.io/aqlm-rs/about.html
[2] лабораторией: https://research.yandex.com/
[3] исследование: https://arxiv.org/abs/2405.14852
[4] писал: https://habr.com/ru/companies/yandex/articles/830410/
[5] AQLM: https://arxiv.org/abs/2401.06118
[6] ШАД: https://shad.yandex.ru/
[7] видео: https://www.youtube.com/watch?v=fPOHT4Zf_NA&feature=youtu.be
[8] GitHub: https://github.com/galqiwi/demo-aqlm-rs
[9] Источник: https://habr.com/ru/companies/yandex/articles/864296/?utm_campaign=864296&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.