Connect with us

SGLang: Эффективное выполнение структурированных программ языковых моделей

Искусственный интеллект

SGLang: Эффективное выполнение структурированных программ языковых моделей

mm
SGLang: Efficient Execution of Structured Language Model Programs

Большие языковые модели (LLM) все чаще используются для сложных задач, требующих нескольких вызовов генерации, продвинутых методов подсказки, управления потоком и структурированных входных/выходных данных. Однако эффективные системы для программирования и выполнения этих приложений отсутствуют. SGLang, недавно представленная система, направлена на решение этой проблемы, обеспечивая эффективное выполнение сложных программ языковых моделей. SGLang состоит из языка frontend и runtime. Frontend упрощает программирование с помощью примитивов для генерации и контроля параллелизма, а runtime ускоряет выполнение за счет новых оптимизаций, таких как RadixAttention для повторного использования кэша KV и сжатых конечных автоматов для более быстрого декодирования структурированных выходных данных. Эксперименты демонстрируют, что SGLang достигает до 6,4 раза более высокой производительности по сравнению с современными системами вывода на различных больших языковых и мультимодальных моделях, решая задачи, такие как контроль агентов, логическое рассуждение, бенчмарки обучения с несколькими примерами, декодирование JSON, пайплайны генерации с поддержкой извлечения и многоходовой чат.

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

Этот сдвиг отмечает переход от простого общения к более сложному программному использованию LLM, где программы планируют и контролируют процессы генерации LLM. Эти программы называются “Программами языковых моделей” (LM Программы). Продвинутые методы подсказки и рабочие процессы агентов входят в сферу LM программ. Существует два общих свойства LM программ: (1) LM программы обычно включают несколько вызовов LLM, чередующихся с управлением потоком для выполнения сложных задач и повышения общего качества. (2) LM программы получают структурированные входные данные и производят структурированные выходные данные, что позволяет составлять LM программы и интегрировать их в существующие программные системы.

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

Введение в SGLang

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

  • Сложность программирования: Разработка LM программ является утомительной и трудной из-за недетерминированной природы LLM. Это включает обширную манипуляцию строками, экспериментальное настройка подсказок, хрупкую парсинг выходных данных, обработку нескольких входных модальностей и реализацию механизмов параллелизма. Эта сложность значительно снижает читаемость даже простых программ.
  • Неэффективность выполнения: Выполнение LM программ является неэффективным из-за избыточных вычислений и использования памяти. Современные системы вывода, оптимизированные для снижения задержки и повышения производительности, не имеют прямого знания о рабочей нагрузке, что приводит к значительным неэффективностям. Примером этого является повторное использование кэша Key-Value (KV), который состоит из повторно используемых промежуточных тензоров, необходимых для вывода. Текущие системы не имеют эффективных механизмов для облегчения повторного использования кэша KV между несколькими вызовами LLM, что приводит к ненужным вычислениям и расточительному использованию памяти. Кроме того, ограниченное декодирование для структурированных выходных данных, таких как режим JSON, является субоптимальным, поскольку существующие системы декодируют только один токен за раз.

Для решения этих проблем SGLang представляет собой структурированный язык генерации для LLM. Основная идея заключается в систематическом использовании многоуровневой структуры в LM программах для эффективного выполнения. Как показано на следующей схеме, SGLang имеет две части: язык frontend и runtime.

Frontend упрощает программирование LM программ, а runtime ускоряет их выполнение. Эти части могут работать вместе для лучшей производительности или функционировать независимо.

SGLang является языком, встроенным в Python, предоставляющим примитивы для генерации (например, extend, gen, select) и контроля параллелизма (например, fork, join). Он совместим с контролем потока и библиотеками Python, позволяя пользователям легко разрабатывать продвинутые рабочие процессы подсказки с помощью родной синтаксиса Python. SGLang включает интерпретатор и компилятор. Интерпретатор управляет состоянием подсказки как потоком и отправляет примитивные операции в поток для асинхронного выполнения, обеспечивая правильный контроль над синхронизацией и параллелизмом внутри программы. Кроме того, программы SGLang можно отслеживать и компилировать для дальнейших оптимизаций. Runtime SGLang предлагает несколько новых оптимизаций для ускорения выполнения LM программ:

  • RadixAttention: Этот метод позволяет автоматически повторно использовать кэш KV между несколькими вызовами генерации. В существующих системах вывода кэш KV запроса отбрасывается после обработки, что предотвращает повторное использование между несколькими вызовами и замедляет выполнение. SGLang поддерживает кэш LRU кэша KV внутри radix дерева, управляя кэшем KV как традиционным кэшем и используя radix дерево для эффективного сопоставления, вставки и исключения. Это позволяет runtime эффективно обрабатывать различные закономерности повторного использования.
  • Сжатый конечный автомат: Этот метод позволяет более быстро декодировать структурированные выходные данные. Существующие системы следуют ограничениям только для следующего токена, что позволяет им декодировать только один токен за раз. Вместо этого SGLang анализирует ограничения и строит сжатый конечный автомат для представления их, сжимая много токенов в один шаг, когда это возможно, что позволяет декодировать несколько токенов одновременно для более быстрой скорости.
  • API спекулятивное выполнение: Для API-моделей, таких как OpenAI’s GPT-4, SGLang вводит API спекулятивное выполнение для оптимизации многоуровневых программ.

Используя SGLang, различные приложения LLM были реализованы, включая контроль агентов, логическое рассуждение, бенчмарки обучения с несколькими примерами, декодирование JSON, пайплайны генерации с поддержкой извлечения и многоходовой чат. Производительность была протестирована на моделях, включая Llama-7B/70B, Mistral-8x7B, LLaVA-v1.5-7B (изображение) и LLaVA-NeXT-34B (видео) на NVIDIA A10G и A100 GPU. Экспериментальные результаты показывают, что SGLang достигает до 6,4 раза более высокой производительности по сравнению с существующими системами программирования и вывода, включая Guidance, vLLM и LMQL.

SGLang: Модель программирования и методология

Модель программирования SGLang представлена через запущенный пример, описывающий его языковые примитивы и режимы выполнения, и очерчивающий возможности оптимизации runtime. Эта модель упрощает утомительные операции в многоуровневых рабочих процессах (например, манипуляцию строками, вызов API, спецификацию ограничений, параллелизм) путем предоставления гибких и составных примитивов. SGLang является языком, встроенным в Python. Следующая схема показывает программу, которая оценивает эссе об изображении, используя метод подсказки branch-solve-merge.

Функция multi_dimensional_judge принимает три аргумента: `s`, `path`, и `essay`. s управляет состоянием подсказки, path является путем к файлу изображения, а essay является текстом эссе. Новые строки и примитивы SGLang можно добавить к состоянию s для выполнения с помощью оператора +=. Сначала функция добавляет изображение и эссе к подсказке. Затем она проверяет, связано ли эссе с изображением, используя select, и сохраняет результат в s[“related”]. Если связано, подсказка разветвляется на три копии для параллельной оценки с разных сторон, используя gen для сохранения результатов в f[“judgment”]. Далее она объединяет оценки, генерирует сводку и присваивает буквенную оценку. Наконец, она возвращает результаты в формате JSON, следующем схеме, определенной регулярным выражением regex. SGLang значительно упрощает эту программу, поскольку эквивалентная программа, использующая интерфейс, подобный OpenAI API, потребовала бы в 2,1 раза больше строк кода из-за ручной манипуляции строками и контроля параллелизма.

SGLang предоставляет примитивы для управления состоянием подсказки, генерации и параллелизма, которые можно использовать с синтаксисом и библиотеками Python. Вот эти примитивы:

gen: Вызывает модель для генерации и сохраняет результаты в переменной с именем, указанным в ее первом аргументе. Он поддерживает аргумент `regex` для ограничения выходных данных, чтобы они следовали грамматике, определенной регулярным выражением (например, схеме JSON).

  • select: Вызывает модель для выбора наиболее вероятного варианта из списка.
  • += или extend: Добавляет строку к подсказке.
  • [variable_name]: Извлекает результаты генерации.
  • fork: Создает параллельные ветки состояния подсказки.
  • join: Объединяет состояние подсказки.
  • image и video: Принимают входные данные изображения и видео.

Самый простой способ выполнить программу SGLang — через интерпретатор, где подсказка рассматривается как асинхронный поток. Примитивы, такие как extend, gen и select, отправляются в поток для асинхронного выполнения. Эти неблокирующие вызовы позволяют коду Python продолжать выполняться без ожидания завершения генерации, подобно запуску ядер CUDA асинхронно. Каждая подсказка управляется исполняющим поток в фоновом потоке, обеспечивая параллелизм внутри программы. Извлечение результатов генерации будет блокироваться до тех пор, пока они не будут готовы, обеспечивая правильную синхронизацию. Альтернативно, программы SGLang можно скомпилировать в вычислительные графы и выполнить с помощью графического исполнителя, что позволяет выполнять дополнительные оптимизации. В этой статье по умолчанию используется режим интерпретатора, а результаты режима компилятора обсуждаются в Приложении D. SGLang поддерживает модели с открытыми весами с помощью собственного runtime SGLang (SRT), а также модели API, такие как OpenAI и Anthropic.

Системы программирования для LLM можно классифицировать как высокоуровневые (например, LangChain, DSPy) и низкоуровневые (например, LMQL, Guidance, SGLang). Высокоуровневые системы предоставляют预определенные или автоматически сгенерированные подсказки, такие как оптимизатор подсказок DSPy. Низкоуровневые системы обычно не изменяют подсказки, но позволяют直接 манипулировать подсказками и примитивами. SGLang является низкоуровневой системой, подобной LMQL и Guidance. Следующая таблица сравнивает их функции.

SGLang фокусируется на runtime-эффективности и поставляется с собственным runtime, что позволяет выполнять новые оптимизации. Высокоуровневые языки (например, DSPy) можно скомпилировать в низкоуровневые языки (например, SGLang). Интеграция SGLang в качестве бэкенда в DSPy для лучшей runtime-эффективности продемонстрирована позже.

Вышеуказанный пример иллюстрирует операции RadixAttention с политикой исключения LRU в течение девяти точек времени, демонстрируя динамическое развитие radix дерева в ответ на различные запросы. Эти запросы включают два сеанса чата, пакет запросов обучения с несколькими примерами и выборку самоувязки. Каждое ребро дерева несет метку, обозначающую подстроку или последовательность токенов. Узлы окрашены в разные цвета, чтобы отразить различные состояния: зеленый для новых добавленных узлов, синий для закэшированных узлов, доступных во время точки времени, и красный для узлов, которые были исключены.

Шаг 1: Radix дерево изначально пусто.

Шаг 2: Сервер обрабатывает входящее сообщение пользователя “Hello” и отвечает выходными данными LLM “Hi”. Системная подсказка “You are a helpful assistant”, сообщение пользователя “Hello!” и ответ LLM “Hi!” объединяются в дерево как единое ребро, связанное с новым узлом.

Шаг 3: Новая подсказка прибывает, и сервер находит префикс подсказки (т.е. первый ход разговора) в radix дереве и повторно использует его кэш KV. Новый ход добавляется к дереву как новый узел.

Шаг 4: Начинается новый сеанс чата. Узел из шага 3 делится на два узла, чтобы позволить двум сеансам чата делить системную подсказку.

Шаг 5: Второй сеанс чата продолжается. Однако из-за ограничений памяти узел из шага 4 должен быть исключен. Новый ход добавляется после оставшегося узла из шага 4.

Шаг 6: Сервер получает запрос обучения с несколькими примерами, обрабатывает его и вставляет в дерево. Корневой узел делится, поскольку новый запрос не разделяет никакого префикса с существующими узлами.

Шаг 7: Сервер получает пакет дополнительных запросов обучения с несколькими примерами. Эти запросы делят один и тот же набор примеров, поэтому узел из шага 6 делится, чтобы позволить делиться.

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

Шаг 9: Сервер получает запрос на выборку дополнительных ответов для вопросов в узле из шага 8, вероятно, для самоувязки. Чтобы освободить место для этих запросов, несколько узлов исключаются.

Этот пример демонстрирует, как RadixAttention обрабатывает динамическое распределение и исключение узлов в ответ на различные запросы, обеспечивая эффективное повторное использование кэша KV и управление памятью.

SGLang: Оценка и результаты

Результаты на моделях с открытыми весами

Результаты задержки и производительности показаны на следующих схемах. SGLang повышает производительность до 6,4 раза и снижает задержку до 3,7 раза. Эти улучшения являются результатом повторного использования кэша KV, использования параллелизма внутри одной программы и более быстрого декодирования ограничений.

На этих бенчмарках коэффициент попадания в кэш варьируется от 50% до 99%. Фигура 13 (Приложение) перечисляет достигнутые и оптимальные коэффициенты попадания в кэш для всех из них, показывая, что подход к планированию, осведомленному о кэше, SGLang достигает 96% оптимального коэффициента попадания в кэш в среднем.

Результаты на более крупных моделях с параллелизмом тензоров

Более крупные модели, Mixtral-8x7B и Llama-70B, были протестированы с параллелизмом тензоров на том же наборе бенчмарков, и результаты сообщаются в следующей схеме. Ускорение на более крупных моделях показывает тенденцию, подобную той, которая наблюдается на меньших моделях, указывая на то, что оптимизация SGLang хорошо обобщается на более крупные модели. Guidance и LMQL были исключены из-за отсутствия эффективных реализаций параллелизма тензоров.

Результаты на мультимодальных моделях

SGLang имеет родную поддержку мультимодальных моделей с помощью примитивов image и video. Оптимизации в этой статье совместимы с мультимодальными моделями. Для RadixAttention вычисляется хэш входных изображений и используется в качестве ключа в radix дереве, что позволяет повторно использовать кэш KV токенов изображения из одного и того же изображения. LLaVA-v1.5-7B (изображение) был запущен на llava-bench-in-the-wild, а LLaVA-NeXT-34B (видео) — на ActivityNet. Поскольку эти модели не хорошо поддерживаются другими базовыми системами, была использована оригинальная реализация авторов моделей в Hugging Face Transformers в качестве базовой. Как показано в следующей таблице, SGLang обеспечивает производительность до 6 раз выше на этих бенчмарках. В llava-bench-in-the-wild обрабатывались несколько вопросов об одном и том же изображении, и runtime SGLang повторно использовал кэш KV в этом случае.

Развертывание в производстве

SGLang был развернут в Chatbot Arena для обслуживания моделей с открытыми весами. Из-за низкого трафика для некоторых моделей только один работник SGLang обслуживает каждую. После одного месяца был наблюдаем коэффициент попадания в кэш RadixAttention 52,4% для LLaVA-Next-34B и 74,1% для Vicuna-33B. Попадания в кэш произошли из общих системных сообщений, часто повторно используемых примеров изображений и историй многоходового чата. Это снизило задержку первого токена в среднем на 1,7 раза для Vicuna-33B.

Заключительные мысли

В этой статье мы говорили о SGLang, недавно представленной системе, направленной на решение проблемы эффективного выполнения сложных программ языковых моделей. SGLang состоит из языка frontend и runtime. Frontend упрощает программирование с помощью примитивов для генерации и контроля параллелизма, а runtime ускоряет выполнение за счет новых оптимизаций, таких как RadixAttention для повторного использования кэша KV и сжатых конечных автоматов для более быстрого декодирования структурированных выходных данных. Эксперименты демонстрируют, что SGLang достигает до 6,4 раза более высокой производительности по сравнению с современными системами вывода на различных больших языковых и мультимодальных моделях, решая задачи, такие как контроль агентов, логическое рассуждение, бенчмарки обучения с несколькими примерами, декодирование JSON, пайплайны генерации с поддержкой извлечения и многоходовой чат.

"Инженер по профессии, писатель по сердцу". Кунал - технический писатель с глубокой любовью и пониманием ИИ и МО, посвященный упрощению сложных концепций в этих областях посредством своей увлекательной и информативной документации.