![]() |
![]() |
![]() |
||||||||||||||||||||||||||||||
![]() |
Machine learning на ESP32 |
|||||||||||||||||||||||||||||||
МЕНЮ Главная страница Поиск Регистрация на сайте Помощь проекту Архив новостей ТЕМЫ Новости ИИ Голосовой помощник Разработка ИИГородские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Искусственный интеллект Слежка за людьми Угроза ИИ Атаки на ИИ Внедрение ИИИИ теория Компьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Нейронные сети начинающим Психология ИИ Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Промпты. Генеративные запросы Распознавание лиц Распознавание образов Распознавание речи Творчество ИИ Техническое зрение Чат-боты Авторизация |
2025-03-19 18:46 Распознавание жестов — это технология, которая позволяет людям взаимодействовать с устройствами без физического нажатия кнопок или сенсорных экранов. Интерпретируя жесты человека, эта технология нашла свое применение в различных потребительских устройствах, включая смартфоны и игровые консоли. В основе распознавания жестов лежат два ключевых компонента: сенсор и программный алгоритм. В этом примере используются измерения акселерометра MPU 6050 и машинное обучение (ML) для распознавания трех жестов рукой с помощью ESP32. Данные из сенсора распознаются на микроконтроллере и результат выводится в консоль в виде названия жеста и вероятности результата. Модель ML использует TensorFlow и Keras и обучается на выборке данных, представляющей три различных жеста: "circle" (окружность), "cross" (пересечение) и "pad" (поступательное движение). Разработка проекта начнется с получения данных из акселерометра для построения набора жестов. Затем мы проектируем полносвязную нейронную сеть для распознавания жестов, и подключим модель в проекте ESP32. В следующей части рассмотрим как настроить Bluetooth LE (BLE) на ESP32 и Android устройстве. Передадим квантированный набор ускорений сенсора по BLE. Настроим Модель ML для распознания жестов на Android. Содержание
Акселерометр MPU6050 MPU-6050 - это Inertial Measurement Unit (IMU), который объединяет трехосевой акселерометр и трехосевые гироскопические датчики для измерения ускорений и угловой скорости тела. Это устройство существует на рынке уже давно, и благодаря своей низкой стоимости и высокой производительности оно по-прежнему является популярным выбором для проектов DIY на основе датчиков движения. Рассмотрим следующую систему, состоящую из массы, прикрепленной к одному концу пружины. ![]() Если мы переместим акселерометр, например, положив на стол, то сможем наблюдать, как масса опустится из за действия силы тяжести. Следовательно, пружина по оси Z смещается от положения равновесия. ![]() По закону Гука противодействующая сила пружины где F - это сила пружины, k - коэффициент жесткости, где m - масса объекта, a - испытываемое ускорение. Смещение пружины - это физическая величина, которую акселерометр фиксирует для измерения ускорения. Краткое описание I2C Контакты SDA и SCL IMU MPU-6050 используются для связи с микроконтроллером через последовательный протокол связи I2C. ![]() Как видно из схемы, есть две сигнальные линии (SCL и SDA) для подключения вторичных устройств. SCL — это тактовый сигнал, вырабатываемый первичным устройством, и используется всеми устройствами I2C для выборки битов, передаваемых по шине данных. Как первичное, так и вторичное устройства могут передавать данные по шине SDA. MPU-6050 поддерживает максимальную частоту SCL 400 кГц. Подтягивающие резисторы (Rpullup) необходимы, поскольку устройство I2C может поставлять сигнал только до низкого уровня (логический уровень 0). В нашем случае подтягивающие резисторы не нужны, поскольку они интегрированы в модуль MPU-6050. С точки зрения протокола связи первичное устройство всегда начинает связь, передавая следующие биты.
![]() Подключение сенсора Для подключения сенсора MPU-6050 к ESP32 достаточно подать питание на пины VCC и GND, и соединить шины SDA, SCL с пинами микроконтроллера. ![]() Программирование ESP32 с использованием драйвера MPU 6050 Драйверы периферийных устройств предлагают абстрактные интерфейсы, не зависящие от микросхемы. Каждое периферийное устройство имеет общий заголовочный файл (например, gpio.h), что избавляет от необходимости решать вопросы поддержки, связанные с различными чипами. Для установки компонента драйвера MPU 6050 необходимо выполнить команду в терминале ESP-IDF: После чего компонент добавится в зависимости манифест-файла idfcomponent.yml Заголовочный файл MPU6050.h, содержащий основные функции работы с сенсором появится в папке include. Его необходимо подключить с исходном файле. Пример инициализации, чтения и записи в I2C в ESP-IDF можно посмотреть в репозитории или в IDF examples. В качестве сигналов SDA и SCL можно использовать пины общего назначения. Я выбрал GPIO4, GPIO 5. Частоту шины указал 100000 Hz. Затем, необходимо сконфигурировать шину I2C Далее, создаем указатель static mpu6050_handle_t mpu6050 и инициализируем сенсор MPU6050 Описание функции mpu6050_config Для тестирования шины I2C, и вывода адреса ведомого устройства можно использовать следующую функцию В нашем примере будем считывать ускорения сенсора по трём осям. Для этого вызываем функцию mpu6050_get_acce(sensor, &acce);, предварительно инициализируем структуру mpu6050_acce_value_t acce; sensor - это указатель mpu6050_handle_t sensor. Значения ускорений получаем как acce.acce_x, acce.acce_y, acce.acce_z Краткое описание машинного обучения (ML) Машинное обучение по своей сути представляет собой процесс построения моделей, способных выявлять закономерности в данных. В отличие от классического программирования, где разработчики прописывают жесткие правила, определяющие работу программ, здесь алгоритмы самостоятельно анализируют данные и находят в них скрытые зависимости. Чтобы наглядно продемонстрировать этот принцип, представим ситуацию: наша компания занимается организацией переездов и хочет разработать систему для оценки стоимости услуги. В традиционном программировании можно было бы написать набор условий вида: Однако такой подход быстро усложняется по мере добавления новых факторов: количество крупных предметов, число коробок с одеждой, наличие хрупких вещей и прочие нюансы. Запрашивать всю эту информацию у клиентов заранее может оказаться не только трудоемким, но и оттолкнуть потенциальных заказчиков от завершения процесса оценки. Вместо этого можно обучить модель на исторических данных о переездах, чтобы она самостоятельно предсказывала стоимость услуги, анализируя параметры предыдущих клиентов. Искусственные нейронные сети представляют собой метод машинного обучения, в котором множество слоев, состоящих из нейронов, обрабатывают информацию и передают её дальше, пока на выходе не будет получен конечный результат. Хотя их устройство нельзя напрямую сопоставить с биологическими нейронами мозга, нейросети часто сравнивают с человеческим мышлением из-за их способности выявлять закономерности в данных и формировать предсказания на их основе. Когда нейросеть содержит более одного скрытого слоя, она классифицируется как глубокая (deep learning). Однако независимо от визуального представления, модели машинного обучения — это математические функции, которые можно реализовать с помощью численных вычислительных пакетов. ![]() Разработчики, работающие в области машинного обучения, как правило, не пишут алгоритмы с нуля, а используют специализированные библиотеки, предоставляющие удобные API для построения моделей. Одним из популярных решений является фреймворк TensorFlow, разработанный Google, с акцентом на глубокое обучение. Для удобства работы применяется API Keras - высокоуровневый инструмент для создания нейронных сетей. Помимо TensorFlow и Keras, существуют альтернативные фреймворки, такие как scikit-learn, XGBoost и PyTorch. Они обеспечивают мощные инструменты для обработки данных и реализации как простых, так и сложных моделей. Интересно, что с развитием технологий машинное обучение становится все более доступным - теперь модели можно выражать даже на языке SQL. Например, инструмент BigQuery ML, позволяющий совмещать подготовку данных и создание моделей в рамках SQL-запросов. Нейросети с единственным входным и выходным слоями относятся к классу линейных моделей. Эти алгоритмы строят прогнозы, используя линейные зависимости между переменными. В то же время деревья решений представляют другой вид моделей, в которых данные разделяются на множество ветвей, каждая из которых соответствует определенному исходу. Другим важным типом моделей являются кластеризационные алгоритмы. Они анализируют данные, выявляют схожие группы и объединяют объекты в кластеры, основываясь на обнаруженных закономерностях. Все задачи машинного обучения можно разделить на два типа:
На практике подавляющее большинство моделей, применяемых в индустрии, относится к обучению с учителем. В рамках обучения с учителем задачи подразделяются на два класса:
Таким образом, машинное обучение предлагает мощные инструменты для автоматизации процессов анализа данных и формирования предсказаний, что делает его ключевой технологией в современной аналитике и разработке интеллектуальных систем. ML на встраиваемых устройствах Одной из главных причин популярности встраиваемых устройств, таких как микроконтроллеры и одноплатные компьютеры является их широкое распространение в различных сферах: автомобилестроение, бытовая электроника, системы здравоохранения, промышленные системы автоматизации, телекоммуникации и многое другое. Представьте, что у вас есть станок, который производит детали. Иногда он выходит из строя, и его ремонт обходится дорого. А что, если можно было бы предсказывать поломки заранее и останавливать работу до того, как произойдет серьезное повреждение? Для этого можно собирать данные о работе станка — например, скорость производства, температуру и уровень вибрации. Возможно, определенная комбинация этих параметров сигнализирует о надвигающейся неисправности. Но как это определить? Именно такие задачи и решает машинное обучение. По сути, это метод использования компьютеров для прогнозирования на основе накопленных данных. Мы собираем информацию о работе станка, затем обучаем компьютерную модель анализировать эти данные и делать прогнозы о будущем состоянии оборудования. Вместо того чтобы разрабатывать алгоритм вручную, программист загружает данные в специальный алгоритм, который самостоятельно находит в них закономерности. В результате мы получаем модель — программу, способную делать прогнозы на основе входных данных. Этот процесс называется обучением. Когда модель уже обучена, мы можем использовать её для предсказаний, и этот процесс называется выводом (inference). Глубокое обучение (DL) играет решающую роль в разработке интеллектуальных систем, способных самостоятельно анализировать данные и принимать решения. Однако для интеграции таких технологий в автономные устройства, работающие от аккумуляторов, необходимо учитывать их ограниченные вычислительные и энергетические ресурсы. Локальные вычисления vs. облачные вычисления Основными причинами по которым отдается предпочтение запуска ML локально можно назвать следующие. 1. Сокращение задержек Передача данных в облако и обратно занимает время, что может оказать негативное влияние на приложения, требующие быстрого отклика (например, голосовые помощники, системы управления движением и т. д.). 2. Энергоэффективность Отправка данных в облако требует затрат энергии, особенно при использовании беспроводной связи. Например, на плате Arduino Nano 33 BLE Sense:
3. Конфиденциальность Облачные вычисления требуют передачи данных, что может представлять риски для конфиденциальности. В отличие от этого, локальная обработка данных на устройстве позволяет сохранять персональные данные в безопасности. Основные этапы работы с глубоким обучением на примере Чтобы создать модель глубокого обучения для прогнозирования отказов станка, нужно пройти несколько этапов.
Подготовка данных для обучения Сбор данных Количество данных, необходимое для обучения, зависит от сложности задачи и уровня шума в данных. Однако общий принцип таков: чем больше данных, тем лучше. Важно собирать данные в разных условиях. Например, если температура станка зависит от сезона, в выборке должны быть данные как для лета, так и для зимы. Это поможет модели обобщать и правильно работать в любых ситуациях. Чаще всего данные представляют собой временные ряды — измерения, записанные через регулярные промежутки времени. Например:
Для обучения модели также нужны метки классов: какой набор данных соответствует нормальной работе, а какой указывает на неисправность. Это называется разметкой данных. После сбора и разметки данных можно приступать к созданию и обучению модели машинного обучения. Проектирование архитектуры модели В глубоких нейронных сетях существует множество архитектур, каждая из которых предназначена для решения определённых задач. При разработке модели можно создать собственную архитектуру или использовать уже существующую, разработанную исследователями. Для многих распространённых задач доступны предобученные модели, которые можно бесплатно найти в открытом доступе. Проектирование модели — это одновременно наука и искусство, а создание новых архитектур остаётся одной из ключевых областей исследований в машинном обучении. Фактически, новые архитектуры появляются буквально каждый день. На практике можно начать с простой модели, состоящей из нескольких слоёв нейронов, а затем постепенно уточнять архитектуру в процессе итеративного обучения, пока не будет получен желаемый результат. Представление данных в виде тензоров Глубокие нейросети работают с входными и выходными данными в формате тензоров. В данном контексте тензор можно представить как многомерный массив чисел. Простые примеры тензоров:
Здесь форма (3, 3), так как матрица состоит из трёх строк и трёх столбцов.
Преобразование временных рядов в признаки В машинном обучении признаки (features) — это ключевые параметры, на основе которых обучается модель. Разные модели работают с разными типами признаков. Например, одна модель может принимать на вход всего одно число (скаляр), в то время как другая — многомерный массив пиксельных значений для анализа изображений. В нашем случае мы используем такие параметры, как скорость производства, температура и вибрация. Однако в их сыром виде (разные интервалы временных рядов) они могут не подходить для подачи в нейросеть. Оконное преобразование данных Временные ряды в задачах прогнозирования могут содержать данные с разными интервалами измерений:
Проблема в том, что если модель анализирует только доступные данные в конкретный момент времени, она может потерять часть информации. Например, в определённый момент могут быть доступны только данные о вибрации, но не о температуре и производительности. Решением является оконное агрегирование данных – объединение всех значений в заданном временном окне (например, 1 минута). Внутри окна мы усредняем значения и заполняем отсутствующие данные последними доступными показателями. Если хотя бы одна метка внутри окна указывает на аномалию, всё окно считается аномальным. Пример окна:
После этого значения временного окна представляются вектором: [102, 34, 0.18] Нормализация входных данных Для эффективного обучения нейросети входные данные должны быть масштабированы в один диапазон. Например, если одно значение измеряется в десятках, а другое – в долях, модель может неправильно интерпретировать их важность. Один из методов нормализации – централизация значений:
Для изображений, хранящихся в виде 8-битных матриц (0–255), нормализация выполняется делением на 255, чтобы привести значения к диапазону [0,1]. Пример: После нормализации: Обучение модели Обучение модели — это процесс, в ходе которого алгоритм учится выдавать корректные результаты на основе заданного набора входных данных. Для этого используется обучающая выборка, проходящая через модель, параметры которой (веса и смещения) постепенно корректируются, чтобы минимизировать ошибку предсказаний. В процессе обучения данные подаются в модель, и её выход сравнивается с эталонными значениями. Для корректировки параметров используется метод обратного распространения ошибки (backpropagation), который итеративно изменяет веса и смещения так, чтобы модель лучше соответствовала ожидаемым результатам. Этот процесс повторяется в течение нескольких эпох — полных проходов через обучающий набор. Завершают обучение, когда улучшение точности прекращается. Графики потерь (loss) и точности (accuracy) позволяют отслеживать динамику обучения. Потери показывают, насколько модель далека от правильного ответа, а точность отражает долю верных предсказаний. Идеальная модель имела бы нулевые потери и 100% точность, но в реальности это маловероятно. Основные проблемы, возникающие при обучении моделей, — это недообучение (underfitting) и переобучение (overfitting).
Для оценки качества модели данные разделяют на три группы:
Обычно данные делят в пропорции 60%-20%-20%. Анализ валидационных потерь помогает определить момент, когда модель начинает переобучаться. Если тестовая выборка показывает плохие результаты, значит, модель адаптировалась не только к обучающим, но и к валидационным данным, что требует пересмотра архитектуры или методики обучения. Конвертация модели Обученные модели, созданные в TensorFlow, изначально предназначены для работы на мощных серверах и настольных компьютерах. Однако для работы на микроконтроллерах необходимо конвертировать их в формат TensorFlow Lite. Конвертация выполняется с помощью инструмента TensorFlow Lite Converter, который также применяет оптимизации, уменьшающие размер модели и повышающие скорость работы. Этот процесс быстр и не требует сложных настроек. Запуск предсказаний (Inference) После конвертации модель готова к внедрению в приложение. Используя библиотеку TensorFlow Lite for Microcontrollers, модель загружается и применяется для предсказаний. На этом этапе входные данные, полученные от датчиков, должны быть предварительно обработаны так, чтобы соответствовать формату, на котором обучалась модель. После обработки данные передаются в модель, которая выполняет предсказание. Выходные данные обычно представляют собой вероятностные оценки классов. Например, для классификатора аномалий результатом будет оценка вероятности, с которой объект относится к категории "норма" или "аномалия". Таким образом, успешное обучение модели включает в себя корректную настройку параметров, контроль за переобучением, оптимизацию структуры сети и адаптацию модели для работы на целевых устройствах. TensorFlow Lite for Microcontrollers (TFML) TensorFlow — это открытая библиотека машинного обучения от Google. Она была представлена в 2015 году и с тех пор стала одной из ведущих платформ для работы с нейросетями. TensorFlow ориентирован на использование в облачных сервисах и на мощных вычислительных платформах, таких как серверы и настольные ПК. Основной язык интерфейса — Python, а размер исполняемых файлов может достигать сотен мегабайт, что не является проблемой для облачной среды. Однако такие характеристики делают TensorFlow малопригодным для мобильных устройств, где каждые несколько мегабайт в приложении могут негативно сказаться на его популярности. В 2017 году Google представил TensorFlow Lite — облегченную версию для мобильных платформ. TensorFlow Lite: оптимизация для мобильных устройств TensorFlow Lite (TFLite) был разработан для выполнения моделей машинного обучения на мобильных устройствах. Для сокращения размера библиотеки и уменьшения нагрузки на процессор в TFLite убраны некоторые возможности, такие как обучение моделей и поддержка всех форматов данных (например, double). Кроме того, библиотека поддерживает оптимизированные вычисления для процессоров Arm Cortex-A и использует API Neural Networks на Android для работы с аппаратными ускорителями. Одним из ключевых преимуществ TensorFlow Lite является поддержка 8-битной квантизации, позволяющей уменьшить размер модели до 75% по сравнению с 32-битными представлениями. Это существенно ускоряет выполнение моделей и снижает требования к вычислительным ресурсам. TensorFlow Lite для встраиваемых систем Несмотря на успех TensorFlow Lite, его требования по объему памяти оставались слишком высокими для микроконтроллеров, где даже сотни килобайт могут быть критичными. В 2018 году Google представил TensorFlow Lite for Microcontrollers (TFLM) — ещё более облегченную версию, специально разработанную для встроенных систем. Основные требования к TFLM:
Некоторые ограничения были сознательно оставлены без изменений ради совместимости с TensorFlow Lite:
FlatBuffers - сериализация для встраиваемых систем FlatBuffers — это библиотека сериализации, разработанная для приложений, где критически важна производительность. Благодаря своей архитектуре она идеально подходит для встраиваемых систем. Одним из главных преимуществ FlatBuffers является то, что ее представление в памяти в режиме выполнения совпадает с сериализованной формой. Это означает, что модели могут быть встроены непосредственно в флеш-память и использоваться без необходимости парсинга или копирования данных. FlatBuffers основан на схеме, определяющей структуру данных для сериализации. Затем компилятор превращает эту схему в код на C++, который позволяет читать и записывать эти данные. В TensorFlow Lite схема расположена в файле tensorflow/lite/schema/schema.fbs, а сгенерированный C++-код хранится в tensorflow/lite/schema/schema_generated.h. Хотя можно было бы генерировать код при каждом новом билде, для упрощения портирования было принято решение хранить его в репозитории исходного кода. Тем, кто хочет глубже разобраться в байтовом уровне формата, рекомендуется изучить внутреннюю документацию проекта FlatBuffers для C++ или C. Однако во многих случаях работа ведется через высокоуровневые интерфейсы, поэтому знание низкоуровневой структуры не всегда требуется. Архитектура TFLM Основные компоненты:
![]() Этот репозиторий содержит компонент esp-tflite-micro и примеры, необходимые для использования Tensorflow Lite Micro на чипсетах Espressif с использованием платформы ESP-IDF. Подготовка модели Перед построением и обучением модели необходимо сделать выборку входных данных ускорений сенсора для определенных жестов. И сохранить результаты в файлы Circle.csv, Cross.csv, Pad.csv. Для этого необходимо подключить сенсор к микроконтроллеру, и загрузить тестовый код. А затем выполнить жест рукой в течении 2.5 s. Пример такой логики на ESP32 находится ниже в разделе реализации проекта для микроконтроллера. Однако можно использовать любой другой микроконтроллер для снятия ускорений сенсора MPU6050, главное чтобы частота опроса была 20 ms, и длительность одной выборки - 2.5 s. Также необходимо учитывать то, что расположение сенсора при снятии выборки должно быть таким же, как и предполагается в дальнейшем использовании. В указанных ниже источниках используется другой подход для реализации подобного проекта - с помощью инструмента Edge Impulse data forwarder на Raspberry Pi Pico. Однако мне было интересно реализовать распознавание жестов на ESP32 с помощью Tensorflow lite. Импорт библиотек:
Функция загрузки данных
Маркирование жестов
Разделение данных на обучающую и тестовую выборку
Создание нейросетевой модели
Компиляция и обучение модели
Сохранение обученной модели Сохраняем обученную модель в файл model_keras.h5, чтобы позже использовать её для предсказаний. Этот пункт не обязательный, если сразу конвертируем в .tflite. Визуализация результатов обучения
![]() Конвертирование модели в tflite Обученную модель в TensorFlow нужно конвертировать в .tflite. Это делается с помощью TensorFlow Lite Converter: В результате получим файл модели gesture_model.tflite. tflite файл можно непосредственно загружать и использовать на Android или одноплатный компьютер, как Raspberry Pi. Следует отметить, что при включенной опции tf.lite.Optimize.DEFAULT, но без квантования модель не будет работать на микроконтроллере. Для использования модели на микроконтроллере ESP32 tflite файл необходимо конвертировать в заголовочный файл model.h с помощью утилиты XXD После этого в model.h создаётся массив типа: Модель подключается как заголовок и передаётся в tflite::GetModel() Реализация исходного кода распознавания жестов на ESP32 Для создания модели машинного обучения по распознаванию жестов на основе данных с MPU6050, необходимо предварительно собрать и подготовить данные. Для этого используем окно сбора данных 2.5 секунды и частоту дискретизации 50 Гц, что означает, что в каждом окне будет 125 измерений. Характеристики сбора данных:
Создание проекта Для создания проекта использовалась среда разработки Visual Studio Code с расширением Espressif, версия ESP-IDF - 4.4.5 Проект можно создавать с нуля или использовать доступный пример. Ранее я писал в статье более подробно про создание и настройку проектов для ESP32, а также пример устройства мобильной платформы. Затем необходимо подключить к проекту зависимость esp-tflite-micro, выполнив команду в терминале ESP-IDF После чего в зависимостях появится строчка espressif/esp-tflite-micro: "*" . Исходный код проекта ESP32 находится в этом репозитории. Исходный код Tensorflow модели находится здесь. Структура проекта Выборка данных для обучения Пример кода для платформы ESP-IDF, который собирает данные с MPU6050 и выводит их в консоль
Я сделал 8 выборок по 125 измерений для каждого жеста. Таким образом сформировал три CSV-файла c 1000 строками: circle.csv, cross.csv, pad.csv. На следующем фото я изобразил, как записывал движения сенсора. Изначально MPU6050 был подключен к ESP32 с помощью гибких перемычек, затем я переместил все на макетную плату. ![]() Пример исходного кода gesture.cc для запуска модели Этот код загружает модель, выделяет память, передаёт входные данные, выполняет инференс и выводит результат. Чтобы загрузить модель необходимо выделить память для tensor_arena. Это можно сделать статически в стеке или динамически в куче. В большинстве примеров память выделяется динамически, тогда при создании задачи FreeRTOS ее размер относительно небольшой. Модель нейросети tflite::Model* model` const tflite::Model* model - эта переменная содержит ссылку на модель, которая была загружена в память. Она указывает на объект tflite::Model, который интерпретирует бинарные данные модели. Интерпретатор tflite::MicroInterpreter* interpreter Интерпретатор запускает модель и управляет входами/выходами. Это центральный компонент, который выполняет вычисления.
Пример создания интерпретатора: После настройки интерпретатора мы передаем в него входные данные и запускаем: Выходные данные можно получить так: где data.f .f - это типа данных float union, если модель оперирует другими типами данных, как int8_t, необходимо выбирать соответствующий тип. Резолвер tflite::MicroMutableOpResolver Этот объект регистрирует все доступные операции (слои нейросети), которые используются в модели. В TensorFlow Lite разные модели могут использовать разные операции. Например:
Так как TFLM не поддерживает динамическую загрузку операций, их нужно заранее зарегистрировать в резолвере. Число 6 в шаблоне указывает количество слоев модели сети. В TensorFlow Lite (TFL) модель загружается динамически, а необходимые операции (слои) автоматически подгружаются в память. Это возможно, потому что:
Но в TensorFlow Lite Micro (TFLM) всё работает иначе:
Поэтому в TFLM мы используем MicroMutableOpResolver и вручную добавляем только те слои, которые реально используются в модели. ![]()
Набор всех методов подключаемых слоев находится в исходном файле micro_mutable_op_resolver.h ReLU (Rectified Linear Unit) — это одна из самых популярных функций активации в нейросетях. Она очень простая, но эффективная: Softmax – это функция активации, которая превращает сырые предсказания - логиты в вероятности, получая экспоненту e каждого значения, а затем подвергая нормализации каждое e, то есть разделяя на их сумму, чтобы сумма всех экспонент равнялась единице. Логиты – это логарифм шансов, он лежит в пределах от минус- до плюс-бесконечности. Когда логиты отрицательны или обладают разными знаками, правильной нормализации выполнить не удастся. Возведение в степень решает эту проблему. Softmax обычно применяется в последнем слое нейросети, если мы решаем задачу классификации. Представь, что у нас есть три объекта, и модель выдала логиты на полносвязном слое: Применим Softmax к этим числам согласно формуле Как видно из преобразования, мы получили вероятности логитов, сумма которых равна единице. Обработка и предсказание Ускорения сенсора считываются с помощью функции mpu6050_get_acce(sensor, &acce); модуля gesture.cc в цикле из 125 итерации с задержкой 20 мс vTaskDelay(pdMS_TO_TICKS(20));, что соответствует 2.5 секунды. Значения ускорений передаются в структуру данных входного тензора model_input->data.f Затем происходит вычисление модели с помощью метода interpreter->Invoke() Для передачи данных между задачами FreeRTOS я решил использовать очередь, в которую передаем указатель на структуру входных данных. В качестве обмена данными можно использовать и другие варианты и структуры, но такой способ в моем случае кажется наиболее удобным. Создаем в модуле main.c очередь. Ее размер равен размеру одного указателя float. В основной функции void app_main(void) модуля main.c создаем задачи для функций:
Для каждой задачи выделяем 8 kB памяти. Приоритет gesture_predict задачи (5) делаем выше, чем ble_loop (6) для того, чтобы первая задача вытесняла вначале вторую. В задачу gesture_predict передается структура MPUparams mpu_params = {mpu6050, sensorQueue};, которая содержит обработчик сенсора mpu6050 и обработчик очереди sensorQueue. Для того, чтобы использовать C++ классы TFML в модуле gesture.cc функцию gesture_predict объявляем, как extern. Из входных параметров, переданных в задачу получаем обработчики сенсора и очереди. В функции ble_loop модуля ble_provider.c первым шагом идет считывание очереди Пока очередь пуста, задача ble_loop блокируется. После инференса модели в функции collect_sensor_data модуля gesture.cc копируем выходные данные - три float вероятности предсказаний в конец структуры входных данных data.f[SAMPLE_SIZE * 3]. После этого передаем указатель входной структуры в очередь В функции collect_sensor_data модуля gesture.cc принимаем данные из очереди в float *data. Копируем последние три значения очереди в локальный массив, затем сравниваем максимальное значение вероятности жеста. Получив индекс максимальной вероятности выбираем название жеста из константного массива имен и передаём его клиенту. После подачи питания на ESP32 с сенсором MPU6050 необходимо открыть консоль монитора последовательно порта устройства, например выполнив Monitor device команду ESP-IDF. А затем выполнить один из определенных жестов: окружность, пересечение или перемещение. Пример вывода в консоль для жеста Circle. На данный момент не реализована логика для неопределенного жеста, поэтому в консоли изначально можно увидеть максимальную вероятность для Cross или некоторые числа для Circle и Pad. Tensorflow lite на Raspberry Pi В некоторых случаях для ускорения тестирования модели tflite с помощью Tensorflow lite фреймворка есть смысл запускать выполнение модели на компьютере, например Raspberry Pi. На этой странице написано руководство как сбилдить Tensorflow lite из исходников. Ранее я упоминал про параметр оптимизации конвертирования converter.optimizations = [tf.lite.Optimize.DEFAULT]. Преобразовав tflite с этой опцией я подключил модель к ESP32, и к Android. На микроконтроллере модель не выполняла предсказания, при это никаких ошибок не было. Однако на Android модель работала корректно. Я решил протестировать модель на Raspberry, предварительно собрав Tensorflow их исходников. К моему удивлению, на Raspberry модель также не работала. Но зато процесс компиляции исходного файла и выполнения занимает гораздо меньше времени, и исходные данные можно принимать в любом формате, например CSV-файле. Это позволило мне провести ряд экспериментов и выявить проблему. Исходный файл тестирования модели на Raspberry находится здесь. Отладка ESP32-S3 В ряде случаев отладка на микроконтроллере является полезным инструментом, позволяющим определить проблемные места в логике работы, и отслеживать значения переменных в точках останова. Поэтому вкратце приведу настройку среды для отладки ESP32-S3, и особенности, с которыми я столкнулся.
Чтобы установить драйвер для отладки ESP32-S3 на Windows необходимо выполнить команду в PowerShell После установки драйвера при попытке запуска отладки можно получить ошибку ESP32-S3 debug issue : libusb_open() failed with LIBUSB_ERROR_NOT_SUPPORTED. Для этого необходимо изменить драйвер с помощью утилиты Zadig, как описано здесь. Для отладки ESP32 в Visual Studio Code необходимо настроить конфигурацию в файле проекта ./vcscode/launch.json Затем необходимо запустить OpenOCD сервер в терминале ESP-IDF с помощью команды Запуск отладки выполняется на Debug в VSCode ![]() Более подробно про отладку ESP-IDF в VSCode можно почитать в документации. Заключение TensorFlow Lite for Microcontrollers открывает возможности машинного обучения для встраиваемых систем, где традиционные модели были невозможны из-за ограничений памяти и вычислительных мощностей. Благодаря продуманной архитектуре, TFLM позволяет запускать нейросетевые модели даже на устройствах с 20 КБ памяти, что делает машинное обучение доступным для IoT, носимых устройств и других встраиваемых решений. Используемые источники Источник: habr.com Комментарии: |
|||||||||||||||||||||||||||||||