Machine Learning и Edge AI — ИИ в кармане
Machine Learning и Edge AI — ИИ в кармане
Edge AI — это когда умные алгоритмы работают прямо на твоём устройстве, а не где-то далеко в облаке. Представь: раньше чтобы спросить у робота “Который час?”, нужно было отправить голос в интернет, подождать ответа от сервера и получить ответ. С Edge AI робот понимает тебя сразу, даже без интернета!
Зачем это нужно?
- Быстро — нет задержек на передачу данных
- Надёжно — работает без интернета
- Конфиденциально — твои данные никуда не уходят
- Дёшево — не нужно платить за облачные серверы
Три уровня сложности
Уровень 1: TinyML (ИИ на микроконтроллерах)
Для чего: Arduino, ESP32, STM32 Что может: Простые команды, базовое распознавание Пример: “Окей, робот” → робот просыпается
Уровень 2: Одноплатники (ИИ на Raspberry Pi)
Для чего: Raspberry Pi, Orange Pi Что может: Распознавание объектов, простое зрение Пример: Видит кошку и говорит “Мяу!”
Уровень 3: Ускорители (Серьёзный ИИ)
Для чего: NVIDIA Jetson, Google Coral Что может: Автономное вождение, сложное зрение Пример: Робот сам едет по коридору, объезжая препятствия
Проект 1: Робот, который понимает голос (TinyML на ESP32)
Что будет делать:
- Слышит команды “вперёд”, “назад”, “стоп”
- Выполняет их без интернета
- Потребляет мало энергии (работает от батареек)
Код для ESP32 (Arduino IDE):
#include <TensorFlowLite.h>
#include <tensorflow/lite/micro/all_ops_resolver.h>
#include <tensorflow/lite/micro/micro_interpreter.h>
#include "model.h" // Наша обученная модель
// Наша модель распознаёт 4 команды:
enum Command {
SILENCE = 0,
FORWARD = 1,
BACKWARD = 2,
STOP = 3
};
// Настройка микрофона (упрощённо)
const int micPin = 34;
const int sampleWindow = 50; // 50 мс записи
const int sampleRate = 16000; // 16 кГц
// Загружаем модель
const tflite::Model* model = tflite::GetModel(g_model);
tflite::MicroInterpreter* interpreter;
void setup() {
Serial.begin(115200);
// Инициализируем TensorFlow Lite
static tflite::AllOpsResolver resolver;
static uint8_t tensor_arena[10 * 1024]; // 10 КБ памяти для модели
static tflite::MicroInterpreter static_interpreter(
model, resolver, tensor_arena, sizeof(tensor_arena));
interpreter = &static_interpreter;
interpreter->AllocateTensors();
Serial.println("Робот слушает...");
Serial.println("Скажи: 'вперёд', 'назад' или 'стоп'");
}
void loop() {
// 1. Записываем звук
float* audio_data = recordAudio();
// 2. Подаём в нейросеть
float* input = interpreter->input(0)->data.f;
for (int i = 0; i < 16000 * 0.05; i++) { // 50 мс аудио
input[i] = audio_data[i];
}
// 3. Запускаем нейросеть
interpreter->Invoke();
// 4. Получаем результат
float* output = interpreter->output(0)->data.f;
int command = 0;
float max_prob = 0;
for (int i = 0; i < 4; i++) {
if (output[i] > max_prob) {
max_prob = output[i];
command = i;
}
}
// 5. Выполняем команду
if (max_prob > 0.7) { // Если уверенность > 70%
switch(command) {
case FORWARD:
Serial.println("Команда: ВПЕРЁД!");
moveForward();
break;
case BACKWARD:
Serial.println("Команда: НАЗАД!");
moveBackward();
break;
case STOP:
Serial.println("Команда: СТОП!");
stop();
break;
default:
// Тишина или нераспознано
break;
}
}
delay(100); // Проверяем каждые 100 мс
}
// Упрощённая запись звука
float* recordAudio() {
static float samples[800]; // 16000 Гц * 0.05 с = 800 сэмплов
unsigned long start = millis();
int i = 0;
while (millis() - start < sampleWindow && i < 800) {
int sample = analogRead(micPin);
samples[i] = (sample - 2048) / 2048.0; // Нормализация -1..1
i++;
delayMicroseconds(62); // ~16 кГц
}
return samples;
}
Как обучить модель (Google Colab):
# 1. Собираем данные
import tensorflow as tf
import numpy as np
# Создаём простой датасет (в реальности нужно записывать голос)
# 4 класса: тишина, вперёд, назад, стоп
def create_synthetic_dataset():
samples = 1000
audio_length = 800 # 50 мс при 16 кГц
X = np.random.randn(samples, audio_length).astype(np.float32)
y = np.random.randint(0, 4, samples)
return X, y
X_train, y_train = create_synthetic_dataset()
# 2. Создаём простую модель
model = tf.keras.Sequential([
tf.keras.layers.Input(shape=(800,)),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(32, activation='relu'),
tf.keras.layers.Dense(4, activation='softmax') # 4 команды
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 3. Обучаем
model.fit(X_train, y_train, epochs=10, batch_size=32)
# 4. Конвертируем для TinyML
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT] # Сжатие
converter.target_spec.supported_ops = [
tf.lite.OpsSet.TFLITE_BUILTINS # Только базовые операции
]
tflite_model = converter.convert()
# 5. Сохраняем как C-массив для Arduino
with open('model.h', 'w') as f:
f.write('const unsigned char g_model[] = {')
f.write(','.join(str(b) for b in tflite_model))
f.write('};\n')
f.write(f'const int g_model_len = {len(tflite_model)};')
Проект 2: Распознавание объектов на Raspberry Pi
Что будет делать:
- По видео с камеры находит людей, машины, животных
- Говорит, что видит
- Работает в реальном времени (2-5 кадров в секунду)
Код для Raspberry Pi (Python):
import cv2
import numpy as np
from tflite_runtime.interpreter import Interpreter
import time
class ObjectDetector:
def __init__(self, model_path='ssd_mobilenet_v2.tflite', labels_path='coco_labels.txt'):
# Загружаем модель TensorFlow Lite
self.interpreter = Interpreter(model_path=model_path)
self.interpreter.allocate_tensors()
# Получаем информацию о вводе/выводе
self.input_details = self.interpreter.get_input_details()
self.output_details = self.interpreter.get_output_details()
# Размер входного изображения
self.input_shape = self.input_details[0]['shape']
self.height = self.input_shape[1]
self.width = self.input_shape[2]
# Загружаем названия классов
with open(labels_path, 'r') as f:
self.labels = [line.strip() for line in f.readlines()]
def detect_objects(self, image):
# Подготавливаем изображение
img_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
img_resized = cv2.resize(img_rgb, (self.width, self.height))
input_data = np.expand_dims(img_resized, axis=0)
# Нормализуем, если нужно
if self.input_details[0]['dtype'] == np.float32:
input_data = (np.float32(input_data) - 127.5) / 127.5
# Запускаем модель
self.interpreter.set_tensor(self.input_details[0]['index'], input_data)
self.interpreter.invoke()
# Получаем результаты
boxes = self.interpreter.get_tensor(self.output_details[0]['index'])[0]
classes = self.interpreter.get_tensor(self.output_details[1]['index'])[0]
scores = self.interpreter.get_tensor(self.output_details[2]['index'])[0]
# Фильтруем по уверенности
min_score = 0.5
detections = []
for i in range(len(scores)):
if scores[i] > min_score:
ymin, xmin, ymax, xmax = boxes[i]
# Переводим координаты в размер исходного изображения
xmin = int(xmin * image.shape[1])
xmax = int(xmax * image.shape[1])
ymin = int(ymin * image.shape[0])
ymax = int(ymax * image.shape[0])
class_id = int(classes[i])
label = self.labels[class_id]
detections.append({
'box': (xmin, ymin, xmax, ymax),
'score': scores[i],
'label': label
})
return detections
def draw_detections(self, image, detections):
for det in detections:
xmin, ymin, xmax, ymax = det['box']
label = det['label']
score = det['score']
# Рисуем прямоугольник
cv2.rectangle(image, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2)
# Подписываем
text = f"{label} {score:.2f}"
cv2.putText(image, text, (xmin, ymin - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
return image
# Главная программа
def main():
print("Запуск распознавания объектов на Raspberry Pi...")
# Инициализируем детектор
detector = ObjectDetector()
# Открываем камеру
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) # Уменьшаем для скорости
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
fps_counter = 0
fps_time = time.time()
try:
while True:
# Читаем кадр
ret, frame = cap.read()
if not ret:
break
# Распознаём объекты
detections = detector.detect_objects(frame)
# Рисуем результаты
frame_with_boxes = detector.draw_detections(frame.copy(), detections)
# Считаем FPS
fps_counter += 1
if time.time() - fps_time >= 1.0:
fps = fps_counter
fps_counter = 0
fps_time = time.time()
print(f"FPS: {fps}, Объектов: {len(detections)}")
# Говорим, что нашли
if detections:
objects = ', '.join(set(d['label'] for d in detections))
print(f"Вижу: {objects}")
# Показываем результат
cv2.imshow('Raspberry Pi Object Detection', frame_with_boxes)
# Выход по 'q'
if cv2.waitKey(1) & 0xFF == ord('q'):
break
except KeyboardInterrupt:
print("\nОстановка...")
finally:
cap.release()
cv2.destroyAllWindows()
print("Программа завершена")
if __name__ == "__main__":
main()
Установка на Raspberry Pi:
# 1. Установка зависимостей
sudo apt-get update
sudo apt-get install python3-opencv python3-numpy
# 2. Установка TensorFlow Lite
pip3 install tflite-runtime
# 3. Скачивание модели и меток
wget https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip
unzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip
# 4. Создание файла с метками
echo "person" > coco_labels.txt
echo "bicycle" >> coco_labels.txt
echo "car" >> coco_labels.txt
# ... и так 80 классов из COCO датасета
Проект 3: Google Coral USB Accelerator — суперскорость
Google Coral — это USB-флешка с нейропроцессором (NPU). Она ускоряет нейросети в 10-100 раз!
Установка и использование:
from pycoral.utils.edgetpu import make_interpreter
from pycoral.adapters import common
from pycoral.adapters import detect
import cv2
# Загрузка модели для Coral
interpreter = make_interpreter('ssd_mobilenet_v2_coco_quant_postprocess_edgetpu.tflite')
interpreter.allocate_tensors()
# Обработка изображения (очень быстро!)
def detect_with_coral(image):
# Подготовка
_, scale = common.set_resized_input(
interpreter, image.shape[:2],
lambda size: cv2.resize(image, size))
# Запуск (в 10 раз быстрее чем на CPU!)
interpreter.invoke()
# Получение результатов
objs = detect.get_objects(interpreter, 0.5, scale)
return objs
# Использование с веб-камерой
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
# Детекция (60 FPS вместо 5 на Raspberry Pi!)
objects = detect_with_coral(frame)
for obj in objects:
bbox = obj.bbox
label = labels[obj.id]
score = obj.score
# Рисование результатов
cv2.rectangle(frame, (bbox.xmin, bbox.ymin),
(bbox.xmax, bbox.ymax), (0, 255, 0), 2)
cv2.putText(frame, f"{label} {score:.2f}",
(bbox.xmin, bbox.ymin-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
cv2.imshow('Coral Accelerator', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Сравнение платформ
| Платформа | Цена | Скорость | Энергия | Сложность | Пример использования |
|---|---|---|---|---|---|
| ESP32 | $5 | Медленно | Очень мало | Средняя | Голосовые команды |
| Raspberry Pi 4 | $35 | Средне | Мало | Низкая | Распознавание объектов (5 FPS) |
| Google Coral | $60 | Быстро | Средне | Низкая | Распознавание объектов (60 FPS) |
| NVIDIA Jetson Nano | $99 | Очень быстро | Много | Высокая | Автономный дрон |
Практические задания
Для начинающих:
- Мигающий светодиод по голосу — скажи “включи” → загорается светодиод на ESP32
- Счётчик людей — Raspberry Pi считает, сколько людей прошло перед камерой
- Распознавание эмоций — определяет, улыбается человек или нет
Для продвинутых:
- Робот-сортировщик — распознаёт объекты и кладёт в разные корзины
- Система безопасности — распознаёт знакомые лица, чужих — предупреждает
- Ассистент для слабовидящих — описывает, что вокруг (человек, машина, дверь)
Готовые проекты для копирования:
- Google AIY Voice Kit — голосовой помощник на Raspberry Pi
- Edge Impulse — платформа для TinyML без кодирования
- TensorFlow Lite примеры — готовые модели для разных задач
Частые проблемы и решения
Проблема 1: Модель не помещается в память
# Решение: квантование (уменьшение размера)
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT] # Сжатие в 4 раза!
converter.target_spec.supported_types = [tf.float16] # Половина точности
tflite_model = converter.convert()
Проблема 2: Работает слишком медленно
# Решение 1: Уменьшить разрешение
# Было: 320x240 -> Стало: 160x120 (в 4 раза быстрее!)
# Решение 2: Использовать готовые оптимизированные модели
# MobileNet, EfficientNet-Lite вместо ResNet
# Решение 3: Аппаратное ускорение (Coral, Jetson)
Проблема 3: Плохо распознаёт в реальных условиях
# Решение: Аугментация данных при обучении
datagen = tf.keras.preprocessing.image.ImageDataGenerator(
rotation_range=20, # Повороты
width_shift_range=0.2, # Сдвиги
brightness_range=[0.8, 1.2], # Яркость
zoom_range=0.2, # Зум
horizontal_flip=True # Отражение
)
# Модель учится на "разных" условиях
Полезные ресурсы
Данные для обучения:
- Google Speech Commands — 65,000 записей голосовых команд
- COCO — 330,000 изображений с объектами
- MNIST — 70,000 рукописных цифр
- CIFAR-10 — 60,000 маленьких цветных изображений
Готовые модели:
- TensorFlow Hub — тысячи готовых моделей
- Model Zoo от Google — оптимизированные для Edge
- ONNX Model Zoo — модели в универсальном формате
Инструменты:
- Edge Impulse — визуальное создание TinyML моделей
- TensorFlow Lite Converter — конвертация моделей
- Netron — просмотрщик моделей нейросетей
Советы от профессионалов:
- Начинай с готовых моделей — не учи с нуля
- Прототипируй на Colab — бесплатный GPU для обучения
- Тестируй на целевом железе — на компьютере всегда быстрее
- Оптимизируй постепенно — сначала работает, потом быстро работает
- Думай о энергии — от батареи или от розетки?
Edge AI — это не будущее, это настоящее. Уже сегодня умные устройства вокруг нас понимают наш мир без облаков. Теперь и ты можешь создавать такие устройства!
