-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathinference.py
More file actions
124 lines (94 loc) · 3.44 KB
/
Copy pathinference.py
File metadata and controls
124 lines (94 loc) · 3.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# Copyright 2025 Yakhyokhuja Valikhujaev
# Author: Yakhyokhuja Valikhujaev
# GitHub: https://github.com/yakhyo
import numpy as np
from PIL import Image
import torch
from torchvision import transforms
from models import (
sphere20,
sphere36,
sphere64,
MobileNetV1,
MobileNetV2,
mobilenet_v3_small,
mobilenet_v3_large,
)
from utils.face_utils import compute_similarity
def get_network(model_name: str) -> torch.nn.Module:
"""
Returns the appropriate model based on the provided model name.
Args:
model_name (str): Name of the model architecture.
Returns:
torch.nn.Module: The selected deep learning model.
"""
models = {
"sphere20": sphere20(embedding_dim=512, in_channels=3),
"sphere36": sphere36(embedding_dim=512, in_channels=3),
"sphere64": sphere64(embedding_dim=512, in_channels=3),
"mobilenetv1": MobileNetV1(embedding_dim=512),
"mobilenetv2": MobileNetV2(embedding_dim=512),
"mobilenetv3_small": mobilenet_v3_small(embedding_dim=512),
"mobilenetv3_large": mobilenet_v3_large(embedding_dim=512),
}
if model_name not in models:
raise ValueError(f"Unsupported network '{model_name}'! Available options: {list(models.keys())}")
return models[model_name]
def load_model(model_name: str, model_path: str, device: torch.device = None) -> torch.nn.Module:
"""
Loads a deep learning model with pre-trained weights.
"""
model = get_network(model_name)
try:
model.load_state_dict(torch.load(model_path, map_location=device))
model.to(device).eval()
except Exception as e:
raise RuntimeError(f"Error loading model '{model_name}' from {model_path}: {e}")
return model
def get_transform():
"""
Returns the image preprocessing transformations.
"""
return transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
def extract_features(model, device, img_path: str) -> np.ndarray:
"""
Extracts face features from an image.
"""
transform = get_transform()
try:
img = Image.open(img_path).convert("RGB")
except Exception as e:
raise FileNotFoundError(f"Error opening image {img_path}: {e}")
tensor = transform(img).unsqueeze(0).to(device)
with torch.no_grad():
features = model(tensor).squeeze().cpu().numpy()
return features
def compare_faces(model, device, img1_path: str, img2_path: str, threshold: float = 0.35) -> tuple[float, bool]:
"""
Compares two face images and determines if they belong to the same person.
"""
feat1 = extract_features(model, device, img1_path)
feat2 = extract_features(model, device, img2_path)
similarity = compute_similarity(feat1, feat2)
is_same = similarity > threshold
return similarity, is_same
if __name__ == "__main__":
# Example usage with model selection
model_name = "mobilenetv2"
model_path = "weights/mobilenetv2_mcp.pth"
threshold = 0.35
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# Load model
model = load_model(model_name, model_path, device)
# Compare faces
similarity, is_same = compare_faces(
model, device,
img1_path="assets/b_01.jpg",
img2_path="assets/b_02.jpg",
threshold=threshold
)
print(f"Similarity: {similarity:.4f} - {'same' if is_same else 'different'} (Threshold: {threshold})")