Адаптация открытого симулятора InferSim для оценки загрузки промышленных GPU

Обложка: Адаптация открытого симулятора InferSim для оценки загрузки промышленных GPU

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

Мы остановились на открытом симуляторе InferSim от Alibaba. Он умеет считать TTFT, TPOT и пропускную способность без запуска реального инференса. Но из коробки поддерживает только несколько топовых GPU и фиксированный набор моделей — для наших сценариев этого было недостаточно. Пришлось дорабатывать.

Как устроен InferSim

В основе симулятора — двухфазная схема. Сначала на целевом железе запускаются микро-бенчмарки: измеряется реальная производительность на типовых операциях внимания и матричных умножениях. Получается таблица коэффициентов Model FLOPs Utilization (MFU) — сколько процентов от теоретического максимума выдаёт конкретная карта на конкретной операции. Затем, уже без доступа к GPU, симулятор на основе этих MFU и аналитической модели вычисляет задержки. Именно такой подход даёт более точные предсказания, чем оценка по паспортной пропускной способности памяти.

Добавляем своё железо

Первым делом мы внесли в hardware/gpu.py поддержку MetaX C500 64GB. Характеристики добавляются через dataclass-экземпляры:

			c500 = GPU(
    fp16_tflops=280,
    fp8_tflops=560,
    mfu=0.35,
    mem=64,
    mem_bw=1800,
    nvlink_bw=450 / 2,
    rdma_bw=40 * 0.8,
)
		

После этого c500 попадает в словарь gpu_map, и симулятор запускается с ключом --device-type C500 --world-size 2. Значения FLOPS и пропускной способности пришлось оценивать по косвенным источникам — производитель не публикует точных цифр. Позже планируем уточнить их через бенчмаркинг на реальном оборудовании. Таким же способом добавили Nvidia 1xH100 и A100.

Конфигурация моделей и одна болезненная ошибка

Симулятор ожидает стандартный config.json в формате Hugging Face. Для Qwen3-32B подготовили файл qwen3_32b_config.json:

			{
  "model_type": "qwen3",
  "hidden_size": 5120,
  "num_hidden_layers": 64,
  "num_attention_heads": 64,
  "num_key_value_heads": 8,
  "head_dim": 80,
  "intermediate_size": 25600,
  "hidden_act": "silu",
  "torch_dtype": "bfloat16",
  "vocab_size": 151936,
  "max_position_embeddings": 40960
}

		

Ключевой момент — правильное значение head_dim. У Qwen3-32B оно равно hidden_size / num_attention_heads = 5120 / 64 = 80. У нас ушло некоторое время, чтобы понять, почему симулятор выдаёт невалидные результаты: изначально в конфиге стояло значение 128. Пока не исправили — KV-кеш переоценивался, и метрики улетали в неадекватные цифры. После исправления всё встало на свои места.

Позже добавили поддержку Qwen3.5‑9B с её гибридной архитектурой, построенной на чередовании Gated DeltaNet и Gated Attention. Главная особенность модели в том, что около трёх четвертей слоёв не создают привычного KV‑кеша, а используют линейное внимание – компактное скрытое состояние, которое лишь обновляется с каждым новым токеном, не увеличиваясь в объёме. Это кардинально снижает расход памяти на длинных контекстах, но привносит и свою цену: на коротких дистанциях такая модель проигрывает в скорости Prefill, потому что Gated DeltaNet работает последовательно и хуже утилизирует матричные вычисления GPU.

Симулятор изначально не умел различать слои двух типов и считал весь KV‑кеш одинаково. Чтобы поддержать Qwen3.5, пришлось доработать расчёт задержек в классе HybridModel: теперь он отдельно обсчитывает full‑attention‑слои с полным кешем и linear‑attention‑слои без кеша, используя параметры num_full_attn_layers и num_linear_attn_layers из конфигурации. В директорию проекта models добавили hybrid_model.py, в котором сделали дополнительные расчёты:

			# full attention (обычные слои с KV-кешем)
full_attn = create_attention(self.config, ...)
t_full_attn_core = full_attn.prefill_attn_core(...)
t_full_attn_others = full_attn.prefill_attn_others(...)
t_full = (t_full_attn_core + t_full_attn_others) * self.config.num_full_attn_layers

# linear attention (Gated DeltaNet – без кеша)
linear_attn = create_linear_attn(self.config, ...)
t_linear_attn_core = linear_attn.prefill_attn_core(...)
t_linear_attn_others = linear_attn.prefill_attn_others(...)
t_linear = (t_linear_attn_core + t_linear_attn_others) * self.config.num_linear_attn_layers

# итоговое время первого токена (без учёта FFN и коммуникаций – они считаются стандартно)
ttft = (t_full + t_linear + t_ffn + t_comm) * 1000  # t_ffn и t_comm – едины для всех моделей
		

Без такой дифференциации симулятор для Qwen3.5‑9B показывал E2E порядка 2 500 секунд вместо реальных нескольких секунд – та ошибка, которую мы долго отлавливали.

Визуализация и эксплуатация

Пользовательский интерфейс на Streamlit

Чтобы не разбирать каждый раз текстовый вывод InferSim, сделали веб-интерфейс на Streamlit. Симулятор дёргается через subprocess, результаты парсятся из stdout и визуализируются:

  • тепловые карты задержек (Prefill, Decode, E2E Total) для разных длин входных и выходных токенов;
  • анализ RPS с расчётом требуемой параллельности и сравнением с доступной памятью;
  • информация о занятой памяти в формате «X ГБ из Y ГБ».

Кэширование через @st.cache_data позволило избежать повторных запусков симуляции при неизменных параметрах. Интерфейс получился достаточно удобным, чтобы даже коллеги без погружения в командную строку могли осмысленно сравнивать конфигурации.

Приложение упаковано в Docker и лежит в репозитории на GitHub. Сервисы — сам Streamlit и Nginx в качестве обратного прокси с SSL-терминацией и базовой HTTP-аутентификацией. Деплой на VDS автоматизирован через GitHub Actions: собрали образ, отправили на сервер, перезапустили контейнеры. SSL-сертификаты Let's Encrypt обновляются по cron.

Что в итоге

Адаптированный InferSim не претендует на абсолютную точность — она ограничена качеством бенчмарков и коэффициентов MFU. Но инструмент позволяет избежать грубых ошибок при планировании, что в условиях ограниченного доступа к GPU и их высокой стоимости само по себе немало. Мы продолжаем калибровку симулятора и готовим обновлённые конфигурации для следующих моделей.

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