Русский
Русский
English
Статистика
Реклама

Блог компании it-центр маи

Оптимизация 3D-графики под WebGL (опыт PLANT-SIM)

09.10.2020 12:10:51 | Автор: admin

В этой статье речь пойдет об оптимизации Unity-сцены проекта Plantsim 1.0.: о визуальной части цифровой копии предприятия Tennessee Eastman Process, реализованного на Unity 2017.1.1f1.


image


Заметка от партнера IT-центра МАИ и организатора магистерской программы VR/AR & AI компании PHYGITALISM.


В первой версии работа осуществлялась с использованием мощного компьютера, а так же стороннего вычислительного устройства PLC. Отличие новой версии заключается в том, что теперь это WEB-приложение, реализованное с помощью WebGL, и для его работы потребуется только ноутбук.


Платформа Unity Команда Зачем
PlantSim 1.0 PC на базе: Intel i7 Nvidia GTX 1070ti 2017.3.0f3 Default Pipeline Несколько 3D художников Энтузиазм моделить и творить красоту
PlantSim 2.0 Ноутбук: Intel i5 Nvidia 1050ti Google Chrome 2019.2.15f1 LWPR Один 3D художник Ещё больше энтузиазма победить страшную задачу

Таблица сравнения разработки проектов


В сравнении с приложением PlantSim 1.0, заметно снижение требований к характеристикам компьютера. Поэтому оптимизация стала главной задачей для PlantSim 2.0.


image
Пайплайн разработки PlantSim 2.0


Анализ предстоящей работы


WebGL это работа 3D графики с использованием возможностей браузеров Google Chrome, Mozilla, Safari. Первостепенными задачами для нас являлись оптимизация, сохранение того же уровня реализма и поддержание работоспособности приложения на 30FPS+. Для этого нам предстояло работать в пайплайне мобильной разработки.


image
Unity: WebGL Build


Красивой визуализации в WebGL добиться можно, но сложно. Имеется ряд особенностей, о которых желательно знать, если вы собираетесь сделать подобный проект самостоятельно и/или работаете с 3D графикой впервые.


Перед тем, как начать непосредственно работу над 3D, мы выстроили четкий план со списком моделей, которые необходимо оптимизировать.


image
Таблица с планом оптимизации для отслеживания хода работы


Вот краткий список моделей, что присутствовали в сцене раньше:


  • OutPutTank 2 шт
  • Reactor 1 шт, модель была раздельная
  • ReactorExplosion 1 шт, отдельная анимации разлета уничтоженного реактора
  • Condenser 1 шт
  • Separator 1 шт
  • PipesSystem различная система труб на сцене
  • Stripper 1 шт
  • Valve 6 шт
  • Tank 4 шт
  • Refrigerator 1 шт
  • Compressor 3 шт
    В PlantSim 1.0 на сцене было 189 736 трисов, и главной задачей для нас была оптимизация модели на 60%. Таким образом мы получим 75 895 треугольников, что будет удовлетворять нашему полигональному бюджету.
    image
    График расчета суммарного предполагаемого количества полигонов после оптимизации

Оптимизация меша


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


image
Модель Reactor (PlantSim 1.0) анализ иерархии и сетки


  • Нелогичные наименования объектов
  • Много отдельных элементов
  • Сложная топология

Сам Reactor имел 21998 треугольников. По плану нам было необходимо избавиться от всего лишнего и малозначительного, и получить 8800 треугольников. Перед тем, как начать оптимизировать, мы проанализировали объекты вновь и заметили новую важную деталь: модели OutPutTank, Reactor и Striper имели одни и те же элементы основание и лестницу. Это означало, что эти элементы можно дублировать и использовать для них один материал.


В итоге, после работы над Reactor объектом (это первый объект, с которого началась оптимизация), мы получили новую модель в 7258 треугольников. Напомню, что по плану было 8000. При условии, что теперь UV карта одна, объект представляет собой объединенный меш и один материал стало ясно, что задачу мы сможем реализовать, а итоговая сумма треугольников окажется намного меньше, чем планировали изначально.


image
Модель Reactor (PlantSim 2.0) оптимизированная иерархия и сетка


  • Исправили наименования объектов
  • Уменьшили количество отдельных элементов
  • Упростили и оптимизировали топологию

Объект ReactorExplosion имел сложную анимацию взрыва, красивую и эффектную разлет маленьких кусков реактора с сохранением только его основания. После первой полной сборки сцены наш FPS сильно проседал непосредственно на моменте взрыва, который помимо этой анимации меша так же имел и анимацию, состоящую из 1000 частиц инструмента Particle System. Появился вопрос, что создавало трудности для отрисовки: анимация или частицы? Мы обсудили задачу с Unity разработчиком и выявили, что оба фактора слишком тяжелые для WebGL движка, поэтому было решено оптимизировать эффект взрыва, используя 5 частиц (это возможно благодаря FlipBook текстурам). Со стороны разработки так же была необходима оптимизация анимации внутри Unity.


FlipBook это покадровая анимация, вложенная в одну текстуру. Соответственно, чем больше кадров, тем больше разрешение самой текстуры и ее вес. Этот способ отрисовки анимации наиболее оптимальный, так как вместо огромного количества частиц и сложных симуляций мы обходимся одной или несколькими частицами, в которых за один цикл проигрывается наш взрыв. Таким образом, используя всего 5 частиц, был оптимизирован эффект с исходными 1000.


С анимацией было сложнее, так как каждый осколок Reactor был индивидуальным и имел свою запеченную анимацию это и тянуло WebGL вниз по FPS. Со стороны Unity разработки было предложено запечь всю анимацию в один объект, а метод отрисовки с Mesh renderer переключить на Skinned mesh renderer. Таким образом вместо одновременного перемещения тысячи transform points у нас была цепочка костей и один transform points (Origin самого объекта). Как итог, FPS вырос с 35 во время воспроизведения эффекта до 1520 во время запуска анимации, благо этот фриз сохранялся лишь 0,5 секунды. Кстати, ReactorExplosion объект имел 41220 треугольников, и в угоду экономии времени, которого было мало, было решено не создавать новую анимацию с нуля, а использовать старую, оптимизируя описанным способом.


В итоге работа по оптимизации меша закончилась успешно. Выше мы упоминали, что на сцене располагалось 189736 треугольников (если не учитывать ReactorExplosion, то 148516 треугольников). Отнимая 60% всей геометрии, мы хотим получить на выходе 59403 треугольника (после оптимизации). У нас получилось 61064 треугольника, что превысило наши планы по оптимизации, но все равно было намного ниже полигонального бюджета, выставленного в самом начале проекта. С учетом ReactorExplosion было 102284 треугольника, что так же было около границы обозначенного бюджета.


Задача выполнена, переходим к текстурированию.


image
График расчета суммарного фактического количества полигонов после оптимизации


Текстурирование


Текстурирование играет важную роль в визуализации моделей. Если вы никогда не слышали о том, из чего состоит модель в ее привычном виде, то давайте вспомним:


  • Base Color/Albedo RGBA изображение, определяющее, какой цвет у поверхностей. Иногда идет с Alpha каналом прозрачности поверхностей.
  • Ambient Occlusion Ч/Б изображение с информацией затенений объекта.
  • Metallness Ч/Б изображение, определяющее металлическую природу поверхности.
  • Smoothness Ч/Б изображение, определяющее степень размытости поверхности или ее мелких отдельных деталей.
  • Normal Map RGB изображение, симулирующее светотень от мелких неровностей поверхности.
  • Height Map Ч/Б изображение, отвечающее за степень искажения неровностей поверхности. Часто используется в связке с Normal Map.
  • Emission RGB изображение, отвечающее за самосвечение отдельных участков или всей поверхности объекта. Может влиять на Global Illumination параметры, то есть участвовать в освещении других объектов в сцене.
    image
    Набор текстур для модели Striper из проекта PlantSim 2.0

Благодаря текстурным картам имитируются поверхности на моделях. После анализа списка можно заметить сходства помимо RGB текстур мы имеем много черно-белых карт. Что же это значит для оптимизации?


Дело в том, что отдельно R G и B, а также A каналы и представляют собой черно-белый слой. А значит отдельно в одну текстуру RGBа можно зашифровать сразу четыре текстуры. Как это работает:


image
Комбинирование четырех ч/б текстурных карт в одну текстуру


Далее эту Combine texture расшифровывают и отдают в отдельные каналы материала в Unity.
Также хотелось бы упомянуть Normal Map. Эта текстура мощный инструмент для оптимизации модели, с помощью нее возможно избавиться от мелкой детализации модели и впоследствии отобразить при рендеринге на сцене.


image
Сравнение двух моделей Compressor


На этом примере наглядно видна разница поверхностей старой модели и новой, оптимизированной. Данную текстуру создают двумя способами:


  1. Отрисовка вручную в специальных программах, например Substance Painter, используя подготовленные кисти неровностей.
  2. Запекание неровностей с HighPoly модели (с повышенной детализацией, фасками, неровностями и углублениями) на LowPoly модель, которая максимально оптимизирована. Данную процедуру используют как в Substance Painter, так и в Blender инструментах.

Материалы и шейдеры


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


image
Набор материалов на различных объектах. Один цвет один материал


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


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


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


Запекание света


Давайте поговорим о том, как работает свет в Unity, а именно о типе освещения Global Illumination. Это честный способ отображения отражения света от поверхности объекта и создания теней. В Unity тени строятся по двум типам объектов Dynamic и Static объекты.


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


В случае статичных объектов подразумевается, что они находятся в покое, а тени всегда сохраняют свое положение. Как раз для таких объектов можно запечь тень объекта на пространство в специальный Lightmap текстуры. Учитывая задачу оптимизации и отказ от Realtime просчета теней, это наиболее оптимальный подход.
image
Представление сцены без Lightmap текстурной карты и после ее создания
В PlantSim 2.0 мы запекали тени от всех объектов, если они не участвовали в анимациях.


Хитрости в работе с WebGL


К финалу разработки мы стали сражаться за количество FPS уже в собранных билдах, отслеживая напрямую в Google Chrome. Сохранялась проблема почему FPS на ноутбуке c i7 процессором и GTX 1070ti не повышается больше 30, а наоборот, иногда даже проседает. Ведь не может быть так, что всей проделанной работы было недостаточно.


Перед тем, как запускать проект на референсном ноутбуке заказчика, мы проводили тесты на различных устройствах (ноутбуки, персональные компьютеры), и анализировали FPS, которое показывало приложение.


image
Таблица стресс-тестов на различных устройствах. Скриншоты фиксируют одинаковую ситуацию и количество FPS в данный момент.


В тестировании участвовали как мощные ноутбуки на базе Windows и Apple MacBook PRO, так и слабые ноутбуки, на которых не предполагалась работа с 3D графикой. Для чистоты тестирования мы так же использовали стационарный компьютер с RTX 2080ti (кстати, на нем FPS был стабильно 60). FPS оказался разным у всех устройств.


Разгадка оказалась куда проще, чем предполагалось изначально. Дело в том, что работу браузера Google Chrome определяет некоторые факторы:


  1. Подключен ли ноутбук к зарядке? Если нет, то вероятно, что мощность видеокарты значительно снижена из за экономии аккумулятора.
  2. Есть ли на ноутбуке интегрированная видеокарта (видеокарта, которая встроена в центральный процессор или материнскую плату)?

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


image
Окно Nvidia Control Panel настройки производительности для отдельного приложения


В итоге, после очередного тестирования билда на Google Chrome, счетчик FPS победно показывал 7090 это означало, что во всех предыдущих тестированиях в отрисовке 3D графики браузера участвовала куда более слабая видеокарта (интегрированная), из-за стараний ноутбука сэкономить заряд батареи.


Вывод


Разработка проекта такого рода специфична, но во многом интересна, так как WebGL это новое направление работы с 3D графикой и представление ее в WEB.


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


Полезные ссылки:


WebGL Wikipedia
Unity Wikipedia
Unity Официальный сайт
Unity WebGL Builds
Unity WebGl Development
UV развертки Wikipedia
Texturing mapping Wikipedia
PBR материалы Habr
3D modeling Wikipedia
PlantSim 1.0
PlantSim 2.0

Подробнее..

Развитие BI-систем тренды и движение в сторону ABI. Взгляд со стороны визуализации

04.05.2021 16:09:09 | Автор: admin

Почему привычные нам BI-системы меняются? Куда движется их развитие, какие технологии сейчас внедряются, как можно улучшить аналитику для бизнеса? В этой статье мы коснемся этих вопросов и постараемся ответить, чего следует ожидать в ближайшем будущем от систем бизнес-аналитики.

Заметка от партнера IT-центра МАИ и организатора магистерской программы VR/AR & AI компанииPHYGITALISM.

Кратко о BI-системах и их преимуществах

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

Рис.1. Преобразование данных в аналитику в BI-системахРис.1. Преобразование данных в аналитику в BI-системах

BI-системы собирают всю информацию в одном месте для удобной аналитики и помогают выявлять закономерности и тренды. Загружая в BI-систему данные о рынке мы получаем более полное представление о ситуации, а, значит, и лучшую аналитику.

Рис 2. Для каких задач внедряют BI-системыРис 2. Для каких задач внедряют BI-системы

Внедрение такого ПО, кстати, совсем не требует усилий, так как оно дополняет существующие инструменты. Аналитика становится простой и быстрой, так как для получения анализа BI-система сама собирает все данные о нужных показателях из множества источников и предоставляет информацию для анализа. Сокращение времени и сил за счет одного приложения, которое еще при этом повышает эффективность работы подтверждение актуальности этого инструмента.

Рис 3. Преимущества BI-системРис 3. Преимущества BI-систем

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

Рис.4. Объем рынка BI-системРис.4. Объем рынка BI-систем

Расширяются границы их применения для стратегического и тактического планирования.

Рис 5. BI-системы как часть бизнесаРис 5. BI-системы как часть бизнеса

Внедрение BI-систем становится все более нужным и прибыльным для компаний.

Рис 6. Эффекты от внедрения BI-систем для компанийРис 6. Эффекты от внедрения BI-систем для компаний

Рынок BI-систем развивается в сторону кроссплатформенности и внедрения новых подходов к аналитике. Именно поэтому важно понимать, какие тренды сейчас есть.

Тренды в развитии BI-систем: эволюция до ABI

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

Современная бизнес-аналитика устроена по-другому: она интерактивна и доступна. Доступ к данным можно предоставить любому, пользователь может сам найти ответы на вопросы, кликая на интерактивные визуализации: графики, карты, таблицы или диаграммы.

Рис.7. Интерактивность современных BI-системРис.7. Интерактивность современных BI-систем

За все время настолько изменилось представление о BI-системах, что большинство специалистов называют используемые self-service BI-системы (такие как Tableau, Power BI или Qlik Sense) просто BI-системой, хотя различия тут есть в традиционных системах в аналитику были вовлечены IT-специалисты, а в self-service пользователи сами выполняют всю работу, без обращения к IT.

Рис.8. Разница между традиционной и self-service BI-системамиРис.8. Разница между традиционной и self-service BI-системами

Появление ABI-систем

Эволюция BI-систем не стоит на месте, появляются новые подходы к аналитике, а данных становится все больше именно поэтому возникла новая концепция Augmented Business Intelligence, которую выделили Gartner.

Рис.9. Эволюция аналитики в BI-системы и в Augmented Business IntelligenceРис.9. Эволюция аналитики в BI-системы и в Augmented Business Intelligence

Augmented Business Intelligence это модель партнерства людей и искусственного интеллекта, которая ориентирована на совместное взаимодействие машины и человека для улучшения аналитики, принятия решений, подготовки данных и получения инсайтов.

Рис.10. Инновационность ABI-системРис.10. Инновационность ABI-систем

ABI это новая ступень развития BI-платформ, так как в ней есть сразу несколько преимуществ. В ней объединяется не только привычная аналитика и таблицы, но и также новые технологии: от дополненной и виртуальной реальности до решений с компьютерной графикой и 3D.

Рис.11. Отличия BI-системы от ABI-системы и ее преимуществаРис.11. Отличия BI-системы от ABI-системы и ее преимущества

Становится очевидным, что BI-системы эволюционируют, они меняются вместе с обществом, наукой и человеком, и есть ряд трендов, которые свидетельствуют о движении в сторону простой, понятной, удобной и быстрой аналитики.

Рис.12. Тренды в развитии BI-системРис.12. Тренды в развитии BI-систем

Тремя основными тенденциями бизнес-аналитики на 2020 год являются управление качеством данных (MD/DQ), DataViz и внедрение self-service BI-систем, и особое место занимает внедрение data-driven подхода в культуру компаний. Мы стараемся внедрять все эти подходы в наше решение с BI-системой для Ingrad, и хотели бы побольше рассказать о самых интересных, на наш взгляд.

Развитие предиктивной аналитики

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

В этом контексте также говорят о концепции DIKW: Data-Information-Knowledge-Wisdom.

Рис.13. Концепция DIKWРис.13. Концепция DIKW

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

BI-системы в этом случае выступают инструментом достижения верхушки пирамиды благодаря визуализации мы можем быстро проанализировать любые данные и информацию для получения знаний. Чтобы получить мудрость мы должны видеть всю ситуацию в пространстве, и здесь может помочь визуализация данных (Data Visualization) и 3D-технологии.

Визуализация данных (Data Visualization, DataViz)

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

Рис. 14. Визуальное потребление информацииРис. 14. Визуальное потребление информации

Именно поэтому и существует визуализация данных (Data Visualization) ряд инструментов наподобие графиков, таблиц, диаграмм и схем, которые представляют информацию наглядно.

Рис.15. Инструментарий DataVizРис.15. Инструментарий DataViz

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

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

Рис.16. Преимущества 3D-визуализацииРис.16. Преимущества 3D-визуализации

Мы считаем, что 3D визуализация данных это не просто тренд, а необходимость для некоторых сфер (AEC, например). Для девелопера на рынке российской недвижимости мы разработали BI-систему аналитики с 3D визуализацией данных, которая намного более эффективна благодаря интерактивности и наглядной демонстрации данных на карте.

Рис.17. Пример 3D визуализации данных на карте для визуализации данных в проекте с IngradРис.17. Пример 3D визуализации данных на карте для визуализации данных в проекте с Ingrad

3D в BI-системах может использоваться и для визуализации объектов например, BIM-модели зданий помогают быстро получать нужную аналитику и информацию о строительном объекте.

Рис.18. Пример интерактивных BIM-моделей зданийРис.18. Пример интерактивных BIM-моделей зданий

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

Data Storytelling

Одним из главных трендов, который был выделен исследованием Dresner это data storytelling. Чтобы человек лучше запомнил и воспринял суть информации и сообщения, он должен пережить опыт. Наблюдая за развитием ситуации в реальном времени, мы невольно попадаем в раскрытие какой-либо истории.

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

Рис. 19. Фокусирование внимания пользователя на данных с помощью анимацииРис. 19. Фокусирование внимания пользователя на данных с помощью анимации

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

Рис.20. Феномен data storytellingРис.20. Феномен data storytelling

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

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

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

Рис.21. Уникальные черты и roadmap разработанной кроссплатформенной BI-системы для IngradРис.21. Уникальные черты и roadmap разработанной кроссплатформенной BI-системы для Ingrad

За какими технологиями нужно следить, чтобы быть в курсе развития BI-систем?

  • Искусственный интеллект и машинное обучение для создания системы предиктивной аналитики, расшифровки данных и выявления тенденций

  • 3D-технологии для внедрения новых инструментов Data Visualization, показа большего числа данных, в том числе с привязкой к географии

  • XR для совместной работы и визуализации аналитики в интерактивном иммерсивном формате.

Заключение

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

Проследив эволюцию BI-систем, тренды и прогнозы развития, которые делают крупные исследовательские компании, выделим целый ряд трендов:

  • MD/MQ Data management

  • Внедрение data-driven культуры в работу

  • Внедрение self-service BI систем

  • Data Visualization

  • Data Storytelling

  • Развитие ABI систем

  • Аналитика в real time

  • Data warehouse modernization

  • Data governance

  • Предиктивная аналитика

  • Внедрение моделей машинного обучения

  • Cloud BI

  • Самостоятельная работа с данными

  • BI-системы для мобильных устройств

  • Добавление и совершенствование уведомлений в BI-системах

Можно сделать вывод, что общая тенденция в развитии BI-систем это уход в сторону упрощения аналитики и предоставления быстрого и полного взгляда на проблему для любого заинтересованного человека (включая тех, кто может не разбираться в аналитике).

Бизнес-аналитика становится проще и доступнее, и развитие технологий только способствует этому.

Источники
Подробнее..

3D ML. Часть 4 дифференциальный рендеринг

23.09.2020 16:18:12 | Автор: admin


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


Мы поговорим о том, почему традиционный пайплайн рендеринга не дифференцируем, зачем исследователям в области 3D ML потребовалось сделать его дифференцируемым и как это связано с нейронным рендерингом. Какие существуют подходы к конструированию таких систем, и рассмотрим конкретный пример SoftRasterizer и его реализацию в PyTorch 3D. В конце, с помощью этой технологии, восстановим все пространственные характеристики Моны Лизы Леонардо Да Винчи так, если бы картина была не написана рукой мастера, а отрендерена с помощью компьютерной графики.


Серия 3D ML на Хабре:


  1. Формы представления 3D данных
  2. Функции потерь в 3D ML
  3. Датасеты и фреймворки в 3D ML
  4. Дифференциальный рендеринг

Репозиторий на GitHub для данной серии заметок.


Заметка от партнера IT-центра МАИ и организатора магистерской программы VR/AR & AI компании PHYGITALISM.


Rendering pipeline: forward and inverse



Если мы рассматриваем все возможные задачи, в которых требуется как-то взаимодействовать с 3D моделями, то глобально появляется возможность разделить их на два класса задач:


  • Задачи, в которых из 3D сцены мы хотим сгенерировать изображение (такие задачи можно отнести к традиционным задачам компьютерной графике) т.н. forward rendering;
  • Задачи, где по изображению нам требуется восстанавливать параметры 3D объектов (такие задачи относятся скорее к компьютерному зрению) т.н. inverse rendering.

До недавнего времени два этих класса задач обычно рассматривались отдельно друг от друга, но сегодня все чаще приходится иметь дело с алгоритмами, которые должны работать в обе стороны (особенно это касается области машинного обучения).



Рис.1 Из презентации TensorFlow Graphics (github page).


В качестве примера такой задачи, можно рассмотреть задачу 3D mesh reconstruction from single image, которую мы уже упоминали в предыдущих заметках. С одной стороны, эту задачу можно решать сравнивая ошибку рассогласования между исходной моделью и предсказанной с помощью функций потерь для 3D объектов (заметка 2 данной серии). С другой стороны, можно генерировать 3D объект сначала, а после его отрендеренную картинку сравнивать с изображением-образцом (пример на рис.2).



Рис.2 Модель деформации меша с помощью модуля дифференциального рендеринга SoftRas (github page).


Далее, при разговоре про рендеринг, мы будем рассматривать несколько основных компонентов 3D сцены:


  • 3D объект, описываемый своим мешем;
  • камера с набором характеристик (позиция, направление, раствор и т.д.);
  • источники света и их характеристики;
  • глобальные характеристики расположения объекта на сцене, описываемые матрицами преобразований.

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


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


Why is rendering not differentiable?



Рис.3 Схема традиционного рендеринга и рендеринга методом Soft Rasterizer [1]. Здесь: $M$ меш объекта на сцене, $P$ модель камеры, $L$ модель источника освещения, $A$ модель текстуры, $N$ карта нормалей для меша, $Z$ карта глубины получаемого изображения, $U$ матрица преобразования 3D в 2D для получения плоского изображения, $F$ растеризованное изображение, $D$ вероятностные карты метода Soft Rasterizer, $I,\bar I$ изображения полученные традиционным рендерингом и методом SoftRas соответственно. Красные блоки недифференцируемые операции, синии дифференцируемые.


Процедуру рендеринга можно подразделить на несколько взаимозависимых этапов (этапы традиционного рендеринга приведены на рис.3 врехняя линия в правой части). Какие-то этапы, к примеру вычисления освещения и позиции камеры, являются дифференцируемыми, поскольку в них участвуют непрерывные функциональные зависимости (см. модель Фонга, на Хабре о ней и моделях освещения писали здесь и здесь), но два последних этапа не являются дифференцируемыми. Давайте разберемся почему.



Последние два этапа, которые являются по сути и ключевыми это растеризация и шейдинг. (Про реализацию этих этапов на JavaScript на Хабре писали здесь).


Грубо говоря, проблему недифференцируемости растеризации можно описать так: пиксели дискретные структуры, с постоянным цветом, а исходная модель непрерывна, поэтому при проецировании из 3D в 2D часть информации теряется.


Проиллюстрируем две основные проблемы с дифференцируемостью при вычислении цвета и расстояния.


Проблема 1 (недифференцируемость цвета по глубине)



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


Проблема 2 (недифференцируемость цвета при сдвигах)



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


Make it differentiable! Soft Rasterizer


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


Основные подходы к реализации дифференцируемого рендеринга можно проследить в следующей подборке публикаций:



Подходы основаны на разных идеях и приемах. Мы подробно остановимся только на одном, Soft Rasterizer, по двум причинам: во-первых, идея данного подхода математически прозрачна и легко реализуема самостоятельно, во-вторых, данный подход реализован и оптимизирован внутри библиотеки PyTorch 3D [6].


Подробно со всеми аспектами реализации дифференциального рендеринга этим методом можно ознакомиться в соответствующей статье [1], мы же отметим основные моменты.


Для решение проблемы 2, авторы метода предлагают использовать размытие границы полигонов, которое приводит к непрерывной зависимости цвета пикселя от координат смещения полигона.

Размытие границ предполагает введение некоторой гладкой вероятностной функции $D_j^i$, которая каждой внутренней или внешней точки пространства $p_i$ ставит в соответствие число от 0 до 1 вероятности принадлежности к данному полигону $f_j$ (чем-то похоже на подход нечеткой логики). Здесь $\sigma$ параметр размытия (чем больше $\sigma$, тем больше размытие), $d(i,j)$ кратчайшее расстояние в проекционной плоскости от проекции точки $p_i$ до границы проекции полигона $f_j$ (данное расстояние обычно выбирают Евклидовым, но авторы метода отмечают, что здесь есть простор для экспериментов и, например, использование барицентрического расстояния или $l_1$ также подходит для их метода), $\delta_j^i$ функция, которая равна 1 если точка находится внутри полигона и -1 если вне (на границе полигона можно доопределить значение $\delta$ нулем, однако это все равно приводит к тому, что на границе полигона данная функция разрывна, поэтому для точек границ она не применяется), $sigmoid$ сигмоидная функция активации, которая часто применяется в глубоком обучении.


Для решения проблемы 1, авторы метода предлагают использовать смешение цветов k ближайших полигонов (blending).

Коротко этот прием можно описать следующим образом: для вычисления итогового цвета $i$-го пикселя $(I^i)$, производят нормированное суммирование цветовых карт $C^i_j$ для k ближайших полигонов $(j =1,..,k)$, причем цветовые карты получают путем интерполяции барицентрических координат цвета вершин данных полигонов. Индекс $b$ в формуле отвечает за фоновый цвет (background colour), а оператор $\mathcal{A}_{S}$ оператор агрегирование цвета. $z^i_j$ глубина $i$-го пикселя относительно $j$-го полигона, а $\gamma$ параметр смешивания (чем он меньше, тем сильнее превалирует цвет ближайшего полигона).


Итоговой подход Soft Rasterizer, заключается в комбинировании этих двух идей, для одновременного плавного размытия границы и цвета.

Рис.4 Схема реализации дифференциального рендеринга в PyTorch 3D (слайд из презентации фреймворка).


Реализация Soft Rasterizer внутри библиотеки PyTorch 3D выполнена так, чтобы максимально эффективно и удобно использовать возможности как базового фреймворка PyTorch, так и возможности технологии CUDA. По сравнению с оригинальной реализацией [github page], разработчикам фреймворка удалось добиться 4-х кратного приращения скорости обработки (особенно для больших моделей), при этом возрастает расход памяти за счет того, что для каждого типа данных (ката глубины, карта нормалей, рендер текстур, карта евклидовых расстояний) нужно просчитать k слоев и хранить их в памяти.



Рис.5 Сравнение характеристик дифференциального рендеринга в PyTorch 3D (слайд из презентации фреймворка).


Поэкспериментировать с настройками дифференциального рендера можно как в PyTorch 3D, так в библиотеке с оригинальной реализацией алгоритма Soft Rasterizer. Давайте рассмотрим пример, демонстрирующий зависимость итоговой картинки отрендеренной модели от параметров дифференциального рендера \sigma, \gamma.


Удобнее всего работать с этой библиотекой в виртуальном окружении anaconda, так как данная библиотека работает уже не с самой актуальной версией pytorch 1.1.0. Также обратите внимание что вам потребуется видеокарта с поддержкой CUDA.


Импорт библиотек и задание путей до обрабатываемых моделей
import matplotlib.pyplot as pltimport osimport tqdmimport numpy as npimport imageioimport soft_renderer as srinput_file = 'path/to/input/file'output_dir = 'path/to/output/dir'

Зададим начальные параметры камеры для рендеринга, загрузим меш объекта с текстурами (есть мод для работы без текстур, в этом случае нужно указать texture_type=vertex), инициализируем дифференциальный рендер и создадим директорию для сохранения результатов.


# camera settingscamera_distance = 2.732elevation = 30azimuth = 0# load from Wavefront .obj filemesh = sr.Mesh.from_obj(                         input_file,                          load_texture=True,                          texture_res=5,                          texture_type='surface')# create renderer with SoftRasrenderer = sr.SoftRenderer(camera_mode='look_at')os.makedirs(args.output_dir, exist_ok=True)

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


# draw object from different viewloop = tqdm.tqdm(list(range(0, 360, 4)))writer = imageio.get_writer(                            os.path.join(output_dir, 'rotation.gif'),                              mode='I')for num, azimuth in enumerate(loop):    # rest mesh to initial state    mesh.reset_()    loop.set_description('Drawing rotation')    renderer.transform.set_eyes_from_angles(                                            camera_distance,                                             elevation,                                             azimuth)    images = renderer.render_mesh(mesh)    image = images.detach().cpu().numpy()[0].transpose((1, 2, 0))    writer.append_data((255*image).astype(np.uint8))writer.close()

Теперь поиграемся со степенью размытия границы и степенью смешения цветов. Для этого будем в цикле увеличивать параметр размытия $\sigma$ и одновременно увеличивать параметр смешения цвета $\gamma$.


# draw object from different sigma and gammaloop = tqdm.tqdm(list(np.arange(-4, -2, 0.2)))renderer.transform.set_eyes_from_angles(camera_distance, elevation, 45)writer = imageio.get_writer(                            os.path.join(output_dir, 'bluring.gif'),                             mode='I')for num, gamma_pow in enumerate(loop):    # rest mesh to initial state    mesh.reset_()    renderer.set_gamma(10**gamma_pow)    renderer.set_sigma(10**(gamma_pow - 1))    loop.set_description('Drawing blurring')    images = renderer.render_mesh(mesh)    image = images.detach().cpu().numpy()[0].transpose((1, 2, 0))    writer.append_data((255*image).astype(np.uint8))writer.close()# save to textured objmesh.reset_()mesh.save_obj(              os.path.join(args.output_dir, 'saved_spot.obj'),               save_texture=True)

Итоговый результат на примере стандартной модели текстурированной коровы (cow.obj, cow.mtl, cow.png удобно скачивать, например, с помощью wget) выглядит так:



Neural rendering



Дифференциальный рендеринг как базовый инструмент для 3D ML, позволяет создавать очень много интересных архитектур глубокого обучения в области, которая получила названия нейронный рендеринг (neural rendering). Нейронный рендеринг позволяет решать множество задач, связанных с процедурой рендеринга: от добавления новых объектов на фото и в видеопоток до сверхбыстрого текстурирования и рендеринга сложных физических процессов.


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


  • большая обзорная статья SOTA архитектур в области нейронного рендеринга [7] на основе прошедшей CVPR 2020;
  • видео с записью утренней и дневной сессией по нейтронному рендерингу с CVPR 2020, на основе которых и была написана статья из предыдущего пункта;
  • видеолекция MIT DL Neural rendering с кратким обзором основных подходов и введении в тему;
  • заметка на Medium на тему дифференциального рендеринга и его приложений;
  • видео с youtube канала two minute papers на данную тему.

Experiment: Mona Liza reconstruction


Разберем пример применения дифференциального рендеринга для восстановления параметров 3D сцены по исходному изображению человеческого лица, представленный в пуле примеров библиотеки redner, которая является реализацией идей, изложенных в статье [ 4 ].


В данном примере, мы будем использовать т.н. 3D morphable model [8] технику текстурированного трехмерного моделирования человеческого лица, ставшую уже классической в области анализа 3D. Техника основана на получение такого крытого представления признаков 3D данных, которое позволяет строить линейные комбинации, сочетающие физиологические особенности человеческих лиц (если так можно выразиться, то это своеобразный Word2Vec от мира 3D моделирования человеческих лиц).


Для работы с примером вам потребуется датасет Basel face model (2017 version). Файл model2017-1_bfm_nomouth.h5 необходимо будет разместить в рабочей директории вместе с кодом.


Для начала загрузим необходимы для работы библиотеки и датасет лиц.


Загрузка библиотек
import torchimport pyrednerimport h5pyimport urllibimport timefrom matplotlib.pyplot import imshow%matplotlib inlineimport matplotlib.pyplot as pltfrom IPython.display import display, clear_outputfrom matplotlib import animationfrom IPython.display import HTML

# Load the Basel face modelwith h5py.File(r'model2017-1_bfm_nomouth.h5', 'r') as hf:    shape_mean = torch.tensor(hf['shape/model/mean'],                               device = pyredner.get_device())    shape_basis = torch.tensor(hf['shape/model/pcaBasis'],                                device = pyredner.get_device())    triangle_list = torch.tensor(hf['shape/representer/cells'],                                  device = pyredner.get_device())    color_mean = torch.tensor(hf['color/model/mean'],                               device = pyredner.get_device())    color_basis = torch.tensor(hf['color/model/pcaBasis'],                                device = pyredner.get_device())

Модель лица в таком подходе разделена отдельно на базисный вектор формы shape_basis (вектор длины 199 полученный методом PCA), базисный вектор цвета color_basis (вектор длины 199 полученный методом PCA), также имеем усредненный вектор формы и цвета shape_mean, color_mean. В triangle_list хранится геометрия усредненного лица в форме полигональной модели.


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


indices = triangle_list.permute(1, 0).contiguous()def model(        cam_pos,         cam_look_at,         shape_coeffs,         color_coeffs,         ambient_color,         dir_light_intensity):    vertices = (shape_mean + shape_basis @ shape_coeffs).view(-1, 3)    normals = pyredner.compute_vertex_normal(vertices, indices)    colors = (color_mean + color_basis @ color_coeffs).view(-1, 3)    m = pyredner.Material(use_vertex_color = True)    obj = pyredner.Object(vertices = vertices,                           indices = indices,                           normals = normals,                           material = m,                           colors = colors)    cam = pyredner.Camera(position = cam_pos,                          # Center of the vertices                                                    look_at = cam_look_at,                          up = torch.tensor([0.0, 1.0, 0.0]),                          fov = torch.tensor([45.0]),                          resolution = (256, 256))    scene = pyredner.Scene(camera = cam, objects = [obj])    ambient_light = pyredner.AmbientLight(ambient_color)    dir_light = pyredner.DirectionalLight(torch.tensor([0.0, 0.0, -1.0]),                                           dir_light_intensity)    img = pyredner.render_deferred(scene = scene,                                    lights = [ambient_light, dir_light])    return img

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


cam_pos = torch.tensor([-0.2697, -5.7891, 373.9277])cam_look_at = torch.tensor([-0.2697, -5.7891, 54.7918])img = model(cam_pos,             cam_look_at,             torch.zeros(199, device = pyredner.get_device()),            torch.zeros(199, device = pyredner.get_device()),            torch.ones(3),             torch.zeros(3))imshow(torch.pow(img, 1.0/2.2).cpu())face_url = 'https://raw.githubusercontent.com/BachiLi/redner/master/tutorials/mona-lisa-cropped-256.png'urllib.request.urlretrieve(face_url, 'target.png')target = pyredner.imread('target.png').to(pyredner.get_device())imshow(torch.pow(target, 1.0/2.2).cpu())


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


# Set requires_grad=True since we want to optimize them latercam_pos = torch.tensor([-0.2697, -5.7891, 373.9277],                        requires_grad=True)cam_look_at = torch.tensor([-0.2697, -5.7891, 54.7918],                            requires_grad=True)shape_coeffs = torch.zeros(199, device = pyredner.get_device(),                            requires_grad=True)color_coeffs = torch.zeros(199, device = pyredner.get_device(),                            requires_grad=True)ambient_color = torch.ones(3, device = pyredner.get_device(),                            requires_grad=True)dir_light_intensity = torch.zeros(3, device = pyredner.get_device(),                                   requires_grad=True)# Use two different optimizers for different learning ratesoptimizer = torch.optim.Adam(                             [                              shape_coeffs,                               color_coeffs,                               ambient_color,                               dir_light_intensity],                              lr=0.1)cam_optimizer = torch.optim.Adam([cam_pos, cam_look_at], lr=0.5)

Остается организовать, оптимизационный цикл и логировать происходящее с функцией ошибки (в нашем случае это попиксельный MSE + квадратичные регуляризаторы параметров) и с самой 3D моделью.


plt.figure()imgs, losses = [], []# Run 500 Adam iterationsnum_iters = 500for t in range(num_iters):    optimizer.zero_grad()    cam_optimizer.zero_grad()    img = model(cam_pos, cam_look_at, shape_coeffs,                 color_coeffs, ambient_color, dir_light_intensity)    # Compute the loss function. Here it is L2 plus a regularization     # term to avoid coefficients to be too far from zero.    # Both img and target are in linear color space,     # so no gamma correction is needed.    loss = (img - target).pow(2).mean()    loss = loss          + 0.0001 * shape_coeffs.pow(2).mean()          + 0.001 * color_coeffs.pow(2).mean()    loss.backward()    optimizer.step()    cam_optimizer.step()    ambient_color.data.clamp_(0.0)    dir_light_intensity.data.clamp_(0.0)    # Plot the loss    f, (ax_loss, ax_diff_img, ax_img) = plt.subplots(1, 3)    losses.append(loss.data.item())    # Only store images every 10th iterations    if t % 10 == 0:        # Record the Gamma corrected image        imgs.append(torch.pow(img.data, 1.0/2.2).cpu())     clear_output(wait=True)    ax_loss.plot(range(len(losses)), losses, label='loss')    ax_loss.legend()    ax_diff_img.imshow((img -target).pow(2).sum(dim=2).data.cpu())    ax_img.imshow(torch.pow(img.data.cpu(), 1.0/2.2))    plt.show()


Чтобы лучше понимать что происходило со сценой в процессе обучения можем сгенерировать анимацию из наших логов:


fig = plt.figure()# Clamp to avoid complainsim = plt.imshow(imgs[0].clamp(0.0, 1.0), animated=True)def update_fig(i):    im.set_array(imgs[i].clamp(0.0, 1.0))    return im,anim = animation.FuncAnimation(fig, update_fig,                                frames=len(imgs), interval=50, blit=True)HTML(anim.to_jshtml())


Conclusions


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


Существуют несколько популярных библиотек глубокого вычисления (например Kaolin, PyTorch 3D, TensorFlow Graphics), которые содержат дифференциальный рендеринг как составную часть. Также существуют отдельные библиотеки, реализующие функционал дифференциального рендеринга (Soft Rasterizer, redner). С их помощью можно реализовывать множество интересных проектов, вроде проекта с восстановлением параметров лица и текстуры портрета человека.


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


References
  1. Liu, S., Li, T., Chen, W. and Li, H., 2019. Soft rasterizer: A differentiable renderer for image-based 3d reasoning. In Proceedings of the IEEE International Conference on Computer Vision (pp. 7708-7717). [ paper ]
  2. Loper, M.M. and Black, M.J., 2014, September. OpenDR: An approximate differentiable renderer. In European Conference on Computer Vision (pp. 154-169). Springer, Cham. [ paper ]
  3. Kato, H., Ushiku, Y. and Harada, T., 2018. Neural 3d mesh renderer. In Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (pp. 3907-3916). [ paper ]
  4. Li, T.M., Aittala, M., Durand, F. and Lehtinen, J., 2018. Differentiable monte carlo ray tracing through edge sampling. ACM Transactions on Graphics (TOG), 37(6), pp.1-11. [ paper ]
  5. Chen, W., Ling, H., Gao, J., Smith, E., Lehtinen, J., Jacobson, A. and Fidler, S., 2019. Learning to predict 3d objects with an interpolation-based differentiable renderer. In Advances in Neural Information Processing Systems (pp. 9609-9619). [ paper ]
  6. Ravi, N., Reizenstein, J., Novotny, D., Gordon, T., Lo, W.Y., Johnson, J. and Gkioxari, G., 2020. Accelerating 3D Deep Learning with PyTorch3D. arXiv preprint arXiv:2007.08501. [ paper ] [ github ]
  7. Tewari, A., Fried, O., Thies, J., Sitzmann, V., Lombardi, S., Sunkavalli, K., Martin-Brualla, R., Simon, T., Saragih, J., Niener, M. and Pandey, R., 2020. State of the Art on Neural Rendering. arXiv preprint arXiv:2004.03805. [ paper ]
  8. Blanz, V. and Vetter, T., 1999, July. A morphable model for the synthesis of 3D faces. In Proceedings of the 26th annual conference on Computer graphics and interactive techniques (pp. 187-194). [ paper ][ project page ]

Подробнее..

3D ML. Часть 6 Обзор алгоритмов семантической сегментации облака точек

29.12.2020 18:11:47 | Автор: admin


Мы уже успели поговорить про сверточные операторы на графах, а теперь посмотрим на реальные архитектуры.


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


Серия 3D ML на Хабре:


  1. Формы представления 3D данных
  2. Функции потерь в 3D ML
  3. Датасеты и фреймворки в 3D ML
  4. Дифференциальный рендеринг
  5. Сверточные операторы на графах
  6. Обзор алгоритмов семантической сегментации облака точек

Репозиторий на GitHub для данной серии заметок.


Заметка от партнера IT-центра МАИ и организатора магистерской программы VR/AR & AI компании PHYGITALISM.


Введение


Если рассматривать обработку трехмерных данных классическими методами машинного обучения, то можно обнаружить, что в этом направлении проделана значительная работа, и для всех, кто хочет ознакомиться с примерами таких алгоритмов, мы рекомендуем обзорную статью [5]. В частности, в статье рассматриваются различные этапы препроцессинга и способы извлечения информативных признаков из ковариационной матрицы разброса ближайших соседей для каждой точки.



Рис. 1. Этапы извлечение признаков и классификации для облака точек [5].


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


Исследователями в области 3D machine learning было предложено достаточно много идей (см. обзоры [3,4]), основанных на разных базовых принципах и формах представлений объектов, для решения задачи классификации объектов в форме облака точек. Так, например, это были методы, использующие последовательность 2D изображений (снимки сцены с разных ракурсов / multi view methods), к которым применялись сверточные нейронные сети (CNN), после чего результат разметки обратно проецировался в трехмерное пространство (поэтому эти методы также называют проекционными методами анализа облков точек).


Другим же подходом, является использование вокселей (voxel based methods) и применение операторов свёрток к ним. Однако, самым лучшим подходом видимо является использование в качестве входа для нейронной сети самого облака точек (т. н. прямой подход).


Посмотреть про актуальные задачи в области 3D ML можно на соответствующих страницах сайта paperswithcode: про задачи 3D в машинном зрении в общем, и про семантическую сегментацию облака точек в частности.


Мы собрали таблицу с разными методами и подходами, упомянутыми в обзорной работе [4], вместе со значениями метрик на разных наборах данных для оценки текущего состояния прогресса в решении задачи семантической сегментации облака точек. Ниже мы дадим краткий анализ основных подходов и их особенностей (там где нам удалось найти реализацию модели в коде, мы приложили ссылку на GitHub страницу проекта).


Кстати, на хабре на подобную тему удалось разыскать только такую заметку.


Примечание

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



Рис. 1.1 Краткая хронология развития алгоритмов семантической сегментации облака точек из обзора [4].


Обзор моделей глубокого обучения


Архитектуры глубокого обучения, предназначенные для обработки облаков точек, можно разделить, аналогично тому как это сделано в обзоре [4], на две большие группы: прямые (direct) и непрямые (indirect). Прямые методы в качестве входных данных для нейронной сети непосредственно используют облако точек, а для использования непрямых методов, необходимо предварительно перевести облако точек в иную форму представления данных.



Рис. 2. Таксономия моделей глубокого обучения, предназначенных для семантической сегментации облака точек [4].


Непрямые методы


Для начала, рассмотрим непрямые методы двух видов: multi view methods и voxel based methods.


Multi-view based methods


Первая группа таких методов, основана на получении множества снимков (двумерных срезов) исходного облака точек с разных ракурсов (multi view methods). Такой подход, позволяет использовать всю мощь методов обработки изображений, которой обладает современное компьютерное зрение в целом, и использующиеся там модели глубокого обучения в частности.


1. MVCNN [6] (2015)


Рис. 3. Схема работы сети MVCNN [6].



Входные данные: Одно или несколько изображений (RGB) 3D объекта.


Выходные данные: Класс формы объекта.


Особенности:


  • Одна из первых работ, посвященная multi-view подходу. Базируется на использовании 2D дескрипторов изображений для определения 3D характеристик.
  • Сеть предназначена для классификации единичных моделей и не приспособлена под сцены или облака точек.
  • В статье можно найти алгоритм настройки камер на сцене для получения двумерных срезов.
  • В заметки упоминается SOTA дескрипторы для изображений векторы Фишера.
  • Есть возможность приспособить сеть под другие задачи, такие как распознавание двумерных скетчей трехмерных объектов (3D visual search на основе скетч запроса).

2. SnapNet [7] (2017)


Рис.4 Схема работы сети SnapNet [7].



Входные данные: Облако точек.


Выходные данные: Семантическая разметка облака точек.


Особенности:


  • В статье предложен подход, использующий генерацию ряда пар RGB и Depth изображений проекций с различных ракурсов для исходного облака точек. Предварительно строится полигональная модель участков. Семантическая разметка происходит для плоских изображений (рис.4).
  • Предложена техника быстрого проецирования из 2D в 3D после семантической сегментации изображений.
  • В работе исследованы различные подходы к 2D семантической сегментации, в частности, был рассмотрен вопрос совмещение RGB-D данных в одной или нескольких сетях (fusion networks).

3. SnapNet-R [8] (2017)


Рис. 5. Схема работы сети SnapNet-R [8].



Входные данные: Облако точек.


Выходные данные: Семантическая разметка облака точек.


Особенности:


  • Сеть использует в качестве базового подхода архитектуру SnapNet, но имеет улучшенный алгоритм расстановки камер на сцене и генерации изображений (рис.5) за счет чего, превосходит свою предшественницу по показателям качества.
  • В работе, авторы исходили из предположения, что в реальной жизни камеры не могут быть расставлены на сцене случайным образом, а скорее всего подчинены определенной логике (например это может быть стереопара на беспилотном транспорте). В этих предположениях сконструирован фреймворк для разметки облаков точек на основе RGB-D снимков и реконструированного из этих снимков облака точек.

Volumetric methods


Вторая группа непрямых методов использует воксельное представление 3D моделей (voxel based methods). Поскольку воксельные сетки имеют регулярную структуру (аналогично пиксельным изображениям), то для них несложно обобщаются понятия сверток и многие другие приемы, применимые для анализа изображений.


4. VoxNet [9] (2015)


Рис.6 Схема работы сети VoxNet [9].



Входные данные: Вокселизированная модель исходного облака точек.


Выходные данные: Семантически сегментированное облако и воксельная маска распознанного объекта.


Особенности:


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

5. SEGCloud [10] (2017)


Рис. 7. Схема работы сети SEGCloud [10].


  • Github page (код отсутсвует)
  • Paper

Входные данные: Вокселизированная модель исходного облака точек.


Выходные данные: Семантически сегментированное облако и воксельная маска распознанного объекта.


Особенности:


  • Комбинированный подход методов классического машинного обучения и глубоких архитектур.
  • Для оптимизации использования памяти и оптимизации по скорости воксельную разреженную сеть сегментируют трехмерными матричными свертками (3D-FCNN), после чего, результат подается на вход трилинейному интерполятору (схема работы сети на рис. 7) для того, чтобы заполнить свободное пространство на основе полученной маски.
  • Дополнительно используется conditional random field (CRF), для комбинирования информативных признаков из исходного облака точек и интерполированной воксельной сетки.

6. PointGrid [11] (2018)


Рис. 8. Схема работы сети PointGrid [11].



Входные данные: Вокселизированная модель исходного облака точек.


Выходные данные: Семантически сегментированное облако и воксельная маска распознанного объекта.


Особенности:


  • Подход аналогичен VoxNet.
  • Можно выделить процедуру семплирования точек в пространстве, которая дополняет исходное облако так, что в каждом вокселе содержится одинаковое количество точек.
  • Используется энкодер-декодер архитектура и свертки на воксельной сетке (рис. 8).
  • По сравнению с другими воксельными моделями работает быстрее и использует меньшее количество памяти.

Прямые методы


Если говорить о прямых методах, то авторы обзора [4] разделили их на несколько групп в зависимости от особенности использованной глубокой архитектуры или в зависимости от того, какую из основных проблем работы с неструктурированными данными решает архитектура.


Methods of point ordering


Первая группа методов направлена на то, чтобы справиться с неупорядоченностью трехмерных данных (methods of point ordering).


7. PointCNN [12] (2018)


Рис. 9. Иерархические свертки (а) и архитектура (b) для сети PointCNN [12].



Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • Основным нововведением является использование $\mathcal{X}$-transformed operator оператора, преобразующего исходное облако точек в информативные признаки (взвешенное облако точек) и представляющего из себя многослойный персептрон (рис. 9).
  • Признаками, на основе которых производится разметка, являются выходы $\mathcal{X}$-персептронов, так как они инвариантны к перестановкам точек.

8. RSNet [13] (2018)


Рис. 10 Схема работы сети RSNet [13].



Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • Предложен специальный слой, который позволяет упорядочивать точки (Slice pooling layer).
  • Объект делится на слои по трем координатным направлениям (все точки проецируются на координатные оси из пространства меньшей размерности). Из каждого слоя извлекаются признаки путем применения рекурентной архитектуры (RNN), после чего применяется оператор обратного проецирования (Slice Unpooling) (рис. 10).
  • Добавление цвета помогает улучшить результаты.

9. SO-Net [14] (2018)


Рис.11 Архитектура сети SO-Net [14].



Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • Главная особенность: предварительно из облака точек извлекаются признаки с помощью метода Карт Кохонена.
  • Сеть предназначена для решения широко спектра задач: классификация, кластеризация, дополнение формы и многие другие. Разнообразие задач является следствием использования архитектуры автокодировщика (AE) (рис. 11).
  • Из минусов можно отметить сложность модели, плохое качество работы с мелкими деталями и невозможность обрабатывать сцены состоящие из нескольких объектов.

Methods based on multi-scale


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


10. PointNet++ [15] (2017)


Рис. 12 Архитектура сети PointNet++ [15].



Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • Используется повторное применение PointNet [27] к уменьшающемуся подмножеству точек (рис. 12).
  • Используется farthest point sampling (FPS) algorithm для изначального разбиения.
  • Рассматриваются случаи, когда специальная структура метрического пространства помогает намного улучшить результат, по сравнению с Евклидовым пространством.

11. 3DMAX-Net [16] (2018)


Рис. 13 Схема работы сети 3DMAX-Net [16].


  • Github page (код отсутствует)
  • Paper

Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • Архитектура состоит из двух подархитектур: multi-scale feature learning block (MS-FLB) и Local and Global feature Aggregation Block (LGAB) (рис. 13).
  • Первая подархитеткура извлекает информативные признаки инвариантные к трансформации, а вторая агрегирует локальные и глобальные признаки.

12. 3P-RNN [17] (2018)


Рис. 14 Схема работы сети 3P-RNN [17].


  • Github page (код отсутствует)
  • Paper

Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • Применяются двунаправленные рекуррентные нейронные сети в пространстве признаков (рис. 14).
  • Предложен поточечный пирамидальный pooling (3P) для выделение скрытых признаков.
  • Нужно знать плоскость (условно пол) т. к.происходит деление облака точек на блоки определенного размера вдоль оси x и y.
  • В отличие от предыдущих методов, эта архитектура показывает приемлемый результат как на облаках точек внутренних помещений, так и на облаках точек открытого пространства.

Methods of feature fusion


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


13. PointSIFT [18] (2018)


Рис. 15 Архитектура сети PointSIFT [18].



Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • Модификация PointNet [27] с предварительным выделением трехмерных SIFT признаков.
  • Тестировалась на сценах с большим количеством объектов (рис. 15).

14. A-CNN [19] (2019)


Рис. 16 Архитектура сети A-CNN [19].



Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • Предложены кольцевые свертки (архитектура сети на рис. 16).
  • Нужно оценить или иметь нормали для облака точек, т. к. они используются в процессе вычислений.

15. SpiderCNN [20] (2018)


Рис. 17 Архитектура сети SpiderCNN [20].



Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • Предложен новый сверточный оператор SpiderConv (архитектура сети на рис. 17).
  • Новый оператор конструируется как произведение двух операторов: кусочно-постоянного и полиномиального, полученных из разложения в ряд Тейлора сверточного фильтра общего вида.
  • Порядок разложения следует из некоторых результатов трилинейной интерполяции на регулярной сетке в 3D.

Methods of fusing GCNN


Если есть возможность восстановить информацию о поверхности объекта (например в случаи, когда мы работаем с полигональной моделью), то можно попытаться применить специфические свойства пространственных графов для решения задачи классификации и сегментации. Следующая группа методов основана на использовании операций сверток на графах, и все модели, так или иначе, базируются на архитектуре Graph Convolutional Neural Networks (GCNN) [28].


16. DGCNN [2] (2018)


Рис. 18 Схема сети DGCNN [2].



Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • В отличие от базового GCNN, в данной архитектуре, граф динамически перестраивается в процессе применения после прохождения информации через каждый последующий слой сети (рис. 18).
  • В качестве операторов в скрытых слоях используются графовые свертки, которые позволяют находить для каждой точки ближайших соседей не только в исходном Евклидовом пространстве, но и в пространстве скрытых признаков.
  • Архитектура почти аналогична PointNet [27], но вместо полносвязных перцептронов, в ней используются графовые свертки.

17. LDGCNN [21] (2019)


Рис. 19 Архитектура сети LDGCNN [21].



Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • Модификация архитектуры DGCNN [2]: отказались от сети для преобразования координат и адаптировали идеи из работы DenseNet [29].
  • Обучение делится на два этапа: обучение модели, которая извлекает признаки, и обучение классификатора при фиксированной модели для извлечения признаков (рис. 19).
  • Модель лучше сходится в процессе обучения и имеет меньшее число параметров по сравнению с DGCNN.

18. RGCNN [22] (2018)


Рис. 20 Архитектура сети RGCNN [22].



Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • Сеть строится из блоков, в каждом из которых используются три оператора: построение графа, свертка на графе, отбор признаков (рис. 20).
  • Для лучшего распознавания структуры динамически изменяющегося от слоя к слою графа, авторы используют матрицу Лапласа заданного графа (graph Laplacian matrix), которая описывает взаимосвязь признаков полученных в разных скрытых слоях.
  • Модель устойчива к выбросам в данных.

19. GAPNet [23] (2018)


Рис. 21 Архитектура сети GAPNet [23].



Входные данные: Облако точек.


Выходные данные: Семантически сегментированное облако.


Особенности:


  • Основная особенностьиспользование механизма внимания, состоящего из двух частей: самовнимание (self attention) для текущей точки и механизма внимания для поиска региона интереса в данных (рис. 21).
  • Архитектура похожа на PointNet [27].

Анализ качества работы глубоких архитектур


Для каждого алгоритма можно определить две группы метрик, для оценки качества их работы:


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

С точки зрения внешних метрик качества для алгоритмов для алгоритмов глубокого обучения обычно выделяют время выполнения (т.н. время прямого распространения сигнала) и количество параметров сети, которое напрямую влияет на количество памяти, необходимое для хранения модели.



Рис. 22 Время прямого распространения сигнала через нейронную сеть в миллисекундах (ms) [4].

Рис. 23 Количество параметров нейронной сети в миллионах (М) [4].


Ниже приведены сравнения работы описанных алгоритмов с помощью метрик качества классификации и семантической сегментации для различных наборов данных (большее количество информации и конкретные данные для сравнения вы можете найти в обзорной статье [4] или в этом github репозитории).


В качестве метрик используются следующие три:


  • Overall accuracy (OA)доля правильных ответов на всех классах / для всех точек.
  • Mean accuracy (MA)среднее значение Overall Accuracy по классам / для всех точек.
  • Mean intersection over union (mIoU)среднее значение метрики IoU [4] на всех классах / для всех точек.

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


The Stanford Large-scale 3D Indoor Spaces Dataset (S3DIS) [24]


Рис. 24 Пример помещений, отсканированных в формате цветного облака точек и семантической разметки из датасета S3DIS [24].



Состоит из 13 категорий, 224 отсканированных сцен для обучения и 48 сцен для валидирования. Все сценыпомещения, отсканированные с помощью лидара и размеченные вручную.


ShapeNet Part [25]


Рис. 25 Пример объектов и их разбиения на составные части из датасета ShapeNet part [25].



Состоит из 16 категорий, 12137 объектов в обучающей выборке, 2874 объектов для валидации. Датасет состоит из одиночных 3D моделей нарисованных художниками и разбитыми на составные части.


ModelNet40 [1]


Рис. 26 Пример объектов класса стул их разбиений на составные части в формате облака точек из датасета ModelNet40 [1].



Состоит из 40 классов, 12311 3D СAD моделей в обучающей и валидационной выборке. Датасет состоит из одиночных 3D параметрических моделей (CAD форматы), для 10-и классов, есть информация об ориентации моделей. Нет разбиения на части, этот датасет используется только для задачи классификации отдельных объектов.


ScanNet [26]


Рис. 27 Пример семантического разбиения отсканированного помещения из датасета ScanNet [26].



Состоит из 21 класса, 1201 сцены в обучающей выборке и 312 сцен в валидационной выборке. Датасет состоит из сцен помещений в виде набора RGB-D ракурсов + семантические размеченные облака точек без цвета.


Сравнения метрик


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


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


Overall Accuracy на наборе данных ModelNet40.


Mean Accuracy на наборе данных ModelNet40.


Overall Accuracy на наборе данных S3DIS.


Mean intersection over union на наборе данных S3DIS.


Overall Accuracy на наборе данных ScanNet.


Mean intersection over union на наборе данных ShapeNet Part.


Выводы


Исходя из проведенного анализа, можно сделать вывод:


  • прямые подходы предпочтительнее непрямых как с точки зрения внутренних, так и внешних метрик;
  • в зависимости от задачи и типа данных, оптимальные подходы могут быть разными;
  • в качестве потенциально применимых на практике подходов можно выделить: все сети основанные на GCNN, SpiderCNN и PointSIFT.

На наш вкус LDGCNN наиболее универсальна и предпочтительна для применения в реальных задачах.


Источники:
  1. Wu, Z., Song, S., Khosla, A., Yu, F., Zhang, L., Tang, X. and Xiao, J., 2015. 3d shapenets: A deep representation for volumetric shapes. In Proceedings of the IEEE conference on computer vision and pattern recognition (pp. 19121920). [paper]
  2. Wang, Y., Sun, Y., Liu, Z., Sarma, S.E., Bronstein, M.M. and Solomon, J.M., 2019. Dynamic graph cnn for learning on point clouds. ACM Transactions on Graphics (TOG), 38(5), pp.112. [paper]
  3. Xie Y., Tian J., Zhu X. X. A review of point cloud semantic segmentation //arXiv preprint arXiv:1908.08854.2019. [paper]
  4. Zhang J. et al. A Review of Deep Learning-based Semantic Segmentation for Point Cloud (November 2019) //IEEE Access.2019. [paper]
  5. Weinmann M. et al. Semantic point cloud interpretation based on optimal neighborhoods, relevant features and efficient classifiers //ISPRS Journal of Photogrammetry and Remote Sensing.2015.Т. 105.С. 286304. [paper]
  6. H. Su, S. Maji, E. Kalogerakis, and E. Learned-Miller, Multi-view convolutional neural networks for 3D shape recognition, in Proc. IEEE Int. Conf. Comput. Vis. (ICCV), Dec. 2015, pp. 945953 [paper]
  7. A. Boulch, B. Le Saux, and N. Audebert, Unstructured point cloud semantic labeling using deep segmentation networks, in Proc. Eurograph. Workshop 3D Object Retr., vol. 2, 2017, pp. 1724. [paper]
  8. J. Guerry, A. Boulch, B. Le Saux, J. Moras, A. Plyer, and D. Filliat, SnapNet-R: Consistent 3D multi-view semantic labeling for robotics, in Proc. IEEE Int. Conf. Comput. Vis. (ICCV), Oct. 2017, pp. 669678. [paper]
  9. D. Maturana and S. Scherer, VoxNet: A 3D convolutional neural network for real-time object recognition, in Proc. IEEE/RSJ Int. Conf. Intell. Robots Syst. (IROS), Dec. 2015, pp. 922928. [paper]
  10. L. Tchapmi, C. Choy, I. Armeni, J. Gwak, and S. Savarese, SEGCloud: Semantic segmentation of 3D point clouds, in Proc. Int. Conf. 3D Vis. (3DV), Oct. 2017, pp. 537547, doi: 10.1109/3DV.2017.00067. [paper]
  11. T. Le and Y. Duan, PointGrid: A deep network for 3D shape understanding, in Proc. IEEE Conf. Comput. Vis. Pattern Recognit. (CVPR), Jun. 2018, pp. 92049214 [paper]
  12. Y. Li, R. Bu, M. Sun, W. Wu, X. Di and B. Chen, PointCNN: Convolution On X-transformed points, in Proc. Adv. Neural Inf. Process. Syst. (NIPS). Dec. 2018, pp. 828838. [paper]
  13. Q. Huang, W. Wang, and U. Neumann, Recurrent slice networks for 3D segmentation of point clouds, in Proc. IEEE Conf. Comput. Vis. Pattern Recognit. (CVPR), Jun. 2018, pp. 26262635. [paper]
  14. J. Li, B. M. Chen, and G. H. Lee, SO-net: Self-organizing network for point cloud analysis, in Proc. IEEE Conf. Comput. Vis. Pattern Recognit. (CVPR), Jun. 2018, pp. 93979406 [paper]
  15. C. R. Qi, L. Yi, H. Su, and L. J. Guibas, PointNet++: Deep hierarchical feature learning on point sets in a metric space, in Proc. Adv. Neural Inf. Process. Syst. 30 (NIPS), 2017, pp. 51055114. [paper]
  16. Y. Ma, Y. Guo, Y. Lei, M. Lu, and J. Zhang, 3DMAX-net: A multi-scale spatial contextual network for 3D point cloud semantic segmentation, in Proc. 24th Int. Conf. Pattern Recognit. (ICPR), Aug. 2018, pp. 15601566, doi: 10.1109/ICPR.2018.8546281. [paper]
  17. X. Ye, J. Li, H. Huang, L. Du, and X. Zhang, 3D recurrent neural networks with context fusion for point cloud semantic segmentation, in Proc. Eur. Conf. Comput. Vis. (ECCV), 2018, pp. 403417 [paper]
  18. M. Jiang, Y. Wu, T. Zhao, Z. Zhao, and C. Lu, PointSIFT: A SIFTlike network module for 3D point cloud semantic segmentation, 2018, arXiv:1807.00652. [paper]
  19. A. Komarichev, Z. Zhong, and J. Hua, A-CNN: Annularly convolutional neural networks on point clouds, in Proc. IEEE Conf. Comput. Vis. Pattern Recognit. (CVPR), Jun. 2019, pp. 74217430 [paper]
  20. Y. Xu, T. Fan, M. Xu, L. Zeng, and Y. Qiao, SpiderCNN: Deep learning on point sets with parameterized convolutional filters, in Proc. Eur. Conf. Comput. Vis. (ECCV), 2018, pp. 87102. [paper]
  21. K Zhang, M. Hao, J. Wang, C. W. de Silva, and C. Fu, Linked dynamic graph CNN: Learning on point cloud via linking hierarchical features, 2019, arXiv:1904.10014. [paper]
  22. G. Te, W. Hu, A. Zheng, and Z. Guo, RGCNN: Regularized graph CNN for point cloud segmentation, in Proc. 26th ACM Int. Conf. Multimedia, Oct. 2018, pp. 746754. [paper]
  23. C. Chen, L. Z. Fragonara, and A. Tsourdos, GAPNet: Graph attention based point neural network for exploiting local feature of point cloud, 2019, arXiv:1905.08705. [paper]
  24. I. Armeni, O. Sener, A. R. Zamir, H. Jiang, I. Brilakis, M. Fischer, and S. Savarese, 3D semantic parsing of large-scale indoor spaces, in Proc. IEEE Conf. Comput. Vis. Pattern Recognit. (CVPR), Jun. 2016, pp. 15341543. [paper]
  25. L. Yi et al., Large-scale 3D shape reconstruction and segmentation from ShapeNet core55, 2017, arXiv:1710.06104. [paper]
  26. A. Dai, A. X. Chang, M. Savva, M. Halber, T. Funkhouser, and M. Niener, ScanNet: Richly-annotated 3D reconstructions of indoor scenes, in Proc. IEEE Conf. Comput. Vis. Pattern Recognit. (CVPR), Jul. 2017, pp. 58285839. [paper]
  27. Qi, C.R., Su, H., Mo, K. and Guibas, L.J., 2017. Pointnet: Deep learning on point sets for 3d classification and segmentation. In Proceedings of the IEEE conference on computer vision and pattern recognition (pp. 652-660). [paper]
  28. Zhang, Y. and Rabbat, M., 2018, April. A graph-cnn for 3d point cloud classification. In 2018 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP) (pp. 6279-6283). IEEE. [paper]
  29. Huang, G., Liu, Z., Van Der Maaten, L. and Weinberger, K.Q., 2017. Densely connected convolutional networks. In Proceedings of the IEEE conference on computer vision and pattern recognition (pp. 4700-4708). [paper]
Подробнее..

Компьютерное зрение в промышленной дефектоскопии Часть 2 Генерируем стремные трубы чтобы порадовать нейронку

18.02.2021 18:15:13 | Автор: admin


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


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

Заметка от партнера IT-центра МАИ и организатора магистерской программы VR/AR & AI компании PHYGITALISM.


Введение


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


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


Если данные сгенерированы корректно, то генератор позволяет:


  • сократить объем необходимых реальных фотографий труб,
  • получить данные, которые в реальности встречаются крайне редко и сделать набор данных более сбалансированным,
  • получить большее число признаков (в данном примере, помимо изображения дефекта, мы получаем его 3D модель).

Поскольку генератор позволяет получать 3D объекты, он способен стать источником новых данных не только для алгоритмов классического компьютерного зрения (CV), но и для целого ряда задач геометрического глубокого обучения (3D ML, GDL).


Применение 3D ML подходов может дать преимущество при решении задач дефектоскопии, так как пространственные сканеры / камеры глубины (RGB-D, Lidar и пр.) позволяют находить менее очевидные человеческому глазу дефекты и реконструировать изучаемые объекты (например, вздутие трубы не всегда можно обнаружить, не потрогав трубу руками или чувствительным щупом).


Часть 1: Реализация генератора данных



Рис.1 Примеры данных, сгенерированных в проекте. Слева направо: меш труб, отрендеренные изображения с текстурами, битовые маски дефектов (авторазметка), ограничивающие прямоугольники дефектов (авторазметка).


Вся работа по созданию искусственного набора данных была осуществлена в Blender, с использованием скриптов на языке Python. Исключение составила лишь программа преобразования растровой разметки в формат Yolo, написанная на языке Rust.


Минутка текстовых шуток для IT-шников:
В нашем проекте Python генерировал змеевики, а Rust получал разметку ржавчины.


Рис.2 Рабочее окно Blender с плагином генератора труб.


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



Рис. 3 Пример сцены, из которой рендерились наборы изображений с разметкой поперечных трещин.


Задача создания генератора синтетических данных была разделена на следующие этапы:


  • Настройка цифрового двойника камеры БПЛА с накамерным светом (рендеринг итоговых изображений должен позволять добиться реалистичности в синтетических данных).
  • Создание инструмента для быстрого моделирования базовой геометрии труб.
  • Настройка процедурных материалов для различных поверхностей труб (металлический блеск, ржавчина и пр.).
  • Настройка процедурных материалов для различных дефектов труб (различные трещины, дыры, изгибы и пр.).
  • Настройка процедурной анимации позиции камеры, освещения и материалов для создания разнообразных изображений из одной сцены.
  • Настройка масок дефектов (битовые маски и ограничивающие прямоугольники для разных классов дефектов).
  • Рендер итоговых сцен.
  • Приведение разметки дефектов к форматам YOLO и MS COCO.

Настройка цифрового двойника камеры БПЛА с накамерным светом



Рис.4 Камера с осветителем на сцене в Blender.


Объект с самосветящимся материалом, имитирующий кольцевой осветитель, и всенаправленная лампа назначены дочерними объектами камеры. Размер сенсора, угол обзора, относительное отверстие объектива и разрешение получаемого изображения настроены в соответствии с реальными характеристиками камеры DJI Mavic 2 Zoom.


Инструмент для быстрого моделирования базовой геометрии труб



Рис.5 Сцена, наполненная змеевиками труб, полученными с помощью скрипта из этого раздела.


В первую очередь нужно отметить, что вся геометрия труб строилась по NURBs без прямой конвертации в полигональные модели (Про использование NURBS в 3D моделировании на хабре писали в этой заметке). Все дефекты, в том числе, геометрические создавались посредством материалов на этапе рендера.


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


Код для процедурной генерации труб:
import bpyimport timefrom math import sin, cos, pi, radians# Генерация змеевиков в плоскости внутри прямоугольника со сторонами# sizeX, sizeYdef create_flat_curve(sizeX, sizeY):    points = []    for y in range(sizeY):        for x in range(sizeX):            if y % 2 == 0:                point = [x, y]            else:                point = [sizeX - x - 1, y]            points.append(point)    curve_name = "Pipe_Flat_" + str(time.time_ns())    curveData = bpy.data.curves.new(curve_name, type='CURVE')    curveData.dimensions = '3D'    curveData.resolution_u = 2    polyline = curveData.splines.new('NURBS')    polyline.points.add(len(points)-1)    for i, point in enumerate(points):        x,y = point        polyline.points[i].co = (x, y, 0, 1)    curveData.bevel_depth = 0.4    #polyline.use_endpoint_u = True    curveOB = bpy.data.objects.new(curve_name, curveData)    bpy.context.collection.objects.link(curveOB)# Генерация змеевиков в пространствеdef create_cyl_curve(radius, angle, height, density, horizontal):    phi = radians(angle)    steps = int(density * phi / (pi*2))     print("Steps:", steps)    points = []    if horizontal:        for z in range(height):            for step in range(steps):                if z % 2 == 0:                    x = radius * cos(step * phi / steps)                    y = radius * sin(step * phi / steps)                    else:                    x = radius * cos(phi - (step+1) * phi / steps)                    y = radius * sin(phi - (step+1) * phi / steps)                  point = [x, y, z]                points.append(point)    if not horizontal:        for step in range(steps):            for z in range(height):                x = radius * cos(step * phi / steps)                y = radius * sin(step * phi / steps)                    if step % 2 == 0:                    point = [x, y, height-z-1]                else:                    point = [x, y, z]                points.append(point)    print("Points:", len(points))    curve_name = "Pipe_Cylinder_" + str(time.time_ns())    curveData = bpy.data.curves.new(curve_name, type='CURVE')    curveData.dimensions = '3D'    curveData.resolution_u = 2    polyline = curveData.splines.new('NURBS')    polyline.points.add(len(points)-1)    for i, point in enumerate(points):        x,y,z = point        polyline.points[i].co = (x, y, z, 1)    curveData.bevel_depth = 0.3    #polyline.use_endpoint_u = True    curveOB = bpy.data.objects.new(curve_name, curveData)    bpy.context.collection.objects.link(curveOB)

Настройка материалов поверхностей труб


От использования готовых наборов текстур из изображений пришлось отказаться по нескольким причинам:


  • необходима корректная проекция изображений на геометрию (что само по себе нетривиальная задача),
  • необходима повторяемость рисунка (здесь мы ограничены информацией из изображений),
  • такие текстуры имеют предел детализации из-за разрешения исходных изображений.

Запекание сгенерированных текстур, например из Substance Painter, было исключено чтобы не множить инструменты и сущности (такая вот бритва Оккама у нас вышла).



Рис.6 Группа нод (назовем ее супернодой) для настройки материалов, объединенные в одну большую ноду.


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


Примечание:

Здесь и далее для конструирования шейдеров используется интерфейс с нодами, поскольку разработчик данного решения CG художник, и этот подход был для него предпочтительным =)



Рис. 7 Содержание суперноды из рис.6: материалы внутри группы собирались преимущественно из шумов и градиентов.


Настройка материалов дефектов труб



Рис.8 Пример сгенерированных труб с дефектами коррозии (слева) и цветами побежалости (справа).


Такие дефекты, как коррозия и цвета побежалости, создавались непосредственно из шума Перлина, градиентов и смещения (Displacement) геометрии модели по нормали к поверхности (само смещение производилась в шейдере, при этом геометрия неподвижна).



Рис.9 Создание дефекта Разрыв трубы в Blender.


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



Рис.10 Создание дефекта Выход трубы из ряда в Blender.


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


Анимация камеры, освещение и материалы


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



Рис.11 Применение шума на анимационных кривых позиции, поворота камеры, интенсивности и позиции источника света для процедурной съемки сцены.


Настройка масок дефектов


Для вывода черно-белых масок разметки дефектов использовался канал Arbitrary Output Value (AOV), в ноду которого подавался коэффициент смешивания базового материала и материала дефекта. Иногда использовалась бинарная математическая нода Greater Than (на выходе 0, если входное значение меньше порогового, иначе 1).


Рендер


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



Рис.12 Директории с сохраненными изображениями (слева) и разметкой (справа).


Приведение разметки к формату YOLO


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



Рис.13 Сгенерированные трубы с дефектом трещины (слева) и соответствующая маска для данного изображения (справа).


Код с поиском масок дефектов на Python (предполагается что на входе имеется изображение как на рис.13 справа):
import bpyimport colorsysimage = bpy.data.images["two_cubes.png"]sizeX = 64sizeY = 64image.scale(sizeX, sizeY)pixels = image.pixelssize = [sizeX, sizeY]print(len(pixels))grid = [[ [0] for y in range(size[1])] for x in range(size[0])] print("LEN:", len(grid))print(len(pixels)/4, " == ", sizeX*sizeY)def rgb_to_hex(rgb):    hex_string = ""    for c in rgb:        hex_string += str(hex(max(min(int(c * 255 + 0.5), 255), 0)))[2::]     return hex_string.upper()def search_neighbours(grid, x, y, color, l,b,r,t):    grid[x][y] = 0    #print("FROM", x, y)    if x < l:        l = x    if x > r:        r = x    if y < b:        b = y    if y > t:        t = y    if x < size[0]-1:            if grid[x+1][y] == color:        #print("RIGHT")            l,b,r,t = search_neighbours(grid, x+1, y, color, l, b, r, t)    if y < size[1]:        if grid[x][y+1] == color:        #print("UP")            l,b,r,t = search_neighbours(grid, x, y+1, color, l, b, r, t)    if x > 0:        if grid[x-1][y] == color:        #print("LEFT")            l,b,r,t = search_neighbours(grid, x-1, y, color, l, b, r, t)    if y > 0:        if grid[x][y-1] == color:        #print("DOWN")            l,b,r,t = search_neighbours(grid, x, y-1, color, l, b, r, t)    return (l,b,r,t)  for i in range(0, int(len(pixels) / 4)):    if pixels[i*4] > 0:#sum(pixels[i*4:i*4+3]) > 0:        x = (i) % size[1]        y = int(i / size[1])        #color = pixels[i*4:i*4+2]        #hex_col = rgb_to_hex(pixels[i*4:i*4+3])        grid[x][y] = 1              #print(x,y)print("GRID FINISHED")        color = 1islands = []for y in range(size[1]):    for x in range(size[0]):        if grid[x][y] == color:            "LOOKING FOR NEW ISLAND"            print(search_neighbours(grid, x, y, color, x, y, x, y))

Часть 2: Создание масок и разметки в Blender



Рис.14 Исходная тестовая сцена в Blender.


В этой части мы постараемся больше показывать, нежели рассказывать. На основе одной тестовой сцены в Blender (рис. 14) покажем, какие возможно сгенерировать полезные для задач компьютерного зрения изображения из трехмерной сцены.


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


1.Комбинированные Рендер-пассы


Рис. 15 Combined Pass: итоговый рендер сцены с учетом всех компонент.


2. Глубина сцены


Рис.16 Depth Pass: карта глубины для данной сцены.


Канал глубины позволяет передать информацию о позициях пикселей в пространстве через их удалённость от камеры. Используя пару изображений Combined+Depth можно тренировать нейросети, восстанавливающие трёхмерные сцены из изображений.


3. Карты нормалей


Рис. 17 Normal Pass: карта нормалей сцены.


Канал нормалей снабжает изображение информацией о нормалях поверхностей, что дает возможность не только менять освещение при постобработке, но и понимать форму объектов (хотя информации об их расположении в пространстве относительно друг друга отсутствует).


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


4. Диффузная составляющая


Рис. 18 Diffuse Color Pass: рассеивающая составляющая материалов (например высокое значение у зеркальных металлических поверхностей и низкое значение у шероховатых диэлектриков).


5. Бликовая составляющая


Рис. 19 Glossy Color Pass: отражающая способность материала (блики).


6. Имитирующая составляющая


Рис. 20 Emission Pass: самосвечение материалов.


7. Суммарная интенсивность света


Рис. 21 Ambient Occlusion Pass: суммарная интенсивность света в каждой точке.


8. Теневая составляющая


Рис. 22 Shadow Pass: тени (для каждой точки пространства просчитываются относительно источников света на сцене).


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


Маски можно создавать на индивидуальные объекты и их группы, материалы, а также на произвольные параметры материалов.


9. Маска индивидуальных объектов (instance segmentation)


Рис. 23 Cryptomatte Object Pass: разметка различных объектов случайным цветом.


10. Разметка объектов по классам материалов


Рис. 24 Cryptomatte Material Pass: разметка различных материалов случайными цветами.


В пассах Cryptomatte всем объектам и материалам присваиваются уникальные цвета.


Допустим, мы хотим создать две маски: на одной будут отмечены все обезьянки, на другой геометрические примитивы. Всем объектам нужно назначить Object ID (он же Pass Index), для обезьянок это будет 1, для примитивов 2, 0 останется для пола. Для удобства объекты разных классов можно распределить по коллекциям и написать скрипт, который присваивает всем объектам коллекции свой Object ID.



Чтобы получить необходимую маску, нужно использовать ноду ID Mask в композиторе.
Также в композиторе можно настроить одновременный вывод пассов и масок в отдельные файлы (см. рисунок ниже).



11. Разметка объектов по категориям (semantic segmentation)


Рис. 25 monkeys mask: маскирование объектов класса обезьяна.



Рис. 26 primitives mask: маскирование объектов класса геометрические примитивы.


Если мы хотим отметить каждый интересующий нас объект по отдельности, им нужно присвоить свои уникальные Object ID.


12. AOV - Arbitrary Output Value

Blender позволяет выводить в изображение любые параметры материалов. Для этого в настройках пассов нужно создать слой AOV, в который будут сохраняться значения из шейдеров в виде RGB или числа с плавающей точкой. В соответствующем материале нужно создать ноду Output/AOV и присвоить ей имя слоя.


Разберём этот материал:

Рис. 27 Combined Pass, умноженный на маску материала.



Здесь текстура шума подана на параметр Scale шейдера подповерхностного рассеивания (см. рис. выше). Допустим, мы хотим получить маску на те области поверхности, в которых параметр Scale больше 1.8.


В результате получим маску:


Проделаем теперь подобное с другим материалом и выделим красные области, подав в AOV фактор смешивания синего и красного цветов:


AOV даёт более широкие возможности для разметки, этот подход можно использовать для обозначения областей объектов, подверженных смещению (Displacement). На объектах на изображении ниже использовалось смещение по нормали поверхности для имитации повреждений:


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



Отдельным примером может служить использование AOV для разметки повреждённых областей объектов, на которых основной материал заменяется на прозрачный. На этой обезьянке применено трёхмерное смещение (Vector Displacement), то есть каждый участок, подверженный такому эффекту смещается не по нормали к исходной поверхности, а по трём осям согласно значениям из цвета, подаваемого на вход (R,G и B соответствуют X, Y и Z).





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




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


Заключение



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


В будущем мы постараемся рассказать и про другие наши эксперименты связанные с 3D ML вобще и с Blender в частности, а пока можете подписаться на наш канал в Telegram 3D ML, где мы рассказываем несколько раз в неделю о новостях и достижениях в этой науке)

Подробнее..

Осваиваем анализ лидарных данных и измеряем дорожные знаки

02.04.2021 20:22:21 | Автор: admin

Всем привет! Сегодня мы хотели бы поделиться с вами нашим опытом анализа лидарных облаков. В заметке расскажем:

  • какими инструментами и библиотеками можно пользоваться для анализа и обработки лидарных данных;

  • рассмотрим практический пример анализа лидарных облаков, полученных с лидарного комплекса, установленного на автомобиле;

  • попробуем применить стандартные библиотеки и техники для анализа и визуализации данных.

Заметка от партнера IT-центра МАИ и организатора магистерской программы VR/AR & AI компанииPHYGITALISM.

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

Инструменты для анализа лидарных данных

Итак, предположим что вы начинающий исследователь в области 3D ML и вам потребовалось работать с лидарными данными. Какие инструменты лучше для этого использовать? В чем особенность различных форматов данных? Какие подходы можно применить? В чем сложность обработки и анализа таких данных? Эти и многие другие вопросы встают перед исследователем. Попробуем начать с источников для изучения, инструментов и библиотек.

В качестве входной точки, можно порекомендовать вот этот репозиторий, в котором собраны инструменты и библиотеки, туториалы и статьи на тему обработки облаков точек. Очень полезный ресурс, обязательно посмотрите, может быть, найдете для себя интересные вещи.

Из перечисленных в этом репозитории инструментов стоит отметить два основных, которыми пользуются многие исследователи и разработчики в области пространственного компьютерного зрения и 3D графики:

  1. MeshLab (Open source, portable, and extensible system for the processing and editing of unstructured 3D triangular meshes).

    Это быстрый, простой в освоении и использовании инструмент, поддерживающий большинство форматов 3D данных для облаков точек и полигонального меша. На официальном сайте можно найти много туториалов. В MeshLab есть инструменты для фильтрации, сегментации, сглаживания и многого другого. На хабре про MeshLab писали тут. MeshLab хорошо подходит для того, чтобы открыть не очень объемный скан или модель, посмотреть на нее, убрать шум или сегментировать на несколько частей, залатать дыры в меше и подобные операции. Для того чтобы работать с большими облаками, которые обычно записывают в .laz и .las формат, лучше подойдет следующий инструмент.

  2. Cloud Compare (3D point cloud and mesh processing software Open Source Project)

    Данный инструмент предназначен для визуализации и обработки больших облаков точек, он поддерживает большинство форматов, используемых для лидарных данных. Есть инструменты для редактирования облака точек, имеются модули из PCL, есть возможность обработки на GPU, для больших облаков можно генерировать октодеревья, для быстрой обработки.На YouTube есть много туториалов по этому инструменту, а на официальном сайте есть облака в .las формате для этих туториалов.

  3. ROS and Webviz

    В области беспилотного транспорта часто встречается ROS (The Robot Operating System) - фреймворк для написания программ в области робототехники. Для записи лидарных данных в ROS используют .bag формат, имеющий много особенностей и подводных камней. ROS и BAG файлы стоят отдельной большой заметки на Хабре (туториал текстовый и видео), и мы не будем подробно на этом останавливаться. Отметим только, что для визуализации BAG файлов и не только есть удобный браузерный визуализатор WebVIZ.

Библиотеки на Python и С++

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

1) Начнем со считывания данных и подготовки их к дальнейшему использованию. Если это .las файлы, можно воспользоваться Python библиотекой pylas.

Pylas не загружает в оперативную память сразу все облако, а создает специальный поток для чтения данных с диска (как memory map в numpy).

Пример чтения .las файла

import pylaswith pylas.open("some_big_file.laz") as f:    for points in f.chunk_iterator(1_000_000):        do_something_with(points)

С помощью методов pylas можно создать фильтр, который пре процессирует точки при первичном считывании.

2) Помимо .las формата, облако точек еще часто встречается в .pcd (PCD format) формате. Этот формат - представление данных в библиотеке PCL. Для работы с таким форматом в Python есть библиотека pypcd.

PyPCD в основном нужна для того, чтобы не возиться с C++ кодом 6 чтобы считать или записать облака точек в PCL формате.

Пример чтения .pcd с помощью pypcd:

import pypcd# also can read from file handles.pc = pypcd.PointCloud.from_path('foo.pcd')# pc.pc_data has the data as a structured array# pc.fields, pc.count, etc have the metadata# center the x fieldpc.pc_data['x'] -= pc.pc_data['x'].mean()# save as binary compressedpc.save_pcd('bar.pcd', compression='binary_compressed')

Также pypcd совместим с rospy - Python оберткой над ROS.

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

3) PDAL (Point Data Abstraction Library) - С++ библиотека, альтернатива для LAStools, имеющая обертки на Java и Python. В ней реализованы несколько стандартных статистических и структурных фильтров. Подойдет для быстрого чтения и фильтрации больших облаков точек. В PDAL вы в виде конфигурационного файла прописываете пайплайн обработки данных, а после в несколько строк кода запускаете пайплайн.

Пример фильтрации облака точек:

import jsonimport pdaldef get_pipeline_filtering(path_to_input: str, path_to_output: str, filter:str):    pipeline = [            path_to_input,            {                "type":"filters." + filter            },            {                "type":"filters.range",                "limits":"Classification[2:2]"            },            path_to_output    ]    return pipelineexample = './example.laz'# Пример фильтрации облака точек c параметрами по умолчаниюmethod = 'pmf' # Доступные фильтры: https://pdal.io/stages/filters.htmlpipeline = get_pipeline_filtering(example, 'result.laz', method)pipeline = json.dumps(pipeline, indent=2)pipeline = pdal.Pipeline(pipeline)if pipeline.validate():    print("Validate: True")    pipeline.execute()

4) pyntcloud - простая в использовании Python 3 библиотека для интерактивной визуализации и обработки полигональных мешей и облаков точек. В ней есть инструменты для конвертации форматов, фильтрации и вычисления некоторых скалярных полей над облаками точек (например ближайших соседей, кривизн поверхностей, собственных векторов облака и пр.)

Пример визуализации облака точек, полученного из меша и визуализации кривизны для точек из облака:

from pyntcloud import PyntCloudanky = PyntCloud.from_file("data/ankylosaurus_mesh.ply")anky_cloud = anky.get_sample("mesh_random", n=100000, rgb=True, normals=True, as_PyntCloud=True)anky_cloud.plot()
curvature = anky_cloud.add_scalar_field("curvature", ev=eigenvalues)anky_cloud.plot(use_as_color=curvature, cmap="jet")

5) Open3D - C++ и Python библиотека, в которой содержатся функции для обработки облаков точек и полигональных мешей. В отличие от всех предыдущих библиотек, Open3D имеет наиболее широкий функционал: это касается и количества поддерживаемых форматов и количества алгоритмов и задач. К библиотеке есть обширная документация с примерами.

Рассмотрим небольшой пример обработки облака точек в формате .ply (данное облако находится в репозитории проекта).

Загрузим и визуализируем исходное облако точек:

pcd = o3d.io.read_point_cloud("../../test_data/fragment.ply")print(pcd)print(np.asarray(pcd.points))o3d.visualization.draw_geometries([pcd],                                  zoom=0.3412,                                  front=[0.4257, -0.2125, -0.8795],                                  lookat=[2.6172, 2.0475, 1.532],                                  up=[-0.0694, -0.9768, 0.2024])

Вывод:

PointCloud with 196133 points.[[0.65234375 0.84686458 2.37890625] [0.65234375 0.83984375 2.38430572] [0.66737998 0.83984375 2.37890625] ... [2.00839925 2.39453125 1.88671875] [2.00390625 2.39488506 1.88671875] [2.00390625 2.39453125 1.88793314]]

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

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

downpcd = pcd.voxel_down_sample(voxel_size=0.05)o3d.visualization.draw_geometries([downpcd],                                  zoom=0.3412,                                  front=[0.4257, -0.2125, -0.8795],                                  lookat=[2.6172, 2.0475, 1.532],                                  up=[-0.0694, -0.9768, 0.2024])

Вывод:

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

downpcd.estimate_normals(    search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))o3d.visualization.draw_geometries([downpcd],                                  zoom=0.3412,                                  front=[0.4257, -0.2125, -0.8795],                                  lookat=[2.6172, 2.0475, 1.532],                                  up=[-0.0694, -0.9768, 0.2024],                                  point_show_normal=True)

Вывод:

Практический пример: анализируем дорожные знаки

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

Цель - в потоке лидарных данных обнаружить дорожные знаки и измерить их линейные размеры.

Задача глобально разбивается на несколько этапов:

  1. Анализ данных, пришедших на сервер;

  2. Предобработка данных глобального облака точек проезда;

  3. Предобработка локального облака точек;

  4. Детектирование знака;

  5. Определение пространственных характеристик.

Входные данные, которыми мы располагаем:

  • Облако точек в форматах .las, .laz глобального скана (проезд автомобиля по целой улице или больше);

  • Информация о распознанных знаках на маршруте (shapefile с координатами, классами и дополнительными атрибутами знака) - т.е. до того, как анализировать облако точек (3D данные) мы полагаем, что были проанализированы 2D данные проезда (панорамные снимки);

  • Метаданные (трек положения лидара в пространстве и временные метки);

  • 2D видео проезда;

  • Размеченные 2D данные (json файл с координатами bounding boxes интересующих объектов);

  • Панорамные снимки проезда.

До начала исследования мы составили план работ (изображение ниже), в котором отобразили основные этапы и гипотезы, а также попытались предположить, что можно будет распараллелить в процессе работы.

Исследование входных данных

Для начала визуализируем имеющиеся данные и попробуем понять, какую полезную информацию можно из этого извлечь. Для каждого проезда лидарного комплекса у нас имелись пары .laz и .las файлов. В них отличается информация по типам источника: Intensity, Colour, Point source. Визуализируем с помощью встроенных возможностей Cloud Compare эти данные.

1. Intensity при одинаковом значении Exposure

Рис 1. las файл.Рис 1. las файл.Рис 2. laz файл.Рис 2. laz файл.

2. Colour

В .laz, видимо, совсем нет информации т. к. всё чёрное, в .las наоборот информация есть, например, многие знаки ярко выделены. Такое ощущение, что они были светоотражающие и их подсветили фарами (это наблюдение можно использовать и пытаться искать знаки по признаку интенсивности отраженного света).

Рис 3. laz файл.Рис 3. laz файл.Рис 4. las файл.Рис 4. las файл.

3. Point source

Рис 5. laz файл.Рис 5. laz файл.Рис 6. las файл.Рис 6. las файл.

Можно сделать вывод, что данные получены с разных источников или в разное время суток. В данном случае Colour в .las является достаточно хорошим признаком для выделения знаков.

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

Рис 7. Трек лидара на карте. Для каждой точке геотрека нам известна соответствующая точка в глобальном облаке.Рис 7. Трек лидара на карте. Для каждой точке геотрека нам известна соответствующая точка в глобальном облаке.

Теперь, используя информацию, полученную от анализа 2D данных (предварительные координаты и классы дорожных знаков, полученные с помощью методов детекции в 2D данных и проецировании точек на основе параметров камеры), проанализируем предварительное расположение объектов интереса.

Кстати, на тему проецирование точек из 2D в 3D на основе параметров камеры есть вот такая замечательная заметка на Medium, которая может быть полезна всем интересующимся исследователям в данной предметной области.

Рис 8. Пример разметки объектов интереса в облаке точек из датасета WAYMO.Рис 8. Пример разметки объектов интереса в облаке точек из датасета WAYMO.

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

Теперь у нас есть два способа разбиения глобального облака на локальные:

  1. Брать сферические или кубические подоблака рядом с положением объектов из shape файлов;

  2. Брать сферические подоблака на основе GPS трека.

Второй подход возник по той причине, что помимо восстановленного облака точек нам доступны сырые данные с лидара (например сферические панорамы карт глубин), и мы можем использовать эти данные для того, чтобы уточнять положения знаков в пространстве.

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

Рис 9. Пример входного сферического изображения.Рис 9. Пример входного сферического изображения.Рис 10. Пример полученного плоского изображения из участка сферического.Рис 10. Пример полученного плоского изображения из участка сферического.

Если мы придерживаемся первого подхода, нам нужно понимать какое распределение в подоблаках точек для плотности мы имеем.

Разделим облако на сегменты и для каждого сегмента подсчитаем статистику плотности:

Рис 11. Гистограмма распределения количества точек в выделенных объектах (всего 529 объектов).Рис 11. Гистограмма распределения количества точек в выделенных объектах (всего 529 объектов).

Всего в нашем распоряжении оказалось 529 объектов. Гистограмма распределения количества точек и типовые объекты приведены на рис.11-12. Среднее количество вершин в объекте 283. Более 75% объектов содержат менее 330-и точек. Помимо самих знаков в таких объектах присутствуют посторонние объекты. Если рассматривать плотность и количество точек только для знаков, то они оказываются еще меньшими.

Основной вывод - облака очень разреженные и это может привести к проблемам. Данный случай - наглядный пример проблемы, часто возникающей в лидарном сканировании: в результате сканирования имеем облако, где точек много, но на объект интереса приходится только малая их часть.

Рис 12. Примеры типичных представителей по количественному признаку.Рис 12. Примеры типичных представителей по количественному признаку.

Помимо того, что точек в объектах интереса мало, в подоблаках часто содержаться шумовые точки (куски других объектов, шум и пр.), поэтому прежде чем использовать эти подоблака, попытаемся их сначала отфильтровать.

Рис 13. Применение SOR фильтрации (изображение слева - до фильтрации, изображение справа - после фильтрации).Рис 13. Применение SOR фильтрации (изображение слева - до фильтрации, изображение справа - после фильтрации).

Для фильтрации воспользовались возможностями ранее упомянутой библиотеки PDAL.

Рассмотрим два базовых типа фильтра: статистические (наиболее типичный представитель - SOR [1] / Рис.13) и поиск опорных поверхностей (наиболее типичный представитель - CSF [2] / Рис. 14).

В зависимости от качества данных, фильтры могли как улучшить ситуацию (убрать посторонние точки), так и ухудшить (убрать точки из объекта интереса).

Основные выводы:

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

  • В совокупности с этими фильтрами, нужно применять сегментацию и детекцию плоскостей (также нужна подгонка гипер параметров на основе целевых данных).

Рис 14. Применение CSF фильтра для выделения посторонних вершин, относящихся к опорной поверхности.Рис 14. Применение CSF фильтра для выделения посторонних вершин, относящихся к опорной поверхности.

Данные для самостоятельных экспериментов

Мы не можем поделиться с вами исходными данными, в силу конфиденциальности проекта, но всем, кто хочет поэкспериментировать со схожими данными, мы рекомендуем обратить внимание на датасет WAYMO, который содержит знаки следующих типов: stop signs, yield signs, speed limit signs, warning signs, guide and recreation signs.

Сегментация знаков внутри под облака

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

Для сегментации были выбраны две модели: DGCNN [3] и PoinNet++ [4]. Кстати, про модели сегментации облаков точек мы писали на хабре вот в этой заметке. DGCNN выбран, как наиболее стабильная и качественная модель, основанная на графовом представлении. PoinNet++ выбрана для сравнения, как классическая модель, основанная на статистических признаках.

Для сравнения были выбраны следующие метрики:

  • F1-Score - агрегированный критерий качества, учитывающий точность и полноту.

  • Mean IoU - метрика, показывающая насколько у двух объектов (эталонного (ground true) и текущего) совпадает внутренний объем.

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

Рис 15. Пример объекта из синтетического датасета.Рис 15. Пример объекта из синтетического датасета.

Ниже представлен график эволюции mean IoU на этапе обучения модели (размер датасета - 5 тыс., количество эпох - 100). Метрика рассчитывалась в конце каждой эпохи.

Рис 16. PoinNet++ mean IoU (слева), DGCNN mean IoU(справа).Рис 16. PoinNet++ mean IoU (слева), DGCNN mean IoU(справа).

Далее было произведено сравнение обученных моделей (инференс) на тестовом наборе данных из 2 тыс. моделей. Результаты представлены в табл. 1.

Таблица 1 Метрики качества сегментации на синтетическом датасете

F1-score

Доля правильно классифицированных точек

Плоскость

Основа знака

Треугольник

Круг

PoinNet++

0.545420

0.685618

0.700799

0.743857

0.668281

DGCNN

0.807792

0.888354

0.959071

0.847574

0.880837

Измерили время работы на видеокарте (GPU) и на процессоре (CPU):

Таблица 2 Время сегментирования на этапе инференса

CPU, c

GPU, c

PoinNet++

0,38

0,01

DGCNN

1,28

0,04

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

На синтетических данных:

На реальных данных (предварительно отфильтрованных):

Здесь стоит отметить, что на самом деле данное облако точек не является круговым сегментом плоскости, а представляет собой заполнение цилиндрического объема.

В результате мы можем наблюдать следующую картину:

  • DGCNN справляется с задачей сегментации лучше, чем PointNet++;

  • Обученная на синтетических данных модель неудовлетворительно справляется с сегментацией реальных данных.

В качестве этапа предобработки, который мог бы улучшить качество сегментации, можно предложить детекции плоскостей в облаке точек (здесь мы исходим от геометрических предпосылок задачи). Для этого можно использовать RANSAC алгоритмом.

Рис 17. Найденная плоскость внутри облака точек.Рис 17. Найденная плоскость внутри облака точек.

Расчет пространственных характеристик

После того, как мы выделили точки, которые предположительно относятся исключительно только к объекту интереса, мы можем приступать к определению пространственных характеристик. Сама по себе задача определения различных пространственных характеристик облака точек не тривиальна. Так, например, в работе [5] авторы определяют множество точек внутри облака, которые соответствуют границе объекта. А в работе [6]авторы использовали механизм геометрического внимания и глубокие архитектуры для того, чтобы выделять острые края объектов.

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

Вторым подходом является использование готового образца (например гостированный знак в виде параметрической или полигональной модели) для наложения его на имеющиеся облако точек. При таком подходе можно в качестве пространственных характеристик облака использовать пространственные характеристики образца (с поправкой на масштабирование). Такое сопоставление можно производить с помощью ICP алгоритмов, реализация которых есть, например, в trimesh.

Рис 18. Результат наложение образца на облако методом ICP.Рис 18. Результат наложение образца на облако методом ICP.

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

Рис 19. Измерение линейного размера дорожного знака в Cloud Compare.Рис 19. Измерение линейного размера дорожного знака в Cloud Compare.

Заключение

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

Источники

  1. Rusu, Radu Bogdan, et al. Towards 3D point cloud based object maps for household environments. Robotics and Autonomous Systems 56.11 (2008): 927-941. [paper]

  2. Zhang, Wuming, et al. An easy-to-use airborne LiDAR data filtering method based on cloth simulation. Remote Sensing 8.6 (2016): 501. [paper]

  3. Phan, A.V., Le Nguyen, M., Nguyen, Y.L.H. and Bui, L.T., 2018. DGCNN: A convolutional neural network over large-scale labeled graphs. Neural Networks, 108, pp.533-543. [paper]

  4. Qi, C.R., Yi, L., Su, H. and Guibas, L.J., 2017. Pointnet++: Deep hierarchical feature learning on point sets in a metric space. In Advances in neural information processing systems (pp. 5099-5108). [paper]

  5. Mineo C., Pierce S. G., Summan R. Novel algorithms for 3D surface point cloud boundary detection and edge reconstruction //Journal of Computational Design and Engineering. 2019. Т. 6. . 1. С. 81-91. [paper]

  6. Matveev A. et al. Geometric Attention for Prediction of Differential Properties in 3D Point Clouds //IAPR Workshop on Artificial Neural Networks in Pattern Recognition. Springer, Cham, 2020. С. 113-124. [paper]

Подробнее..

Компьютерное зрение в промышленной дефектоскопии Часть 1 Как мы заставляли нейронку пялиться на ржавчину

11.02.2021 14:07:02 | Автор: admin


Сегодня мы хотим поделиться опытом решения задачи детекции дефектов на снимках промышленных объектов методами современного компьютерного зрения.


Наш рассказ будет состоять из нескольких частей:


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

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


Заметка от партнера IT-центра МАИ и организатора магистерской программы VR/AR & AI компании PHYGITALISM.


Описание задачи



Рис 1. Схематичное изображение рассматриваемого проекта.


Машинное обучение (machine learning / ML) в общем и компьютерное зрение (computer vision / CV) в частности находят сегодня все больше применений в решение задач из промышленной области (пример). Начиная от задач нахождения бракованных деталей на конвейере и заканчивая управлением беспилотным транспортом везде используются глубокие архитектуры, позволяющие детектировать многочисленные объекты разных категорий, предсказывать пространственное расположение объектов друг относительно друга и многое другое.


Сегодня мы рассмотрим кейс (проект Defects detector CV) по созданию прототипа программного обеспечения (ПО), которое использует нейронные сети, для того, чтобы на фото или видеопотоке детектировать объекты заданных категорий. В качестве предметной области, в данном проекте, выступила дефектоскопия промышленных труб.



Рис 2.Схематичное изображение парового котла, аналогичного тому, что рассматривался в проекте.


Кратко опишем предметную постановку задачи:


В системах теплового обогрева городов и промышленных предприятий используются специальные паровые котлы (см. пример на рис. 2), внутренность которых пронизана многочисленными трубами, которые в процессе эксплуатации могут получать различные повреждения (разного рода трещины, разрывы, деформации, коррозию и многое другое). Для того, чтобы своевременно устранять повреждения и поддерживать работоспособность котлов, периодически их работа останавливается, из них выкачиваются все жидкости, вскрывается проход во внутреннее пространство котла, которое представляет из себя ряд связанных пространственных отсеков без освещения, способных вместить внутрь себя трехэтажный дом. После производят очистку поверхности труб, выстраивают промышленные леса, чтобы у специалистов по дефектоскопии была возможность получить прямой доступ к трубам, которые они будут осматривать и проверять с помощью специальной аппаратуры. После того как все дефекты обнаружены, производится замена или ремонт поврежденных участков, после чего необходимо разобрать леса, законсервировать котел и снова его запустить.


Зачастую, большую часть времени отнимает сбор и демонтаж промышленных лесов и визуальный осмотр труб специалистами. Для того, чтобы сократить время на выполнение этих этапов было предложено использовать пилотируемый дрон с системой освещения, фото и видеосъемки, который смог бы быстро облететь внутреннее пространство котла (в том числе, небольшие размеры дрона позволяют попасть во внутрь труднодоступных узких шахт, куда человеку сложно проникнуть), собрать данные для обработки, и с помощью алгоритмов компьютерного зрения, выделить все обнаруженные дефекты.


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


Мы постараемся осветить все основные этапы при разработке проекта, связанного с машинным


  • обучением;
  • сбор данных;
  • разметка данных;
  • дополнение данных (аугментация);
  • обучение модели;
  • оценка качества работы модели;
  • подготовка к внедрению.

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


Набор данных



Рис. 3 Пример объекта обучающей выборки фото, сделанное при осмотре внутренности остановленного котла.


Данные в нашей задачи представлены классическим для CV образом в виде цветных RGB снимков. На каждом снимки может как присутствовать сразу несколько дефектов, так и не присутствовать вовсе.


Ниже постараемся ответить на следующие основные вопросы о данных, которые возникают почти во всех проектах, связанных с компьютерным зрением:


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

Виды задач распознавания образов на изображениях



Рис.4 Пример разметки для задачи детекции объектов на изображениях из датасета MS COCO. Иллюстрация из репозитория detectron2.


Сложность задачи в области компьютерного зрения отчасти определяется формой предсказания. Отметим сразу, что задача распознавания образов на изображения логически подразделяется на две подзадачи:


  • выделения области интереса;
  • классификация объекта в области интереса.

В зависимости от формы области интереса, задачи детекции делят на детектирование в виде ограничивающих прямоугольников (bounding boxes), в виде многоугольников, в виде битовых масок, в виде точек интереса и пр.


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


Помимо формы предсказания, также необходимо было определить формат датасета (способ организации данных и аннотаций). Формат датасета обычно определяется группами исследователей и разработчиков, которые создают значимые датасеты или архитектуры. В нашем случае, датасеты рассматривались в форматах MS COCO и YOLO.


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


Про устройство формата MS COCO и формы предсказаний можно узнать здесь.


Разметка данных



Рис. 5 Демонстрация работы CVAT для разметки дефекта трубы в виде полигональной маски.


Для того, чтобы разметить сырые данные существует несколько основных способов. Во-первых, можно воспользоваться услугами сервисов облачной распределенной разметки данных, вроде Amazon Mechanical Turk или Яндекс.Толока, во-вторых, если данные приходят не из реального мира, а генерируются искусственно, то разметку можно генерировать вместе с данными, ну и самым доступным способом является использование специализированного ПО для разметки данных.


В нашей задаче, мы воспользовались вторым и третьим способами. Про наш генератор синтетических данных мы расскажем отдельно во второй части. В качестве ПО для разметки мы выбрали Intel CVAT (заметка про инструмент на хабр), который был развернут на сервере заказчика.


Некоторые альтернативные инструменты разметки:



Усиление обобщающей способности


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



Рис. 5.1 Изображение из сообщества Memes on Machine Learning for Young Ladies. Там же можно увидеть пример того как не нужно делать аугментации.


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


Подробнее про примеры аугментации данных в задачах компьютерного зрения можно прочитать здесь и здесь.


Метрики качества


Для того, чтобы измерять качество работы алгоритма после процесса обучения на тестовой выборке в задачах детекции объектов на изображениях традиционно используют метрику mean average precision (mAP), рассчитанную для каждого класса по отдельности и усредненную для всех классов. Значение этой метрики рассчитываются при разных уровнях характеристики Intersection over Union (IoU). Здесь мы не будем подробно останавливаться на разъяснении устройства этих функций, всем заинтересованным предлагаем пройти по ссылкам ниже на статьи и заметки, которые помогут освоится в данном вопросе, но все же поясним некоторые основные моменты оценки качества работы алгоритмов в нашей задаче.


Для оценки результатов были выбраны следующие метрики:


  • mAP (mean average precision) среднее значение точности по всем классам (поскольку у термина могут быть разные трактовки, рекомендуем ознакомится с различными вариантами здесь).
  • AP (средняя точность) средняя точность по каждому отдельному классу.
  • Precision Recall кривая.
  • Число случаев когда дефект был обнаружен и он на самом деле был (TP).
  • Число случаев когда дефект был обнаружен, но его не было на самом деле (FP) т. е. ложное срабатывание.

Расчет метрик производился следующим образом. Так как целевым объектом для оценки был ограничивающий прямоугольник (bounding box), то интерес для оценки представляет три свойства:


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

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


Рассмотрим пример вычисления метрик на основе примера из рис. ниже. Для этого определяется величина IoU, которая равна отношению площади пересечения прямоугольников (серый прямоугольник) к площади их объединения. Она принимает значения в отрезке [0;1]. Можно выбрать определённый порог и считать, что при превышении этого порога прямоугольники совпадают.


Определение TP:
Если IoU больше определенного порога и метки классов совпадают, то предсказание считается правильным.


Определение FP:
Если IoU меньше определенного порога и метки классов совпадают, то предсказание считается ложным.


На основании этих показателей рассчитывается точность и полнота. Если кратко, то точность показывает насколько хорошо модель предсказывает дефекты определенного класса из тех которые были обнаружены вообще. Чем больше значение, тем меньше ошибок совершается. Значение в отрезке от [0;1].



Рис. 6 Пример рассчитанной Precision-Recall кривой для одного из классов дефектов для архитектуры DetectoRS.


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



Рис. 7 Сравнение технических метрик для выбранных архитектур для процесса обучения.


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


Заметку с примерами и объяснениями всей терминологии про метрики качества в CV можно посмотреть здесь.


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



*Рис. 8 Сравнение технических метрик для выбранных архитектур для процесса использования.* тестирование проводилось на видеокарте RTX 2080 Ti, тестирование проводилось на CPU AMD Ryzen 7 2700X Eight-Core Processor.*


Деление данных на обучающую и тестовую выборку


Для тестирования алгоритмов и оценки качества их работы часто нужно поделить данные на несколько частей. Одна часть используется при обучении, а другая для проверки обобщающей способности и подсчета метрик. Обычно это не представляет проблемы, но в нашем случае ситуация сложнее, т. к. каждое изображение (объект) может содержать несколько классов и в разном количестве. Изображение атомарно и мы не можем его как-то разделить логически, чтобы число примеров каждого класса поделилось в нужном соотношении. Тут стоит заметить, что фактически можно разделить изображение на множество отдельных частей, в которых есть только один класс, но это приведёт к уничтожению изначальной структуры изображений.


Рассмотрим пример, изображенный на рис. 9 случай, когда каждый объект принадлежит одному классу:

Рис. 9 Деление данных на тестовую и обучающую выборку.


Особой проблемы здесь нет и разделение на две выборке можно сделать достаточно просто. В нашем же случае картина с распределением объектов и классов будет такая:

Рис. 10 Каждый объект может содержать иметь несколько классов.


Для решения проблемы разделения такого вида данных на подвыборки была использована библиотека scikit-multilearn и метод iterative_train_test_split. На вход подавалась матрица из нулей и единиц. Каждая строка обозначала изображение. Единицы стояли в столбцах с номерами соответствующими номерам классов. Если применить функцию к объектам на рис. выше, то получится следующее разделение:

Рис. 11 Результат разделения на тестовую и обучающую выборку.


Конечно, здесь не учитывается количество повторений классов в рамках одного изображения (объекта), поэтому деление может быть несбалансированным.


Выбор архитектуры


На основе результатов анализа известных архитектур собранных на paperwithcode (на момент 3 квартала 2020 года) для детектирования дефектов были выбраны две архитектуры:




Рис. 12 Сравнение архитектур на бенчмарке MS COCO object detection с сайта papesrwithcode (3 квартал 2020 года).



Рис.13 Сравнение архитектур на бенчмарке MS COCO, полученное авторами архитектуры YOLOv4.


YOLOv4 попала в этот список из-за своей скорости работы. Мы хотели посмотреть на результаты разных моделей и выбрать итоговый вариант в зависимости от требований. Потенциально могла быть потребность в обработке видео и для этого случая планировалось использовать YOLOv4. Более точная, но медленная работа ожидалась от DetectoRS.


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


DetectoRS


Данная архитектура базируется на использовании специального типа сверток (Switchable Atrouse Convolution / SAC) и в верхнем уровне устроена в виде рекурсивной пирамиды (Recursive Feature Pyramid / RFP), объединяющий локальные и глобальные признаки.



Рис. 14 Основные нововведения, используемые авторами архитектуры DetectoRS: (a) рекурсивная пирамида признаковых описаний, используемая для объединения глобальных признаков на изображении; (b) переключательные свертки типа atrouse для работы с локальными признаками.


Реализация данной модели присутствует внутри фреймворка MMDetection.
Об устройстве архитектуры можно прочитать здесь.


YOLOv4


Эта модель делает свои предсказания на основе анализа изображения, разбивая его на квадратную сетку как на рис. ниже:

Рис. 15 Принцип работы из оригинальной статьи про YOLO.


Видео с объяснением работы можно найти здесь.


YOLOv4 это дальнейшее улучшение (четвертая версия) оригинальной архитектуры как с точки зрения устройства так и процесса обучения. В данной статье про YOLOv4 исследуются как различные техники аугментации изображений влияют на конечный результат.


Фреймворки для обучения моделей в задачах CV


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


Для разработки под Python, двумя наиболее популярными фреймворками являются MMdetection (open source) и Detectron2 (Facebook research). Для разработки под C, существует фреймворк Darknet (open source). Подробнее про то, как использовать данные фреймворки можно прочитать в заметках один, два, три.


MMDetection


Поскольку архитектура DetectoRS имела единственную реализацию на момент работы над проектом и эта реализация была написана на фреймворке MMDetection, имплементация архитектуры была основана на использовании данного фреймворка.


Устройство фреймворка


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


  • подготовить веса при тренированной модели в формате .pth или прописать самостоятельно инициализацию новых весов;
  • написать конфигурационный файл в виде Python скрипта со всеми настройками для сети и описание хода обучения, валидации и пр.;
  • выбрать способ логирования процесса обучения (доступна запись в текстовый файл и логирование с помощью tensorboard);
  • организовать данные в файловой системе согласно выбранному типу разметки (доступны MS COCO, Pascal VOC и поддерживается возможность внедрение пользовательских форматов);
  • написать основный скрипт, собирающий воедино все перечисленные выше составные части.

После тестов локально на компьютере, на котором была установлена и развернута среда для работы с MMDetection, аналогично YOLOv4, сборка была перенесена внутрь NVidia Docker контейнера.


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


Наш конфигурационный файл для обучения на данных с трубами для 9 классов дефектов:
# Обучения на 9 классах без масокmodel = dict(    type='CascadeRCNN',    pretrained='torchvision://resnet50',    backbone=dict(        type='DetectoRS_ResNet',        depth=50,        num_stages=4,        out_indices=(0, 1, 2, 3),        frozen_stages=1,        norm_cfg=dict(type='BN', requires_grad=True),        norm_eval=True,        style='pytorch',        conv_cfg=dict(type='ConvAWS'),        sac=dict(type='SAC', use_deform=True),        stage_with_sac=(False, True, True, True),        output_img=True),    neck=dict(        type='RFP',        in_channels=[256, 512, 1024, 2048],        out_channels=256,        num_outs=5,        rfp_steps=2,        aspp_out_channels=64,        aspp_dilations=(1, 3, 6, 1),        rfp_backbone=dict(            rfp_inplanes=256,            type='DetectoRS_ResNet',            depth=50,            num_stages=4,            out_indices=(0, 1, 2, 3),            frozen_stages=1,            norm_cfg=dict(type='BN', requires_grad=True),            norm_eval=True,            conv_cfg=dict(type='ConvAWS'),            sac=dict(type='SAC', use_deform=True),            stage_with_sac=(False, True, True, True),            pretrained='torchvision://resnet50',            style='pytorch')),    rpn_head=dict(        type='RPNHead',        in_channels=256,        feat_channels=256,        anchor_generator=dict(            type='AnchorGenerator',            scales=[8],            ratios=[0.5, 1.0, 2.0],            strides=[4, 8, 16, 32, 64]),        bbox_coder=dict(            type='DeltaXYWHBBoxCoder',            target_means=[0.0, 0.0, 0.0, 0.0],            target_stds=[1.0, 1.0, 1.0, 1.0]),        loss_cls=dict(            type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),        loss_bbox=dict(            type='SmoothL1Loss', beta=0.1111111111111111, loss_weight=1.0)),    roi_head=dict(        type='CascadeRoIHead',        num_stages=3,        stage_loss_weights=[1, 0.5, 0.25],        bbox_roi_extractor=dict(            type='SingleRoIExtractor',            roi_layer=dict(type='RoIAlign', out_size=7, sample_num=0),            out_channels=256,            featmap_strides=[4, 8, 16, 32]),        bbox_head=[            dict(                type='Shared2FCBBoxHead',                in_channels=256,                fc_out_channels=1024,                roi_feat_size=7,                num_classes=9,                bbox_coder=dict(                    type='DeltaXYWHBBoxCoder',                    target_means=[0.0, 0.0, 0.0, 0.0],                    target_stds=[0.1, 0.1, 0.2, 0.2]),                reg_class_agnostic=True,                loss_cls=dict(                    type='CrossEntropyLoss',                    use_sigmoid=False,                    loss_weight=1.0),                loss_bbox=dict(type='SmoothL1Loss', beta=1.0,                               loss_weight=1.0)),            dict(                type='Shared2FCBBoxHead',                in_channels=256,                fc_out_channels=1024,                roi_feat_size=7,                num_classes=9,                bbox_coder=dict(                    type='DeltaXYWHBBoxCoder',                    target_means=[0.0, 0.0, 0.0, 0.0],                    target_stds=[0.05, 0.05, 0.1, 0.1]),                reg_class_agnostic=True,                loss_cls=dict(                    type='CrossEntropyLoss',                    use_sigmoid=False,                    loss_weight=1.0),                loss_bbox=dict(type='SmoothL1Loss', beta=1.0,                               loss_weight=1.0)),            dict(                type='Shared2FCBBoxHead',                in_channels=256,                fc_out_channels=1024,                roi_feat_size=7,                num_classes=9,                bbox_coder=dict(                    type='DeltaXYWHBBoxCoder',                    target_means=[0.0, 0.0, 0.0, 0.0],                    target_stds=[0.033, 0.033, 0.067, 0.067]),                reg_class_agnostic=True,                loss_cls=dict(                    type='CrossEntropyLoss',                    use_sigmoid=False,                    loss_weight=1.0),                loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))        ],        train_cfg=[            dict(                assigner=dict(                    type='MaxIoUAssigner',                    pos_iou_thr=0.5,                    neg_iou_thr=0.5,                    min_pos_iou=0.5,                    match_low_quality=False,                    ignore_iof_thr=-1),                sampler=dict(                    type='RandomSampler',                    num=512,                    pos_fraction=0.25,                    neg_pos_ub=-1,                    add_gt_as_proposals=True),                pos_weight=-1,                debug=False),            dict(                assigner=dict(                    type='MaxIoUAssigner',                    pos_iou_thr=0.6,                    neg_iou_thr=0.6,                    min_pos_iou=0.6,                    match_low_quality=False,                    ignore_iof_thr=-1),                sampler=dict(                    type='RandomSampler',                    num=512,                    pos_fraction=0.25,                    neg_pos_ub=-1,                    add_gt_as_proposals=True),                pos_weight=-1,                debug=False),            dict(                assigner=dict(                    type='MaxIoUAssigner',                    pos_iou_thr=0.7,                    neg_iou_thr=0.7,                    min_pos_iou=0.7,                    match_low_quality=False,                    ignore_iof_thr=-1),                sampler=dict(                    type='RandomSampler',                    num=512,                    pos_fraction=0.25,                    neg_pos_ub=-1,                    add_gt_as_proposals=True),                pos_weight=-1,                debug=False)        ],        test_cfg=dict(            score_thr=0.05, nms=dict(type='nms', iou_thr=0.5),            max_per_img=100)))train_cfg = dict(    rpn=dict(        assigner=dict(            type='MaxIoUAssigner',            pos_iou_thr=0.7,            neg_iou_thr=0.3,            min_pos_iou=0.3,            match_low_quality=True,            ignore_iof_thr=-1),        sampler=dict(            type='RandomSampler',            num=256,            pos_fraction=0.5,            neg_pos_ub=-1,            add_gt_as_proposals=False),        allowed_border=0,        pos_weight=-1,        debug=False),    rpn_proposal=dict(        nms_across_levels=False,        nms_pre=2000,        nms_post=2000,        max_num=2000,        nms_thr=0.7,        min_bbox_size=0),    rcnn=[        dict(            assigner=dict(                type='MaxIoUAssigner',                pos_iou_thr=0.5,                neg_iou_thr=0.5,                min_pos_iou=0.5,                match_low_quality=False,                ignore_iof_thr=-1),            sampler=dict(                type='RandomSampler',                num=512,                pos_fraction=0.25,                neg_pos_ub=-1,                add_gt_as_proposals=True),            pos_weight=-1,            debug=False),        dict(            assigner=dict(                type='MaxIoUAssigner',                pos_iou_thr=0.6,                neg_iou_thr=0.6,                min_pos_iou=0.6,                match_low_quality=False,                ignore_iof_thr=-1),            sampler=dict(                type='RandomSampler',                num=512,                pos_fraction=0.25,                neg_pos_ub=-1,                add_gt_as_proposals=True),            pos_weight=-1,            debug=False),        dict(            assigner=dict(                type='MaxIoUAssigner',                pos_iou_thr=0.7,                neg_iou_thr=0.7,                min_pos_iou=0.7,                match_low_quality=False,                ignore_iof_thr=-1),            sampler=dict(                type='RandomSampler',                num=512,                pos_fraction=0.25,                neg_pos_ub=-1,                add_gt_as_proposals=True),            pos_weight=-1,            debug=False)    ])test_cfg = dict(    rpn=dict(        nms_across_levels=False,        nms_pre=1000,        nms_post=1000,        max_num=1000,        nms_thr=0.7,        min_bbox_size=0),    rcnn=dict(        score_thr=0.05, nms=dict(type='nms', iou_thr=0.5), max_per_img=100))dataset_type = 'CocoDataset'data_root = 'data/coco/'classes = ('ПРМУ_поперечная трещина на изгибе', 'ПРМУ_выход трубы из ряда',           'ПРМУ_Крип', 'ПРМУ_свищи', 'ПРМУ_разрыв трубы',           'ПРМУ_поперечная трещина в околошовной зоне',           'ПРМУ_трещина в основном металле', 'ПРМУ_продольные трещины',           'ПРМУ_Цвета побежалости')img_norm_cfg = dict(    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)train_pipeline = [    dict(type='LoadImageFromFile'),    dict(type='LoadAnnotations', with_bbox=True),    dict(type='Resize', img_scale=(1280, 720), keep_ratio=True),    dict(type='RandomFlip', flip_ratio=0.5),    dict(        type='Normalize',        mean=[123.675, 116.28, 103.53],        std=[58.395, 57.12, 57.375],        to_rgb=True),    dict(type='Pad', size_divisor=32),    dict(type='DefaultFormatBundle'),    dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels'])]test_pipeline = [    dict(type='LoadImageFromFile'),    dict(        type='MultiScaleFlipAug',        img_scale=(1280, 720),        flip=False,        transforms=[            dict(type='Resize', keep_ratio=True),            dict(type='RandomFlip'),            dict(                type='Normalize',                mean=[123.675, 116.28, 103.53],                std=[58.395, 57.12, 57.375],                to_rgb=True),            dict(type='Pad', size_divisor=32),            dict(type='ImageToTensor', keys=['img']),            dict(type='Collect', keys=['img'])        ])]data = dict(    samples_per_gpu=2,    workers_per_gpu=1,    train=dict(        type='CocoDataset',        classes=('ПРМУ_поперечная трещина на изгибе',                 'ПРМУ_выход трубы из ряда', 'ПРМУ_Крип', 'ПРМУ_свищи',                 'ПРМУ_разрыв трубы',                 'ПРМУ_поперечная трещина в околошовной зоне',                 'ПРМУ_трещина в основном металле', 'ПРМУ_продольные трещины',                 'ПРМУ_Цвета побежалости'),        ann_file='data/coco/annotations/instances_train.json',        img_prefix='data/coco/train/',        pipeline=[            dict(type='LoadImageFromFile'),            dict(type='LoadAnnotations', with_bbox=True),            dict(type='Resize', img_scale=(1280, 720), keep_ratio=True),            dict(type='RandomFlip', flip_ratio=0.5),            dict(                type='Normalize',                mean=[123.675, 116.28, 103.53],                std=[58.395, 57.12, 57.375],                to_rgb=True),            dict(type='Pad', size_divisor=32),            dict(type='DefaultFormatBundle'),            dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels'])        ]),    val=dict(        type='CocoDataset',        classes=('ПРМУ_поперечная трещина на изгибе',                 'ПРМУ_выход трубы из ряда', 'ПРМУ_Крип', 'ПРМУ_свищи',                 'ПРМУ_разрыв трубы',                 'ПРМУ_поперечная трещина в околошовной зоне',                 'ПРМУ_трещина в основном металле', 'ПРМУ_продольные трещины',                 'ПРМУ_Цвета побежалости'),        ann_file='data/coco/annotations/instances_val.json',        img_prefix='data/coco/val/',        pipeline=[            dict(type='LoadImageFromFile'),            dict(                type='MultiScaleFlipAug',                img_scale=(1280, 720),                flip=False,                transforms=[                    dict(type='Resize', keep_ratio=True),                    dict(type='RandomFlip'),                    dict(                        type='Normalize',                        mean=[123.675, 116.28, 103.53],                        std=[58.395, 57.12, 57.375],                        to_rgb=True),                    dict(type='Pad', size_divisor=32),                    dict(type='ImageToTensor', keys=['img']),                    dict(type='Collect', keys=['img'])                ])        ]),    test=dict(        type='CocoDataset',        classes=('ПРМУ_поперечная трещина на изгибе',                 'ПРМУ_выход трубы из ряда', 'ПРМУ_Крип', 'ПРМУ_свищи',                 'ПРМУ_разрыв трубы',                 'ПРМУ_поперечная трещина в околошовной зоне',                 'ПРМУ_трещина в основном металле', 'ПРМУ_продольные трещины',                 'ПРМУ_Цвета побежалости'),        ann_file='data/coco/annotations/instances_val.json',        img_prefix='data/coco/val/',        pipeline=[            dict(type='LoadImageFromFile'),            dict(                type='MultiScaleFlipAug',                img_scale=(1280, 720),                flip=False,                transforms=[                    dict(type='Resize', keep_ratio=True),                    dict(type='RandomFlip'),                    dict(                        type='Normalize',                        mean=[123.675, 116.28, 103.53],                        std=[58.395, 57.12, 57.375],                        to_rgb=True),                    dict(type='Pad', size_divisor=32),                    dict(type='ImageToTensor', keys=['img']),                    dict(type='Collect', keys=['img'])                ])        ]))evaluation = dict(interval=1, metric='bbox')optimizer = dict(type='SGD', lr=0.0001, momentum=0.9, weight_decay=0.0001)optimizer_config = dict(grad_clip=None, type='OptimizerHook')lr_config = dict(    policy='step',    warmup=None,    warmup_iters=500,    warmup_ratio=0.001,    step=[8, 11],    type='StepLrUpdaterHook')total_epochs = 12checkpoint_config = dict(interval=-1, type='CheckpointHook')log_config = dict(    interval=10,    hooks=[dict(type='TextLoggerHook'),           dict(type='TensorboardLoggerHook')])dist_params = dict(backend='nccl')log_level = 'INFO'load_from = './checkpoints/detectors_cascade_rcnn_r50_1x_coco-32a10ba0.pth'resume_from = Noneworkflow = [('train', 1)]work_dir = './logs'seed = 0gpu_ids = range(0, 1)

Обучение модели


Обучение модели занимало порядка 2 часов на RTX 2080 Ti. Прогресс можно было отслеживать с помощью запущенного tensorboard. Ниже приведены графики эволюции метрик и функции ошибки в процессе обучения на реальных данных.



Рис. 16 Зависимость mAP от числа итераций обучения для архитектуры DetectoRS для датасета дефектов труб по 9 классам на валидационном датасете.



Рис. 17 Зависимость функции потерь (multiclass cross entropy) от числа итераций обучения для архитектуры DetectoRS для датасета дефектов труб по 9 классам.


Подготовка модели для использования


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


Стоит отметить, что, несмотря на то, что данная архитектура обучается в несколько раз быстрее чем YOLOv4, она занимает в 2 раза больше памяти (500 MB для DetectoRS против 250 MB для YOLOv4 для хранения весов модели) и работает на порядок медленнее (1 с. для DetectoRS против 10 мс. для YOLOv4).


Малое время обучения DetectoRS отчасти объясняется тем, что веса базовых слоев сети (backbone и neck) были взяты из претренированной на ImageNet датасете аналогичной архитектуры и в процессе обучения не изменялись. Такой прием называется transfer learning. Про него вы можете подробнее прочитать в этой заметке.


Darknet


Оригинальная реализация YOLOV4 написана на C c использованием CUDA C. Было принято решение использовать оригинальную реализацию модели, хотя обычно доминируют эксперименты на Python. Это накладывало свои ограничения и риски, связанные с необходимость разбираться в коде на C, в случае каких-то проблем или переделки частей под свои нужды. Подробной документации с примерами не было, поэтому пришлось в некоторых местах смотреть исходный код на C.
Для успешного запуска нужно было решить несколько проблем:


  1. Собрать проект.
  2. Понять что необходимо для обучения модели.
  3. Обучить модель.
  4. Подготовить код для использования.

Сборка проекта


Первая сборка проекта происходила на Windows. Для сборки использовался CMake, поэтому особых проблем с этим не возникло. Единственная проблема была с компиляцией динамической библиотеки для обёртки на Python. Пришлось редактировать файл с проектом для Visual Studio, чтобы включить поддержку CUDA. Динамическая библиотека была нужна т. к. это позволяло использовать код на Python для запуска модели.


После было принято решение перенести сборку внутрь Docker контейнера. Для того чтобы оставить возможность использовать видеокарту был установлен NVIDIA Container Toolkit. Это позволяет достаточно просто организовать перенос проекта на другую машину при необходимости, а также упрощает дальнейшее использование. Благодаря наличию различных образов nvidia/cuda на Docker Hub, можно достаточно просто менять конфигурации. Например, переключение между различными версиями CUDA или cuDNN.


Необходимые файлы для обучения


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


Обучение модели


Обучение модели производилось в контейнере NVIDIA Docker. Занимало порядка 12 часов на RTX 2080 Ti. Прогресс можно было отслеживать периодически копируя график функции потерь из контейнера на хост, где запущен контейнер. Красным показано значение mAP на тестовой выборке.



Рис. 18 График обучения YOLOv4.


Подготовка модели для использования


После обучения модели была необходимость в ее использовании для визуализации результатов. От кода на Python пришлось отказаться т. к. были проблемы с неожиданным завершением программы. Некоторые части кода пришлось дописать на языке С под собственные нужды.


Результаты


После всех экспериментов были выявлены следующие зависимости:


  • Обучение на смеси данных (реальные + искусственные) приводит к небольшому ухудшению обобщающей способности (это связано с тем, что в данной итерации генератора синтетических данных присутствуют недостаточно разнообразные данные и однотипное освещение);
  • После недолгого подбора гиперпараметров для архитектуры DetectoRS удалось добиться показателя $mAP (IoU=0.5) = 0.85$, а для архитектуры YOLOv4 $mAP(IoU=0.5) = 0.74$ ;
  • Некоторые типы дефектов, такие как разного рода трещины или выход труб из ряда, детектируются лучше чем иные типы дефектов, такие как вздутие труб. Это можно объяснить не только дисбалансом и малым количеством примеров, но и тем, что для определения некоторых типов дефектов, нужно больше пространственной информации (аналогично этому, в реальной детекции дефектов, некоторые дефекты определяются на глаз, а некоторые требуют специальных измерительных приборов). Потенциально, использование помимо RGB каналов с камеры также еще и канала глубины (RGB-D) могло бы помочь с детектированием этих сложных пространственных дефектов: в этом случае мы смогли бы прибегнуть к методам и алгоритмама 3D ML.


Рис. 19 Сравнение работы архитектур, обученных на разных датасетах: Real только реальные изображение, Mixed обучении на смеси реальных и синтетических изображений, Mask обучения на реальных изображениях, с многоугольной разметкой областей.



Рис. 20 Пример некорректной детекции модели DetectoRS, обученной на синтетических данных отсутствие посторонних предметов в синтетическом датасете приводит к определению куска деревянной балки как трещины.



Рис. 21 Пример детекции дефектов в виде многоугольных масок модели DetectoRS, обученной на датасете реальных изображений с соответствующей разметкой.



Рис. 22 Пример детекции дефектов в виде прямоугольников для одного и того же изображения с помощью разных архитектур.


Финальное решение с интерфейсом


В итоге, был получен работающий прототип ПО с интерфейсом, который можно было бы просто использовать как со стороны пользователя так и для разработчиков. Так как проекты на основе ML часто требуют вычислительных мощностей видеокарт NVIDIA для своей работы, то было принято решение сделать клиент-серверное приложение. При необходимости всё можно развернуть на одном компьютере. Если же есть в наличии свободный сервер с видеокартой, то основную логику можно перенести туда, оставив возможность любым пользователям использовать сервис даже на слабом по вычислительным возможностям компьютере.


Для архитектуры ПО была выбрана следующая схема:
Финальное решение с интерфейсом
В итоге, был получен работающий прототип ПО с интерфейсом, который можно было бы просто использовать как со стороны пользователя так и для разработчиков. Так как проекты на основе ML часто требуют вычислительных мощностей видеокарт NVIDIA для своей работы, то было принято решение сделать клиент-серверное приложение. При необходимости всё можно развернуть на одном компьютере. Если же есть в наличии свободный сервер с видеокартой, то основную логику можно перенести туда, оставив возможность любым пользователям использовать сервис даже на слабом по вычислительным возможностям компьютере.


Для архитектуры ПО была выбрана следующая схема:

Рис. 23 Схема архитектуры прототипа ПО для детектирования дефектов на изображениях.


Все модели для детектирования дефектов работают внутри NVIDIA Docker. Остальные части, кроме Web-интерфейса внутри обычных контейнеров Docker. Логика работы следующая:


  1. Пользователь загружает изображение и выбирает нужную модель вместе с порогом принятия решения.
  2. Изображение отправляется на сервер. Оно сохраняется на диске и сообщение с заданием на обработку попадает в RabbitMQ, в соответствующую очередь.
  3. Модель берёт сообщение с заданием из очереди, когда готова выполнить предсказание. Выполняет предсказание и сохраняет необходимые файлы на диск. Отправляет сообщение в RabbitMQ о готовности результат.
  4. Когда результат готов он отображается в web-интерфейсе.

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


RabbitMQ также позволяет изолировать систему друг от друга и начать разработку независимо. При разработке сервера не надо дожидаться реализации ML моделей и наоборот. Каждая система общается только с RabbitMQ. В случае падения какого-то сервиса сообщение не потеряется, если соответствующим образом настроить RabbitMQ.



Рис. 24 Демонстрация работы созданного прототипа ПО для детекции дефектов на трубах.


В заключении, отметим, что при разработке ПО, в котором используются модели машинного обучения, требуется очень много обмениваться данными и целыми пайплайнами эксперементов с членами команды. Для того, чтобы это было удобно делать мы пользовались на протяжении всего проекта системой DVC. Примеры использования этой системы контроля данных и моделей машинного обучения можно посмотреть в этой статье на хабре.


Основные источники


Статьи описывающие SOTA глубокие архитектуры в задаче детекции:

Статьи, посвященные выбору метрик качества в задачах детекции объектов на изображениях:

Фундаментальные монографии на тему современного компьютерного зрения:
  • Szeliski, R., 2010. Computer vision: algorithms and applications. Springer Science & Business Media.
  • Nixon, M. and Aguado, A., 2019. Feature extraction and image processing for computer vision. Academic press.
  • Jiang, X. ed., 2019. Deep Learning in Object Detection and Recognition. Springer.
  • Pardo, A. and Kittler, J. eds., 2015. Progress in Pattern Recognition, Image Analysis, Computer Vision, and Applications: 20th Iberoamerican Congress, CIARP 2015, Montevideo, Uruguay, November 9-12, 2015, Proceedings (Vol. 9423). Springer.
Подробнее..

Дополненная реальность для проектов механики применения и эффект для бизнеса

21.04.2021 16:08:09 | Автор: admin

Как не запутаться в большом объеме информации о дополненной реальности, где ее применять и как она работает?

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


Заметка от партнера IT-центра МАИ и организатора магистерской программы VR/AR & AI компанииPHYGITALISM.

Что вы будете знать после прочтения?

  • Как работает AR, механики применения;

  • Возможности дополненной реальности;

  • Обязательно ли скачивать приложение, чтобы просмотреть контент в дополненной реальности, какие платформы еще можно использовать;

  • Тренды развития AR.

  • Новые и интересные кейсы с бизнес-метриками и актуальную аналитику.

Подробнее о содержимом whitepaper

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

1. Механики дополненной реальности

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

AR-механика это способ показа контента. В нашем whitepaper мы описали привязку к маркеру, плоскости, геолокации и физическому объекту, а также механику порталов, и привели примеры к каждому из них :)

2. Возможности дополненной реальности

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

3. Платформы для реализации

В каждом проекте мы должны понимать, кто наша целевая аудитория, так как от этого будет зависеть то, где наш AR-контент можно будет увидеть. Для понимания всех различий мы добавили примеры и преимущества каждой платформы, а также ранее составляли сравнение.

4. Тренды и подборка приложений

Если вы хотите быть в курсе новейших разработок и материалов, мы также выделили тренды в развитии технологий (спойлер: связка дополненной реальности и машинного обучения становится все сильнее). А еще есть подборка крутых приложений для тестов и вдохновения :)

Мы давно выпускаем материалы по VR и AR-технологиям для бизнеса, поэтому также советуем к прочтению:

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

Давайте вдохновляться на проекты вместе.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru