Всем доброго дня. Совсем недавно я закончила продвинутый курс от Deep Learning School. Курс объемный, много свежей информации. Мне, как закончившей прикладную математику (нейросетки, генетика, fuzzy logics) было не сильно сложно, но мега-увлекательно за счет того, что ребята очень заинтересованные и рассказывали про свежие интересные модели, еще и на русском языке. Приятно видеть, что ИИ-сфера в нашей стране тоже не стоит на месте.
В качестве проекта на курсе мне хотелось сделать своими руками что-нибудь эдакое и полезное, и одновременно мега-современное, и вот что я придумала. У нас есть частный дом, там есть дворовые коты, которых надо кормить и в мое отсутствие. А так же есть еще птицы, кроты, чужие вездесущие собаки и другая живность, которых не стоит кормить, если не хотим, чтобы они у нас все поселились. Так вот, а что, если прикрутить модель детекции изображений к умной кормушке? Далее было бы здорово научиться использовать голосовые команды, например, на закрытие кормушки. Интересненько :-)
Сразу замечу, это учебный проект, увлекательный но поверхностный процесс, о котором собираюсь рассказать в этой статье. Акцент сделаю именно на то, как можно пользоваться моделями детекции изображений на практике и что из этого всего может выйти. И чтобы не писать никаких специальных программ, воспользуемся очень популярным сервисом телеграмм-ботов, который есть почти в каждом смартфоне.
Логика предполагалась следующая:
Кот приходит к кормушке, его снимает рядом стоящая IP камера и отправляет снимок в телеграмм-бот.
Бот обрабатывает сообщение, если это фото, то отправляет его в модель детекции.
Модель детекции распознает кота или не распознает.
Если это кот, бот посылает сигнал умной кормушке открыться и уведомляет об этом владельца.
Умная кормушка открывается (и потом закрывается по таймеру, например).
Владелец в любой момент времени может подать голосовую команду, например, на закрытие кормушки через телеграмм-бот.
Команда из голосовой преобразуется в текст.
Если будет обнаружена команда "закрыть кормушку", бот отправит сигнал на закрытие кормушки и сообщение владельцу, что принял команду.
Моделей детекции в современном мире тьма, в целях данной работы я выбрала Single Shot MultiBox Detector model for object detection (далее SSD-модель), разработанную компанией NVIDIA. Эта модель архитектуры глубоких нейронных сетей на основе модели ResNet-50 (победившей на соревнованиях ImageNet 2015 года), специально заточенная под детекцию изображений. Статья у нас практическая, не будем вдаваться в сложности архитектуры, только подчеркнем, что данная архитектура нейронных сетей стала практически стандартом качества и часто используется в задачах обнаружения объектов и сегментации изображений. SSD-модель заточена под быструю обработку и детекцию объектов даже в реальном времени, она обеспечивает высокую точность и быстроту обработки изображений.
1 часть: подготовка к работе
Писать будем на Python 3.11
Создаем новый проект, новое виртуальное окружение, в которое устанавливаем необходимые библиотеки
pip install numpy scipy scikit-image matplotlib
pip install pyTelegramBotAPI
pip install SpeechRecognition
pip install pydub
pip install pydub[ffmpeg]
pip install pydub opencv-python-headless opuslib
Скачиваем и настраиваем выбранную модель: переводим ее в "боевой" режим. Расчеты следует производить на GPU или на CUDA, т.к. CPU будет считать очень долго и медленно. Я делала проект в Google Colab GPU
import torch
precision = 'fp32'
ssd_model = torch.hub.load('NVIDIA/DeepLearningExamples:torchhub',
'nvidia_ssd', model_math=precision)
utils = torch.hub.load('NVIDIA/DeepLearningExamples:torchhub',
'nvidia_ssd_processing_utils')
ssd_model.to('cuda')
ssd_model.eval()
Монтируем google disk, на котором будем хранить все материалы
from google.colab import drive
drive.mount('/content/drive')
torch.save(ssd_model.state_dict(), 'ssd_model.pth')
Подгружаем необходимые библиотеки
import telebot
import cv2
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
from matplotlib import pyplot as plt
import matplotlib.patches as patches
import os
import speech_recognition as sr
from pydub import AudioSegment
import subprocess
import time
2 часть: реализация логики
Ниже пример самой простой логики обработки изображения нашей моделью. В целях нашей задачи мы обнаруживаем только кота, но возможности модели очень широкие - она может опознавать большое количество различных объектов и даже в онлайн режиме.
def filter(uri):
# Инициализация флага обнаружения объекта "cat"
is_detected_cat = 0
# Подготовка входных данных
inputs = [utils.prepare_input(uri)]
# Подготовка тензора для модели с учетом точности 'fp16'
tensor = utils.prepare_tensor(inputs, precision == 'fp16')
# Выполнение обнаружения объектов с использованием SSD-модели
with torch.no_grad():
detections_batch = ssd_model(tensor)
# Декодирование результатов обнаружения
results_per_input = utils.decode_results(detections_batch)
# Выбор лучших результатов с пороговой уверенностью 0.20
best_results_per_input = [utils.pick_best(results, 0.20) for results in results_per_input]
# Получение словаря с соответствием классов меткам
classes_to_labels = utils.get_coco_object_dictionary()
# Итерация по изображениям с лучшими результатами
for image_idx in range(len(best_results_per_input)):
# Создание графика для визуализации результатов
fig, ax = plt.subplots(1)
# Отображение оригинального изображения
image = inputs[image_idx] / 2 + 0.5
ax.imshow(image)
# Отображение прямоугольников вокруг обнаруженных объектов и меток с уверенностью
bboxes, classes, confidences = best_results_per_input[image_idx]
for idx in range(len(bboxes)):
left, bot, right, top = bboxes[idx]
x, y, w, h = [val * 300 for val in [left, bot, right - left, top - bot]]
rect = patches.Rectangle((x, y), w, h, linewidth=1, edgecolor='r', facecolor='none')
ax.add_patch(rect)
# Проверка, является ли обнаруженный объект классом "cat"
class_cat = classes_to_labels[classes[idx] - 1]
if (class_cat == 'cat'):
is_detected_cat = 1
# Вывод метки класса и уверенности
ax.text(x, y, "{} {:.0f}%".format(classes_to_labels[classes[idx] - 1], confidences[idx]*100), bbox=dict(facecolor='white', alpha=0.5))
# Сохранение отфильтрованного изображения
plt.savefig("filtered_image.jpg")
# Возвращение флага обнаружения объекта "cat"
return is_detected_cat
3 часть: создание телеграмм-бота
Бота создаем через @BotFather, в целях безопасности отдельно в файле сохраняем токен.
Пишем логику бота, наш бот будет уметь:
Здороваться
@bot.message_handler(commands=['start'])
def start_message(message):
bot.send_message(message.chat.id, 'Привет! Пожалуйста, загрузи картинку.')
В рамках учебного проекта я не делала полноценную интеграцию с камерой, поэтому бот и модель детекции будет работать на примере загруженных в него фотографий. Справедливости ради стоит заметить, что реагировать данная модель будет на любого кота. Чтобы модель реагировала только на какого-то одного определенного кота, надо собрать отдельный дата-сет с фотографиями этого кота и дообучить скачанную и сохраненную модель на него.
Посылать сигнал на открытие кормушки при обнаружении кота
@bot.message_handler(content_types=['photo'])
def process_image(message):
# Получаем информацию о картинке
file_id = message.photo[-1].file_id
file_info = bot.get_file(file_id)
file_path = file_info.file_path
# Скачиваем картинку
downloaded_file = bot.download_file(file_path)
# Сохраняем картинку на диск
with open('image.jpg', 'wb') as f:
f.write(downloaded_file)
is_detected_cat = filter("image.jpg")
# Отправляем пользователю преобразованное изображение
with open('filtered_image.jpg', 'rb') as f:
bot.send_photo(message.chat.id, f)
if is_detected_cat == True:
bot.reply_to(message, "Пришел твой кот. Кормушка открыта")
Обрабатывать команды пользователя в виде голосовых сообщений, в нашем примере будет реагировать только на одну команду "закрой кормушку". Код ниже наверняка можно оптимизировать.
@bot.message_handler(content_types=['voice'])
def process_voice_message(message):
# Получаем информацию о голосовом сообщении
file_id = message.voice.file_id
file_info = bot.get_file(file_id)
file_path = file_info.file_path
# Скачиваем голосовое сообщение
downloaded_file = bot.download_file(file_path)
# Сохраняем голосовое сообщение на диск
voice_file_path = 'voice_message.ogg'
with open(voice_file_path, 'wb') as f:
f.write(downloaded_file)
# Преобразование голосового сообщения в текст
input_file = 'voice_message.ogg'
audio = AudioSegment.from_file(input_file, format='ogg')
# Конвертация в формат WAV
output_file = 'audio.wav'
audio.export(output_file, format='wav')
recognizer = sr.Recognizer()
with sr.AudioFile(output_file) as source:
audio_data = recognizer.record(source)
text = recognizer.recognize_google(audio_data, language='ru') # Здесь можно указать другой язык, если нужно
print(text)
# Отправляем текст пользователю
bot.reply_to(message, text)
# Удаляем временные файлы
os.remove(output_file)
4 часть: запуск!
Напрямую в Google Colab можно запустить бота вот так:
bot.polling()
А можно выгрузить в облако, тогда бот будет работать круглосуточно и без необходимости держать открытым Google Colab. Например, в яндекс облако.
Вот такое интересное и практичное применение возможно моделям искусственного интеллекта, а не вот эти вот все скучные захваты мира))))
А что же дальше...
Главное - желание, а уж идеи найдутся. Например, можно дообучить модель. Собрать собственный датасет пользователя с его питомцем и оттюнинговать модель в целях повышения качества "узнавания" именно конкретно заданного домашнего питомца. Бескрайний простор работы с расширением функционала протокола взаимодействия с кормушкой и другими "умными" вещами, разнообразными датчиками и усложнение их логики. Подключение онлайн детекции питомца по потоковому видео.
Источники
SSD: Single Shot MultiBox Detector
Школа глубокого обучения ФПМИ МФТИ
Прыжок до небес: запускаем телеграм бота на Python в serverless облаке
Послесловие
Да, конечно, в обычных ситуациях проще купить систему умного дома, сейчас они получили широкое повсеместное использование. Но, как правило, в промышленное использование поступают наиболее распространенные запросы, наиболее популярные модели. Плюс на это требуется время. А вот с помощью предобученных моделей мы практически не ограничены в своих возможностях их использования.