Contexte et objectif

Le projet vise à remplacer l’API payante Gemini 3.1 Pro, utilisée pour extraire les marques, modèles et aciers de couteaux dans les commentaires Reddit, par un modèle open‑source. Gemini a traité 4 290 commentaires pour 9 $, soit 0,0021 $ par commentaire. L’idée était de créer un jeu d’étiquettes à partir de ces sorties, puis d’entraîner GLiNER (large v2.5, 459 M de paramètres) afin de reproduire les mêmes annotations sans coût récurrent.

Méthodologie d’annotation et de fine‑tuning

Gemini a été sollicité via OpenRouter avec temperature=0 pendant 25 minutes, en demandant les chaînes exactes plutôt que les offsets. Le code TypeScript a ensuite calculé les positions des entités. Les réponses de Gemini ont été stockées sous forme JSON :

{ "entities": [ { "text": "Benchmade", "label": "knife brand" }, { "text": "940", "label": "knife model" }, { "text": "S30V", "label": "knife steel" } ] }

Un regex spécial a conservé les notations comme VG-10, CPM-154 ou 1.4116. Environ 30 % des exemples contenaient volontairement aucun produit (déclencheurs faux‑positifs tels que "gyuto" ou "carbon"). Le jeu d’entraînement final comptait 2 029 exemples, dont 225 réservés à la validation et jamais réutilisés.

Le fine‑tuning a été exécuté sur un Tesla T4 via Modal, avec les hyperparamètres suivants : per_device_train_batch_size=2, gradient_accumulation_steps=8, learning_rate=1e-5, threshold=0.45. Le processus a duré 24 minutes et a coûté environ 2,50 $ de GPU.

Problèmes rencontrés et résolutions

Cinq des dix runs ont échoué. Les trois premiers étaient dus à une mauvaise configuration du HF Trainer : max_steps écrasait num_train_epochs, l’option load_best_model_at_end était mal combinée avec eval_strategy, et les clés du state_dict manquaient du préfixe model.. Après correction, les runs 4 et 5 ont planté à cause d’un tenseur words_mask mal construit. Ce tenseur, censé contenir des indices de mots, avait été rempli comme un masque d’attention (1 pour les tokens réels, 0 pour le padding), ce qui a conduit à une perte plate autour de 70‑130 et à un F1 proche de zéro.

En réexaminant le code de GLiNER, l’auteur a remplacé le masque par un indice de mot incrémental, a rétabli la liste des étiquettes sur chaque exemple négatif, et a ajusté le nombre d’exemples négatifs. Ces correctifs ont permis aux runs 6 à 10 de produire des modèles utilisables, le meilleur atteignant 0,879 F1 avant la validation finale.

Résultats et analyse de performance

Le modèle final a obtenu 0,83 F1 lorsqu’on le compare aux étiquettes générées par Gemini sur le jeu de validation de 225 commentaires. Le coût total du projet était de 9 $ pour les appels Gemini plus 2,50 $ de temps GPU, soit 11,50 $ pour un pipeline entièrement autonome. En supposant que chaque nouveau commentaire soit similaire en longueur, le modèle devient rentable dès le 4 291ᵉ commentaire, car il n’y a plus de frais d’API.

Il faut toutefois rappeler que la métrique repose sur l’accord avec Gemini, pas sur une vérité terrain. Les erreurs de Gemini sont donc propagées comme « correctes » dans l’évaluation. Malgré cette limitation, l’expérience démontre que, avec un jeu d’étiquettes limité et un ajustement minutieux du processus d’entraînement, un modèle open‑source peut remplacer une API propriétaire à moindre coût.