Как стать автором
Поиск
Написать публикацию
Обновить

Распределённый инференс и шардирование LLM. Часть 2: скрипт vLLM, Ray Serve для вывода API и настройка KubeRay Cluster

Уровень сложностиСложный
Время на прочтение14 мин
Количество просмотров4.5K
Всего голосов 20: ↑20 и ↓0+29
Комментарии8

Комментарии 8

  • CUDA Graph для Gemma-3-12B пришлось отключить (ENABLE_ENFORCE_EAGER=true), иначе модель падала. На Dolphin3.0 с графом производительность была ≈ 40 t/s.

Нашел решение - ошибка была в том, что я использовал почти всю доступную видеопамять ("GPU_MEMORY_UTIL": "0.98") и при включении CUDA Graph ему не хватало места, а дальше приходил ООМ и всё убивал

Сменил показатель на "GPU_MEMORY_UTIL": "0.92" и всё заработало

Провели ряд тестов производительности с помощью LLMPerf. Средняя межтокеновая задержка составила ≈0,116 с, а throughput — ≈10 т/с, что наглядно подтверждает стабильность и корректность работы инференса. Не так быстро, как хотелось бы, но я продолжаю исследовать возможности улучшить результат.

Скорость увеличилась почти в 2 раза: межтокеновая задержка ≈0.067 с, а throughput — ≈19.5 т/с

Здравствуйте, спасибо за материал! Первый в выдаче по запросу "serving distributed LLM with vLLM and Ray")
Вопрос: прочитал про стенд и увидел, что карты разные. По материалу не нашёл, но следили ли за тем, чтобы количество голов внимания модели делилось на количество блоков по 12gb, раз это общий делитель для ёмкости карт? По идее, если не разделить головы внимания по картам строго, то тензорный параллелизм будет неэффективен, так как при расчёте значений блок матрицы, соответствующий голове (или двум головам, если 12gb для одной, то 24gb для двух) будет перемножаться не внутри одной карты, а будет шаффлиться между ними. Если в такой ситуации есть шаффл, и шаффл между машинами, то, кажется, это может значительно снижать скорость?

Здравствуйте! Спасибо, отличный вопрос!

Не смотря на то что карты разные - LLM я запускаю на двух rtx 3090 (по одной GPU на каждой ноде) — стараюсь избегать гетерогенности, в противном случае узким местом становится наименее мощная карта (у меня это rtx 3060) и остальные карты работают не на полную.

Вручную heads не делил, в vLLM это делается автоматически на уровне tensor parallelism. В моей конфигурации (pipeline parallelism = 2, tensor parallelism = 1) все головы внимания идут на одну карту в рамках этапа, и доп. шаффлов между GPU не возникает. Если бы использовал tensor parallelism >1, тогда heads делились бы между GPU, и тут уже важно, чтобы их количество делилось без остатка. Но настроек для ручного закрепления heads за картой в vLLM сейчас нет (на сколько я знаю) — только автоматически, и посмотреть детали распределения внутри движка стандартно нельзя.

В планах пересобрать стенд на несколько gpu на одной ноде и попробовать распределение ipeline parallelism = 2, tensor parallelism = 2

А можете пояснить, зачем сделали приоритетным pipeline parallelism? Кажется, что эффективнее в параллели перемножать ортогональные матрицы, так скорость должна подняться вдвое (если, конечно, действительно, веса поделятся ровно).

Несколько причин))

первая - это банально не хватило слотов в одном сервере (rtx 3090 занимают 3 слота и перекрывают второй x16 PCIe)

вторая - меня в первую очередь терзали вопросы - что делать если модель не будет влазить в 8 GPU на хосте (как правило пром сервера имеют столько GPU)? можно ли ее дальше масштабировать и на сколько это эффективно? Какая сеть нужна для этого, когда мы начинаем в нее упираться и вообще до какого количества нод имеет смысл параллелить?)

Но сейчас присматриваю двуслотовые или однослотовые карты, чтобы потестировать tensor, а так же планирую исследовать новый тренд на встроенные в CPU ускорители (AI NPU) с unified LPDDR5X памятью (по аналогии как это сделано в Mac Studio) - например вот такой

Наверно, я не до конца понял ответ. Как я поверхностно понимаю, pipeline parallelism это когда вы раскладываете слои по картам, и при инференсе сначала вы добегаете до последнего слоя первой карты, затем вынуждены перекинуть активации на вторую карту, и гоните их по слоям дальше, а tensor parallelism - когда раскладываете по картам подпространства векторов и матриц QKV с которыми идёт работа, и если получилось раскидать так, что головы внимания находятся целиком на картах без пересечений, то может получиться все тензорные операции проводить в рамках каждой из карт локально без всякого шаффла, и объединять результаты с карт только уже после получения всех частей токена (это уже супер дёшево и не важно какая пропускная способность каналов). Соответственно, pipeline parallelism вас неизбежно утыкает в скорость взаимодействия между хостами, а tensor parallelism, кажется, позволяет в некоторых случаях сильно снизить зависимость от этой скорости.

Да, я полностью согласен! В первую очередь нужно использовать tensor parallelism и стараться модель разместить полностью на 1 ноде. Но я не смог у себя исследовать tensor parallelism, потому что на момент написания статьи не было возможности организовать такую топологию даже из двух карт (Сейчас я ищу возможность потестировать tensor parallelism и думаю в одном из следующих материалов поделюсь результатами)

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

Класс! Спасибо, тогда буду с нетерпением ждать следующей части статьи!

Зарегистрируйтесь на Хабре, чтобы оставить комментарий