Вот и наступил новый этап в развии Raspberry-танка.

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

Мозговой штурм и комментарии позволили определить следующие направления развития:

  • обучить собственную E-net сеть под нужный размер картинок
  • передать запуск нейросети с самой Raspberry на специальную железку, из которых наиболее часто упоминался Intel Movidius (он же Neural Compute Stick aka NCS).

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

Несколько дней — и интеловская чудо-железка у меня в руках.

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

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

На этом hardware часть была завершена.



Intel NCS


Интел недавно выпустил вторую версию NCS, причем API оказался полностью несовместим с предыдущей версией, о чем пользователи излили немало боли в интернете.

Как следствие, вся база знаний о предыдущей версии в настоящее время является просто информационным мусором.

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

Вот несколько вводных статей по NCS2 и OpenVino:


Начало работы с NCS оказалось вполне себе гладким.

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

Приятным бонусом оказалось, что в OpenVino входит OpenCV 4.1, это экономит время, так как предыдущие версии OpenCV мне пришлось собирать на Raspberry самостоятельно.

Вот как выглядит NCS2 сам по себе:



Дальше оказалось интереснее.

NCS поддерживает только свой собственный формат нейросетей, а Интел предоставляет инструмент Model Optimizer в составе OpenVino для конвертации графов самых популярных фреймворков: Tensorflow, Caffe, Torch. Подробнее про это будет дальше.

Кроме того, Интел также предоставляет model zoo — набор готовых моделей на многие случаи жизни.

Среди них были две модели для дорожной сегментации:


Нейросети на NCS


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

Инициализировать девайс


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

from openvino.inference_engine import IENetwork, IEPlugin

ncs_plugin = IEPlugin(device="MYRIAD", plugin_dirs="/opt/intel/openvino/inference_engine/lib/armv7l")

Загрузить модель


Дальше надо загрузить модель на девайс.

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

Хорошие новости в том, что загружать модель нужно только раз и можно загрузить несколько моделей.

        model = IENetwork(model=xml_path, weights=bin_path)
        net = ncs_plugin.load(network=model)

Запустить расчет


Теперь модель можно использовать.

    input_blob = next(iter(model.inputs))
    out_blob = next(iter(model.outputs))
    n, c, h, w = model.inputs[input_blob].shape
    images = np.ndarray(shape=(n, c, h, w))
    images[0] = image
    res = net.infer(inputs={input_blob: images})
    res = res[out_blob]

Однопроцессность


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

E: [ncAPI] [    684447] resetAll:348     Failed to connect to stalled device, rc: X_LINK_ERROR
E: [ncAPI] [    691700] ncDeviceOpen:672        Failed to find suitable device, rc: X_LINK_DEVICE_NOT_FOUND
Traceback (most recent call last):
    net = ncs_plugin.load(network=model)
  File "ie_api.pyx", line 395, in openvino.inference_engine.ie_api.IEPlugin.load
  File "ie_api.pyx", line 406, in openvino.inference_engine.ie_api.IEPlugin.load
RuntimeError: Can not init USB device: NC_ERROR

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

Сегментация OpenVino


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

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

Enet работал лучше, но запустить Enet под NCS надо еще постараться, так что попробуем с тем что есть.



Что интересно, узнать больше о модели из OpenVino и переобучить ее не так то просто.

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

По скорости преимущество очень значительно:
Если у Enet сегментация занимала 6 секунд, то у этой модели на обработку одной картинки уходило 0.8 секунд (при этом 14 секунд занимала загрузка модели на девайс, но это делается единовременно).

Классификация направлений


Для принятие решений о направлении движения танк использует простую нейросеть, как описано в соотвествующей статье.

Нейросеть обучена на Keras и работает на Raspberry через Tensorflow, который имеет встроенный адаптер для этого формата.

Модель очень простая и даже на Raspberry показывает приемлемые по скорости результаты.
(0.35 секунд на картинку).

Тем не менее, имея интеловскую железку, можно рассчитывать добиться лучших результатов.
Среди форматов, которые принимает интеловский Model Optimizer для конвертации, есть Tensorflow, но нет Keras.

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

У этого же автора есть более обширная статья, как раз на тему, как модель Keras запустить на OpenVino.

Еще можно воспользоваться руководством от Интела.

В общем, скомпилировав источники, я получил такой скрипт для преобразования модели Keras в TF:

import tensorflow as tf
from tensorflow.python.framework.graph_util import convert_variables_to_constants
from keras import backend as K
from keras.models import load_model
from keras.models import model_from_json

def load_keras_model(json_file, model_file):
    jf = open(json_file, 'r')
    loaded_model_json = jf.read()
    jf.close()
    loaded_model = model_from_json(loaded_model_json)
    loaded_model.load_weights(model_file)
    return loaded_model

def freeze_session(session, keep_var_names=None, output_names=None, clear_devices=True):
    graph = session.graph
    with graph.as_default():
        freeze_var_names = list(set(v.op.name for v in tf.global_variables()).difference(keep_var_names or []))
        output_names = output_names or []
        output_names += [v.op.name for v in tf.global_variables()]
        # Graph -> GraphDef ProtoBuf
        input_graph_def = graph.as_graph_def()
        if clear_devices:
            for node in input_graph_def.node:
                node.device = ""
        frozen_graph = convert_variables_to_constants(session, input_graph_def,
                                                      output_names, freeze_var_names)
        return frozen_graph


model = load_keras_model('./model.json', './model.h5')
frozen_graph = freeze_session(K.get_session(),
                              output_names=[out.op.name for out in model.outputs])
tf.train.write_graph(frozen_graph, ".", "ktf_model.pb", as_text=False)

Этот же код лежит на гитхабе.

Получившуюся TF-модель дальше перегоняем в OpenVino формат:

python mo_tf.py --input_model "model/ktf_model.pb" --log_level=DEBUG -b1 --data_type FP16

Тесты показали, что классификация картинки проходит за 0.007 секунд.
Такой результат очень радует.

Все обученные модели (Keras, TF, OpenVino) также выложены на гитхаб.

Распознавание объектов


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

В начале был детектор кота, который потом вырос в универсальный детектор на основе MobileSSD и OpenCV-DNN.

Теперь пришла пора покрутить эту же задачу на NCS.

В интеловском model_zoo достаточно детекторов более узкой специфики на основе MobileSSD, но точный аналог отсутствует.

Тем не менее, эта сеть указана как совместимая в списке поддерживаемых моделей TF.

Что интересно, на момент написания статьи здесь указана версия MobileSSD 2018_01_28.

Однако, читать эту модель OpenCV отказывается:

cv2.error: OpenCV(4.1.0-openvino) /home/jenkins/workspace/OpenCV/OpenVINO/build/opencv/modules/dnn/src/tensorflow/tf_importer.cpp:530: 
error: (-2:Unspecified error) Const input blob for weights not found in function 'getConstBlob'

(Зато мы узнали, что они используют Jenkins).

При этом, конвертация в OpenVino проходит успешно.

Если же попробовать сконвертировать версию Mobile SSD, совместимую с OpenCV-DNN (11_06_2017), то получаем такое:

[E0919 main.py:317] Unexpected exception happened during extracting attributes for node FeatureExtractor/MobilenetV1/Conv2d_13_pointwise_1_Conv2d_2_1x1_256/Relu6.
Original exception message: operands could not be broadcast together with remapped shapes [original->remapped]: (0,) and
 requested shape (1,0,10,256)

Как-то так, технически OpenVino и OpenCV-DNN в одной поставке, но несовместимы по версиям используемых нейросетей.

То есть, если хочется использовать одновременно оба подхода, надо тащить две версии MobileSSD.

По скорости сравнение конечно же в пользу NCS: 0.1 секунды против 1.7.

По качеству...(Хотя это вопрос не к NCS, а к эволюции Mobile SSD).



Классификация картинок


Танк умеет классифицировать картинки через Tensorflow, используя Inception на Imagenet.
Причем я использовал Inception 2015-12-05, когда она была еще одна.

Оказалось, я сильно отстал от жизни, ибо ребята из Гугла не даром едят свой хлеб и уже наплодили аж 4 версии!

Но ребята из Интела от них не отстают и все 4 версии поддержали в OpenVino.

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

Классифицируем картинку с котом и лаптопом на столе.

Запоминаем результаты работы текущей версии:

  • laptop, laptop computer 62%
  • notebook, notebook computer 11%
  • 13 секунд
  • где кот?

Теперь читаем инструкцию по конвертацию Inception в OpenVino.

Конвертация проходит успешно, запускаем классификатор на NCS:

  • laptop, laptop computer 85%
  • notebook, notebook computer 8%
  • 0.2 секунды
  • кота опять нет

Заключение


Таким образом, все сценарии, требовавшие Tensorflow, были воспроизведены с помощью NCS, и это означает что от использования Tensorflow можно отказаться.

Все таки этот фрейморк тяжеловат для Raspberry.

Скорость, с которой NCS переваривает нейросети позволяет его расширить горизонты его применения.

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

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

Ссылки


Комментарии (15)


  1. REPISOT
    24.09.2019 06:18

    Какой-то маловероятный кот — всего 59%. А вроде нормальное фото, стандартная поза и расцветка…


    1. Stantin Автор
      24.09.2019 06:40

      На реальных фотках с большим количеством объектов у нейросетей нередко рвет крышу.
      59% — очень большая достоверность в таких условиях.


      1. WhiteBlackGoose
        24.09.2019 08:57

        Я бы сказал, что зачастую эти проценты ничего не значат. Это же не вероятность в математическом смысле. А результат нормализации суммы с последнего слоя. Если нарукожопить с сигмоидой, можно получать результаты 0.49-0.51, причем 0.49 — это 0, а 0.51 — 1. А можно нарукожопить и в другую сторону, получится если хоть чуть похоже на кота — 0.99, чуть непохоже — 0.01. Просто следует подобрать коэффициент


  1. degressor
    24.09.2019 10:05

    Подскажите где такое шасси купить


    1. Stantin Автор
      24.09.2019 15:00

      На Алиэкспресс конечно.
      Мой вот:
      ru.aliexpress.com/item/32413892216.html


      1. degressor
        24.09.2019 15:07

        Я как то покупал дешевое шасси(за 9$ кажись), но оно очен гремело, еле ехало и батарейки жрало. Вот думаю теперь, лучше инвестирую да не буду потом жалеть. Спасибо за наводку!


        1. Stantin Автор
          25.09.2019 01:09

          Батарейки же не шасси жрет, а моторы, которые можно купить отдельно и с любыми характеристиками.


  1. d1ss4pp34r
    24.09.2019 14:58

    теперь пора смотреть в сторону nvidia jetson nano) очень хорош по производительности


    1. Stantin Автор
      24.09.2019 14:58

      Да, это в to-do списке)


  1. DrBulkin
    24.09.2019 14:58

    Подскажите, а с NVC реально запустить inference DeepLab или Mask-RCNN? Нужна сегментация при помощи обученных мною сеток. Где-то 0.5 сек на картинку 2 мегапикселя. Комп с GTX1080TI вывозит, но греет комнату, перегружает соседнюю подстанцию и сильно шумит.
    Задумывался о Google Coral или NVC, но не уверен, что смогу свои задачи решать этими свистками.


    1. d1ss4pp34r
      24.09.2019 15:05

      скорее всего, на сайтах производителей или на towardsdatascience.com вы найдёте сравнения скорости разных моделей на разных железках. Если с трудом вывозит 1080, то скорее всего никакой из базовых свистков не спасёт. Придется оптимизировать модель.


      Ещё есть nvidia jetson tx2, у нее вроде бы flops достаточно высокий, но сходу не скажу, сравним ли с 1080.


      В целом, задача перехода на edge (nvidia jetson, Google coral) устройства сейчас выглядит вполне решаемой для большинства моделей, но есть много плясок с переводом сети в их форматы.


      1. dinam
        24.09.2019 17:36

        1070 раз в 10 быстрее jetson tx2. А tx2 раз в 10 быстрее интела. Интел хоть как-то может потягаться с tx2, если удастся сконвертить сетку в fp16.
        Очень сильное ускорение (в разы) дает конвертация и запуск в TensorRT.


  1. Sensimilla
    25.09.2019 01:10

    Я понял, разрабатывается танк-охотник на котов


    1. Stantin Автор
      25.09.2019 01:10

      Так было в альфа-версии.:) Сейчас амбиции выросли


  1. YurasovAlexey
    25.09.2019 15:14

    Будет интересно посмотреть на jetson nano.
    Одноплатник с CUDA ядрами на борту. Можно питонить нс и сразу в GPIO
    Пример работы с Intel RealSense T265 Tracking Camera