Если с тобой за карьеру не случалось никаких факапов - либо ты начал свой путь примерно три дня назад, либо на работе ты только тапаешь хомяка или рубишься в Харстоун. Фейлы, провалы, косяки - всё это офигенные способы чему-то научиться и стать лучше, но это работает только, если после факапов проводить их "вскрытие" - анализировать, какие причины привели к неудаче, и что нужно изменить, чтобы уменьшить вероятность возникновения похожей ситуации в будущем.
Если вы хотите узнать ещё больше об организации процессов ML-разработки, подписывайтесь на наш Телеграм-канал Варим ML
Причины факапов можно поделить на такие группы:
Личные факторы - усталость, отсутствие мотивации, постоянное переключение контекста, несоблюдение правил
Техдолг и инженерная культура - отсутствие тестов, запутанный код и конфиги, неудобная постановка экспериментов, отсутствие версионирования, отсутствие средств мониторинга и алертов, плохая документация, плохие или устаревшие тестовые датасеты, отсутствие возможности быстрого отката релиза
Процессы и коммуникация - недопонимание между командами, непонимание бизнес-требований и некорректная постановка задачи, отсутствие релизных чек-листов, плохие процессы взаимодействия с новыми клиентами, изменение формата данных во внешних источниках, игнорирование существования человеческого фактора при использовании системы
Случайность - иногда реально все факторы просто складываются против тебя, shit happens
Проблема в том, что факапы редко происходят по злой воле или из-за плохого качества работы. Чаще всего, особенно в стартапах, они являются результатом осознанных решений или ограниченности ресурсов. Например, на ранней стадии стартапа вряд ли будет хорошим решением обеспечивать стопроцентое покрытие тестами и обложиться подробной документацией - на это просто уйдут все и так небогатые ресурсы. Конечно, работа с техдолгом и пересмотр процессов должны происходить регулярно, но это не может полностью уберечь от ошибок - процессы, тесты, код начинают устаревать в ту же секунду, когда они внедрены или написаны.
Последствия у факапов могут быть самые разные - от лёгкого испуга до потери внутреннего доверия внутри компании, испорченной репутации у клиентов, денежных потерь, юридических последствий и даже вреда здоровью (всё-таки медициной занимаемся). Тяжесть ущерба зависит не только от самих факапов, но и от качества инструментов и процессов по их обнаружению и устранению последствий. Некоторые проблемы могут висеть незамеченными часами и даже днями.
Это всё теоретические размышления, а что по примерам? Я как раз делал доклад про три факапа, которые случились в Цельсе на разных этапах жизни компании, но записи нет, так что расскажу про них текстом. А ещё недавно был вот такой пост со смешным багом.
Факап 1 - Кошмар с конфигами
Время действия - август 2020
Человек в ML-отделе - 8
2020 год был знаковым для всей индустрии искусственного интеллекта в рентгенологии, по крайней мере в России. Разбушевался COVID-19, врачи работали на износ, это сильно подогрело интерес к средствам частичной автоматизации и облегчения труда медицинских работников. На этой волне в Москве появился Эксперимент по использованию компьютерного зрения в радиологии. Мы вошли с него в июне с системой по анализу маммографических снимков, а в августе решили зарелизить новую версию с улучшенными метриками. В Эксперименте новая версия модели должна пройти калибровочное тестирование - для проверки метрик на внешнем датасете. Мы его успешно прошли, и новая модель начала работать на проде.
За пару дней мы поняли, что немного ошиблись с настройкой бинарного порога классификации на патологию и норму. На визуализацию для врача и ROC-AUC на потоке это никак не влияло, но немного подкрутить всё равно хотелось. Исторически у нас было два тестовых пайплайна - быстрые тесты на корректность работы системы и долгие тесты, включающие в себя небольшой метрик-тест. Ради такого незначимого изменения гонять долгий пайплайн (больше часа) мне не захотелось, и я оверрайднул пулл-реквест.
Как-то так выглядел этот PR
Через несколько дней я решил посмотреть, что творится на потоке, и у меня слегка похолодело внутри. Вот что я увидел:
А должно быть примерно так:
Почти на всех исследованиях находились какие-то мелкие непонятные объекты. Быстрое расследование показало, что изменён был не порог срабатывания, а порог бинаризации изображения, который используется при поиске маски груди во время препроцессинга. В итоге маски груди находились абсолютно неправильные, маленькие, обрубленные, и в нейронку попадали рандомные рейсайзнутые куски изображения.
Итого - три дня мусорных предсказаний, 1500 абсолютно неверно обработанных изображений. Забавно, но обошлось без финансовых потерь - на тот момент в Эксперименте оплачивали все обработанные исследования, даже с явными ошибками. Репутационные издержки тоже удалось сдержать на адекватном уровне - нашим бизнес-ребятам пришлось поговорить с организаторами, объяснить ситуацию и рассказать, что мы сделаем, чтоб такого больше не повторилось.
Какие же выводы я для себя тогда сделал?
Технические:
При абсолютно любых изменениях прогоняем все имеющиеся тесты. Если они занимают слишком долго, значит нужно их ускорить или убрать лишнее. Оверрайд только в критических ситуациях при исправлениях критических багов.
Добавляем тест на неизменность результата - если PR не предполагает изменений ответа нейронки, то следует это явно проверить.
Проверяем адекватность нейминга в конфигах и вообще корректность его разбиения на подконфиги. bin_threshold - явно плохое название для такой переменной в ML-системе, поскольку может значить много разных вещей.
Процессные и коммуникационные:
Не скрываем инциденты, сразу после обнаружения начинаем коммуницировать с клиентами. Тут мы так и поступили, но хорошее поведение тоже нужно подмечать и закреплять.
После релиза вводим особый усиленный режим ручного мониторинга. Нужно разработать инструмент для удобства таких проверок. На первое время сделали телеграм-бот, сейчас есть полноценная платформа.
Личные:
Правила равны для всех. Конечно, у кого-то должны быть права на оверрайд, но в 99.9% случаев введённые правила должны соблюдаться всеми - от джуна до CTO. Не зря же они внедрялись?
Не стоит принимать важные решение в уставшем состоянии. Вся эта возня с Экспериментом изрядно меня потрепала, и мне точно нужно было хорошенько отдохнуть. Это хорошо ещё, что в данном случае последствия были не особо жёсткие.
Факап 2 - Катастрофа с округлением
Время действия - декабрь 2020
Человек в ML-отделе - 12
К концу года наши системы по ММГ и ФЛГ уже работали в продакшне по полгода, и мы решили выводить в Эксперимент новый сервис - детекция COVID-19 на компьютерной томографии лёгких. Задача с точки зрения ML не очень сложная, на внутренних тестах мы получили ROC-AUC выше 0.9.
Схема работы нашего сервиса по сравнению с первыми прототипами немного усложнилась, появилась прослойка между клиентом и нейронкой в виде бэкенда, который отвечает за получение и валидацию исследований, отправку запросов на ML, получение результатов в виде JSON, а также генерацию ответов для клиента - обычно в виде SR и SC-серий.
Очередное калибровочное тестирование, уже знакомая процедура - 100 исследований, 50 с патологией, 50 без патологии. Несколько дней ждём результаты, а на выходе получаем ROC-AUC 0.53. Настолько негенерализуемая модель получилась? Данные слишком отличаются?
Конечно же, нет. При таком расхождении между внутренними и внешними тестами ответ почти всегда один и тот же - баг. Оказалось, что ML отдаёт вероятность в формате float от 0 до 1, а на бэкенде она автоматически округлялась до ближайшего целого и отдавалась в формате 1-100. Вероятности были не очень откалиброванные и почти все округлялись просто до единицы. Отсюда и "рандомный" AUC.
Проблему обнаружили быстро, так что из последствий только отложенный на две недели релиз, который можно оценить примерно в 400 тысяч рублей неполученной прибыли. Репутационных потерь здесь не было, так как проблема вскрылась на тестировании. Итак, выводы.
Технические:
Необходимо внедрить автоматическое end-to-end тестирование. Тесты на ML-часть сервиса недостаточны для покрытия таких случаев, нужно проверять то, что в итоге видит и получает клиент.
Процессные и коммуникационные:
Требуется перестроить коммуникацию между командами ML и бэка, очевидно, здесь случился рассинхрон по контракту взаимодействия. Вероятно, требуется какая-то роль аналитика для "перевода" между двумя командами и создания постановок задач для бэкенда при изменениях на ML.
Предрелизное тестирование на данных клиента - это круто. Намного приятнее найти косяк на тесте, чем на продакшне. К сожалению, клиентам часто лень организовывать такое тестирование.
Личные:
С ростом компании растёт и количество точек, где что-то может пойти не так, особенно это касается зон взаимодействия между командами. Поэтому важно не зацикливаться на своей области интереса (в моём случае - ML), и вовремя переключаться на новые проблемы.
Факап 3 - Who will watch the watchmen?
Время действия - сентябрь 2022
Человек в ML-отделе - 20
Прошло ещё два года, и сервис КТ ОГК разросся аж до 8 патологий и стал так называемым "комплексным сервисом". К тому моменту у нас уже был накоплен солидный опыт разработки, тестирования и продакшн-эксплуатации ML-систем в рентгенологии.
Месяцы поиска данных, разметки, обучения моделей, заворачивания их в единый сервис - и мы готовы тестироваться. Открываю протокол результатов - и по 6 из 8 патологий результаты по ROC-AUC в районе 0.5. Короче, легче монетку подбросить.
Наученные горьким опытом, мы сразу ринулись искать баг. Перепроверили всё, даже на всякий случай уточнили, нет ли бага в расчёте метрик на стороне организаторов. Разметили данные с тестирования - метрики никак не сходятся. Неужели у наших врачей и у врачей-экспертов настолько разное мнение? В общем, ничего мы в итоге не нашли и не придумали ничего лучшего, как уйти на новый цикл улучшения моделей.
Спустя несколько месяцев мы решили ещё раз попытать счастья с улучшенными моделями, но тут - бомба. Ребята внезапно смогли почти точно воспроизвести метрики с тестирования. Дело было вот в чём. Система отдаёт 9 вероятностей - 8 вероятностей по каждой патологии и общую вероятность наличия хотя бы одной патологии, которая рассчитывалась просто как максимум по всем остальным вероятностям. Оказалось, что метрики воспроизводятся, если для каждой патологии в качестве вероятности брать именно эту общую максимальную вероятность. Упс. Пара популярных патологий чаще всего влияли на этот максимум, по ним и были более-менее нормальные метрики.
Итого - полгода недополученной прибыли + частично потраченная впустую работа команды, хотя за это время мы сильно прокачали качество системы. И, конечно же, бесконечное количество нервишек и шизы. Итак, выводы.
Технические и процессные:
Проблема может находиться и вне пределов компании. Такие кейсы намного сложнее обнаружить и доказать, но возможность эту отбрасывать не стоит.
Доверяйте внутренней валидации! Уроки Кеггла актуальны и для реального мира и продакшн-систем. Если между внутренними и внешними метриками слишком радикальное расхождение - либо что-то не так со своей валидацией и это надо срочно фиксить, либо что-то не так с внешними тестами.
Личные:
Нужно доверять свои командам и их компетентности. Да, ошибиться может каждый, но если ты не доверяешь людям, которых нанял - а на своём ли ты вообще месте?
Если вы хотите узнать ещё больше об организации процессов ML-разработки, подписывайтесь на наш Телеграм-канал Варим ML