Juger un jeu d’évaluation avant de s’y fier
Un jeu d’évaluation est la liste de cas qui sert à noter une fonction d’IA. Une note ne vaut que ce que vaut cette liste.
Le module sur l’évaluation et les tests montre comment bâtir un premier jeu. Cette leçon pose une question plus dure : peut-on se fier à la note ?
À la fin de cette leçon
Remarque
Je peux dire si un jeu d’évaluation est assez bon pour qu’on s’y fie.
Mots clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Couverture | la façon dont les cas se répartissent entre les genres d’entrées | |
| Étiquette | la réponse qu’une personne juge juste pour un cas | oui |
| Désaccord | deux personnes qui donnent deux étiquettes à un même cas | |
| Marge | de combien un score peut bouger par pur hasard | |
| Écart | la différence entre les scores de deux versions |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
La couverture : chaque genre est testé
Rangez vos cas par genre : simple, mixte, limite ou refus. Comptez chaque genre. Un genre qui n’a qu’un ou deux cas est mince.
Un genre mince cache les échecs. Si la fonction rate tous les refus, deux cas sur vingt font à peine bouger le score.
Exemple détaillé : vingt cas par genre
| Genre | Cas | Part | Verdict |
|---|---|---|---|
| simple | 10 | 50 % | Assez |
| mixte | 5 | 25 % | Assez |
| limite | 3 | 15 % | Assez |
| refus | 2 | 10 % | Mince, à compléter |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Deux personnes vérifient les étiquettes l’une de l’autre
Une étiquette est l’avis d’une personne. Demandez à une seconde personne d’étiqueter les mêmes cas sans voir les premières étiquettes. Puis comparez.
Quand elles concordent, le cas est clair. Quand elles divergent, le cas ou la règle est flou. Revoyez ces cas avant de noter quoi que ce soit.
Une erreur courante
Attention
Beaucoup pensent que l’étiquette d’un expert est la vérité. C’est un seul avis. Ne la gardez que si une seconde personne est d’accord, ou si vous avez noté pourquoi le cas porte cette étiquette.
Un petit jeu ne sépare pas deux versions
Un score bouge par hasard. Une règle approchée donne la marge : 100 divisé par la racine carrée du nombre de cas, en points. Avec 100 cas, la marge est de 10 points.
Un écart plus petit que la marge peut être du bruit. Pour voir un écart de 5 points, il faut environ 400 cas.
Exemple détaillé : cas et marge
| Cas | Marge en points | Plus petit écart fiable |
|---|---|---|
| 25 | 20 | Environ 20 points |
| 100 | 10 | Environ 10 points |
| 400 | 5 | Environ 5 points |
| 2 500 | 2 | Environ 2 points |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Écrire l’assistant du modèle, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// Les jetons d’une réponse, ou null si elle n’en donne pas.' 'function compter(donnees, nom) {' ' return donnees.usage && typeof donnees.usage[nom] === \"number\" ? donnees.usage[nom] : null;' '}' > model.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire l’assistant du modèle, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function demander(messages, echantillon, max) {' ' try {' ' const res = await fetch(base + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"statut \" + res.status);' ' const d = await res.json();' ' return { texte: d.choices[0].message.content, entree: compter(d, \"prompt_tokens\"), sortie: compter(d, \"completion_tokens\"), enregistre: false };' ' } catch (erreur) {' ' console.log(\"Échantillon enregistré : aucun modèle n’a répondu (\" + erreur.message + \").\");' ' return { texte: echantillon, entree: null, sortie: null, enregistre: true };' ' }' '}' 'module.exports = { demander };' >> model.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire l’audit du jeu, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' 'const lignes = [' ' \"1 simple oui oui\", \"2 simple oui oui\", \"3 simple non non\", \"4 simple oui oui\", \"5 simple non non\",' ' \"6 simple oui oui\", \"7 mixte oui non\", \"8 mixte non non\", \"9 mixte oui oui\", \"10 simple non non\",' ' \"11 mixte non non\", \"12 limite oui oui\", \"13 mixte oui non\", \"14 limite non non\", \"15 simple oui oui\",' ' \"16 simple non non\", \"17 limite oui oui\", \"18 simple oui non\", \"19 refus non non\", \"20 refus non non\",' '].map(function (l) {' ' const p = l.split(\" \");' ' return { id: Number(p[0]), genre: p[1], a: p[2], b: p[3] };' '});' > audit.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire l’audit du jeu, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const comptes = {};' 'lignes.forEach(function (l) { comptes[l.genre] = (comptes[l.genre] || 0) + 1; });' 'const minces = Object.keys(comptes).filter(function (g) { return comptes[g] < 3; });' 'const ecartes = lignes.filter(function (l) { return l.a < l.b || l.a > l.b; });' 'const memes = lignes.length - ecartes.length;' 'const ecart = 5;' 'const necessaire = (100 / ecart) * (100 / ecart);' >> audit.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire l’audit du jeu, partie 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' console.log(\"cas : \" + lignes.length + \" par genre : \" + JSON.stringify(comptes));' ' console.log(\"genres minces (moins de 3) : \" + minces.join(\", \"));' ' console.log(\"accord : \" + (memes * 100 / lignes.length) + \" pour cent\");' ' console.log(\"numéros à revoir : \" + ecartes.map(function (l) { return l.id; }).join(\", \"));' ' console.log(\"pour voir un écart de \" + ecart + \" points, il faut environ \" + necessaire + \" cas\");' >> audit.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire l’audit du jeu, partie 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' const q = \"En une phrase courte, pourquoi deux personnes doivent-elles étiqueter les mêmes cas ?\";' ' const echantillon = \"Là où elles divergent, le cas ou la règle est flou, et un score dessus vaut peu.\";' ' const reponse = await demander([{ role: \"user\", content: q }], echantillon, 60);' ' console.log(\"le modèle dit : \" + reponse.texte);' '}' 'main();' >> audit.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Lancer l’audit
docker exec -w /home/node/project agent node audit.jsAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Ce que l’audit affiche
| Ligne | Ce qu’elle montre |
|---|---|
| cas : 20 par genre : {...} | Le nombre de cas de chaque genre |
| genres minces (moins de 3) : refus | Les genres qui veulent plus de cas |
| accord : 85 pour cent | La fréquence où les deux personnes concordent |
| numéros à revoir : 7, 13, 18 | Les cas où elles divergent |
| le modèle dit : ... | Une phrase du labo. Un échantillon enregistré si aucun modèle ne répond |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.