Розробка системи ідентифікації обличчя (Face Identification, 1:N)

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1Усі 1566 послуг
Розробка системи ідентифікації обличчя (Face Identification, 1:N)
Складний
від 2 тижнів до 3 місяців
Часті запитання

Напрямки AI-розробки

Етапи розробки AI-рішення

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1285
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    902
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1122
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    859

Розробка систем ідентифікації облич (1:N)

Ідентифікація облич — пошук людини в базі без попередньоготаким указання кандидата. Система отримує фото обличчя та повертає: хто це зі зареєстрованих людей або "невідомо". Технічно складніше за верифікацію: потрібно масштабоване сховище, швидкий ANN-пошук, правильне керування порогами в міру зростання бази.

Архітектурне рішення для масштабування

При базі > 100k облич грубий силовий пошук стає занадто повільним. Ієрархія підходів:

Розмір бази Метод пошуку Затримка
< 10k Brute-force косинусна подібність (NumPy) < 1 мс
10k–1M FAISS IVFFlat < 5 мс
1M–100M FAISS IVFPQ (Product Quantization) < 10 мс
> 100M ScaNN або кластер Milvus < 20 мс
import faiss
import numpy as np
from dataclasses import dataclass

@dataclass
class IdentificationResult:
    person_id: str | None
    person_name: str | None
    similarity: float
    identified: bool

class FaceIdentificationSystem:
    def __init__(self, embedding_dim: int = 512,
                 n_lists: int = 100,  # параметр IVF
                 threshold: float = 0.45):
        self.dim = embedding_dim
        self.threshold = threshold

        # FAISS IVFFlat індекс з Inner Product (косинус через нормалізацію)
        quantizer = faiss.IndexFlatIP(embedding_dim)
        self.index = faiss.IndexIDMap(
            faiss.IndexIVFFlat(quantizer, embedding_dim, n_lists,
                               faiss.METRIC_INNER_PRODUCT)
        )
        self.index.nprobe = 20  # більше = точніше але повільніше

        self.id_map = {}  # faiss_int_id -> {'person_id': str, 'name': str}
        self._next_id = 0

    def register(self, person_id: str, name: str,
                 embeddings: np.ndarray) -> int:
        """Реєстрація декількох фото однієї людини"""
        faiss.normalize_L2(embeddings)
        ids = np.arange(self._next_id, self._next_id + len(embeddings))

        if not self.index.is_trained:
            # Потрібен мінімальний набір даних для навчання IVF
            self.index.train(embeddings)

        self.index.add_with_ids(embeddings, ids)

        for fid in ids:
            self.id_map[int(fid)] = {'person_id': person_id, 'name': name}

        self._next_id += len(embeddings)
        return len(embeddings)

    def identify(self, query_embedding: np.ndarray,
                 k: int = 5) -> IdentificationResult:
        query = query_embedding.reshape(1, -1).copy()
        faiss.normalize_L2(query)

        similarities, faiss_ids = self.index.search(query, k)

        best_sim = float(similarities[0][0])
        best_id = int(faiss_ids[0][0])

        if best_id == -1 or best_sim < self.threshold:
            return IdentificationResult(None, None, best_sim, False)

        person_info = self.id_map[best_id]
        return IdentificationResult(
            person_info['person_id'],
            person_info['name'],
            best_sim,
            True
        )

Декілька зображень на людину

Реєстрація декількох фото під різними кутами та умовами освітлення підвищує recall. При ідентифікації з агрегацією за всіма фото людини:

def identify_with_aggregation(self, query_emb: np.ndarray,
                               k: int = 10) -> IdentificationResult:
    """k кандидатів → агрегація голосів за person_id"""
    query = query_emb.reshape(1, -1).copy()
    faiss.normalize_L2(query)
    similarities, faiss_ids = self.index.search(query, k)

    votes = {}
    for sim, fid in zip(similarities[0], faiss_ids[0]):
        if fid == -1:
            continue
        pid = self.id_map[int(fid)]['person_id']
        votes[pid] = votes.get(pid, 0) + float(sim)

    if not votes:
        return IdentificationResult(None, None, 0.0, False)

    best_pid = max(votes, key=votes.get)
    best_score = votes[best_pid] / k  # normalize

    if best_score < self.threshold:
        return IdentificationResult(None, None, best_score, False)

    name = self.id_map[next(
        fid for fid, info in self.id_map.items()
        if info['person_id'] == best_pid
    )]['name']
    return IdentificationResult(best_pid, name, best_score, True)

Закрита множина vs відкрита множина ідентифікація

Закрита множина: всі запити належать одній із зареєстрованих людей. Завдання зводиться до ранжування.

Відкрита множина: система повинна відхилити "невідомих" — людей не з бази. Вимагає налаштування порога відхилення. В міру зростання бази поріг може потребувати коригування: від 1000 до 100k людей ймовірність випадкового збігу зростає.

Оновлення бази в реальному часі

Додавання нових користувачів без переіндексації: index.add_with_ids() працює інкрементально. Видалення: IndexIDMap.remove_ids(). Персистентність через faiss.write_index().

Метрики production-системи

  • CMC (Cumulative Match Characteristic): Rank-1, Rank-5, Rank-10 точність
  • DIR@FAR (Detection and Identification Rate): для відкритої множини
  • Latency p95/p99 під піковим навантаженням
  • QPS (queries per second) — для планування інфраструктури
Розмір бази Рекомендоване обладнання QPS
< 100k 1 CPU-сервер 500+
100k–10M 1 GPU + FAISS GPU 2000+
> 10M кластер Milvus 5000+
Масштаб проекту Графік
До 100k облич, одна локація 4–6 тижнів
1M+ облич, multi-site 8–14 тижнів
Enterprise real-time система 12–20 тижнів