• XSS.stack #1 – первый литературный журнал от юзеров форума

Лучший ИИ для распознавания лица

Готовых решений не знаю. Но можно попробовать прогонять лица через самую большую модель yolo-seg, получить эмбеддинги под каждое лицо. И если тебе повезет и пути обобщения будут иметь какие то явные различия, то в теории это можно использовать для распознавания лиц. Я использовал когда то такой код для визуализации эмбеддингов из двух кллючевых слоев, но под твою задачу подойдет только эмбеддинг из 16 слоя.

Python:
import cv2
import numpy as np
import torch
from ultralytics import YOLO
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.interpolate import CubicSpline

torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
torch.use_deterministic_algorithms(True)
def process_image(image_path, model):
    image = cv2.imread(image_path)
    if image is None:
        raise ValueError(f"Не удалось загрузить изображение: {image_path}")
    original_shape = image.shape[:2]
    yolo_size = (max(32, (original_shape[0] + 31) // 32 * 32), max(32, (original_shape[1] + 31) // 32 * 32))
    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.uint8)
    image_tensor = torch.from_numpy(image_rgb).permute(2, 0, 1).float() / 255.0
    image_tensor = image_tensor.clamp(0.0, 1.0).unsqueeze(0).to(model.device)
    activations = {}
    def get_activation(name):
        def hook(module, input, output):
            activations[name] = output
        return hook
    layers = model.model.model
    layers[4].register_forward_hook(get_activation("layer_4"))
    layers[16].register_forward_hook(get_activation("layer_16"))
    with torch.no_grad():
        results = model(image, conf=0.4, imgsz=yolo_size)
    embeddings = []
    for layer_name in ["layer_4", "layer_16"]:
        activation = activations.get(layer_name, torch.zeros(1))
        embedding = activation.mean(dim=[2, 3]) if len(activation.shape) == 4 else torch.zeros(1)
        embeddings.append(embedding)
    return embeddings
def visualize_generalization_path(embeddings_list, image_paths):

    fig = plt.figure(figsize=(12, 12))
    ax = fig.add_subplot(111, projection='3d')
   
    colors = ['green', 'orange']       # цвета для разных изображений
    point_colors = ['cyan', 'magenta']
    for idx, (embeddings, image_path) in enumerate(zip(embeddings_list, image_paths)):

        layer_4_emb = embeddings[0].cpu().numpy().flatten()          #тебе именно этот слой не нужен, можешь его удалить.
        layer_16_emb = embeddings[1].cpu().numpy().flatten()
        all_values = np.concatenate([layer_4_emb, layer_16_emb])  # Все значения активаций (~200) включая 4 и 16 слой.

        N = len(all_values)
        z = np.linspace(0, 10, N)
        x = all_values
        y = np.zeros(N)

        t = np.arange(N)
        t_fine = np.linspace(0, N-1, 1000)
        cs_x = CubicSpline(t, x)
        cs_y = CubicSpline(t, y)
        cs_z = CubicSpline(t, z)
        x_traj = cs_x(t_fine)
        y_traj = cs_y(t_fine)
        z_traj = cs_z(t_fine)

        ax.scatter(x, y, z, c=point_colors[idx], s=50, alpha=0.6,
                   label=f'Activations ({image_paths[idx].split("/")[-1]})')

        # точки 4-го и 16-го слоев
        ax.scatter(layer_4_emb, np.zeros(len(layer_4_emb)),
                   np.linspace(0, 10 * len(layer_4_emb) / N, len(layer_4_emb)),
                   c=point_colors[idx], s=70, alpha=0.8,
                   label=f'Layer 4 ({image_paths[idx].split("/")[-1]})')
        ax.scatter(layer_16_emb, np.zeros(len(layer_16_emb)),
                   np.linspace(10 * len(layer_4_emb) / N, 10, len(layer_16_emb)),
                   c=point_colors[idx], s=70, alpha=0.8,
                   label=f'Layer 16 ({image_paths[idx].split("/")[-1]})')

        ax.plot(x_traj, y_traj, z_traj, c=colors[idx], linestyle='-', linewidth=2,
                label=f'Path ({image_paths[idx].split("/")[-1]})')

    ax.set_xlabel('Activation Value')
    ax.set_ylabel('Fixed Axis')
    ax.set_zlabel('Feature Index (Layer 4 -> Layer 16)')
    ax.set_title('3D Comparison of Generalization Paths (Two Images)')
    ax.set_box_aspect([1, 1, 3]) 
    ax.legend()
    plt.show()

device = torch.device("cpu")
model = YOLO("yolo11n-seg.pt").to(device)
image_paths = ["путь к изображению 1.png", "путь к изображению 2.png"]  # пути к условным лицам

embeddings_list = [process_image(image_path, model) for image_path in image_paths]

visualize_generalization_path(embeddings_list, image_paths)


При запуске откроется такая шняга, тут 2 линии показывают путь обобщения. В моем примере я прогонял 2 максимально похожих изображения, различия в несколько пикселей мб, но в твоем случае пути будут явно разные.
Снимок экрана 2025-06-04 191225.png

Снимок экрана 2025-06-04 191236.png
 
Последнее редактирование:


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх