Тестирование ML-модели методами QA: возможно ли?

от автора

О чём эта статья

Когда ML-модель становится частью продукта, стандартных метрик качества недостаточно. Риски проявляются не в средних показателях, а на конкретных группах пользователей, на граничных значениях и в нестандартных сочетаниях параметров. Дата-сайентист видит эти риски иначе, чем QA-инженер, и разница во взглядах способна привести к пропущенным дефектам.

Моя работа представляет собой учебный фреймворк. Он показывает, как классические техники тестирования применяются к ML-модели. Фреймворк построен на простой модели и открытых данных, чтобы его можно было легко развернуть и модифицировать. Код написан на Python с дашбордом на Streamlit и использует открытый датасет VK-LSVD. В конце статьи будет ссылка на GitHub.

Существуют промышленные инструменты мониторинга моделей, такие как Evidently, NannyML. Они созданы дата-сайентистами для дата-сайентистов и решают задачи контроля метрик, дрейфа данных, алертов. Но у QA-инженеров другой угол зрения: не хуже и не правильнее, а просто другой. Им привычнее мыслить техниками тест-дизайна, классами эквивалентности, граничными значениями, таблицами решений. Задача этого фреймворка: показать тестировщикам, как можно выполнять свою работу в новой и действительно сложной области, оставаясь в рамках знакомых подходов.

Два взгляда на качество модели: Data Science и QA

Дата-сайентист оценивает модель через метрики (AUC, точность, полнота), исследует распределения, ищет аномалии в данных. Эти проверки опираются на статистику и агрегированные показатели. Однако высокие агрегированные метрики на миллионах строк могут скрывать локальные проблемы: крайние значения признаков, неочевидные пары параметров и неравномерность работы на разных сегментах. Именно там зарыты дефекты и логические перекосы.

В классической разработке QA-инженер вооружён техниками тест-дизайна: эквивалентное разбиение, граничные значения, pairwise, таблицы решений. Эти техники позволяют системно покрыть пространство входных данных и гарантировать, что ни один класс сценариев не пропущен. Когда ML-модель становится частью продукта, те же техники применимы и к ней.

Фреймворк переводит ML-специфику на язык тестов, понятный QA, и делает проверку модели воспроизводимой и прозрачной для всей команды.

Данные и модель

Датасет: VK-LSVD, предоставленный компанией VK. Взят маленький срез up0.001_ip0.001 для быстрого запуска.

Модель: логистическая регрессия, предсказывающая вероятность лайка.

Признаки модели:

  • timespent (время просмотра, секунды, 0…255).

  • duration (длительность видео, секунды, 5…180).

  • category (суррогат тематики, целое число 0…19). В реальном проекте здесь были бы «спорт», «юмор», «мода». В открытом датасете настоящих категорий нет, поэтому мы получили номер группы из ID видео.

  • author_popularity (количество взаимодействий с автором в обучающей выборке, Count Encoding).

Перед тестированием данные проходят препроцессинг, идентичный production: кодирование автора и стандартизация признаков. Пайплайн сохраняется как pipeline.pkl и загружается дашбордом.

Структура фреймворка

Фреймворк состоит из пяти тестов:

  1. Segmented AUC: качество по категориям контента (адаптация эквивалентного разбиения, где в качестве классов выступают изолированные бизнес-сегменты данных).

  2. Boundary Test: поведение на граничных значениях.

  3. Decision Table: проверка бизнес-гипотез (адаптация техники под ML — проверка метаморфных инвариантов).

  4. Pairwise Test: попарное тестирование параметров.

  5. Stability Test: контроль дрейфа данных (PSI).

Все тесты выполняются при старте Streamlit-приложения (команда streamlit run app.py). Дашборд служит интерфейсом для отображения результатов. На каждой странице есть пояснения: что показывает график, откуда взялись цифры. В дашборде также есть вкладка «Справочник» с расшифровкой терминов и перечнем допущений.

Как читать тесты. Памятка для QA

Чтобы понимать результаты тестов, не нужно знать математику модели. Достаточно увидеть, как знакомые техники тест-дизайна применены к новому объекту. Вот прямые аналогии.

Эквивалентное разбиение

  • Обычно: делим пользователей на роли (админ, оператор, гость) и проверяем, что функциональность работает в каждой.

  • Здесь: делим видео на 20 групп по признаку category. Для каждой группы считаем AUC (качество предсказания лайка). Если в какой-то группе AUC ниже порога 0.65, тест подсветит проблему. Это аналог проверки «работает ли форма логина для всех типов учётных записей».

Граничные значения

  • Обычно: проверяем границы, которые важны для бизнес-логики. Например, если для доступа нужен возраст 18+, тестируем на значениях 17, 18, 19. Если пенсионный возраст 64, 65, 66.

  • Здесь: берём крайние значения четырёх признаков (timespent, duration, category, author_popularity). Для каждого признака взято по 4 граничных значения. Для неварьируемых признаков подставляются медианные/модальные значения. Тест проверяет, что на экстремальных входных данных production-пайплайн не падает, а предсказания остаются в [0, 1] и не содержат NaN.

Таблица решений

  • Обычно: «если пользователь авторизован и корзина не пуста, показываем кнопку Оформить».

  • Здесь (адаптация техники под ML — проверка метаморфных инвариантов): формулируем бизнес-правила (гипотезы) вроде «досмотренное видео лайкают чаще, чем недосмотренное». Делим записи на две группы. Фреймворк автоматически вычисляет средние предсказанные вероятности в каждой группе и сравнивает разницу с минимальным значимым эффектом.

Попарное тестирование

  • Обычно: у нас поля «тип карты», «сумма», «статус клиента». Полный перебор всех комбинаций нереален, поэтому генерируем минимальный набор, покрывающий все пары значений.

  • Здесь: признаки timespent, duration, category, author_popularity. Непрерывные признаки (timespent, duration) сначала разбиваются на диапазоны (квантуются). Затем алгоритм AllPairs генерирует минимальный набор комбинаций, покрывающий все возможные пары этих диапазонов и категорий. Каждая комбинация подаётся модели, и мы проверяем, что предсказание остаётся корректным.

Дрейф данных

  • Обычно: сравниваем, не изменилась ли среда: операционная система, браузер, география.

  • Здесь: сравниваем распределения признаков (timespent, duration, category, author_popularity) между обучающей и валидационной выборками с помощью индекса PSI. Если PSI превышает 0.25, значит, данные стали другими, и модель может работать хуже. Для уникальных идентификаторов вроде author_id классический PSI математически неприменим из-за высокой кардинальности, поэтому фреймворк отдельно контролирует долю новых, ранее не встречавшихся авторов.

Тест 1: Segmented AUC — качество по категориям контента

Техника: адаптация эквивалентного разбиения (сегментация данных).

Как в памятке: делим контент на группы и смотрим, нет ли перекосов. Мы разбили все видео на 20 групп и для каждой посчитали AUC. Чем выше столбец, тем лучше модель предсказывает лайк в этой группе. Красная линия обозначает порог 0.65. Столбец ниже линии означает, что в этой группе модель работает хуже.

Цифры от 0 до 19 это номера групп. В реальном проекте здесь были бы названия: «спорт», «юмор», «мода». Рядом с каждым столбцом указано количество записей. Если в группе слишком мало данных или отсутствуют представители одного из классов (например, совсем нет лайков), AUC не считается, и группа помечается как «недостаточно данных».

Результат: модель стабильна во всех категориях, падений ниже порога не обнаружено.

Segmented AUC

Segmented AUC

Тест 2: Boundary Test — поведение на граничных значениях

Техника: анализ граничных значений.

Как в памятке: подаём крайние значения и смотрим, не падает ли код. Для каждого из четырёх признаков мы взяли по 4 граничных значения: для timespent это 0, 1, 254, 255; для duration — 5, 6, 179, 180; для category — 0, 1, 18, 19; для author_popularity — 0, 1, медианное значение из обучающей выборки и удвоенная медиана. Фреймворк формирует комбинации этих границ, подставляя для остальных параметров медианные или модальные значения из обучающей выборки. Всего получается 96 комбинаций.

Тест проверяет, что на экстремальных входных данных весь production-пайплайн (препроцессинг и модель) отрабатывает без ошибок, а предсказанная вероятность остаётся в допустимом диапазоне [0, 1] и не содержит NaN. Это гарантирует стабильность системы на границах, где возможны деление на ноль или переполнение при масштабировании.

Результат: все 96 комбинаций отработали корректно. Модель не падает и не выдаёт некорректных значений на граничных данных.

Boundary Test

Boundary Test

Тест 3: Decision Table — проверка бизнес-гипотез

Техника: таблица принятия решений (адаптация — проверка метаморфных инвариантов).

В контексте ML таблица решений проверяет направленность бизнес-логики: если мы меняем параметры в сторону заведомо позитивного исхода (например, от нулевого времени просмотра к полному досмотру), предсказанная вероятность лайка обязана расти.

Как в памятке: условие и ожидаемый результат. Мы сформулировали четыре гипотезы и проверили их через сравнение средних предсказанных вероятностей. Для каждой гипотезы указаны две группы (А и Б), средние вероятности, разница (B−A) и минимальный значимый эффект.

Как читать вердикты:

  • Подтверждена — разница направлена в ожидаемую сторону. Для гипотез с направлением (greater / less) этого достаточно, порог не применяется. Для гипотез без направления (two-sided) разница должна быть больше 0.02.

  • Противоречит — разница направлена в противоположную сторону (ожидали рост, а получили падение, или наоборот).

  • ⚠️ Недостаточно данных — разница есть, но она слишком мала (меньше 0.02), чтобы считать гипотезу подтверждённой. Применяется только к гипотезам без направления (two-sided).

Почему для направленных гипотез нет порога: если модель говорит «досмотренное видео лайкают чаще», но разница всего 1% — это всё ещё верное направление. Модель не ошиблась, просто эффект слабый. Мы не наказываем модель за слабый эффект, если она правильно поняла закономерность. Порог 0.02 оставлен только для случаев, где мы проверяем сам факт различия без указания направления.

Статистические тесты не применяются — фреймворк сознательно смещает фокус на практическую значимость (Effect Size).

Проверяемые гипотезы:

  1. Недосмотренное видео получает более низкую вероятность лайка, чем досмотренное.
    Группа А: timespent < duration (недосмотрели).
    Группа Б: timespent == duration (досмотрели полностью).
    Ожидаемое направление: Б > А (greater).
    Вердикт: ✅ подтверждена.

  2. Короткие видео (<30 с) лайкают чаще длинных (>120 с).
    Группа А: duration > 120 (длинные).
    Группа Б: duration < 30 (короткие).
    Ожидаемое направление: Б > А (greater).
    Вердикт: ❌ противоречит.

  3. Популярный автор vs обычный — есть ли разница?
    Группа А: автор в топ-50.
    Группа Б: автор не в топ-50.
    Ожидаемое направление: А ≠ Б (two-sided).
    Вердикт: ⚠️ недостаточно данных (разница меньше порога).

  4. Видео короче 60 с vs длиннее 60 с.
    Группа А: duration >= 60.
    Группа Б: duration < 60.
    Ожидаемое направление: А ≠ Б (two-sided).
    Вердикт: ⚠️ недостаточно данных (разница меньше порога).

Это честная картина: модель усвоила не все ожидаемые закономерности. Дата-сайентисту стоит на это посмотреть.

Decision Table

Decision Table

Тест 4: Pairwise Test — попарное тестирование параметров

Техника: попарное тестирование.

Как в памятке: покрываем все пары значений. У модели четыре параметра, полный перебор дал бы 8640 комбинаций. Непрерывные признаки timespent и duration были предварительно разбиты на диапазоны (классы эквивалентности), и уже для этих дискретных классов алгоритм AllPairs сгенерировал 182 комбинации с покрытием всех пар 100%.

Важное архитектурное допущение: наша базовая модель это линейная логистическая регрессия. Математически она просто складывает признаки с весами и по своей природе не умеет учитывать их сложные сочетания (интерференцию). Для логрега этот тест во многом является демонстрационным. Однако мы закладываем Pairwise во фреймворк «на вырост». Если завтра команда Data Science заменит линейную модель на нелинейный CatBoost или Random Forest, этот тест станет главным защитником от багов переобучения на стыке редких комбинаций параметров.

Результат: все 182 комбинации отработали без ошибок. Модель не ломается ни на одном сочетании параметров.

 Pairwise Test

Pairwise Test

Тест 5: Stability Test — контроль дрейфа (PSI)

Техника: обнаружение дрейфа данных.

Как в памятке: проверяем, не изменилась ли среда. PSI (Population Stability Index) сравнивает распределения признаков в тренировочной и валидационной выборках. Порог 0.25 считается сигналом о значительном дрейфе.

Признаки разделены на две группы:

  • Признаки модели (timespent, duration, category, author_popularity). Их дрейф влияет на предсказания, и для них рассчитывается PSI.

  • Контекстные признаки (platform, place, agent). Они не влияют на модель, но сигнализируют об изменении среды.

Для уникальных идентификаторов вроде author_id классический PSI математически неприменим из-за высокой кардинальности. Вместо этого фреймворк отдельно контролирует долю новых, ранее не встречавшихся авторов в валидационной выборке.

Результаты PSI для признаков модели:

  • timespent: 0.02 — дрейфа нет.

  • duration: 0.24 — близко к порогу, но не превышает.

  • category: 0.01 — дрейфа нет.

  • author_popularity: 0.48 — значительный дрейф.

Что означает дрейф author_popularity: признак показывает количество взаимодействий автора в обучающей выборке. Если в валидационной выборке распределение популярности авторов сильно отличается от тренировочной, это может означать, что в проде пошли видео от авторов, которых модель «не знает» или знает плохо. Модель может начать ошибаться на таких видео, потому что признак author_popularity для них будет низким или нулевым, а в обучении таких примеров было мало. Дата-сайентисту стоит проверить, изменился ли состав авторов в новых данных.

Результат: по author_popularity обнаружен значительный дрейф. По остальным признакам дрейф не выявлен.

Stability Test

Stability Test

Что должен делать QA, а что нет

Фреймворк имитирует реальный процесс, в котором роли распределены так.

Дата-сайентист предоставляет:

  • Сериализованный пайплайн препроцессинга, идентичный production-окружению.

  • Список признаков, подаваемых в модель.

  • Минимальный размер группы для Segmented AUC.

  • Порог тревоги для PSI.

  • Стратегию заполнения неварьируемых признаков в Boundary и Pairwise тестах.

Бизнес (совместно с дата-сайентистом) предоставляет:

  • Бизнес-гипотезы и их ожидаемое направление.

  • Минимальный практически значимый размер эффекта.

  • Порог AUC для Segmented AUC.

QA-инженер:

  • Не придумывает перечисленные параметры и артефакты.

  • Получает их как входную спецификацию.

  • Проверяет, что модель предсказывает корректно на границах и в комбинациях при использовании предоставленного пайплайна.

  • Проверяет, что Segmented AUC и PSI соответствуют заданным порогам.

  • Проверяет, что бизнес-гипотезы либо подтверждаются, либо отклоняются строго по правилам, зафиксированным в спецификации.

В production-среде эти цифры поступают от бизнеса и дата-сайентиста. Здесь мы воспроизводим этот процесс с демонстрационными значениями, чтобы показать механику.

Ограничения и развитие

Фреймворк построен на учебной модели и данных, поэтому в нём есть упрощения: категории от 0 до 19 служат суррогатом настоящих тематик; пороги (AUC = 0.65, размер эффекта = 0.02, минимальная группа = 30) выбраны для демонстрации; pairwise покрывает пары, но не более высокие взаимодействия; модель является простейшей логистической регрессией.

В планах: расширение на реальные сценарии, интеграция с CI/CD, добавление новых техник тестирования и расширение справочника. Код открыт, предложения и критика приветствуются.

Выводы

Классические техники тест-дизайна применимы к ML-модели напрямую. Фреймворк показывает, что эквивалентное разбиение, граничные значения, таблицы решений и попарное тестирование не требуют от QA умения строить модели или выводить формулы. Достаточно спецификации, которую предоставляют дата-сайентист и бизнес. При этом QA необходимо понимать механику работы модели на уровне терминов и причинно-следственных связей: что такое AUC, PSI, предсказанная вероятность и как интерпретировать результаты тестов. Без понимания проверка формальна, а с пониманием осмысленна. Такой подход сокращает разрыв между DS и QA и делает качество модели прозрачным для всей продуктовой команды.

Ссылки

Сводка дашборда. Пять тестов, пять цветных карточек. Быстрый взгляд на общее состояние модели

Сводка дашборда. Пять тестов, пять цветных карточек. Быстрый взгляд на общее состояние модели

ссылка на оригинал статьи https://habr.com/ru/articles/1048944/