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

Потоковая передача данных

Перевод Стриминг Edge2AI на NVIDIA JETSON Nano 2Гб с использованием агентов MiNiFi в приложениях FLaNK

03.03.2021 10:13:29 | Автор: admin

Мне некогда было снимать своё видео распаковки - не терпелось запустить это превосходное устройство. NVIDIA Jetson Nano 2GB теперь можно купить всего за 59 долларов!!!
Я провел пробный запуск, у него есть все функции, которые вам нравятся для Jetson, всего на 2 Гб оперативной памяти и 2 USB порта меньше. Это очень доступное устройство для создания классных кейсов.

Распаковка: https://www.youtube.com/watch?v=dVGEtWYkP2c&feature=youtu.be

Подключение к приложениям ИИ-сообщества: https://youtu.be/2T8CG7lDkcU

Образовательные проекты: https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-nano/education-projects/

Технические характеристики:
Графический процессор: NVIDIA Maxwell со 128 ядрами CUDA
Процессор: Четырехъядерный ARM A57 с частотой 1,43 ГГц
Память: 2 Гб LPDDR4, 64-bit 25,6 Гбит/с
Накопитель: microSD (не входит в комплект)
Кодирование видео: 4K с частотой 30 Гц | 4 потока в разрешении 1080p с частотой 30 Гц | 9 потоков в разрешении 720p с частотой 30 Гц (H.264/H.265)
Декодирование видео: 4K с частотой 60 Гц | 2 потока в разрешении 4K с частотой 30 Гц | 8 потоков в разрешении 1080p с частотой 30 Гц | 18 потоков в разрешении 720р с частотой 30 Гц (H.264/H.265)
Соединение: Беспроводное подключение Gigabit Ethernet, 802.11ac*
Камера: 1 разъем MIPI CSI-2
Разъемы дисплея: Разъем HDMI
USB: 1x USB 3.0 Type A, 2x USB 2.0 Type A, 1x USB 2.0 Micro-B
Прочие разъемы: Разъем 40-пин (GPIO, I2C, I2S, SPI, UART)
Разъем: 12-пин (питание и связанные сигналы, UART)
Разъем вентилятора: 40-пин *
Размеры: 100 x 80 x 29 мм

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

Все мои существующие рабочие нагрузки отлично работают в версии на 2 ГБ, но с очень хорошей экономией средств. Настройка проста, система быстрая, я настоятельно рекомендую всем, кто ищет быстрый способ поэкспериментировать с ИИ на периферии и другими пограничными рабочими нагрузками. Это может быть отличный вариант для самостоятельного обучения. Я также подключил свой Jetson к монитору, клавиатуре и мыши, и я могу использовать его сразу же как для вычислений на периферии, так и в качестве основного рабочего ПК. С большим количеством таких устройств можно будет легко запустить MiNiFi агентов, модель классификации на Python и модели Deep Learning.

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

Пример запуска модели глубокого обучения

Исходники и настройки: https://github.com/tspannhw/SettingUpAJetsonNano2GB/blob/main/README.md

Устройство NVIDIA Jetson Nano 2GB великолепно - ничего лишнего. Я скопировал своего агента MiNiFi и код из других Jetson Nanos, Xavier NX и TX1, и все работает нормально. Скорость вполне подходит для большинства потребностей, особенно для задач разработки и прототипирования. Я предпочитаю Xavier, но за эту цену выбор достойный. Для большинства сценариев использования IoT/ИИ на периферии я собираюсь задействовать несколько Jetson Nano. Я уже использовал NVidia Jetson 2GB для демонстрации на некоторых мероприятиях, включая ApacheCon, BeamSummit, Open Source Summit и AI Dev World:
https://www.linkedin.com/pulse/2020-streaming-edge-ai-events-tim-spann/

Для захвата неподвижных изображений и создания их каталога для обработки я установил fswebcam.

Обычно я использую этот гайд: https://github.com/dusty-nv/jetson-inference.
Вы получите отличные библиотеки, руководства, документацию и примеры. Обычно я создаю свои приложения, пользуясь одним из этих примеров, а также использую одну из превосходных готовых моделей NVIDIA. Это значительно ускоряет разработку и развертывание Edge2AI-приложений, будь то задачи IoT или другие цели. Это все работает со стандартными подключаемыми камерами Raspberry Pi и отличными USB веб-камерами Logitech, которые я использовал со всеми другими устройствами NVIDIA.

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

Во время проведения презентации на NetHope Global Summit, и подумал, что эти устройства за 59 долларов вполне способны стать отличным вариантом для некоммерческих организаций, которые могут использовать их для сбора и анализа данных в поле. https://www.nethopeglobalsummit.org/agenda-2020#sz-tab-44134

Я исследую некоторые сценарии использования, чтобы посмотреть, можно ли заранее создать несколько простых приложений, которые такая организация могла бы просто взять и запустить. Посмотрим, что получится. Периферийное устройство с графическим процессором за 59 долларов позволяет использовать некоторые новые приложения по очень доступной цене. За 59 долларов я не получу много ресурсов облака, но смогу получить небольшое и мощное устройство для сбора данных, которое справится с нагрузками МО, DL, обработкой видео с камеры, работой с агентами MiNiFi, Python и Java. Воображение здесь ограничивается только 2-мя гигабайтами быстрой оперативной памяти и однимграфическим процессором.

Пример приложения

Пример выходных данных:

{"uuid": "nano_uuid_cmq_20201026202757", "ipaddress": "192.168.1.169",
"networktime": 47.7275505065918, "detectleft": 1.96746826171875,
"detectconfidence": 52.8866550521850pidence ": 52.8866550521850pidence":
52.8866550521850p , "gputemp": "30.0", "gputempf": "86", "cputempf": "93",
"runtime": "169", "host": "nano5",
"filename": "/ opt / demo /images/out_iue_20201026202757.jpg ",
" host_name ":" nano5 "," macaddress ":" 00: e0: 4c: 49: d8: b7 ",
" end ":" 1603744246.924455 "," te ":" 169.4200084209442 ",
systemtime: 26.10.2020 16:30:46, cpu: 9,9, diskusage: 37100,4 МB,
Memory: 91,5, id: 20201026202757_64d69a82-88d8-45f8-be06 -1b836cb6cc84 "}


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

root@nano5:/opt/demo/minifi-jetson-nano# jetson_clocks

root@nano5:/opt/demo/minifi-jetson-nano# python3 detect.py

[gstreamer] initialized gstreamer, version 1.14.5.0

[gstreamer] gstCamera -- attempting to create device v4l2:///dev/video0

[gstreamer] gstCamera -- found v4l2 device: HD Webcam C615

[gstreamer] v4l2-proplist, device.path=(string)/dev/video0, udev-probed=(boolean)false, device.api=(string)v4l2, v4l2.device.driver=(string)uvcvideo, v4l2.device.card=(string)"HD\ Webcam\ C615", v4l2.device.bus_info=(string)usb-70090000.xusb-3.2, v4l2.device.version=(uint)264588, v4l2.device.capabilities=(uint)2216689665, v4l2.device.device_caps=(uint)69206017;

[gstreamer] gstCamera -- found 30 caps for v4l2 device /dev/video0

[gstreamer] [0] video/x-raw, format=(string)YUY2, width=(int)1920, height=(int)1080, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)5/1;

[gstreamer] [1] video/x-raw, format=(string)YUY2, width=(int)1600, height=(int)896, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 15/2, 5/1 };

[gstreamer] [2] video/x-raw, format=(string)YUY2, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 10/1, 15/2, 5/1 };

[gstreamer] [3] video/x-raw, format=(string)YUY2, width=(int)960, height=(int)720, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [4] video/x-raw, format=(string)YUY2, width=(int)1024, height=(int)576, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [5] video/x-raw, format=(string)YUY2, width=(int)800, height=(int)600, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [6] video/x-raw, format=(string)YUY2, width=(int)864, height=(int)480, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [7] video/x-raw, format=(string)YUY2, width=(int)800, height=(int)448, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [8] video/x-raw, format=(string)YUY2, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [9] video/x-raw, format=(string)YUY2, width=(int)640, height=(int)360, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [10] video/x-raw, format=(string)YUY2, width=(int)432, height=(int)240, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [11] video/x-raw, format=(string)YUY2, width=(int)352, height=(int)288, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [12] video/x-raw, format=(string)YUY2, width=(int)320, height=(int)240, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [13] video/x-raw, format=(string)YUY2, width=(int)176, height=(int)144, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [14] video/x-raw, format=(string)YUY2, width=(int)160, height=(int)120, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [15] image/jpeg, width=(int)1920, height=(int)1080, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [16] image/jpeg, width=(int)1600, height=(int)896, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [17] image/jpeg, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [18] image/jpeg, width=(int)960, height=(int)720, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [19] image/jpeg, width=(int)1024, height=(int)576, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [20] image/jpeg, width=(int)800, height=(int)600, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [21] image/jpeg, width=(int)864, height=(int)480, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [22] image/jpeg, width=(int)800, height=(int)448, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [23] image/jpeg, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [24] image/jpeg, width=(int)640, height=(int)360, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [25] image/jpeg, width=(int)432, height=(int)240, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [26] image/jpeg, width=(int)352, height=(int)288, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [27] image/jpeg, width=(int)320, height=(int)240, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [28] image/jpeg, width=(int)176, height=(int)144, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] [29] image/jpeg, width=(int)160, height=(int)120, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 24/1, 20/1, 15/1, 10/1, 15/2, 5/1 };

[gstreamer] gstCamera -- selected device profile: codec=mjpeg format=unknown width=1280 height=720

[gstreamer] gstCamera pipeline string:

[gstreamer] v4l2src device=/dev/video0 ! image/jpeg, width=(int)1280, height=(int)720 ! jpegdec ! video/x-raw ! appsink name=mysink

[gstreamer] gstCamera successfully created device v4l2:///dev/video0

[gstreamer] opening gstCamera for streaming, transitioning pipeline to GST_STATE_PLAYING

[gstreamer] gstreamer changed state from NULL to READY ==> mysink

[gstreamer] gstreamer changed state from NULL to READY ==> capsfilter1

[gstreamer] gstreamer changed state from NULL to READY ==> jpegdec0

[gstreamer] gstreamer changed state from NULL to READY ==> capsfilter0

[gstreamer] gstreamer changed state from NULL to READY ==> v4l2src0

[gstreamer] gstreamer changed state from NULL to READY ==> pipeline0

[gstreamer] gstreamer changed state from READY to PAUSED ==> capsfilter1

[gstreamer] gstreamer changed state from READY to PAUSED ==> jpegdec0

[gstreamer] gstreamer changed state from READY to PAUSED ==> capsfilter0

[gstreamer] gstreamer stream status CREATE ==> src

[gstreamer] gstreamer changed state from READY to PAUSED ==> v4l2src0

[gstreamer] gstreamer changed state from READY to PAUSED ==> pipeline0

[gstreamer] gstreamer stream status ENTER ==> src

[gstreamer] gstreamer message new-clock ==> pipeline0

[gstreamer] gstreamer message stream-start ==> pipeline0

[gstreamer] gstreamer changed state from PAUSED to PLAYING ==> capsfilter1

[gstreamer] gstreamer changed state from PAUSED to PLAYING ==> jpegdec0

[gstreamer] gstreamer changed state from PAUSED to PLAYING ==> capsfilter0

[gstreamer] gstreamer changed state from PAUSED to PLAYING ==> v4l2src0

[gstreamer] gstCamera -- onPreroll

[gstreamer] gstCamera -- map buffer size was less than max size (1382400 vs 1382407)

[gstreamer] gstCamera recieve caps: video/x-raw, format=(string)I420, width=(int)1280, height=(int)720, interlace-mode=(string)progressive, multiview-mode=(string)mono, multiview-flags=(GstVideoMultiviewFlagsSet)0:ffffffff:/right-view-first/left-flipped/left-flopped/right-flipped/right-flopped/half-aspect/mixed-mono, pixel-aspect-ratio=(fraction)1/1, chroma-site=(string)mpeg2, colorimetry=(string)1:4:0:0, framerate=(fraction)30/1

[gstreamer] gstCamera -- recieved first frame, codec=mjpeg format=i420 width=1280 height=720 size=1382407

RingBuffer -- allocated 4 buffers (1382407 bytes each, 5529628 bytes total)

[gstreamer] gstreamer changed state from READY to PAUSED ==> mysink

[gstreamer] gstreamer message async-done ==> pipeline0

[gstreamer] gstreamer changed state from PAUSED to PLAYING ==> mysink

[gstreamer] gstreamer changed state from PAUSED to PLAYING ==> pipeline0

RingBuffer -- allocated 4 buffers (14745600 bytes each, 58982400 bytes total)

jetson.inference -- detectNet loading build-in network 'ssd-mobilenet-v2'

detectNet -- loading detection network model from:

-- model networks/SSD-Mobilenet-v2/ssd_mobilenet_v2_coco.uff

-- input_blob 'Input'

-- output_blob 'NMS'

-- output_count 'NMS_1'

-- class_labels networks/SSD-Mobilenet-v2/ssd_coco_labels.txt

-- threshold 0.500000

-- batch_size 1

[TRT] TensorRT version 7.1.3

[TRT] loading NVIDIA plugins

[TRT] Registered plugin creator - ::GridAnchor_TRT version 1

[TRT] Registered plugin creator - ::NMS_TRT version 1

[TRT] Registered plugin creator - ::Reorg_TRT version 1

[TRT] Registered plugin creator - ::Region_TRT version 1

[TRT] Registered plugin creator - ::Clip_TRT version 1

[TRT] Registered plugin creator - ::LReLU_TRT version 1

[TRT] Registered plugin creator - ::PriorBox_TRT version 1

[TRT] Registered plugin creator - ::Normalize_TRT version 1

[TRT] Registered plugin creator - ::RPROI_TRT version 1

[TRT] Registered plugin creator - ::BatchedNMS_TRT version 1

[TRT] Could not register plugin creator - ::FlattenConcat_TRT version 1

[TRT] Registered plugin creator - ::CropAndResize version 1

[TRT] Registered plugin creator - ::DetectionLayer_TRT version 1

[TRT] Registered plugin creator - ::Proposal version 1

[TRT] Registered plugin creator - ::ProposalLayer_TRT version 1

[TRT] Registered plugin creator - ::PyramidROIAlign_TRT version 1

[TRT] Registered plugin creator - ::ResizeNearest_TRT version 1

[TRT] Registered plugin creator - ::Split version 1

[TRT] Registered plugin creator - ::SpecialSlice_TRT version 1

[TRT] Registered plugin creator - ::InstanceNormalization_TRT version 1

[TRT] detected model format - UFF (extension '.uff')

[TRT] desired precision specified for GPU: FASTEST

[TRT] requested fasted precision for device GPU without providing valid calibrator, disabling INT8

[TRT] native precisions detected for GPU: FP32, FP16

[TRT] selecting fastest native precision for GPU: FP16

[TRT] attempting to open engine cache file /usr/local/bin/networks/SSD-Mobilenet-v2/ssd_mobilenet_v2_coco.uff.1.1.7103.GPU.FP16.engine

[TRT] loading network plan from engine cache /usr/local/bin/networks/SSD-Mobilenet-v2/ssd_mobilenet_v2_coco.uff.1.1.7103.GPU.FP16.engine

[TRT] device GPU, loaded /usr/local/bin/networks/SSD-Mobilenet-v2/ssd_mobilenet_v2_coco.uff

[TRT] Deserialize required 2384046 microseconds.

[TRT]

[TRT] CUDA engine context initialized on device GPU:

[TRT] -- layers 117

[TRT] -- maxBatchSize 1

[TRT] -- workspace 0

[TRT] -- deviceMemory 35449344

[TRT] -- bindings 3

[TRT] binding 0

-- index 0

-- name 'Input'

-- type FP32

-- in/out INPUT

-- # dims 3

-- dim #0 3 (SPATIAL)

-- dim #1 300 (SPATIAL)

-- dim #2 300 (SPATIAL)

[TRT] binding 1

-- index 1

-- name 'NMS'

-- type FP32

-- in/out OUTPUT

-- # dims 3

-- dim #0 1 (SPATIAL)

-- dim #1 100 (SPATIAL)

-- dim #2 7 (SPATIAL)

[TRT] binding 2

-- index 2

-- name 'NMS_1'

-- type FP32

-- in/out OUTPUT

-- # dims 3

-- dim #0 1 (SPATIAL)

-- dim #1 1 (SPATIAL)

-- dim #2 1 (SPATIAL)

[TRT]

[TRT] binding to input 0 Input binding index: 0

[TRT] binding to input 0 Input dims (b=1 c=3 h=300 w=300) size=1080000

[TRT] binding to output 0 NMS binding index: 1

[TRT] binding to output 0 NMS dims (b=1 c=1 h=100 w=7) size=2800

[TRT] binding to output 1 NMS_1 binding index: 2

[TRT] binding to output 1 NMS_1 dims (b=1 c=1 h=1 w=1) size=4

[TRT]

[TRT] device GPU, /usr/local/bin/networks/SSD-Mobilenet-v2/ssd_mobilenet_v2_coco.uff initialized.

[TRT] W = 7 H = 100 C = 1

[TRT] detectNet -- maximum bounding boxes: 100

[TRT] detectNet -- loaded 91 class info entries

[TRT] detectNet -- number of object classes: 91

detected 0 objects in image

[TRT] ------------------------------------------------

[TRT] Timing Report /usr/local/bin/networks/SSD-Mobilenet-v2/ssd_mobilenet_v2_coco.uff

[TRT] ------------------------------------------------

[TRT] Pre-Process CPU 0.07802ms CUDA 0.48875ms

[TRT] Network CPU 45.52254ms CUDA 44.93750ms

[TRT] Post-Process CPU 0.03193ms CUDA 0.03177ms

[TRT] Total CPU 45.63248ms CUDA 45.45802ms

[TRT] ------------------------------------------------

[TRT] note -- when processing a single image, run 'sudo jetson_clocks' before

to disable DVFS for more accurate profiling/timing measurements

[image] saved '/opt/demo/images/out_kfy_20201030195943.jpg' (1280x720, 4 channels)

[TRT] ------------------------------------------------

[TRT] Timing Report /usr/local/bin/networks/SSD-Mobilenet-v2/ssd_mobilenet_v2_coco.uff

[TRT] ------------------------------------------------

[TRT] Pre-Process CPU 0.07802ms CUDA 0.48875ms

[TRT] Network CPU 45.52254ms CUDA 44.93750ms

[TRT] Post-Process CPU 0.03193ms CUDA 0.03177ms

[TRT] Total CPU 45.63248ms CUDA 45.45802ms

[TRT] ------------------------------------------------

[gstreamer] gstCamera -- stopping pipeline, transitioning to GST_STATE_NULL

[gstreamer] gstCamera -- pipeline stopped


Мы используем расширенный пример сценария, скрипт detect.py. Чтобы сделать снимок веб-камеры и классифицировать его: camera = jetson.utils.gstCamera(width, height, camera)

Модель работает достаточно быстро и дает нам те результаты и данные, которые нужно.

классификация изображения моделью на Jetson Nano 2GBклассификация изображения моделью на Jetson Nano 2GB

Ссылки:

https://github.com/tspannhw/minifi-jetson-nano

https://youtu.be/fIESu365Sb0

https://developer.nvidia.com/blog/ultimate-starter-ai-computer-jetson-nano-2gb-developer-kit/

Подробнее..

Перевод Kafka как хранилище данных реальный пример от Twitter

07.01.2021 14:19:53 | Автор: admin
Привет, Хабр!

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


Введение



Когда разработчики потребляют общедоступные данные Twitter через API Twitter, они рассчитывают на надежность, скорость и стабильность. Поэтому некоторое время назад в Twitter запустили Account Activity Replay API для Account Activity API, чтобы разработчикам было проще обеспечить стабильность своих систем. Account Activity Replay API это инструмент восстановления данных, позволяющий разработчикам извлекать события со сроком давности до пяти дней. Этот API восстанавливает события, которые не были доставлены по разным причинам, в том числе, из-за аварийных отказов сервера, происходивших при попытках доставки в режиме реального времени.

Инженеры Twitter стремились не только создать API, которые будут положительно восприняты разработчиками, но и:

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


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

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

Контекст


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

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



Рис. 1: Конвейер генерации данных

Хранение и сегментирование



Как правило, при создании системы воспроизведения, требующей подобного хранилища данных, выбирается архитектура на основе Hadoop и HDFS. В данном случае, напротив, был выбран Apache Kafka, по двум причинам:

  • Система для работы в режиме реального времени была по принципу публикация-подписка, органичному для устройства Kafka
  • Объем событий, который требуется хранить в системе воспроизведения, исчисляется не петабайтами. Мы храним данные не более чем за несколько дней. Кроме того, обращаться с заданиями MapReduce для Hadoop затратнее и медленнее, чем потреблять данные в Kafka, и первый вариант не отвечает ожиданиям разработчиков.


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

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

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

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

Запросы и обработка



В системе, сконструированной таким образом, API отправляет запросы на воспроизведение. В составе полезной нагрузки каждого валидируемого запроса приходит webhookId и диапазон данных, для которых должны быть воспроизведены события. Эти запросы долговременно хранятся в MySQL и ставятся в очередь до тех пор, пока их не подхватит сервис воспроизведения. Диапазон данных, указанный в запросе, используется, чтобы определить смещение, с которым нужно начать считывание с диска. Функция offsetForTimes объекта Consumer используется для получения смещений.



Рис. 2: Система воспроизведения. Она получает запрос и отправляет его сервису конфигурации (уровень доступа к данным) для дальнейшего долговременного хранения в базе данных.

Инстансы сервиса воспроизведения обрабатывают каждый запрос на воспроизведение. Инстансы координируются друг с другом при помощи MySQL, чтобы обработать следующую запись на воспроизведение, хранимую в базе данных. Каждый рабочий процесс, обеспечивающий воспроизведение, периодически опрашивает MySQL, чтобы узнать, нет ли там задания, которое следует обработать. Запрос переходит от состояния к состоянию. Запрос, который не был подхвачен для обработки, находится в состоянии OPEN. Запрос, который только что был выведен из очереди, находится в состоянии STARTED. Запрос, обрабатываемый в данный момент, находится в состоянии ONGOING. Запрос, претерпевший все переходы, оказывается в состоянии COMPLETED. Рабочий процесс, отвечающий за воспроизведение, подбирает только такие запросы, обработка которых еще не началась (то есть, находящиеся в состоянии OPEN).

Периодически, после того, как рабочий процесс выведет запрос из очереди на обработку, он отстукивается в таблице MySQL, оставляя метки времени и демонстрируя тем самым, что задание на воспроизведение до сих пор обрабатывается. В случаях, когда инстанс воспроизводящего рабочего процесса отмирает, не успев закончить обработку запроса, такие задания перезапускаются. Следовательно, воспроизводящие процессы выводят из очереди не только запросы, находящиеся в состоянии OPEN, но и подбирают те запросы, что были переведены в состояние STARTED или ONGOING, но не получили отстука в базе данных, спустя заданное количество минут.



Рис. 3: Уровень доставки данных: сервис воспроизведения опрашивает MySQL по поводу нового задания на обработку запроса, потребляет запрос из топика Kafka и доставляет события через сервис Webhook.

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

Категории

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

  • Имя: Макс
    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