Блокировка экрана от raspberry pi и разблокировка только после того, как вы сделали достаточно отжиманий, в каком мире мы живем.

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

Короче говоря, идея состоит в том, чтобы блокировать мой компьютер каждый час и заставлять себя делать некоторые физические упражнения, чтобы снова разблокировать его. Это делается с помощью raspberry pi в углу моей комнаты, подключенного к камере с искусственным интеллектом OAK-1. Пи удаленно заблокирует мой компьютер и начнет считать отжимания с помощью OAK-1, пока не обнаружит определенное их количество, а затем снова удаленно разблокирует компьютер. В этом посте мы расскажем о некоторых интересных технических проблемах, которые не попали в видео.

Блокировка компьютера

Я работаю в Linux, поэтому эта часть должна быть проще, чем в других операционных системах. И после некоторого поиска стало ясно, что будут две основные проблемы:

  1. Автоматически заблокировать экран легко, разблокировать снова сложно.
  2. Почти каждый экран блокировки использует пароль от основной системной учетной записи.

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

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

Но разблокировка — это совсем другая история (проклятая безопасность всегда портит удовольствие). Через некоторое время единственным решением стала команда loginctl unlock-session, но я так и не заставил ее работать должным образом. Эти хранители экрана неизменно связаны с аутентификацией основной системы с использованием основных системных паролей, поэтому ни одна из этих команд не имеет аналогичного аргумента команды --unlock.

На самом деле, нам еще предстоит решить вторую проблему. Я знаю пароль, поэтому, даже если бы я мог использовать эти экраны блокировки, как бы я помешал себе ввести пароль и игнорировать систему отжиманий? Я чуть было не подумал об автоматическом изменении системного пароля на какую-то случайную строку, а затем сбросе его, когда закончу, но эта мысль была быстро отправлена ​​в корзину «катастрофически плохие идеи».

Потом я подумал о xdotool. Эта замечательная утилита позволяет мне отправлять любое нажатие клавиши из командной строки, поэтому, если я найду хороший экран блокировки, который фиксирует xdotoolнажатия клавиш, когда он заблокирован, мы в золоте! Затем просто спамьте backspace всякий раз, когда детектор отжиманий активен, и я не могу ввести свой пароль!

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

С этим небольшим скриптом правая часть нашей диаграммы теперь готова к работе. Просто удаленно подключитесь с raspberry pi через SSH к моему ПК и запустите эти команды на основе логики внутри детектора отжиманий.

Машинное обучение

Блейзпоз

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

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

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

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

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

ДУБ-1

Blazepose быстрый, но не настолько быстрый, чтобы легко работать на Raspberry Pi, поэтому мне нужно было что-то еще.

Здесь тоже очень много вариантов. Я мог бы запустить его на своем компьютере, на Nvidia jetson, в своей домашней лаборатории с API, на флешке Movidius, на Coral EdgeTPU от Google и т. д. Но, в конце концов, я выбрал OAK-1, потому что он с открытым исходным кодом и уже имеет встроенную камеру. (Кроме того, мой босс платил, а edgeTPU дешевле, так что…)

Я уже немного пофангался по этому поводу в видео, но это так здорово!

Он работает на чипе Intel Myriad X, а это означает, что любые модели, которые мы, возможно, захотим использовать, должны будут быть преобразованы в собственную платформу искусственного интеллекта Intel OpenVino. Обычно вы запускаете док-контейнер OpenVino, конвертируете модель и извлекаете ее оттуда. Luxonis также предлагает онлайн-инструмент конвертации здесь, но, к счастью для нас, есть 2 совершенно замечательных человека, которые сделали жизнь намного проще.

Первый — легендарный (в узких кругах) PINTO0309. У него есть целый арсенал моделей и инструментов, которые он использует для конвертации с одного фреймворка на другой, и он действительно делает божью работу для инженеров встроенного ИИ. Он преобразовал модель blazepose во множество различных форматов, одним из которых является OpenVino. Конечно, Luxonis также предлагает собственный веб-инструмент для этого, но это всегда непросто.

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

Прежде чем найти их репозиторий, я пытался сделать это сам, но это просто беспорядок. Модели Mediapipe, хотя и очень хороши с точки зрения производительности, не так хороши с точки зрения документации. Например. В собственной документации Google blazepose говорится, что выходные данные модели имеют формат (1, 33, 5) 5 точек данных для каждой из 33 ключевых точек в виртуальном скелете. Координаты 2x2 и видимое/невидимое логическое значение. Но потом вы скачиваете их же модель, закидываете в Нетрон и сразу видите 5 выходных тензоров, ни один из которых не имеет размера, который можно привести обратно к (1, 33, 5). 33*5=165, так что это не первое и не последнее, уж точно не второе которое (1, 1), а так же остальные даже близко не стоят.

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

Маркировка данных

Инструмент для маркировки

Теперь наиболее эффективным способом сделать это было бы установить таймер, чтобы сфотографироваться со мной в разных позах, сделать это несколько раз, запустить blazepose по изображениям и вручную пометить их, к какому классу они принадлежат, либо отжимание ВВЕРХ или отжимания ВНИЗ.

Гораздо худшее решение — заменить таймер голосовой активацией ИИ.

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

Идея была проста. Просто сфотографируйте, когда слово «этикетка» было обнаружено где-либо в расшифровке. Эти миллиарды долларов инвестиций действительно принесли пользу, как вы можете видеть из прекрасных стенограмм, которые я сохранил в процессе маркировки. Если вы видели видео, то знаете, откуда они взялись.

Управление версиями набора данных

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

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

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

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

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

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

Обучение модели классификации

Менеджер экспериментов

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

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

Увеличение данных

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

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

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

Обучение и оптимизация гиперпараметров

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

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

О да, еще один совет: я использовал StandardScaler() для своих данных, потому что модели, не основанные на деревьях, такие как SVM, не любят данные, когда они не нормализованы. Никогда не забывайте:

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

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

Развертывание всего

Модель

Развертывание модели было достаточно простым, просто запустите скейлер, запустите model.predict() и вперед. Опять же, Sklearn был очень прост для этого по сравнению с любой системой глубокого обучения. Подготовить модель на OAK-1 также было просто благодаря репозиторию Geaxgx, поэтому нужно было просто склеить все вместе с помощью слюны и жевательной резинки.

Пользовательский интерфейс

Мне нужно было что-то быстрое и простое для пользовательского интерфейса, которое могло бы работать изначально. Я всерьез не собираюсь раскручивать чертов веб-сервер javascript и съедать половину памяти pi только для того, чтобы показать несколько кнопок. Особенно, когда мне может понадобиться эта память для запуска классификатора.

Итак, всем и каждому, кто в той же лодке, что и я: используйте PySimpleGui.

Это оболочка для многих различных фреймворков пользовательского интерфейса, таких как tkinter, wx и qt (мой личный фаворит). Но это как-то объединяет их и действительно упрощает. Приведенный ниже код — это все, что потребовалось для отображения приятного пользовательского интерфейса, и я мог легко изменить цвета и т. д. на основе вывода модели. Серьезно, попробуйте, это круто!

Дисплей Raspberry Pi

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

Спасибо!

Какого хрена ты все это прочитал? Спасибо! Это был потрясающий проект, и вы можете найти код здесь, если хотите попробовать его самостоятельно. Не стесняйтесь зайти на наш слабый канал, чтобы поздороваться, или написать мне в Твиттере @VictorSonck.