Месяц искал, почему нейросеть слышит в записи мотора тишину. Трижды ошибся и вот что это стоило
Коротко
- Три ошибки подряд: обвинил дешёвые телефоны, распространил вывод одной платформы на все, доверился метрике с фиксированным порогом.
- Цена: три недели, шесть дней сломанной записи у трети пользователей, полтысячи записей, негодных для обучения.
- Настоящая причина нашлась только когда я стал записывать не выводы, а то, что происходит на самом деле.
Я делаю бесплатную предварительную диагностику двигателя по звуку: человек записывает мотор на телефон, модель говорит, в какой зоне искать неисправность. Сорок-пятьдесят диагнозов в день, полторы тысячи записей в базе, проект веду один.
Три недели назад я заметил, что модель ставит «поломка» в 71% случаев. Либо ко мне приходят одни владельцы умирающих моторов, либо продукт не работает. Дальше начались три недели поисков и три ошибки, каждая из которых в момент принятия выглядела разумной.
Ошибка первая: обвинить того, на кого проще подумать
Первая гипотеза была про дешёвые телефоны: плохие микрофоны, модель принимает шум за стук. Она красиво объясняла всё и требовала только проверки на корпусе.
Проверка её не подтвердила. Внутри одного диапазона громкости марки вели себя одинаково, а разброс между диапазонами был вдвое больше, чем между вендорами. Дорогие телефоны выглядели лучше просто потому, что пишут громче.
Чего это стоило. Неделя. И, что хуже, запись в моей внутренней документации: «марка телефона почти ни при чём, дело в самой записи». Формально верно, а по сути тупик, на который я потом ссылался ещё дважды, отметая варианты, связанные с устройством.
Вывод, который я тогда сделал правильно: не марка. Вывод, который я не сделал: значит, надо искать, что стоит между микрофоном и файлом.
Настоящая причина: браузер вычитал двигатель
Нашлась она, когда я перестал резать данные по маркам и разрезал по формату файла: он выдаёт способ записи.
- Android, запись в браузере: громкость −38,6 дБ, доля тишины 70%
- айфоны: громкость −24,8 дБ, доля тишины 0%
- загрузка готовым файлом: громкость −22,3 дБ, доля тишины 1%
Когда сайт просит у браузера микрофон, тот по умолчанию включает подавление шума, эхоподавление и автоматическую регулировку громкости. Все три настроены на разборчивость речи. А подавление шума по построению вычитает ровный широкополосный шум, то есть ровно работающий двигатель.
Я просил браузер записать мотор, браузер старательно вычитал мотор.
Правка состоит из трёх полей в запросе. Результат через пять дней, 175 новых записей против 102 до:
- доля тишины: было 36%, стало 2%
- вердикт «поломка»: было 65%, стало 39%
- вердикт «норма»: было 14%, стало 25%
Модель я при этом не трогал. Она всё это время добросовестно отвечала на заданный вопрос. Просто вопрос был не тот, который я думал, что задаю.
Ошибка вторая: распространить вывод за пределы замера
Стенд, на котором я проверял гипотезу, был десктопным Chromium под Linux. Поле, на котором она подтвердилась, был Android. А правку я выкатил на всех, включая iOS.
Через сутки записи с айфонов начали приходить пустыми, до семи из восьми за день. Айфоны дают около трети трафика.
Разбирался шесть дней. За это время выдвинул и отверг четыре версии: кэш браузера, версия Safari, версия iOS, состав аудитории после публикации на Хабре. Все четыре были правдоподобны, все четыре оказались мимо.
Ответ дал отчёт с реального айфона, для которого пришлось делать отдельную страницу самодиагностики:
- по умолчанию: громкость −43,2 дБ, шумовой пол −44,9 дБ
- обработка выключена: громкость −61,0 дБ, шумовой пол −62,5 дБ
На iOS выключение обработки роняет весь тракт на восемнадцать децибел разом: и сигнал, и шумовой пол одинаково. Это не вычитание фона, при котором полезное остаётся, а снижение усиления целиком. На Android правка убирала помеху, на iOS просто делала запись тише.
Чего это стоило. Шесть дней сломанной записи у трети пользователей. Они приходили, записывали мотор, получали бессмысленный ответ и уходили. Сколько из них вернётся, я не знаю и узнать не могу.
Ошибка третья: поверить метрике, а не данным
Когда стало ясно, что на iOS правка вредит, я её откатил. И через сутки посмотрел на цифры: доля тишины у айфонов осталась высокой. Значит, откат не помог, значит, причина в другом.
Это был неверный вывод, и стоил он ещё трёх дней поисков.
Дело было в метрике. «Доля тишины» у меня считалась как доля фрагментов тише фиксированного порога. Запись со средним уровнем чуть ниже этого порога давала «сто процентов тишины», не будучи при этом пустой. Откат сработал. Просто в те дни люди записывали в тихих помещениях, и записи всё равно попадали под порог.
Метрика с абсолютным порогом измеряла не то, что я думал. Теперь тишина считается относительно собственного шумового пола записи: тишина это неотличимость от фона, а не малая громкость.
Что в итоге оказалось правдой
Android действительно писал хуже. Но не из-за цены телефона, а из-за того, что обработку выполняет реализация производителя в звуковом чипе, и она не обновляется вместе с браузером.
Внутри одного бренда аппараты ведут себя противоположно:
- TECNO LJ8: 11% тишины
- TECNO LH7n: 85%
- Redmi M2004J19C: 0%
- Redmi 21061119DG: 69%
Разброс между ста семьюдесятью моделями составил от нуля до ста процентов. Усреднение по бренду это прятало ровно так же, как усреднение по цене на первом шаге.
То есть первая гипотеза была права в направлении и неправа в объяснении. «Дешёвые телефоны» не причина, а «конкретный аппарат» причина.
Полный счёт
Три недели на поиск причины, из них шесть дней с заведомо сломанной записью на iOS и три дня погони за призраком из-за плохой метрики.
Полтысячи записей, снятых на Android до правки, негодны для обучения модели. Подавление шума необратимо: восстановить из них исходный звук нельзя. Для проекта, у которого главный актив это накопленный корпус реальных записей, это самая дорогая часть счёта.
Одна выкаченная правка, которую пришлось откатывать, и вторая, уже с разделением по платформам.
Чего это не стоило: трафика. Он всё это время шёл своим чередом, потому что люди не видят разницы между «модель ошиблась» и «модель права». В этом и коварство: продукт был сломан три недели, и ни один пользователь об этом не сообщил.
Что я изменил в том, как работаю
Записывать не только вывод, но и чем он опровергается. Строчка «дело не в марке телефона» месяц закрывала мне целое направление поиска. Если бы рядом стояло «проверено на марках, но не на моделях», второй заход случился бы раньше.
Телеметрия до гипотез, а не после. Причина на iOS нашлась в тот день, когда я начал сохранять, что браузер реально сделал с микрофоном, а не что мы у него попросили. До этого я три дня гадал по косвенным признакам. Правило простое: если система принимает решение, которое влияет на данные, записывайте само решение, а не его последствия.
Метрики с абсолютным порогом врут, когда меняется масштаб. Любой порог в децибелах, рублях или секундах надо перепроверять, когда меняется то, что вы измеряете. У меня поменялся уровень записи, и метрика начала мерить другое, не сообщив об этом.
Не распространять вывод за границы замера. Стенд был на одной платформе, поле на другой, а правку я выкатил на все. Это самая дорогая из трёх ошибок и самая типичная.
Что осталось нерешённым
Чтобы закрыть вопрос, нужны замеры с устройств, которых у меня нет.
Поэтому страница самодиагностики открыта для всех: avtouho.ru/mic-check. Она делает два захвата подряд, считает всё в браузере, и отправляет только по нажатию - "Отправить отчет". Было бы неплохо проверить еще раз айфоны, кроме моего, да.