Введение в область
Каждый из нас хоть раз в жизни сталкивался с плохой работой светофора на перекрестке: неравномерное движение трафика по нему, слишком долгие интервалы переключения и т. д. Всё это из‑за наивного способа переключения «зеленого» и «красного»: светофоры просто работают по расписанию, а где‑то за ними даже присматривают люди, чтоб вовремя переключить. Выглядит как проблема, которую надо решать. Поэтому наша команда поставила перед собой цель разработать «мозг» для светофора, где будут приниматься эффективные решения о переключении его сигналов.
![Грустно, да? Грустно, да?](https://habrastorage.org/getpro/habr/upload_files/3f8/ee4/937/3f8ee49373f7faa472235dfc27a756b2.png)
Примитивные алгоритмы и идея с ML
По существу, для работы светофора нужна «коробочка», которая принимает какие‑то данные о состоянии перекрестка и сообщает оптимальный сигнал. Соберем в кучу идеи, которые могут быть внутри «коробочки»:
Стандартный светофор, который циклически переключает сигнал. Рассчитан на конкретное соотношение загруженности дорог, неэффективен при изменении загруженности
Алгоритм, включающий зеленый свет более загруженной дороге. На первый взгляд хороший алгоритм, однако при равной загруженности дорог светофор будет постоянно переключать сигнал, что приведет к большому количеству задержек (при переключении светофора нужна задержка, чтобы машины успели уехать с перекрестка)
Алгоритм, включающий зеленый сигнал автомобилям, которые дольше всех стоят на перекрестке. Неэффективен при разной загруженности дорог.
Видно, что хороший алгоритм должен уметь классифицировать ситуацию на перекрестке в зависимости от загруженности дорог, длины задержки и времени ожидания. Поскольку различных соотношений загруженности может быть очень много даже в самом простом перекрестке (загруженность 1:0, 1:1, 1:2, 1:10), создавать примитивный алгоритм с кучей условий нецелесообразно, поэтому, как часто делается в подобных случаях, мы решили обучить нейронную сеть определять оптимальный сигнал.
Отступление про собственный эмулятор
«Стартер пак» для обучения нейросети почти готов — осталось лишь обзавестись хорошей средой (он же эмулятор). Причем хочется, чтобы среда была как можно эффективнее, ведь учатся нейронки не быстро. К сожалению, эмулятора только с одним светофором и удобным API просто не нашлось в дикой природе. Наиболее подходящий под наши нужды вариант — Carla. Это тяжеловесный реалистичный симулятор дорожного движения, разработанный огромной командой. Однако его использование на раннем этапе было нерациональным из‑за излишнего масштаба и сложностей (но позже мы к нему вернемся). Поэтому было принято решение сделать собственный простой эмулятор на Python с отрисовкой на PyGame. Теперь модели (нейросети) можно «скармливать» саму картинку перекрестка, количества машин на дорогах и т. д. Этим и займемся
![Спецэффекты в студию! Спецэффекты в студию!](https://habrastorage.org/getpro/habr/upload_files/f0b/3ea/0e4/f0b3ea0e469976b0974712776f4b604b.png)
Для обучения модели будем использовать обучение с подкреплением (оно же Reinforcement Learning). Если совсем просто, то процесс обучения состоит из непрерывной череды двух фаз: действия модели и реакции среды. В первой модель получает сведения о среде (состояние перекрестка в каком‑то виде) и совершает действие (переключает сигнал светофора), во второй среда обрабатывает совершенное действие (машинки катятся) и передает модели новые сведения о себе, включая вознаграждение (reward) за предыдущее действие. Наверное, вы догадались, что самая творческая и трудная задача здесь — изобрести принцип этого вознаграждения. Теперь, наконец, попробуем вразумить сам светофор.
Среди множества алгоритмов обучения с подкреплением (RL) мы решили выбрать алгоритм DQN (Deep Q Network), поскольку это один из классических алгоритмов RL, он хорошо подходит для задач с неограниченным или очень большим количеством возможных входных параметров (в нашем случае это будет загруженность каждой из дорог и текущий сигнал светофора, позже мы будем передавать обработанное изображение перекреста вместо загруженности)
Обучение модели через количество машин
Как светофору понимать, нужно ли переключать свет? Первая идея — передавать ему количества машин на дорогах перекрестка и делать из этого выводы. Понятно, что это не привязать к реальности (откуда, например, брать точные координаты машин?), но в качестве первой пробы решили реализовать такую идею. После этого перед нами возникла новая задача — придумать reward‑функцию. Мы провели множество экспериментов, выясняя, как лучше «поощрять» нашу модель, чтобы понять, какие факторы действительно «роляют». В итоге получилась довольно сложная формула, зависящая от загруженности дорог, от изменений этой загруженности и того, сколько уже не переключался сигнал на светофоре (на удивление это действительно важный параметр, до которого мы не сразу догадались), с некоторыми коэффициентами. Такая формула показала себя лучше всего в ходе экспериментов.
Для реализации алгоритма DQN мы решили воспользоваться библиотекой torch, получилась вот такая модель:
class QNetwork(nn.Module):
def __init__(self, env):
super().__init__()
self.network = nn.Sequential(
nn.Linear(np.array(env.single_observation_space.shape).prod(), 120),
nn.ReLU(),
nn.Linear(120, 84),
nn.ReLU(),
nn.Linear(84, env.single_action_space.n),
)
def forward(self, x):
return self.network(x)
Модель принимает на вход 5 чисел — 4 из них обозначают количество ожидающих машин на разных дорогах, и пятое число обозначает текущий сигнал светофора. На выходе же имеем 1 число (env.single_action_space.n = 1 из конфигурации среды) — оптимальный сигнал светофора в данной ситуации.
Результаты данной модели были заметно лучше примитивных алгоритмов в большинстве дорожных ситуаций, поэтому мы решили приблизить наши наработки к реальной жизни — подключить обработку картинок, чтобы можно было отслеживать дорожную ситуацию через камеры видеонаблюдения.
Обучение модели через картинку
Теперь вместо загруженности дорог мы решили передавать нейронной сети изображения двух участков перекрестка, которые бы содержали всю информацию о нем. На эту роль хорошо подходят снимки перекрестка, будто сделанные с его разных углов (как разделено на картинке)
![Углы разных цветов - наши снимки Углы разных цветов - наши снимки](https://habrastorage.org/getpro/habr/upload_files/662/7ca/a91/6627caa917b6167fcce2a6540368d8c2.jpeg)
Количество пикселей на изображении слишком велико, чтобы использовать каждый пиксель как входной параметр для модели, поэтому, перед передачей данных на вход, надо их обработать. Сделаем это при помощи библиотек Numpy и PIL:
pil_string_image = pygame.image.tostring(self.painter.canvas, "RGB", False)
pil_image = Image.frombytes("RGB", (1_200, 1_200), pil_string_image)
width = 64
height = 64
resized_image = pil_image.resize((width, height))
cam1 = np.array(resized_image.crop((0, 0, 44, 44))) # high left angle
cam2 = np.array(resized_image.crop((20, 20, 64, 64))) # down right angle
cam1 = np.transpose(cam1, (2, 0, 1))
cam2 = np.transpose(cam2, (2, 0, 1))
observation = np.array([cam1, cam2]) # result
Вход для нейросети готов. Поговорим об её устройстве. Ясно, что такому искусственному разуму нужно понять, что делать со светофором, используя лишь изображения местности, которые для неё лишь трехмерные массивы чисел‑пикселей. Чтоб облегчить ей задачу, добавим в этот «путь понимания» ещё один узел, где она поймет для себя (не важно, в каком виде), какая ситуация на перекрестке сложилась на языке цифр. На этой половине пути модель «зашифрует» (encode) для себя состояние перекрестка. А на следующей, «расшифрует» (decode) в вид, плюс‑минус понятный для принятия решения для переключения светофора. Итого, наша нейросеть — по сути склейка этих двух путей: Encoder и Decoder. А так как изображений 2, то и Encoder»ов тоже 2. Они оба «зашифруют» свои изображения в массивы по 32 числа, которые мы передадим Decoder»у, добавив текущий сигнал светофора. Наконец, Decoder выдаст 2 числа — на какой дороге врубить зеленый.
А вот и реализация вышесказанного
class Encoder(nn.Module):
def __init__(self):
super().__init__()
self.seq = nn.Sequential(
nn.Conv2d(3, 16, 3),
nn.ReLU(),
nn.MaxPool2d(3, 3),
nn.Conv2d(16, 64, 3),
nn.ReLU(),
nn.MaxPool2d(3, 3),
nn.Conv2d(64, 8, 3)
)
def forward(self, x):
x = self.seq(x)
return x.view(x.shape[0], -1)
class Decoder(nn.Module):
def __init__(self, n):
super().__init__()
self.seq = nn.Sequential(
nn.Linear(n, 2 * n), # nn.Linear(n + 1, 2 * n),
nn.ReLU(),
nn.Linear(2 * n, 8 * n),
nn.ReLU(),
nn.Linear(8 * n, 2)
)
def forward(self, x):
# input shape: torch.Size([2, 2, 2])
# output shape: torch.Size([2, 2, 1])
x = self.seq(x)
return x
class Net(nn.Module):
def __init__(self):
super().__init__()
self.enc1 = Encoder()
self.enc2 = Encoder()
self.dec = Decoder(n=32+1) # +1 - signal
def forward(self, img1, img2, current_signal):
if len(img1.shape) == 3:
img1 = torch.unsqueeze(img1, 0)
img2 = torch.unsqueeze(img2, 0)
current_signal = torch.tensor([[current_signal]])
else:
current_signal = torch.unsqueeze(current_signal, 1)
x = self.enc1(img1) + self.enc2(img2)
x = torch.concat((x, current_signal), dim=1)
x = self.dec(x)
return x # logits
Такая модель обучается значительно дольше, чем предыдущая, однако показывает лучшие результаты тестов, про них мы написали в конце статьи
Генератор трафика
Во время проведения тестов, мы заметили, что наша модель плохо себя показывает на тестах с сильно отличающейся загруженностью дорог (например, когда одна дорога совсем пуста). Светофор начинал «сходить с ума» и хаотично переключал сигнал светофора. Сначала мы искали ошибку в формулах reward‑функции, но как бы мы ее не меняли, ничего не помогало. Тогда мы поняли, что проблема не в ней, а в том, на чем учится наша модель. Мы генерировали машины на каждой дороге равновероятно, что привело к тому, что загруженность дорог была всегда примерно одинаковой и модель, обучающаяся только на таких случаях не справлялась ни с какими другими. После того как мы доработали генератор (добавили случаи с пустыми дорогами, с генерацией машин на дорогах по синусоиде и еще несколько вырожденных случаев), наш светофор перестал вести себя непредсказуемо в нетривиальных дорожных ситуациях и начал отлично справляться со всеми, что нас вполне устроило.
Реализация скорректированного алгоритма для обучения с Carla
Сменим среду с кастомной на Carla. Принцип обучения оставим такой же, однако стоит увеличить размер изображений перекрестка, потому как машины заметны сильно хуже на городском фоне, чем фиолетовые кружки на черном полотне. Обратная сторона такого решения — сильное увеличение процесса обучения такой нейросети по времени. Если предыдущая модель смогла успешно обучиться в нашей «песочнице» за пол часа, то нынешней не хватило и суток.
Итоги
Самое время для обещанных экспериментов и сравнений методов обучения!
![](https://habrastorage.org/getpro/habr/upload_files/18f/525/b15/18f525b1573e5fae0ccb185a50fcd48b.jpg)
![](https://habrastorage.org/getpro/habr/upload_files/037/441/678/037441678a8f55fe207e19f10c7555fc.png)
![](https://habrastorage.org/getpro/habr/upload_files/6dc/662/15f/6dc66215f554daa0257ad002ce2e8396.png)
Из результатов тестов видно, что полученный нами алгоритм машинного обучения работает эффективнее примитивных алгоритмов в различных ситуациях на перекрестке, что не может не радовать!
P. S.
Для самых любопытных оставим на обозрение репозиторий нашего проекта. В нем вы наверняка найдёте что-то полезное для себя, будь то использование API симулятора Carla, или даже алгоритм обучения.
P. P. S.
Мы были бы не мы, если бы не представились (хоть и в самом конце). Знакомьтесь, наша команда!
На этом прощаемся!
Комментарии (24)
ktotomskru
19.08.2024 15:34+5один конкретный светофор не интересно. управлять надо системой светофоров, в городе, или хотя бы районе
nv13
19.08.2024 15:34+1Давным давно... В общем в каком то журнале в статье про QNX описывался проект по организации дорожного движения в канадском городке - там на всех дорогах и светофорах стояли датчики считающие авто, все эти данные через модемы стекались на сервера и они управляли светофорами во всём городе. На всех контроллерах и серверах стоял QNX. ИИ тогда не было
atues
19.08.2024 15:34+9Нейро, нейро... Достало, честно говоря. В 1976 году в серии "Математическое обеспечение ЭВМ" была издана книга Э.Хамби "Программирование таблиц решений". Там сквозной пример - как раз со светофорами. Есть, конечно, и другие, но уже не так подробно. Чисто алгоритмический подход. Плюс к тому же вопросы минимизации таблиц таблиц решений, их непротиворечивость, полнота. Вполне систематично, но не сухо, а местами так и весело. Любим мы изобретать лисапеты
VBDUnit
19.08.2024 15:34+3Как думаете, что лучше продаётся: «алгоритм управления светофором» или «нейроблокчейн платформа трафикменеджмента с ИИ»?
ИМХО, всё же смысл в нейросетях имеется, так как оно может опираться на прогнозируемый трафик, а также кучу других факторов, вроде погоды, выражения лиц водителей и прочего, причём, самостоятельно находить корреляции.
inkelyad
19.08.2024 15:34+3Я вот не уверен. Предсказуемость - достаточно хорошее свойство, т.к. люди приучаются наблюдаемое поведение учитывать и тоже участвуют в оптимизации. А если светофор ведет себя непонятно как, по понятным только ему наблюдениям и соображениям - то это может быть чревато лишней нервотрепкой и дестабилизацией ситуации. "Да, <набор междометий>, почему эта железка сейчас заставляет в два раза дольше ждать? Вчера же нормально работала?"
OlegZH
19.08.2024 15:34+1Замечательно! Пропустили табун машин. Теперь они мчатся к другим светофорам, а там стоит уже наш человек с нашим же эффективным алгоритмом..
В каком-то смысле, простое расписание работы эффективнее заумных алгоритмов, потому что смысл расписания в том, чтобы делить поток, нарезать его на мелкие фракции и делать в целом поток машин более равномерным.
KirOFF_YT
19.08.2024 15:34А теперь вспоминаем про то, что мы это сделали только со светофорами на одном перекрёстке. А в городе таких со светофорами очень много. Плюс пешеходы, некоторые из которых имеют наглость перебегать дорогу в непригодном для этого месте и иногда даже пьяными, плюс ко всему прочему добавим некоторых неадекватных водителей, которые также могут быть пьяными, плюс вспоминаем про время суток, про которое в статье ни слова, и понимаем, что по итогу мы просто сделали себе ещё больше геморных проблем. Только теперь некоторые из них будет решать нейронка.
Traveller0968
19.08.2024 15:34+7Вставлю свои пять копеек, как человек который 10 лет занимался этим, т.е. оптимизацией работы светофоров!
По моему сейчас все с ума по сходили с этим искусственным интеллектом, некоторым он даже мозги заменил :), про то что в нашем городе внедрят, внедряют или уже внедрили управление перекрестками при помощии ИИ я слышу и читаю уже года два, но на некоторых ключевых перекрестках как были пробки, так остаются и до сих пор :) А вся проблема в том, что пытаются лечить отдельные места, а не весь организм в целом!Ну например, когда то составлял такие графики координации, т.е. проще говоря все светофоры работали независима друг от друга, но с привязкой ко времени (время бралось от системы GPS или Глонасс), это называется бесцентровая координация.
И да, в этот период времени когда это не было сломано и за этим следили все ехало, потом сменился подрядчик и система потихоньку перестала работать.
Была даже идея сделать мобильное приложение, которое на телефонах водителей выдавало бы информацию об оптимальной скорости движения что бы можно было ехать без остановок или с минимальным их кол-вом и даже был найден разработчик, но все остановилось даже не начавшись, по простой причине что мы не могли дать гарантию, что базы данных о координации светофорных объектов, будут актуальны при смене подрядной организации обслуживающей СО города.Резюмируя, нужно лечить не отдельные объекты а все объекты на улице, где это необходимо, я бы лучше бы сделал бы так, что бы одни светофорные объекты умели "договариваться" с другими, скажем если на один объект прет избыточный поток, то он должен "сказать" предыдущему, что бы тот по придержал (вот тогда была бы истинная нейронка), тем самым поток нужно дробить и из "турбулентного" в одном месте делать "ламинарным" по всему протяжению улицы. Но если представить в какие цены это выльется, это же ведь каждый СО нужно оснащать датчиками транспорта, и что бы каждый объект умел это дело анализировать, ну не знаю, чет мне с трудом в это вериться и даже не по причине того денег на это не найдется, денег то может и найдется, но вот где взять специалистов, кто смог бы настроить эту систему и в последующем грамотно обслуживать? А то у нас же так, сначала одни делают и настраивают, потом меняют подрядчика приходят новые и новая метла по новому метет! В общем это проблема не только одно конкретного светофорного объекта, это ооооочень комплексная проблема... :)
homeles
19.08.2024 15:34О, г.Владимир :) :) :) Сейчас то Вы как - в процессе установки детекторов участвуете ?!
keinohrhasen_pitersky
19.08.2024 15:34Программа, из которой вы взяли данный график, уже имеет мобильную реализацию)
Traveller0968
19.08.2024 15:34Ничего не понял! Это вопрос или утверждение?
Что бы два раза не вставать, могу сказать что это я рисовал в 2013 году на древнем DELL Inspirion 2200 в Microsoft Visio 2003, чисто руками и ни какая программа мне это не считала, просто рисовал полоски и расставлял и двигал их относительно вектора скорости, не понимаю нахрена здесь нужна мобильная реализация, я чё с мобильника должен это делать на милипизерном экранчике, бред какой то... :)
ASDF59
19.08.2024 15:34Ещё бы добавить приложение, которое отображало бы рекомендуемую скорость для водителя, чтоб при приближении к светофору, проехать на зелёный. Без торможения и разгона.
Traveller0968
19.08.2024 15:34Такие мысли были еще в далеком 2014 году, но все упирается в "административный" ресурс... Приложение написать не проблема и разработчики найдутся, проблема в другом, кто будет постоянно поддерживать базу данных в актуальном состоянии на протяжении жизни всей этой системы, одни сделают, потом на тендере поменяют подрядчика, ибо он будет более "дешевым", а в связи этой дешевизны у него ресурса или просто ума не хватит поддерживать эту систему в рабочем состоянии, поэтому если даже такое приложение и напишут, то жить оно будет не долго...
mpa4b
19.08.2024 15:34+1Очень часто было и бывает так, что поставили светофор -- появились пробки. Многие годы все ездили без пробок, потом гениальный управленец решил
получить откатпобеспокоиться о безопасности движения -- опа, теперь пробки торчат на километр во все стороны от светофора. Потому лично я считаю, что без светофоров лучше.Traveller0968
19.08.2024 15:34Ну бывали и обратные ситуации, стоят два светофора причем на федералке, а между ними нерегулируемый пешеходный переход, и там постоянные затыки, т.к. не регулируемый, пока ставим на этом переходе светофор, все начинают блажить, вот жопа здесь, а будет еще хуже, но когда все настраиваем и координируем, все поехало и затыки куда то ушли!
Проблема не в светофорах, а в том что их работа не настроена и не координирована, потому что это некому делать, дяди Васи, которые это дело обслуживают оценивают работу светофора по принципу красный, желтый, зеленый переключаются, значит работает, а все остальное их уже не волнует...
Могу сказать лишь одно, что чем больше будет светофоров, при условии что они будут грамотно настроены, тем будет лучше, движение будет более растянутым и равномерным, в любом случае поток будет ехать, а не дергаться, это уже доказано на практике...
Zhabrozavr
19.08.2024 15:34Самая большая в мире страна, хотим друг другу по головам, живём друг у друга на головах С этим нужно что-то делать, а не следствия лечить, по большому счёту. Может, на круг, проще и дешевле получится. Но мы одним днём живём.
Brakomes
19.08.2024 15:34Зачем выдумывать велосипед? Есть навигаторы, которые давно показывают загруженность участка дороги. Возьмите за основу данные такой программы. Прикрутить анализатор траффика и алгоритм переключения светофоров. Как говорил участник выше, который с этой темой работал, анализировать надо не каждый светофор непосредственно, а все созависимые светофоры в районе и на основе выходных данных принимать решение. ИМХО, считывать конкретное количество транспорта бессмысленно и неэффективно с точки зрения ресурсозатрат. Вполне достаточно три состояния - зелёный, жёлтый, красный.
itshnick88
19.08.2024 15:34Сразу вспомнил университетские годы... по имитационному моделированию делали такое через AnyLogic - моделирование систем массового обслуживания. Конкретно я даже курсовой проект делал по моделированию очереди людей к банкоматам в отделении банка с разными параметрами... по-моему и перекрёстки со светофорами там тоже моделируются)
jbourne
19.08.2024 15:34@Crazy-Explorer31 Низкоуровневый технический вопрос к вам:
В видео с 3D эмулятором на 10 секунде видно, что после того как загорелся зеленый, все машины одновременно стартонули и поехали вместе. Это отличается от реальности, в которой машины стартуют одна за другой с определенными интервалами, что приводит иногда к известным проблемам: видео
Получается, что это отличие приводит в реальности к ситуациям, которых в эмуляции нет.
Рассматривали этот момент? Проверяли на сколько это искажает эмуляцию? Позволяет ли эмулятор это учесть?
Crazy-Explorer31 Автор
19.08.2024 15:34+1Очень интересное замечание, даже в голову не пришло!
В Carla (то, что на видео), такое, судя даже по видео, не предусмотрено. Ну сама логика движения машин там вшита глубоко в C++-вых скриптах, менять её, скорее всего, -- такое себе развлечение :)
В статье упоминался рукописный эмулятор, в нём логику движения прописывал я. Если заинтересованы в симуляции этого процесса (что в вашем видео), то склонируйте себе репозиторий проекта, измените в ветке main в файле emulator.py строки 295:299 на следующие:
if ( abs(new_current_car_coordinates[0] - next_car_coordinates[0]) + abs(new_current_car_coordinates[1] - next_car_coordinates[1]) > 5 * self.car_radius # maybe bigger than 5 ):
И запустите всё, согласно инструкции в ридмишке. Может, у вас получится более приближенный к реальности результат!
mpa4b
19.08.2024 15:34Очень интересное замечание, даже в голову не пришло!
Что же это получается, про симуляции и настройки светофоров рассказывают люди, ни разу сами не проезжавшие светофор в качестве водителя?
Traveller0968
19.08.2024 15:34Ну да, когда поток не раздробленный, это очень большая проблема, теряется до половины, а то и весь цикл свечения зеленого и эту проблему не решить при помощи ИИ, да, ИИ может увеличить цикл свечения зеленого в одном направлении, но в это время скопится в других направлениях и что с ними делать, поэтому здесь и нужно, дробить поток на мелкие фракции, что бы перед светофорами не копилось по многу...
inkelyad
А потом начинаем учитывать психологию водителей, которые ускоряются, надеясь проскочить, Вспоминаем, что есть еще и пешеходы со своими проблемами (включая перебегание дороги не на перекрестке), вводим в весовую функцию количество получившихся в результате аварий и трупов и понимаем, что ничего не понимаем.
Это я к тому - что регулирование движения -- оно не только про оптимальный машинопоток, что в статье упомянуто приблизительно никак.