惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
G
Google Developers Blog
Latest news
Latest news
Know Your Adversary
Know Your Adversary
O
OpenAI News
腾讯CDC
月光博客
月光博客
P
Privacy International News Feed
Google Online Security Blog
Google Online Security Blog
Help Net Security
Help Net Security
L
LINUX DO - 最新话题
雷峰网
雷峰网
AI
AI
Hacker News - Newest:
Hacker News - Newest: "LLM"
有赞技术团队
有赞技术团队
N
News and Events Feed by Topic
V
Vulnerabilities – Threatpost
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
D
Docker
Google DeepMind News
Google DeepMind News
T
Tor Project blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Hacker News: Ask HN
Hacker News: Ask HN
爱范儿
爱范儿
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Heimdal Security Blog
I
Intezer
WordPress大学
WordPress大学
C
CERT Recently Published Vulnerability Notes
Attack and Defense Labs
Attack and Defense Labs
www.infosecurity-magazine.com
www.infosecurity-magazine.com
P
Privacy & Cybersecurity Law Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
V
V2EX
博客园 - 三生石上(FineUI控件)
G
GRAHAM CLULEY
Security Archives - TechRepublic
Security Archives - TechRepublic
F
Fortinet All Blogs
L
LangChain Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V2EX - 技术
V2EX - 技术
Stack Overflow Blog
Stack Overflow Blog
Recent Announcements
Recent Announcements
T
Tenable Blog
Microsoft Azure Blog
Microsoft Azure Blog
V
Visual Studio Blog
SecWiki News
SecWiki News
Cisco Talos Blog
Cisco Talos Blog

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Кэширование и трекинг. Как YOLO экономит время и нервы
rRenegat · 2026-05-14 · via Все публикации подряд на Хабре

Средний

7 мин

16K

Случалось мне работать с CV: запускаешь сорокаминутное видео, YOLO честно находит людей, машины, собак. На двадцатой минуте падает сеть или, что хуже, камера наблюдения выходит из строя. Перезапускаешь. Модель снова смотрит те же кадры, снова инференс, трекинг ID, пошла пахота GPU…

Так продолжаться не может — подключаю кеширование.

Сегодня разбираемся, как совместить YOLO и кэширование Redis с трекингом объектов так, чтобы каждый кадр считался ровно один раз и чтобы информация не терялась. В конце будут готовые сниппеты, которые можно сразу скопировать и запустить.


Почему нельзя «просто детектить»?

Любой, кто запускал model.track() на видео из десяти тысяч кадров, знает, что модель будет мусолить каждый пиксель, даже если в кадре пустая стена. А если стена неподвижна десять секунд, триста одинаковых кадров получат триста одинаковых вызовов нейросети. Умножаем на цену GPU и стараемся не заплакать.

Вторая проблема: трекинг объектов (ByteTrack, BoT-SORT, DeepSORT) держит своё состояние в оперативной памяти. Выключили свет/сломали камеру или, в конце концов, краш VS-code — потерялись ID всех, кто был в кадре. При перезапуске объект получает новый id, и смысл видеоаналитики обесценивается.

Третья проблема: повторное распознавание. Одна и та же машина паркуется каждое утро, но модель каждый раз с нуля извлекает её признаки, читает номер, определяет цвет. Ненужные телодвижения, не правда ли?

Решение описанных проблем достаточно тривиально: нужен кэш. Простые решения (а-ля пикл-файл и другие локальные кэши) не удовлетворяли моим требованиям архитектуры (прежде всего масштабируемость, модульность), поэтому я использовал Redis, который можно развернуть на отдельном порту.

Кэшируем детекции: Redis

Рассмотрим на простом примере: Redis запущен в докере

На всякий случай

docker run -d --name redis-yolo -p 6372:6379 redis:alpine

Ключ — MD5-хэш изображения. Если кадр поменялся, хэш будет другой.

import hashlib
import pickle
import cv2
from ultralytics import YOLO
import redis

r = redis.Redis(host='127.0.0.1', port=6379, db=0, socket_connect_timeout=2)
model = YOLO("yolo11n.pt")

def frame_hash(frame: cv2.Mat) -> str:
    return hashlib.md5(frame.tobytes()).hexdigest()

def get_detections(frame):
    key = f"yolo_det:{frame_hash(frame)}"
    cached = r.get(key)
    if cached:
        return pickle.loads(cached)

    results = model(frame, verbose=False)[0]
    detections = []
    if results.boxes is not None:
        for box in results.boxes:
            x1, y1, x2, y2 = box.xyxy[0].tolist()
            detections.append({
                "box": [x1, y1, x2, y2],
                "confidence": float(box.conf[0]),
                "class": int(box.cls[0])
            })
    r.setex(key, 1800, pickle.dumps(detections))
    return detections

Что здесь происходит:

  • frame_hash вычисляет MD5-хэш картинки.

  • При отсутствии кэша model(frame).

  • Результат сериализуется через pickle и сохраняется в Redis.

В сущности имеем следующее: первый вызов — порядка 30–50 мс на хорошем GPU. Повторный вызов того же кадра из Redis — около 0.5–1 мс. Приятно? Приятно.

Устойчивый трекинг

Кэширование кадров — отлично. Но что, если вы отслеживаете объекты и вам важно, чтобы ID не скакал после перезапуска системы? (База видеоаналитики)

YOLO изначально даёт трекинг: model.track(frame, persist=True, tracker="bytetrack.yaml"). Проблема в том, что внутреннее состояние трекера живёт в оперативной памяти процесса. При любом падении вы потеряете данные трекинга.

Здесь Redis снова выручает: сохраняем не только детекции, но и сами треки — последовательность bounding boxes с ID для каждого кадра.

import json
import cv2
from ultralytics import YOLO
import redis

r = redis.Redis(host='127.0.0.1', port=6379, db=0)
model = YOLO("yolo11n.pt")

VIDEO_PATH = "parking.mp4"
cache_key = f"track:{VIDEO_PATH}"

cached_tracks = r.get(cache_key)
if cached_tracks:
    tracks = json.loads(cached_tracks)
    print("Треки загружены из Redis.")
else:
    print("Кэш пуст, запускаем полный трекинг.")
    cap = cv2.VideoCapture(VIDEO_PATH)
    tracks = []
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        results = model.track(frame, persist=True, tracker="bytetrack.yaml",
                              verbose=False)
        frame_data = {"frame_idx": len(tracks), "objects": []}
        boxes = results[0].boxes
        if boxes is not None and boxes.id is not None:
            for box, track_id in zip(boxes.xyxy.cpu().numpy(),
                                     boxes.id.cpu().numpy()):
                x1, y1, x2, y2 = map(float, box)
                frame_data["objects"].append({
                    "box": [x1, y1, x2, y2],
                    "id": int(track_id)
                })
        tracks.append(frame_data)
    cap.release()
    r.set(cache_key, json.dumps(tracks))
    print(f"Готово, {len(tracks)} кадров записаны в Redis.")

Теперь систему можно ронять в любой момент) При перезапуске все треки восстановятся из Redis’а и объекты сохранят свои ID.

Эмбеддинги

А что, если кэшировать не просто детекции, а признаки объекта? Векторное представление (embedding) — это сжатая «личность» машины, человека или товара. Извлекли один раз — и потом просто сравниваем новый кадр с сохранённым вектором. Без повторного распознавания.

Какие модели используют для эмбеддингов в CV?

Задача «превратить картинку в вектор» называется извлечением признаков (feature extraction). Под капотом используется свёрточная нейросеть (CNN) или Vision Transformer. На выходе получается вектор, как правильно, имеющий размерность 512, 768 или 2048, который описывает содержимое изображения. Дальше такой вектор можно сравнивать с другими через стандартное косинусное расстояние.

Пример подобных моделей:

  • CLIP от OpenAI. Понимает связь между текстом и картинками, но даже если использовать только визуальную часть — качество эмбеддингов очень высокое.

  • Модели:
    openai/clip-vit-base-patch16,
    openai/clip-vit-large-patch14.

  • Плюсы: отлично работает изначально, не нужно дообучать.

  • Минусы: имеет зависимость в виде либы transformers, весит прилично.

  • TIMM (EfficientNet, ConvNeXt и подобные). Библиотека timm — это швейцарский нож для CV. Внутри — предобученные модели, выбирай не хочу. Для эмбеддингов чаще всего берут efficientnet_b0 (1280 признаков) или convnext_tiny (768 признаков).

  • Плюсы: легковесные, быстрые, отличный выбор для поиска похожих изображений.

  • Минусы: ввиду разнообразия содержимого нет конкретики по решению. Придётся выбирать и сравнивать.

  • Torchvision (ResNet50, MobileNetV3) Классика, которая идёт в комплекте с PyTorch. ResNet50 (2048 признаков) — проверенное временем решение. MobileNetV3-Large (960 признаков) — шустрая темка для слабого GPU.

  • Плюсы: всегда под рукой, не надо ставить лишние зависимости.

  • Минусы: для задач распознавания, требующих внимания к большому числу признаков и деталей (например, отличить двух похожих людей) может уступать CLIP.

Рассмотрим несколько гипотетических кейсов:

Парковка или гараж с распознаванием номеров, КПП/въезд на объект. Машина въезжает впервые. YOLO находит авто и вырезает номерную пластину. OCR-модель считывает госномер «А123БТ777». Этот номер — уникальный идентификатор. В Redis по ключу plate:A123BT777 сохраняется эмбеддинг внешнего вида автомобиля (цвет, форма, особые приметы) — вектор на 512 или 1024 числа. Плюс дата первого появления, марка, модель.

При следующем въезде YOLO снова детектит машину, OCR читает номер. Система находит совпадение в Redis: «Это же тот самый рено логан чёрного цвета XX века, я его знаю». Подтягивается его эмбеддинг, сравнивается с текущим изображением для идентификации, и открывается шлагбаум. OCR для номера вызывается, но модель/алгоритм распознавания самой машины со всеми её признаками — нет.

Конвейерная проверка качества. Идут сотни одинаковых плат. Первая — эталонная — детектится YOLO, её разметка (bbox’ы компонентов) сохраняются в Redis как pcb_template:model_X. Для всех последующих плат модель включается только при отклонении от этого эталона по гистограмме или площади.

Фотоловушки в заповеднике. Камера снимает медведя, YOLO вырезает его морду, модель распознавания извлекает эмбеддинг — уникальные особенности шкуры, форму ушей, шрамы. Этот эмбеддинг кэшируется в Redis. Когда через три дня тот же медведь приходит к водопою, система не создаёт новую запись в журнале учёта, а говорит: «Повторная встреча, особь №67».

Общий код такого кэширования:

import numpy as np
import redis
from redis.commands.search.field import VectorField, TagField
from redis.commands.search.indexDefinition import IndexDefinition, IndexType
from redis.commands.search.query import Query
from PIL import Image
import torch
from transformers import CLIPModel, CLIPProcessor
import cv2


class CLIPEmbedder:
    def __init__(self, model_name="openai/clip-vit-base-patch16"):
        self.device = "cuda" if torch.cuda.is_available() else "cpu"
        self.model = CLIPModel.from_pretrained(model_name).to(self.device)
        self.processor = CLIPProcessor.from_pretrained(model_name)
        self.model.eval()

    def extract(self, image: Image.Image) -> np.ndarray:
        inputs = self.processor(images=image, return_tensors="pt").to(self.device)
        with torch.no_grad():
            features = self.model.get_image_features(**inputs)
        features = features / features.norm(dim=-1, keepdim=True)
        return features[0].cpu().numpy()


r = redis.Redis(host='127.0.0.1', port=6379, db=0)
embedder = CLIPEmbedder()

# Параметры индекса
INDEX_NAME = "idx:objects"
VECTOR_DIM = 512  
DISTANCE_METRIC = "COSINE"  
PREFIX = "object:"         


def create_index():
    """Создаёт векторный индекс, если он ещё не существует."""
    try:
        r.ft(INDEX_NAME).info()
        print("Индекс уже существует.")
    except:
        print("Создаём индекс...")
        schema = (
            VectorField(
                "embedding",
                "COSINE",  
                {
                    "TYPE": "FLOAT32",
                    "DIM": VECTOR_DIM,
                    "DISTANCE_METRIC": DISTANCE_METRIC,
                },
            ),
            TagField("id"),  
        )
        definition = IndexDefinition(prefix=[PREFIX], index_type=IndexType.HASH)
        r.ft(INDEX_NAME).create_index(schema, definition=definition)
        print("Индекс создан.")


create_index()


def get_or_identify(crop: np.ndarray) -> str:
    # Преобразуем BGR (OpenCV) → RGB 
    crop_rgb = cv2.cvtColor(crop, cv2.COLOR_BGR2RGB)
    pil_image = Image.fromarray(crop_rgb)

    emb = embedder.extract(pil_image)
    emb_bytes = emb.astype(np.float32).tobytes()
    query = (
        Query("*=>[KNN 1 @embedding $vec]")
        .return_field("__embedding_score")  # расстояние (1 - cosine)
        .return_field("id")
        .dialect(2) 
    )
    results = r.ft(INDEX_NAME).search(query, query_params={"vec": emb_bytes})

    if results.docs:
        distance = float(results.docs[0].__embedding_score)
        similarity = 1.0 - distance
        if similarity > 0.8:
            object_id = results.docs[0].id.split(":")[1]
            return object_id

  
    new_id = str(r.incr("next_object_id"))
    object_key = f"object:{new_id}"
    r.hset(
        object_key,
        mapping={
            "id": new_id,
            "embedding": emb_bytes,
        },
    )
    return new_id



Заключение

Итого после проделанных махинаций, имеем:

  • Каждый кадр считается один раз. Даже если скрипт упал, Redis помнит всё, что уже было посчитано.

  • Трекинг больше не боится перезагрузок. Потому что состояние хранится в базе данных, а не в оперативной памяти.

  • Повторные объекты идентифицируются мгновенно. Машины, люди, платы, медведы — им не нужно повторное распознавание.


Спасибо за прочтение! Буду рад обратной связи!

Какие методы для кэширования объектов в системах видеоаналитики используете вы?

© 2026 ООО «МТ ФИНАНС»