Как стать автором
Обновить
365.77
Яндекс
Как мы делаем Яндекс

Как мы тестируем беспилотные автомобили с помощью симуляций

Уровень сложностиПростой
Время на прочтение12 мин
Количество просмотров4.2K

Всем привет! Это Александр Чистяков из команды беспилотных автомобилей Яндекса. Мой доклад посвящён симуляторам: что это, зачем, как это устроено изнутри и какие в симуляции есть подводные камни, неожиданные парадоксы. Также расскажу, с помощью каких алгоритмических или архитектурных решений мы со всеми этими парадоксами боремся.

Как устроен беспилотный автомобиль

Автомобили Яндекса уже проехали почти 30 миллионов километров по самым разным дорогам, перевезли десятки тысяч пассажиров, а роботы‑доставщики привезли сотни тысяч заказов и каждый год наши технологии продолжают совершенствоваться.

Сперва расскажу, как наши автомобили устроены. С виду это обычные легковые автомобили, на которые навешали кучу датчиков и сенсоров: радары, лидары, камеры, в багажник установили вычислители с ГПУ. И выпустили на дороги. Вот как это выглядит:

А вот как наш автомобиль видит окружающий мир:

Слева — лидарные облака. Лидар — это такая вращающаяся лазерная указка, которая нащупывает расстояние до соседних объектов и по форме пытается узнать, что это за предмет. Лидар «видит» даже ночью, в полной темноте.

Но лидары не могут распознать дорожные знаки, сигналы поворотников, стоп‑сигналы, дорожную разметку. Поэтому по периметру автомобиля есть ещё и камеры.

Весь этот огромный поток данных с сенсоров проходит сквозь здоровенный пайплайн компьютерного зрения из сегментации, детекции и трекинга. На выходе мы получаем вот такую векторную картинку, как на левой половинке слайда.

Грубо говоря, мы считаем все машины параллелепипедами с какой‑то метаинформацией. Например, включены ли поворотник или аварийная мигалка.

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

Вся эта конструкция ездит по городу, получает векторное представление, отправляет его в поведенческую компоненту беспилотного автомобиля, понимает, как в этой ситуации проложить маршрут, чтобы достигнуть цели. И потом — что надо сделать, чтобы маршрут воплотить: когда нажать на газ, как повернуть руль и так далее.

Зачем нужен симулятор

Пока почти во всех автомобилях, которые мы испытываем в городе, на водительском или переднем пассажирском месте сидит страхующий водитель. Если что‑то пойдёт не так, этот человек вмешается и поможет нашей машине.

Каждый сложный случай мы тщательно разбираем, чтобы исправить. И первый вопрос, на который необходимо дать ответ: а что было бы, если бы водитель не вмешался?

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

А дальше сравниваем с тем, что теперь получилось.

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

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

Тут надо уточнить, что таких вмешательств водителя на самом деле мало. И для нас это проблема с двух сторон. Первая: водителю всё ещё иногда приходится вмешиваться, мы не можем совсем его убрать, чтобы сделать наш автомобиль абсолютно самостоятельным. Но, с другой стороны, проблем настолько мало, что нам очень сложно улучшать технологию.

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

За годы существования беспилотных автомобилей мы накопили десятки тысяч разных интересных сложных сцен: вмешательство водителей, просто проезд каких‑то сложных участков, сложных перекрёстков, перестроения и так далее.

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

Таких сцен мы можем накопить столько, сколько нам нужно для тестирования любой новой фичи. Например, мы можем также по другим сценам понять, что при повороте налево надо учитывать не только едущий навстречу транспорт, но и тот, что следует за нами.

Как устроен симулятор

Самые внимательные, наверное, уже заметили, что слева и справа иногда машинки едут чуть по‑разному. И это нормально. На самом деле мы знаем только то, как агенты вокруг нас ехали в реальном мире. Но, как только мы меняем поведение беспилотного автомобиля, например убираем вмешательство водителя или тестируем какую‑то новую логику перестроений, в ответ на это должны по‑другому начать вести себя окружающие водители. Мы проехали уже десятки миллионов километров и знаем, как окружающие водители обычно реагируют на наши всевозможные действия.

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

На левой картинке машины, которые стояли за нами, чуть‑чуть раздвоились, от них отделились серые «привиденьица» — это то, где машины были в реальности. Теперь же мы в симуляции понимаем, что обычно сквозь нас машины не едут. У них включается специальная ML‑модель, которая моделирует поведение окружающих агентов, и они подстраиваются под наши новые траектории.

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

Чтобы лучше понять концепцию, которая лежит в устройстве симулятора, полезно обратить внимание и на робота‑доставщика. Если кто‑то с ним ещё не сталкивался, это такая милая коробочка на шести колёсах на специальной подвеске — катается по городу и доставляет, например, продукты из Лавки.

Его проблема в том, что он маленький. На роботакси на крыше стоит куча сенсоров: камеры, лидары. И, например, в пробке мы можем заглянуть за соседнюю машину, понять её размеры, прощупать слепые зоны. А робот — где‑то по пояс человеку. Когда он сквозь толпу везёт свои товары, разглядеть окружающий мир сквозь ноги людей для него сложно.

Выглядит это как-то так:

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

Начался какой‑то хаос. И что происходит на камерах? Всю левую камеру нам закрыли бампером, спереди всё застлано выхлопными газами. Робот стоит в панике, не понимает, что происходит. Потом машина уедет, дым рассеется, робот придёт в норму и продолжит свой маршрут.

Чтобы симулировать такую сцену, нам надо понять, что именно надо симулировать. Мы пришли к концепции объективной реальности. Ниже — верхнеуровневая схема того, как вообще устроен симулятор. Красным цветом выделен тот кусок, про который я уже рассказал.

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

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

Параллельно с этим мы можем не спеша, но, главное, максимально точно понять, что же на самом деле в мире творилось.

Какие у нас здесь есть хаки?

  • Мы можем взять какую‑то более тяжёлую модель компьютерного зрения, которая на настоящий беспилотник не влезала бы по перформансу.

  • Также мы можем «заглянуть в будущее». Например, в какой‑то момент где‑то на горизонте в тумане появился серый непонятный силуэт, мы пролистаем видео вперёд, поймём, что это был автобус и габариты его не менялись. То есть в будущем мы можем понимать заранее, что за серый силуэт с похожими параметрами перед нами.

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

Как всё это выглядит для машинки? Вот такая картинка из серии «найдите десять различий»:

Слева — то, как этот момент видит сам беспилотный автомобиль, справа — то, что мы записали в объективную реальность.

Верхняя строчка — это машины на парковке. В проезде мы видим только самые ближние из них. Потом мы посмотрели внимательно и поняли, что там ещё ряд машин на парковке.

Вторая строчка. В проезде мы видим пешехода, стоящего на автобусной остановке. В объективной реальности мы взглянули внимательнее и поняли, что пешеходов там два. И вот в симуляции нам бы надо было учитывать второго пешехода. Например, он мог выходить на проезжую часть.

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

Эффект бабочки и параллельные миры

Вся наша симуляция работает. Но к нам периодически приходили разработчики с такой жалобой: «Смотрите, я тут тестирую какую‑то свою фичу, и вот на этой сцене слева и справа две версии — с фичей и без фичи. Беспилотный автомобиль‑то едет одинаково. Но вот ваши умные агенты поехали как‑то по‑разному, в итоге меня спровоцировали на новые действия, а мне это ухудшило метрики. Всё неправильно делаете».

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

И на самом деле там, где внешне всё выглядело одинаково, траектория беспилотника могла начать отличаться буквально на один сантиметр. И этот сантиметр по‑другому заходил на вход какой‑то модели, выход модели отклонялся уже на два сантиметра, эти два сантиметра влияли на что‑то следующее в пайплайнах, было отклонение уже на пять сантиметров, десять, метр.

Поскольку у нас каждый такт симуляции зависит от всего предыдущего, за несколько секунд симуляция разваливалась и начиналось какое‑то совершенно другое развитие событий в этом мире. И срабатывал так называемый эффект бабочки.

Мы долго думали, как с этим бороться, а потом поняли, что бороться не надо. Ведь мир непредсказуем. Поэтому мы решили: давайте мы будем эксплуатировать этот эффект бабочки и умышленно вносить искажения как в распознанный мир, так и в объективную реальность.

В итоге из одной сцены мы можем наплодить четыре, десять, сто параллельных вселенных, в которых как‑то по‑разному начнут развиваться события. И заметить, что в одной из вариаций, например, происходит какая‑то авария. Соответственно, часто сцены бывают у нас какие‑то редкие, их очень тяжело воспроизвести где‑то на реальных дорогах, а тут мы сможем как раз по‑разному варьировать сцены, получить из одной сцены целый датасет, на котором уже внимательно следить за улучшением каких‑то характеристик или поведения наших беспилотников.

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

Как измерить качество симуляции

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

И тут всё не так просто. Для беспилотника есть понятные продуктовые метрики. Доехал до цели — молодец. Врезался во что‑то по пути — не молодец. Если мы начнём что‑то такое же улучшать в нашем симуляторе, то придём к странным эффектам.

Например, мы начнём хвалить симулятор за то, что в нём стало меньше аварийных ситуаций. Тогда получится идеальный симулятор, в первую секунду в нём все агенты будут бросаться врассыпную, лишь бы не задеть беспилотник, ни с кем не столкнуться. Если мы будем увеличивать количество аварий — ведь мы же хотим в симуляции что‑то промоделировать, сгенерировать сложные случаи, — тогда у нас агенты начнут устраивать какой‑то «кармагеддон», гоняться за беспилотником, таранить его. Это не тот мир, к которому мы готовим наши машины. Что делать?

Давайте проникнемся, представим себя разработчиками. Здесь будет снова две симуляции, но в них беспилотник едет абсолютно одинаково. А то, как повёл себя симулятор в ответ на встраивание беспилотника перед ним, различается.

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

Мы столкнулись с проблемой, что дошли до того состояния качества симулятора, когда над каждым следующим улучшением мы уже сами начнём спорить. Включается субъективизм: мы не понимаем, правда ли здесь стало лучше. Приходится отсматривать какое‑то немыслимое количество сцен, чтобы хоть как‑то прийти к соглашению, какая из ML‑моделей лучше. Хотелось от этого избавляться и объективно оценивать качество.

Что мы сделали? Использовали прекрасную идею из генеративных моделей — дискриминатор.

У нас есть десятки, сотни тысяч разных сцен. Мы можем запустить их все в нашем симуляторе. Возможно, мы внесём какие‑то искажения, чтобы полностью не повторить сцену, а спровоцировать какие‑то новые поведения агентов, беспилотных автомобилей. На части пар таких сцен «реальность — симуляция» обучим МL‑модель, которая будет угадывать, что из этого реальность. На оставшейся части пар протестируем качество этой модели. И поймём, в какой доле случаев модель угадала, что из этого реальность.

Если бы наш симулятор был идеальным, то у модели не было бы шансов угадать, что из этого реальность. Если бы симулятор явно выдавал себя, то модель легко зацепилась бы за какие‑то утечки и, соответственно, почти в 100% случаев угадывала бы.

Понятно, что здесь по‑разному можно считать метрику, но сейчас у нас на дашбордах вероятность угадывания чуть больше 60%. Ещё не идеально, но и не всё так плохо.

Таким образом, у нас появилась объективная численная метрика, которую от релиза к релизу можно считать, и можно сравнивать, где она меньше. И теперь мы можем ещё применять к этой ML‑модели специальные методы реверс‑инжиниринга, чтобы понимать, за что она цепляется и что нам надо исправлять в первую очередь в симуляторе.

Открытые проблемы симуляции

Есть ещё много проблем. Одна из них — сохранение намерений агентов из сцены.

Беспилотный автомобиль выехал неудачно на перекрёсток и перегородил путь поворачивающей налево машине. В симуляции мы ещё дальше выезжаем на этот перекрёсток, совсем перегораживаем путь той машине. И смотрите на синюю машину. «Привиденьице» поворачивает налево, водитель синей машины думает: «Там всё занято, поеду прямо». Если не знать, что же было тогда в реальности, выглядит достаточно реалистично.

Мы добавляли этот кейс в наши пулы, тесты, чтобы проверить как раз разъезд с поворачивающей машиной, а тут тест сломан. Соответственно, дело у нас не только в реалистичности, но и в каких‑то других, более скрытых от понимания вещах.


Механика симуляции возникает в самых разных областях. И принципы, которыми я сегодня поделился, везде общие.

  • Как бы вы ни продумывали систему ручных тестов, в реальности вы столкнётесь с кейсами, о которых вы раньше не думали, и они будут сложнее, чем вы изначально пытались описать.

  • Когда будете улучшать алгоритмы и повторять их в каких‑то сценах из реальности, ваша реальность должна будет уметь адаптироваться к этим новым алгоритмам и делать это правдоподобно.

  • Алгоритмы при запуске никогда не будут видеть настоящий мир. Они будут видеть какие‑то свои входные сигналы. Но мир сложнее, и это надо как‑то учитывать. Более того, вы сами знаете, что мир неопределёнен.

  • Неопределённостью мира можно пользоваться, чтобы с помощью порождения мультивселенных протестировать все возможные варианты срабатывания ваших алгоритмов.

  • Очень часто замерить качество системы тестирования гораздо сложнее, чем качество самого тестируемого объекта.

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

Теги:
Хабы:
Всего голосов 23: ↑23 и ↓0+27
Комментарии8

Публикации

Информация

Сайт
www.ya.ru
Дата регистрации
Дата основания
Численность
свыше 10 000 человек
Местоположение
Россия