Aller au contenu principal

Coûts et optimisation

Comprendre la structure des coûts

Le fine-tuning OpenAI engendre deux types de coûts : le coût d’entraînement (ponctuel) et le coût d’inférence (récurrent). Comprendre et optimiser ces coûts est essentiel pour un déploiement rentable.

Coût d’entraînement

Le coût d’entraînement est facturé au nombre de tokens traités pendant l’entraînement :

Coût entraînement = tokens_totaux × nombre_epochs × prix_par_token_entrainement

Estimer le coût avant de lancer

import json

def estimer_cout_entrainement(
    fichier_jsonl: str,
    n_epochs: int,
    prix_par_million_tokens: float
) -> dict:
    """Estime le coût d'entraînement avant de lancer le job."""
    total_tokens = 0

    with open(fichier_jsonl, "r") as f:
        nb_exemples = 0
        for ligne in f:
            nb_exemples += 1
            obj = json.loads(ligne)
            for msg in obj["messages"]:
                # Estimation grossière : 1 token ~ 4 caractères en français
                total_tokens += len(msg["content"]) // 4

    tokens_entrainement = total_tokens * n_epochs
    cout = tokens_entrainement * prix_par_million_tokens / 1_000_000

    return {
        "exemples": nb_exemples,
        "tokens_par_passage": total_tokens,
        "epochs": n_epochs,
        "tokens_total": tokens_entrainement,
        "cout_estime": f"{cout:.2f} $"
    }

resultat = estimer_cout_entrainement(
    "training_data.jsonl",
    n_epochs=3,
    prix_par_million_tokens=8.0  # vérifiez le tarif actuel
)

for k, v in resultat.items():
    print(f"{k} : {v}")

Coût d’inférence

Le coût d’inférence est facturé par appel au modèle, au nombre de tokens en entrée et en sortie. Les modèles fine-tunés ont généralement un tarif légèrement supérieur au modèle de base.

Comparer le coût total

def cout_mensuel(
    requetes_par_jour: int,
    tokens_input_moyen: int,
    tokens_output_moyen: int,
    prix_input_par_million: float,
    prix_output_par_million: float
) -> float:
    """Calcule le coût mensuel d'inférence."""
    requetes_mois = requetes_par_jour * 30
    cout_input = requetes_mois * tokens_input_moyen * prix_input_par_million / 1_000_000
    cout_output = requetes_mois * tokens_output_moyen * prix_output_par_million / 1_000_000
    return cout_input + cout_output

# Scénario : modèle de base avec long prompt
cout_base = cout_mensuel(
    requetes_par_jour=5000,
    tokens_input_moyen=800,    # long prompt système + question
    tokens_output_moyen=200,
    prix_input_par_million=0.15,
    prix_output_par_million=0.60
)

# Scénario : modèle fine-tuné avec prompt minimal
cout_ft = cout_mensuel(
    requetes_par_jour=5000,
    tokens_input_moyen=100,    # prompt court, comportement intégré
    tokens_output_moyen=200,
    prix_input_par_million=0.30,  # tarif FT plus élevé
    prix_output_par_million=1.20
)

print(f"Coût mensuel base : {cout_base:.2f} $")
print(f"Coût mensuel fine-tuné : {cout_ft:.2f} $")
print(f"Différence : {cout_ft - cout_base:+.2f} $")

Stratégies d’optimisation

Réduire les tokens d’entrée

Le principal levier d’économie avec un modèle fine-tuné est la réduction du prompt :

Approche Tokens input Économie
Modèle de base + prompt détaillé 500-1000 tokens Référence
Fine-tuné + prompt minimal 50-100 tokens 80-90 % sur l'input
Fine-tuné + sans prompt système 20-50 tokens 95 % sur l'input

Optimiser le nombre d’exemples

Plus de données = meilleur modèle, mais aussi coût d’entraînement plus élevé. Trouvez le point d’équilibre :

def trouver_optimal(resultats_par_taille: dict):
    """Identifie la taille de dataset optimale."""
    print("Taille dataset | Score qualité | Coût entraînement")
    print("-" * 55)

    meilleur_ratio = 0
    taille_optimale = 0

    for taille, data in sorted(resultats_par_taille.items()):
        score = data["score"]
        cout = data["cout"]
        ratio = score / cout if cout > 0 else 0

        print(f"{taille:>14} | {score:>13.2f} | {cout:>17.2f} $")

        if ratio > meilleur_ratio:
            meilleur_ratio = ratio
            taille_optimale = taille

    print(f"\nTaille optimale : {taille_optimale} exemples")

Choisir le bon modèle de base

GPT-5.3-mini est moins cher que GPT-5.4-mini, tant en entraînement qu’en inférence. Commencez toujours par le modèle le moins cher et montez en gamme uniquement si la qualité est insuffisante.

Réduire les epochs

Chaque epoch supplémentaire multiplie le coût d’entraînement. Si 2 epochs donnent 95 % de la qualité de 4 epochs, le choix est vite fait.

Surveiller les coûts en production

class CostTracker:
    """Suivi des coûts en temps réel."""

    def __init__(self, budget_mensuel: float):
        self.budget = budget_mensuel
        self.depenses = 0.0
        self.appels = 0

    def enregistrer(self, tokens_input: int, tokens_output: int,
                    prix_input: float, prix_output: float):
        """Enregistre le coût d'un appel."""
        cout = (
            tokens_input * prix_input / 1_000_000 +
            tokens_output * prix_output / 1_000_000
        )
        self.depenses += cout
        self.appels += 1

        # Alerte si on approche du budget
        utilisation = self.depenses / self.budget * 100
        if utilisation > 80:
            print(f"ALERTE : {utilisation:.1f}% du budget mensuel utilisé")

    def rapport(self):
        """Rapport de consommation."""
        print(f"Appels : {self.appels}")
        print(f"Dépenses : {self.depenses:.2f} $")
        print(f"Budget restant : {self.budget - self.depenses:.2f} $")
        if self.appels > 0:
            print(f"Coût moyen par appel : {self.depenses / self.appels:.4f} $")

Calcul du ROI

def calculer_roi(
    cout_entrainement: float,
    economie_mensuelle: float,
    gain_qualite_valeur: float = 0
) -> dict:
    """Calcule le retour sur investissement du fine-tuning."""
    benefice_mensuel = economie_mensuelle + gain_qualite_valeur
    mois_amortissement = cout_entrainement / benefice_mensuel if benefice_mensuel > 0 else float("inf")

    return {
        "cout_entrainement": f"{cout_entrainement:.2f} $",
        "benefice_mensuel": f"{benefice_mensuel:.2f} $",
        "amortissement": f"{mois_amortissement:.1f} mois",
        "roi_annuel": f"{(benefice_mensuel * 12 - cout_entrainement) / cout_entrainement * 100:.0f}%"
    }

Points clés à retenir

  • Estimez le coût d’entraînement avant de lancer le job
  • Le principal levier d’économie est la réduction des tokens d’entrée
  • Commencez par GPT-5.3-mini avant de considérer GPT-5.4-mini
  • Surveillez les coûts en production avec des alertes de budget
  • Calculez le ROI en incluant les gains de qualité et les économies de tokens