К обычному разбору
Тренировка по собеседованиюТехническое собеседованиеHuawei2026-05-08

Huawei: Техническое собеседование

Идите сверху вниз: сначала попробуйте сами, затем откройте разбор. Если шаг с кодом, пишите решение прямо здесь и запускайте проверки на странице.

Шагов
14
Вопросов
10
Задач
4
1Вопрос10 мин

Как оптимизировать LLM inference pipeline

Как оптимизировать LLM inference pipeline: routing, batching, serving, latency и стоимость? Какие рычаги ускорения и удешевления стоит назвать?

Ответьте без подсказки

Сначала проговорите ответ вслух или тезисами.

Запишите черновик

Формулы, план решения, риски и примеры.

Сравните с разбором

Откройте разбор только после своей попытки.

Показать разбор

Короткий ответ

Нужно говорить про throughput/latency trade-off: continuous batching, padding-aware batching, KV cache, quantization, model/runtime choice, async serving, streaming, scheduler и мониторинг tail latency.

Подробный разбор

Сильный ответ начинается с метрики: оптимизируем не абстрактно "быстрее", а latency, TTFT, tokens/sec, throughput, GPU utilization, cost per 1k tokens и tail latency. После этого можно разложить pipeline на prefill, decode, scheduler, batching, memory, runtime и сетевой слой.

Практические рычаги: continuous batching, grouping запросов по длине, ограничение max context, KV cache reuse, paged attention, quantization, выбор dtype, tensor/pipe parallel при больших моделях, speculative decoding, prefix caching, streaming ответов, асинхронный API и backpressure.

Важно проговорить ограничения: слишком крупные batch ухудшают latency, quantization может бить по качеству, длинный context раздувает KV cache, а оптимизация runtime не помогает, если bottleneck в продуктовой логике или внешних tools.

Типичные ошибки

  • Перечислить только quantization и не обсудить batching/scheduler.
  • Не разделить prefill и decode.
  • Не назвать измеримые метрики: TTFT, tokens/sec, p95 latency, GPU utilization.

Как сказать на собеседовании

  • Сначала спроси, что оптимизируем: latency, throughput или cost.
  • Раздели ответ на model-level, runtime-level и service-level оптимизации.
2ЗадачаMedium

Ускорить рекурсивную функцию с тремя вызовами

Условие

На собеседовании дана рекурсивная функция:

def g(n):
    if n < 3:
        return 1
    return g(n - 1) + g(n - 2) + g(n - 3)

Сначала нужно оценить сложность такой реализации, а затем переписать функцию так, чтобы она возвращала тот же ответ, но работала быстрее.

Сигнатура

def g_fast(n: int) -> int:

Пример

g_fast(10) -> 193

Follow-up с собеседования: как считать такие значения быстрее, чем за O(n), если n очень большое?

Решение прямо на странице

Напишите код, запустите проверки и только потом открывайте разбор.

Проверка решения

Нажмите «Запустить проверки» или Ctrl+Enter.

Показать разбор

Подсказки

  • Какие значения нужны для следующего шага?

    Чтобы посчитать g(i), нужны только g(i-1), g(i-2), g(i-3).

  • Не храните весь массив

    Можно держать три переменные и обновлять их на каждой итерации.

  • Follow-up

    Рекурренту можно представить матрицей перехода и использовать binary exponentiation.

Идея решения

Наивная сложность. Для исходной функции число вызовов удовлетворяет рекурренте T(n)=T(n-1)+T(n-2)+T(n-3)+O(1), поэтому растет экспоненциально. Асимптотика определяется корнем уравнения a^3 = a^2 + a + 1.

Быстрое решение. Значение g(n) зависит только от трех предыдущих значений. Поэтому можно идти слева направо и хранить g(n-3), g(n-2), g(n-1).

Follow-up. Для очень больших n рекурренту можно записать как умножение companion matrix на вектор состояния и возводить матрицу в степень бинарным возведением за O(log n).

Эталонный код

def g_fast(n: int) -> int:
    if n < 3:
        return 1

    a = b = c = 1
    for _ in range(3, n + 1):
        a, b, c = b, c, a + b + c
    return c
Сложность
Время: O(n). Память: O(1).
После перехода от рекурсивного дерева к итеративной динамике достаточно хранить последние три значения.
3ЗадачаMedium

Шахматная матрица с порядковыми числами

Условие

Напишите функцию, которая принимает размер n и создает квадратную матрицу n x n.

Нужно заполнить клетки шахматного цвета, начиная с левого верхнего угла, последовательными числами 1, 2, 3, ..., а остальные клетки оставить нулями.

Для n = 6 результат должен быть:

[
  [1, 0, 2, 0, 3, 0],
  [0, 4, 0, 5, 0, 6],
  [7, 0, 8, 0, 9, 0],
  [0, 10, 0, 11, 0, 12],
  [13, 0, 14, 0, 15, 0],
  [0, 16, 0, 17, 0, 18],
]

Если n <= 0, верните пустой список.

На собеседовании отдельно просили избегать вложенного Python-цикла и использовать NumPy/broadcasting. Даже векторизованное решение остается O(n^2) по памяти, поэтому очень большие n ограничены RAM и форматом возвращаемого list[list[int]].

Сигнатура

def make_chessboard(n: int) -> list[list[int]]:

Решение прямо на странице

Напишите код, запустите проверки и только потом открывайте разбор.

Проверка решения

Нажмите «Запустить проверки» или Ctrl+Enter.

Показать разбор

Подсказки

  • Маска шахматных клеток

    Клетка заполняется, если (номер строки + номер столбца) % 2 == 0.

  • Broadcasting индексов

    Используйте np.arange(n)[:, None] и np.arange(n)[None, :] для матрицы сумм индексов.

  • Одно присваивание

    После построения mask можно сделать result[mask] = np.arange(1, mask.sum() + 1).

Идея решения

Подход: создаем матрицу нулей и boolean-маску для клеток, где (row + col) % 2 == 0.

NumPy broadcasting позволяет получить все суммы индексов без двойного цикла:

i = np.arange(n)[:, None]
j = np.arange(n)[None, :]
mask = (i + j) % 2 == 0

Количество заполненных клеток равно mask.sum(). В эти позиции можно одним присваиванием положить np.arange(1, count + 1).

На реальном собеседовании ключевой критерий был не просто корректность, а отсутствие медленного вложенного Python-цикла на больших n.

Эталонный код

import numpy as np

def make_chessboard(n: int) -> list[list[int]]:
    if n <= 0:
        return []

    result = np.zeros((n, n), dtype=int)
    i = np.arange(n)[:, None]
    j = np.arange(n)[None, :]
    mask = (i + j) % 2 == 0
    result[mask] = np.arange(1, int(mask.sum()) + 1)
    return result.tolist()
Сложность
Время: O(n^2). Память: O(n^2).
Нужно создать n x n выходную матрицу. Векторизация переносит основную работу в NumPy, но размер результата и маски остается квадратичным.
4Вопрос8 мин

Какой constant classifier минимизирует binary logloss

Есть датасет с N0 отрицательными и N1 положительными примерами. Классификатор всегда выдает одну вероятность p. Какое p минимизирует binary logloss?

Ответьте без подсказки

Сначала проговорите ответ вслух или тезисами.

Запишите черновик

Формулы, план решения, риски и примеры.

Сравните с разбором

Откройте разбор только после своей попытки.

Показать разбор

Короткий ответ

Если N0 + N1 > 0, оптимальная константа равна доле положительного класса: p = N1 / (N0 + N1). При N1 = 0 оптимум на границе p = 0, при N0 = 0 - p = 1.

Подробный разбор

Binary logloss для константного предсказания:

L(p) = -N1 log(p) - N0 log(1-p).

Берем производную:

dL/dp = -N1 / p + N0 / (1-p).

Приравниваем к нулю:

N1 / p = N0 / (1-p), значит N1(1-p)=N0p, откуда p = N1 / (N0 + N1).

Интерпретация: если модель ничего не знает о признаках и должна выдавать одну вероятность для всех объектов, лучший calibrated прогноз - это base rate положительного класса.

Типичные ошибки

  • Ответить 0.5 независимо от class balance.
  • Потерять знак при дифференцировании log(1-p).
  • Забыть граничные случаи N1 = 0 или N0 = 0 и численное clipping в реализации.

Как сказать на собеседовании

  • Сначала запиши loss по N0/N1, потом производную.
  • После формулы дай интуицию: оптимум равен base rate.
5ЗадачаMedium

Оптимальная константа для binary logloss

Условие

Есть датасет с n0 отрицательными и n1 положительными примерами.

Классификатор всегда возвращает одну и ту же вероятность положительного класса p.

Нужно вернуть p, которое минимизирует binary logloss:

L(p)=n1logpn0log(1p)L(p) = -n_1 \log p - n_0 \log(1 - p)

Сигнатура

def optimal_constant_logloss(n0: int, n1: int) -> float:

Если n0 + n1 == 0, функция должна поднять ValueError.

Решение прямо на странице

Напишите код, запустите проверки и только потом открывайте разбор.

Проверка решения

Нажмите «Запустить проверки» или Ctrl+Enter.

Показать разбор

Подсказки

  • Производная

    Приравняйте производную logloss по p к нулю.

Идея решения

Берем производную:

dLdp=n1p+n01p\frac{dL}{dp} = -\frac{n_1}{p} + \frac{n_0}{1-p}

В оптимуме:

n1p=n01p,p=n1n0+n1\frac{n_1}{p} = \frac{n_0}{1-p}, \quad p = \frac{n_1}{n_0 + n_1}

Это ровно доля положительного класса в датасете.

Эталонный код

def optimal_constant_logloss(n0: int, n1: int) -> float:
    total = n0 + n1
    if total == 0:
        raise ValueError('dataset must contain at least one example')
    return n1 / total
Сложность
Время: O(1). Память: O(1).
Оптимум получается из аналитической производной logloss.
6Вопрос8 мин

Зачем нужны positional embeddings в Transformer

Для чего нужны positional embeddings и какие виды positional embeddings используются в LLM?

Ответьте без подсказки

Сначала проговорите ответ вслух или тезисами.

Запишите черновик

Формулы, план решения, риски и примеры.

Сравните с разбором

Откройте разбор только после своей попытки.

Показать разбор

Короткий ответ

Self-attention без позиционного сигнала permutation-equivariant: при перестановке токенов переставятся и выходы. Поэтому модели нужен явный сигнал о порядке: learned/sinusoidal positions, relative bias, RoPE или ALiBi.

Подробный разбор

Без позиционной информации Transformer сравнивает content-векторы, но не получает отдельного признака "первый", "следующий" или "далеко справа". Если одновременно переставить входные токены, attention переставит выходы тем же образом, поэтому одного content-attention недостаточно для языка.

Основные варианты: learned absolute positional embeddings, синусоидальные absolute embeddings, relative position bias, RoPE и ALiBi. В современных LLM часто встречается RoPE: позиция кодируется вращением query/key векторов, что удобно для relative distances и extrapolation к более длинному context при аккуратной настройке.

Важно отделять positional signal от causal mask. Causal mask задает видимость слева направо, но сам по себе не сообщает модели точную дистанцию и абсолютную/относительную позицию токенов.

Типичные ошибки

  • Сказать, что порядок уже есть в последовательной подаче токенов.
  • Назвать только learned embeddings и не вспомнить RoPE.
  • Не объяснить, почему self-attention без позиции не различает порядок.

Как сказать на собеседовании

  • Начни с permutation-invariance self-attention.
  • Назови 2-3 современных варианта: RoPE, ALiBi, relative bias.
7Вопрос9 мин

Что такое prefill и decode стадии в LLM inference

Что такое prefill и decode стадии при генерации LLM и почему их важно различать при оптимизации inference?

Ответьте без подсказки

Сначала проговорите ответ вслух или тезисами.

Запишите черновик

Формулы, план решения, риски и примеры.

Сравните с разбором

Откройте разбор только после своей попытки.

Показать разбор

Короткий ответ

Prefill обрабатывает весь prompt и заполняет KV cache; decode генерирует новые токены по одному, переиспользуя KV cache. Prefill обычно compute-heavy, decode часто memory-bandwidth/latency sensitive.

Подробный разбор

Prefill - это первый проход по входному prompt. Модель обрабатывает все prompt tokens, считает hidden states и складывает K/V для каждого слоя в KV cache. Эта стадия зависит от длины входного контекста и хорошо параллелится по токенам.

Decode - это autoregressive генерация следующих токенов. На каждом шаге добавляется один новый токен, query текущего токена attends к уже сохраненным K/V из cache, затем выбирается следующий token. Decode плохо параллелится по time dimension и часто упирается в memory bandwidth и scheduler.

Разделение важно для оптимизации: long prompt бьет по TTFT через prefill, long generation бьет по tokens/sec через decode. Continuous batching должен уметь смешивать запросы в разных стадиях.

Типичные ошибки

  • Считать, что вся генерация одинаково обрабатывает весь контекст заново.
  • Не связать prefill с TTFT.
  • Не связать decode с autoregressive one-token-at-a-time loop.

Как сказать на собеседовании

  • Используй термины TTFT и tokens/sec.
  • Скажи, что prefill parallel по prompt tokens, decode sequential по generated tokens.
8Вопрос8 мин

Как работает temperature при генерации текста

В какой момент применяется temperature при генерации LLM, какая формула scaling и что происходит после softmax?

Ответьте без подсказки

Сначала проговорите ответ вслух или тезисами.

Запишите черновик

Формулы, план решения, риски и примеры.

Сравните с разбором

Откройте разбор только после своей попытки.

Показать разбор

Короткий ответ

Temperature применяется к logits перед softmax: softmax(logits / T). T < 1 делает распределение острее, T > 1 - более плоским. После softmax токен либо выбирают argmax, либо sampling из распределения.

Подробный разбор

Модель на каждом decode step выдает logits по словарю. Перед превращением logits в вероятности можно применить temperature:

p_i = exp(z_i / T) / sum_j exp(z_j / T).

Если T < 1, большие logits становятся еще более доминирующими, распределение острее, генерация более deterministic. Если T > 1, распределение выравнивается, растет разнообразие и риск мусора. При T -> 0 поведение приближается к greedy argmax.

После softmax можно выбрать самый вероятный токен или сэмплировать из распределения, часто вместе с top-k/top-p фильтрацией.

Типичные ошибки

  • Говорить, что temperature применяется после выбора токена.
  • Перепутать эффект T < 1 и T > 1.
  • Не объяснить sampling как случайный выбор из categorical distribution.

Как сказать на собеседовании

  • Запиши softmax(logits / T).
  • Объясни крайние случаи: T -> 0 и большая T.
9Вопрос12 мин

Как работает KV cache и от чего зависит его память

Что такое KV cache, почему его можно переиспользовать при decode и от каких факторов зависит его объем?

Ответьте без подсказки

Сначала проговорите ответ вслух или тезисами.

Запишите черновик

Формулы, план решения, риски и примеры.

Сравните с разбором

Откройте разбор только после своей попытки.

Показать разбор

Короткий ответ

KV cache хранит key/value vectors прошлых токенов по слоям. При decode прошлые K/V не меняются, поэтому их не надо пересчитывать. Память зависит от batch, context length, layers, KV heads, head dim и dtype.

Подробный разбор

В causal self-attention новый токен attends ко всем предыдущим токенам. Key и value для уже обработанных токенов зависят от их hidden states и весов слоя, но не меняются при генерации следующих токенов. Поэтому после prefill их можно сохранить и дальше доставать из cache.

На каждом decode step модель считает Q/K/V только для нового токена, добавляет новый K/V в cache и делает attention текущего Q к сохраненным K/V.

Оценка памяти примерно:

batch * seq_len * num_layers * num_kv_heads * head_dim * 2(K,V) * bytes_per_value.

Для MHA num_kv_heads обычно равно числу attention heads, для MQA/GQA меньше. Поэтому MQA/GQA сильно уменьшают KV cache.

Типичные ошибки

  • Сказать, что cache хранит logits или все hidden states.
  • Не учитывать layers и batch size.
  • Не отличать attention heads от KV heads в MQA/GQA.

Как сказать на собеседовании

  • Объясни неизменность K/V прошлых токенов в causal decode.
  • Дай формулу памяти и отдельно упомяни dtype.
10ЗадачаMedium

Оценка памяти KV cache

Условие

В LLM inference KV cache хранит key и value в каждом transformer-слое для уже обработанных токенов.

Напишите функцию, которая возвращает размер KV cache в байтах.

Для каждого токена, каждого слоя и каждой KV-head нужно хранить два вектора: key и value.

Сигнатура

def kv_cache_bytes(
    batch_size: int,
    context_length: int,
    num_layers: int,
    num_kv_heads: int,
    head_dim: int,
    bytes_per_element: int = 2,
) -> int:

Решение прямо на странице

Напишите код, запустите проверки и только потом открывайте разбор.

Проверка решения

Нажмите «Запустить проверки» или Ctrl+Enter.

Показать разбор

Подсказки

  • K и V

    Не забудьте множитель 2: отдельно key и value.

  • KV heads

    Для MQA/GQA количество KV-heads может отличаться от количества query heads.

Идея решения

Размер cache:

batch_size * context_length * num_layers * num_kv_heads * head_dim * 2 * bytes_per_element.

Множитель 2 появляется потому, что cache хранит и K, и V. В MQA/GQA num_kv_heads может быть меньше числа query heads, поэтому важно использовать именно количество KV-heads.

Эталонный код

def kv_cache_bytes(
    batch_size: int,
    context_length: int,
    num_layers: int,
    num_kv_heads: int,
    head_dim: int,
    bytes_per_element: int = 2,
) -> int:
    return (
        batch_size
        * context_length
        * num_layers
        * num_kv_heads
        * head_dim
        * 2
        * bytes_per_element
    )
Сложность
Время: O(1). Память: O(1).
Функция считает одну формулу по параметрам модели и запроса.
11Вопрос12 мин

Чем MQA, GQA и MLA отличаются от обычного Multi-Head Attention

Какие есть варианты attention для экономии KV cache, например Multi-Query Attention, Grouped-Query Attention и MLA?

Ответьте без подсказки

Сначала проговорите ответ вслух или тезисами.

Запишите черновик

Формулы, план решения, риски и примеры.

Сравните с разбором

Откройте разбор только после своей попытки.

Показать разбор

Короткий ответ

MHA хранит K/V для каждой head. MQA оставляет много query heads, но один общий K/V head. GQA делает группы query heads с общими K/V внутри группы. MLA сжимает KV в low-rank latent representation и уменьшает cache.

Подробный разбор

В обычном Multi-Head Attention у каждой головы свои Q, K, V. Это гибко, но дорого для decode: KV cache растет пропорционально числу heads.

Multi-Query Attention сохраняет несколько query heads, но использует один общий key/value head. Это резко уменьшает KV cache и memory bandwidth, но может стоить качества.

Grouped-Query Attention - компромисс: query heads разбиваются на группы, и внутри каждой группы общий K/V. Память меньше, чем в MHA, качество обычно лучше, чем у MQA.

MLA, известная по DeepSeek, идет дальше: вместо полного K/V cache модель хранит компактное low-rank latent KV representation плюс отдельную позиционную/RoPE-компоненту, а нужные компоненты восстанавливаются для attention. Суть ответа - показать, что это семейство методов уменьшает memory footprint cache и pressure на memory bandwidth, а не просто "ускоряет attention".

Типичные ошибки

  • Сказать, что MQA уменьшает число query heads.
  • Не объяснить GQA как компромисс между MHA и MQA.
  • Описывать MLA как обычное переиспользование cache без compression.

Как сказать на собеседовании

  • Рисуй шкалу: MHA -> GQA -> MQA по уменьшению KV heads.
  • Свяжи все варианты с памятью KV cache.
12Вопрос12 мин

Как устроены MoE-модели и их inference

Чем Mixture-of-Experts отличается от dense модели, какие преимущества и недостатки, и как устроен router при inference?

Ответьте без подсказки

Сначала проговорите ответ вслух или тезисами.

Запишите черновик

Формулы, план решения, риски и примеры.

Сравните с разбором

Откройте разбор только после своей попытки.

Показать разбор

Короткий ответ

MoE заменяет часть FFN на набор экспертов и router, который выбирает top-k экспертов для каждого токена. Активных параметров меньше, чем total parameters, но serving сложнее из-за routing, load balancing, memory и distributed communication.

Подробный разбор

Dense модель использует одни и те же параметры для каждого токена. В MoE обычно feed-forward блок заменяется несколькими expert FFN. Router получает hidden state токена, считает logits по экспертам и выбирает top-k экспертов. Итоговый output - взвешенная комбинация ответов выбранных экспертов.

Плюс: можно иметь огромное общее число параметров, но активировать только малую часть на токен, получая хорошее качество при умеренном FLOPs/token. Минусы: сложное обучение, load balancing, expert collapse, коммуникация между устройствами, сложный batching и необходимость держать экспертов в памяти.

При inference важно помнить: FLOPs могут быть ниже dense модели того же total size, но memory footprint и distributed routing могут быть сложнее. Разные токены batch могут уходить к разным экспертам.

Типичные ошибки

  • Сказать, что MoE всегда быстрее dense без оговорок.
  • Не объяснить router как top-k classifier по hidden state.
  • Не упомянуть load balancing и expert parallelism.

Как сказать на собеседовании

  • Раздели total parameters и active parameters.
  • Обязательно скажи про routing per token и top-k experts.
13Вопрос12 мин

Что такое speculative decoding и EAGLE

Что такое speculative decoding для LLM inference, как он ускоряет decode, и что за идея у EAGLE-подобных методов?

Ответьте без подсказки

Сначала проговорите ответ вслух или тезисами.

Запишите черновик

Формулы, план решения, риски и примеры.

Сравните с разбором

Откройте разбор только после своей попытки.

Показать разбор

Короткий ответ

Speculative decoding генерирует несколько draft tokens дешевой моделью, а target model считает распределения для draft-последовательности одним forward pass и принимает/отклоняет токены по acceptance rule. Ускорение есть при высоком acceptance rate.

Подробный разбор

Autoregressive decode медленный, потому что большая модель обычно добавляет один токен за forward pass. Speculative decoding добавляет draft model: маленькая модель быстро предлагает несколько следующих токенов, а target model считает распределения для всей draft-последовательности одним батчевым forward pass. После этого токены принимаются или отклоняются по acceptance rule на основе target/draft probabilities; greedy token matching - только упрощенный частный случай.

Ускорение зависит от того, насколько часто draft угадывает target distribution, от стоимости draft model и от overhead верификации. Метод хорошо работает, когда draft близок к target или задача имеет предсказуемое продолжение.

EAGLE-подобная идея: использовать легкую feature-level draft model, которая предсказывает будущие hidden states/features target model и из них строит speculative candidates. Это не "бесплатное знание будущих hidden states", а отдельный быстрый предиктор для улучшения acceptance rate при небольшом overhead.

Типичные ошибки

  • Сказать, что маленькая модель просто заменяет большую.
  • Не объяснить verification target model.
  • Игнорировать acceptance rate как главный фактор ускорения.

Как сказать на собеседовании

  • Опиши pipeline: draft -> verify -> accept/reject.
  • Скажи, когда метод не ускорит: плохой draft или большой overhead.
14Вопрос10 мин

Как VLM обрабатывает изображение вместе с текстом

Как visual language model принимает картинку на вход: что делает vision encoder, как появляются visual tokens и как они совмещаются с текстом?

Ответьте без подсказки

Сначала проговорите ответ вслух или тезисами.

Запишите черновик

Формулы, план решения, риски и примеры.

Сравните с разбором

Откройте разбор только после своей попытки.

Показать разбор

Короткий ответ

Картинку режут на patches, vision encoder превращает их в image embeddings, projection/alignment layer переводит их в пространство LLM, после чего visual tokens подаются вместе с text tokens в language model.

Подробный разбор

Типичная VLM архитектура состоит из vision encoder, projection/alignment модуля и LLM. Изображение приводят к нужному размеру, режут на patches, например 14x14 или 16x16, и прогоняют через ViT/CLIP-like encoder. На выходе получается последовательность визуальных embedding vectors.

Дальше эти embeddings через линейную проекцию или небольшой adapter переводятся в размерность и пространство LLM. После этого они становятся visual tokens и добавляются в общий prompt рядом с text tokens. LLM учится отвечать, attending одновременно к текстовым и визуальным токенам.

Для больших картинок важны tiling, patch resolution, positional information и ограничение числа visual tokens: слишком много токенов резко увеличивают compute и KV cache.

Типичные ошибки

  • Сказать, что картинка просто конвертируется в текстовое описание до LLM.
  • Не упомянуть patches/ViT.
  • Не связать число visual tokens с latency и context length.

Как сказать на собеседовании

  • Разложи на три блока: vision encoder, projector, LLM.
  • Упомяни patches и visual tokens как аналог text tokens.