![](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/38d/e12/f82/38de12f8263c75a27d6ae439631baf9e.png)
Мир, в котором мы с вами живём и который непосредственно ощущаем, является объёмным: расположение любой точки в нём можно описать тремя координатами, и этот факт элементарно зашит в нашу природу. Чем больше “понимания” система искусственного интеллекта будет иметь относительно истинной сущности вещей, включая их расположение, форму и объем, тем легче она будет справляться с задачами, которые до сих пор мог выполнять только человек.
В этой статье разберём, как ИИ помогает решать одну из ключевых задач робототехники, а именно - понимание и ориентация в объёмных пространствах!
SLAM
Задача, на которую сделаем основной упор в этой статье, именуется SLAM (Simultaneous Localization and Mapping - одновременная локализация и построение карты).
В чём она заключается? Предполагается, что некий аппарат помещается в среду, о которой у него нет никакой заранее известной информации. Используя только имеющиеся у него сенсоры, робот должен пройти в этой среде из начального положения в заданное, при этом построить карту местности и получить точную оценку собственной траектории.
![Пример карты, построенной роботом от Boston Dynamics при помощи лидара Пример карты, построенной роботом от Boston Dynamics при помощи лидара](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/e75/02f/862/e7502f86251028e4288a7e2ac99af1f8.png)
![А вот как строит карту дрон, созданный для детектирования пожаров на объекте, также при помощи лидара А вот как строит карту дрон, созданный для детектирования пожаров на объекте, также при помощи лидара](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/851/699/67c/85169967c26f0c8b2844acfb6d843dee.png)
Всё это выглядит весьма нетривиально, однако, первая реализация подобной системы появилась аж в 1989 и была основана на расширенном фильтре Калмана (EKF SLAM). В целом про разновидности не нейросетевых подходов к SLAM можно почитать в следующей статье. Всех их объединяет одна особенность - необходимость наличия дорогих и сложных датчиков, по типу лидаров, камер глубины (RGB-D), инерциальных модулей (IMU) и др. Нейросетевые подходы, в свою очередь, стараются обойтись лишь одним RGB-видео, доступным с любой цифровой камеры (так называемый монокулярный SLAM).
![Сравнение лидара с цифровой камерой. Их соответствующие стоимости и габариты Сравнение лидара с цифровой камерой. Их соответствующие стоимости и габариты](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/000/4da/8c7/0004da8c7930f58de9cc238205e9df28.png)
Начнём разбор!
NeuralRecon
Данная модель появилась в 2021 году и оставалась непревзойденной в своей нише несколько лет подряд. Она уже не нова и появились подходы, превосходящие её во всех отношениях. Тем не менее, это первая модель, давшая такое качество реконструкции с таким большим отрывом по производительности (по сути реконструкция происходит в реальном времени в 33 FPS на 2080Ti, обычной для 2021 года десктопной GPU). Именно поэтому я считаю важным изучить принципы работы NeuralRecon для дальнейшего понимания развития представленного направления.
Множество других примером сравнения NeuralRecon с предыдущими подходами можно посмотреть в оригинальной статье.
TSDF
Чтобы изучить работу как этого NeuralRecon, так и следующих методов, не обойтись нам без такого понятия, как TSDF (Truncated Signed Distance Function - усечённая функция расстояния со знаком). Сначала определим обычную функцию расстояния со знаком (SDF):
Пусть - множество точек, составляющих объект,
- множество точек, лежащих на поверхности объекта,
- евклидова метрика, или, проще говоря, расстояние от точки x до точки y.
Пусть также
Тогда,
![Пример SDF на плоскости Пример SDF на плоскости](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/108/f12/791/108f12791e00ee37c72dc62edaaa5a72.png)
Нетрудно догадаться, что TSDF, в отличие от SDF, будет ещё отсекать все значения, не попадающие в заданный диапазон. Например, для диапазона [-1,1] будет следующая красивая формула:
Где sng(x) - обычная функция знака:
Картинка соответствующая:
![Пример TSDF на плоскости для диапазона [-1,1] Пример TSDF на плоскости для диапазона [-1,1]](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/972/6d1/577/9726d1577f133e06a1d38f572b97d9ea.png)
В нашем объёмном случае TSDF представляет собой трехмерный массив вокселей, в котором каждому вокселю задаётся усечённое расстояние до ближайшей поверхности.
Суть метода
Что ж, мы поняли, какую задачу решаем и разобрались с терминологией, перейдём к самой NeuralRecon! По традиции приведём схему из оригинальной статьи и разберём её слева-направо сверху-вниз:
![](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/c2b/73e/144/c2b73e14478371c9a79224b27df045fb.png)
Key Frame Selection
Сразу бросается в глаза, что не каждый фрейм из видео попадет в нейросеть, а только определённо выделенный набор, обведенный слева жёлтыми рамками. Данный подход вычленения ключевых фреймов позволяется добиться скорости, необходимой для проведения реконструкции в реальном времени. Чтобы обеспечить достаточный угол обзора, сохраняя при этом согласованность изображений между собой, выбранные ключевые кадры не должны располагаться слишком близко или слишком далеко друг от друга. Новый кадр, поступающий из потока, помечается ключевым, если соответствующее относительное смещение камеры больше и её относительный угол поворота больше
.
Совокупность из N ключевых фреймов и соответствующих им положений камеры определяется, как локальный фрагмент , где
- RGB-изображение с камеры в момент времени
, а
- соответствующее положение камеры в момент времени t.
Возникает резонный вопрос: “Откуда нам известны положения камеры в пространстве , если у нас имеется исключительно RGB-камера и нет никаких IMU-датчиков?”. Дело в том, что в данном методе параллельно применяется ещё один SLAM-алгоритм, заточенный как раз на определение относительного местоположения камеры по монокулярному видео. Авторы статьи приводят в качестве примера ORB-SLAM3.
Для каждого фрагмента по входящим в него фреймам находится ограничивающий кубический объём с фиксированной максимальной глубиной или FBV (fragment bounding volume). Для лучшего понимания обвёл FBV красным:
![Реконструируемый FBV сцены Реконструируемый FBV сцены](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/e5f/da4/6f8/e5fda46f8d427a11dc72b27edfcd9010.png)
Конструирование объёмной карты признаков
Далее идёт блок с выделением признаков изображений фрагмента. В нашем случае авторы в качестве backbone-модели взяли MnasNet, легковесную архитектуру для мобилок, чтобы опять же не проседать по производительности. Важно отметить, что признаки выделяются пирамидально: на выходе из MnasNet мы имеем три уровня признаков разных масштабов, что видно на схеме.
После предыдущего этапа с выделением признаков, берём последний уровень и начинаем его последовательно расширять. Параллельно производим так называемый back-projection (или unprojection), получая при этом объёмные представления признаков .
Back-projection
Разберёмся с back-projection поподробнее. Впервые это понятие появилось в компьютерной томографии и означает алгоритм реконструкции изображения по показаниям с датчиков излучения, полученных с разных ракурсов. Допустим у нас есть некий объект в виде таблицы чисел, через который проходит луч, суммирующий значения по пути:
![Полученные суммарные значения и есть показания с датчиков Полученные суммарные значения и есть показания с датчиков](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/7bc/ea4/4c7/7bcea44c7ca37d7eaa64b3546d9f386b.gif)
А что, если по показаниям с датчиков мы теперь хотим восстановить исходный объект? В этом случае будем делать что-то такое:
![Пример back-projection Пример back-projection](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/8a1/0ea/41b/8a10ea41b274b2a15d646d2a04d68cbf.gif)
Эта картинка получена с одного ракурса, с других ракурсов будут соответствующие проекции. Имея несколько таких проекций, мы можем взять их взвешенную сумму и получить хоть и размытую, но реконструкцию исходного объекта.
Вернёмся к первоначальной задаче и взглянем на схему из статьи:
![](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/5b1/e83/b96/5b1e83b96f7a2d36d90a641afd9bea5a.png)
В случае компьютерной томографии мы имели одномерные данные и получали их двумерные проекции. В NeuralRecon мы имеем двумерные карты признаков и хотим получить их трёхмерные проекции, поэтому делаем всё то же самое, только используем воксели в качестве спроецированных элементов 3D-сцены.
Подробности реализации как back-projection, так и всей нейросети в целом можно найти в официальном репозитории.
Далее идёт Coarse-To-Fine, блок получения TSDF имеющегося FBV методом последовательных улучшений (Coarse-To-Fine).
Coarse-To-Fine (RNN)
Завершающий этап выглядит следующим образом:
![](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/477/45b/902/47745b902fd9815343c948f84b6c05ec.png)
По имеющимся объёмным полям признаков , полученным после back-projection, мы итеративно при помощи рекуррентной нейросети строим TSDF исходной FBV (
). Впоследствии она встраивается в общую реконструкцию
, что завершает цикл работы нейросети.
Осталось разобраться с устройством RNN, а именно GRU Fusion.
GRU Fusion
Схемы - наше всё, начнём опять с них:
![](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/80a/e15/196/80ae15196723f5ab6d61c69f3ac07da5.png)
Что такое GRU в данном случае понятно - это блок для учёта скрытого состояния текущего фрагмента всей сцены, которое строится и достраивается в процессе работы нейросети. Подробнее про GRU и другие RNN можно почитать здесь.
Перейдём теперь к Sparse Conv, это очередная оптимизация, которая представляет из себя конволюцию по разреженным данным (коей воксельная сетка и является). Подробности также по ссылке.
На выходе из GRU Fusion мы получаем обновлённое скрытое состояние фрагмента , которое подменяем в аналогичном участке глобального скрытого состояния
.
После GRU Fusion скрытое состояние идёт на вход обычной MLP, предсказывающей новый TSDF
на текущем уровне детализации. Затем этот TSDF апсемплится и конкатенируется с объёмной картой признаков следующего уровня, пока не дойдёт до конечной TSDF -
.
Обучение модели
Перед тем как закончить разбор, взглянем на процесс обучения NeuralRecon. В ней фигурирует 2 лосс-функции:
Ошибка для предсказанной воксельной сетки. Как известно по предыдущим статьям цикла, она считается при помощи бинарной кросс-энтропии.
Ошибка для значений функции SDF. Находится с применением L1-расстояния между истинным и предсказанным значением.
При этом использовалось 2 датасета:
ScanNet (V2) - набор сцен внутри замкнутых помещений с заданными положениями камер, семантической сегментацией и реконструкцией поверхностей. Использовался для обучения модели и её валидации.
7-Scenes - датасет, состоящий из RGB-D изображений замкнутых помещений. Использовался исключительно для валидации модели.
3D FORMER
Основной недостаток NeuralRecon, а именно, малая точность реконструкции, отчасти происходит из использования рекуррентных нейронных сетей в костяке своей архитектуры. В данный исторический период рекуррентные сети уступили место трансформерным моделям, тем самым трансформерам, которые дали небывалый толчок развитию генеративных моделей, моделей детекции да и вообще всей сферы искусственного интеллекта. В связи с этим в голову приходит очевиднейшая оптимизация - давайте использовать трансформеры. Собственно этим и занимается наша следующая модель - 3D FORMER.
Улучшение качества реконструкции на лицо!
![](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/949/b26/f59/949b26f596ebd87dfcdcb992ca651a77.png)
При этом скорость работы уменьшилась почти в 2 раза.
Перейдём к рассмотрению схемы этой замечательной модели:
![Схема 3D FORMER Схема 3D FORMER](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/540/262/1b3/5402621b30625b46e0a80aed9bd7e872.png)
Ничего схемка-то не напоминает? Да это тот же NeuralRecon, только с трансформерами, вместо рекуррентных блоков! Мы точно также выделяем 3 уровня признаков для фрагмента, проецируем их в объёмные представления и передаём всё это дело в Coarse-To-Fine модуль, чтобы сгенерировать конечный TSDF.
Стоит отметить, что механизм получения объёмного представления по всем проекциям работает немного иначе: мы берём не просто среднее по всем значениям прозрачности вокселей проекций, а взвешенное среднее, веса для которого получаем из небольшой предобученной MLP. Таким образом, больший вклад вносят те проекции, которые наилучшим образом повлияют на конечное качество реконструкции.
Coarse-To-Fine блок с трансформерами рассмотрим отдельно:
Coarse-To-Fine (Transformer)
Авторы оригинальной статьи осознавали, что использование трансформеров в 3D на полной воксельной сетке приведет к кратному увеличению количества значений для attention (внимания). Их полное количество будет считаться по следующей формуле:
где - количество вокселей по осям x, y и z соответственно.
В случае , получим
, что при
даст порядка одного петабайта данных! Решение рассмотренной проблемы заключается в том, что мы будем считать значение внимания для заданного вокселя, используя только непустые воксели, располагающиеся в пределах фиксированного окна, что и продемонстрировано на рисунке:
![](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/540/e7a/e53/540e7ae5358d00a551050e242a5dd6e8.png)
При этом мы считаем внимание и для соседей заполненных вокселей (dialated voxels, закрашенные жёлтым). Это необходимо для сохранения полноты геометрической структуры реконструируемой поверхности, которая обычно теряется после downsample-блоков с 3D конволюциями.
Теперь мы уже готовы взглянуть на полную схему одного 3D SDF Former’а и завершить разбор модели:
![](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/ad3/d43/cf0/ad3d43cf01029a72169bef26d4153517.png)
Что тут происходит? Давайте посмотрим:
Сначала принимаем на вход объёмную карту признаков , прогоняем её через Sparse 3D CNN, тем самым получая уменьшенную карту признаков (Down). Затем конкатенируем её с посчитанным Dilate Attention и всё вместе передаём в 3D Sparse Window Attention. Повторяем описанную выше процедуру 4 раза подряд.
Казалось бы, давайте теперь расширять выделенные признаки до TSDF, но не всё так просто. Появляется проблема, связанная с тем, что все наши выделенные признаки являются достаточно локальными и ограниченными заданным окном. Происходит так называемая потеря глобальных взаимосвязей внутри сцены (или малый receptive field).
3D Global Attention и Global Encoder призваны решить выявленную проблему. Учитывая, что после четырёх конволюций, разрешение последнего уровня достаточно мало, мы находим значение attention между всеми его непустыми вокселями. Это и есть Global Attention, он позволяет учесть долгосрочные глобальные зависимости, теряющиеся после применения ряда Sparse 3D CNN. Далее работает Global Encoder, который производит 3 операции average pooling с разным масштабом. В статье, на которую ссылаются авторы в этот момент, приведена такая вот картинка:
![](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/202/32c/ad0/20232cad0430a7ff3b18955ecb541422.png)
Нас интересует часть, обведённая красным прямоугольником. Да, это 2D случай и пулингов здесь 4, а не 3, но для нас важен сам принцип выделения разных уровней признаков при помощи разных пулингов, что прекрасно видно на схеме.
Затем выход Global Encoder и 3D Global Attention объединяются и расширяются до TSDF. Вот и весь метод!
Gaussian Splatting SLAM
Последняя модель, которую хотелось бы рассмотреть - это SLAM, основанный на относительно недавнем методе реконструкции сцен - Gaussian Splatting.
![Сравнение рендеринга в NeRF и Gaussian Splatting Сравнение рендеринга в NeRF и Gaussian Splatting](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/edd/e9a/aa4/edde9aaa420bc19b210cb4c2305a9e09.png)
Если вкратце, Gaussian Splatting - это, можно сказать, метод разложения объёмного пространства по базисным функциям (объёмным гауссианам разного цвета, формы и прозрачности). Такого рода непрерывное представление нашего мира оказывается достаточно эффективным как в случае построения сцены, так и в случае её рендеринга. Подробнее про реализацию Gaussian Splatting можно почитать в оригинальной статье и в разборе с Medium. Если есть много времени, можете также посмотреть трёхчасовой разбор статьи на YouTube)
Нас в свою очередь интересует, как можно применить концепты из Gaussian Splatting к решению задачи SLAM. Предшествующие методы основывались на представлении сцены в виде воксельной сетки (TSDF), мешей (треугольной сетки), облака точек или нейронных полей. Каждый из них имеет свои недостатки:
Воксельные сетки жрут ну уж очень много памяти, а различные оптимизации, вроде тех же октодеревьев, которые рассматривались в моей предыдущей статье, весьма неповоротливы и их неудобно в дальнейшем модифицировать.
Меши тоже сложно перестраивать при появлении новой информации + нужно тратить много ресурсов, чтобы добиться точной детализации пространства при помощи треугольной сетки.
Облако точек разрежено, состоит из по большей части пустого пространства. В силу этого им очень трудно аппроксимировать геометрию сцены и как-то её в дальнейшем оптимизировать.
Нейронные поля требуют ресурсоемкого восстановления сцены, используя MLP и попиксельное пускание лучей с сэмплированием, что сильно усложняет процесс рендеринга.
И тут нам в помощь приходят объёмные гауссианы, которые не имеют ни одного из перечисленных выше недостатков. Что ж, давайте разбираться, как работает эта удивительная технология:
![Схема работы Gaussian Splatting SLAM Схема работы Gaussian Splatting SLAM](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/d09/736/f9d/d09736f9d0d2d408d002a61b9b175d34.png)
Tracking
Вначале, как и полагается, у нас на вход поступают RGB-изображения, исходя из которых нам нужно оценить текущее местоположение камеры внутри сцены. Данный процесс происходит при помощи минимизации фотометрической ошибки, формула для которой выглядит так:
где - рендер гауссиан
с положения камеры
,
- исходное изображение с камеры.
Минимизация данной ошибки происходит при помощи градиентного спуска по параметрам положения камеры . Пройдя порядка 50 шагов оптимизации, мы получаем положение камеры внутри сцены, близкое к реальному.
Keyframing
Выделение ключевых кадров из всего видеопотока - это очень важная часть любого монокулярного SLAM. Этот блок непосредственно влияет на скорость и качество работы метода. Здесь keyframing реализован следующим образом: каждый кадр проверяется на совместную видимость одних и тех же гауссиан с предыдущим кадром посредством подсчёта коэффициента Жаккара (IoU). Если значение IoU становится меньше, чем заданный порог, или если смещение камеры относительно большое, мы сдвигаем окно фрагмента и рассматриваем новый кадр в качестве ключевого.
Gaussian Insertion and Pruning
Вставление гауссиан в сцену происходит на каждом ключевом кадре, чтобы либо покрыть впервые увиденные элементы, либо увеличить детализацию уже существующих.
Пусть у нас есть новый ключевой кадр. Для него мы воссоздаем карту глубины - она будет известна в конкретном пикселе, если луч, проходящий через него внутрь сцены пересекает хотя бы одну гауссиану. В противном случае глубина пикселя неизвестна. Алгоритм добавления новых гауссиан выглядит следующим образом:
Если для определенных пикселей доступна информация о глубине, то средние значения гауссиан инициализируются вокруг этих известных глубин с низкой дисперсией (то есть, с большой уверенностью в их точности).
В случае, если для некоторых пикселей нет информации о глубине (например, в областях, которые не были видны ранее), то средние значения гауссиан инициализируются вокруг медианной глубины рендеринга изображения с высокой дисперсией (то есть, с меньшей уверенностью в их точности).
Если вставленная гауссиана не видна в, как минимум, трёх предыдущих кадрах, то она удаляется, поскольку маловероятно, что её присутствие геометрически состоятельно. Большая же часть неправильно вставленных гауссиан очистится в процессе оптимизации, т.к. в силу неверного размещения, они не будут удовлетворять условию совместной видимости с разных кадров.
Mapping
Последняя часть метода, которую нам стоит рассмотреть - это маппинг. Он способствует сохранению согласованности объёмной реконструкции и занимается оптимизацией параметров вновь вставленных гауссиан.
Мы берём ключевые кадры из нашего окна - и добавляем 2 случайных кадра из прошлого –
, чтобы избежать забывания глобальной структуры сцены. Получаем множество
, по которому будем производить оптимизацию фотометрической ошибки. К этой ошибке добавляем регуляризацию, ограничивающую сильное растяжение гауссиан в пространстве, и приходим к следующей задаче:
где - та самая регуляризация на растяжение гауссиан
,
- коэффициент растяжения i-ой гауссианы,
- среднее растяжение по всем гауссианам.
Результаты
Вообще качество и скорость работы метода удивляют:
Заключение
Как показывает практика, методы машинного обучения весьма неплохо справляются с решением задачи SLAM. Это, в свою очередь, размывает грань между виртуальным миром и реальным, даёт роботам возможность наравне с человеком получать и обрабатывать визуальную информацию, поступающую с соответствующих сенсоров.
Что имеет на текущий момент?
Недавно анонсированные гуманоидные роботы от Tesla уже сейчас не используют ни лидары, ни радары, ни ультразвуковые датчики. У них есть на борту только те сенсоры, которые свойственны человеку. Следовательно, используя лишь камеры для получения визуальной информации, роботы применяют нейросетевые технологии для построения карт и решения задачи SLAM.
![Optimus Gen 2 Optimus Gen 2](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/400/a68/5e9/400a685e91867549dd20d4ca4887dbd7.png)
С беспилотными авто такая же ситуация. Вы, наверное, заметили, как по началу беспилотники имели здоровенные блямбы на крыше в виде лидаров, но постепенно производители ушли от подобных решений и начали размещать незаметные камеры по периметру автомобилей.
![](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/8ef/eb4/606/8efeb460633350929988dad1fc00f771.png)
А что скоро будет?
Давайте ещё немного поразмышляем о недалёком будущем.
В связи с развитием понимания роботами объёмных пространств, недалеко от нас и тот день, когда воплотится в жизнь концепт умных городов: множество роботов-помощников, беспилотных автомобилей и дронов помогут людям эффективно управлять инфраструктурой, увеличат чистоту и безопасность городов.
![](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/02c/b5c/6e0/02cb5c6e068e67bddb0711f28bed9ec9.png)
Далее стоит ожидать появления множества персональных роботов во всех домах, выполняющих функции чуть более изощренные, нежели обычная уборка пола. По всей видимости софт уже достаточно развился для воплощения таких идей в жизнь. Всё это станет возможным, когда у по большей части инженеров получится создать компактные, дешёвые и точные манипуляторы, сравнимые по функционалу с возможностями человеческой руки, на эту тему сейчас также существует огромное количество работ.
![](https://webcf.waybackmachine.org/web/20240319153801/https://habrastorage.org/getpro/habr/upload_files/fb2/e5e/30b/fb2e5e30bcb97ef5a053bab87cad7439.png)
Нужно продолжать следить за развитием индустрией в этом направлении, и стараться своевременно находить применение полученным разработкам в нашем мире. Только так у человечества получится прийти к тому светлому утопическому будущему, где вкалывают роботы, а не человек 😉