Probleme : 12% des CV comportent des informations falsifiees
Selon des etudes recentes, entre 10 et 15% des candidats exagerent ou falsifient des informations sur leur CV : diplomes, experiences, certifications. Notre client, un cabinet de recrutement specialise dans les postes techniques, perdait en moyenne 3 semaines et 2 500 euros par recrutement rate suite a des embauches sur la base de faux documents.
Objectif : Detecter automatiquement les incohérences visuelles dans les documents (diplomes, certificats, bulletins de salaire) avant la phase d'entretien. Precision cible : superieure a 90%.
Dataset et augmentation de donnees
Le plus grand defi : le manque de donnees labelisees. Nous avons constitue un dataset de 8 500 documents en collaboration avec le client :
- 4 200 documents authentiques (diplomes, certificats, bulletins)
- 4 300 documents falsifies (crees par nos soins pour l'entrainement)
- Augmentation data : rotation, bruit gaussien, compression JPEG, variations d'eclairage
import torch
import torchvision.transforms as T
from torchvision.datasets import ImageFolder
# Pipeline d'augmentation robuste
transform_train = T.Compose([
T.Resize((224, 224)),
T.RandomHorizontalFlip(p=0.1), # Documents souvent en portrait
T.RandomRotation(degrees=3), # Legerement penches
T.ColorJitter(brightness=0.3, contrast=0.3, saturation=0.1),
T.GaussianBlur(kernel_size=3, sigma=(0.1, 0.5)),
T.ToTensor(),
T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
dataset = ImageFolder(root="data/documents", transform=transform_train)
train_set, val_set = torch.utils.data.random_split(dataset, [0.8, 0.2])
Fine-tuning ResNet-50
import torchvision.models as models
import torch.nn as nn
# Chargement du ResNet-50 pre-entraine
model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V2)
# Gel des couches basses (features generiques)
for name, param in model.named_parameters():
if "layer4" not in name and "fc" not in name:
param.requires_grad = False
# Remplacement du classifieur final
num_features = model.fc.in_features
model.fc = nn.Sequential(
nn.Dropout(0.4),
nn.Linear(num_features, 256),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(256, 2) # 0=authentique, 1=falsifie
)
# Optimiseur avec learning rates differencies
optimizer = torch.optim.AdamW([
{"params": model.layer4.parameters(), "lr": 1e-4},
{"params": model.fc.parameters(), "lr": 1e-3}
], weight_decay=1e-4)
Resultats apres 50 epochs
- 94.2% de precision globale sur le set de test
- 96.8% de recall sur les documents falsifies (peu de faux negatifs)
- Temps d'inference : 180ms par document sur CPU, 45ms sur GPU
- Deploye comme API FastAPI sur AWS Lambda (cout < 0.01 euro par analyse)
- ROI client : 2 800 euros economises par recrutement, soit x15 sur l'investissement initial
Limites et pistes d'amelioration
Le modele est moins performant sur des falsifications sophistiquees (Photoshop professionnel). Piste : ajouter une detection de metadonnees EXIF et un modele de detection de splicing d'image (ELA - Error Level Analysis) en complementation du ResNet.