Spaces:
Running
Running
import streamlit as st | |
st.set_page_config(layout="wide") | |
from streamlit_extras.switch_page_button import switch_page | |
st.markdown(""" | |
## Dépanner la reproductibilité | |
Imaginons que vous ayez lu un rapport technique sur un nouveau modèle très cool et que vous souhaitiez reproduire ses résultats sur votre machine... mais que vous n'y parveniez pas ? | |
Voyons pourquoi. | |
""", unsafe_allow_html=True) | |
st.markdown(""" """) | |
st.markdown(""" """) | |
st.markdown(""" """) | |
st.markdown(""" | |
### Base de code différente | |
Pour reproduire les scores d'évaluation à la virgule près, vous devez d'abord vous assurer que vous utilisez exactement la même base de code que le papier que vous voulez reproduire. | |
En général, cela signifie que vous utilisez le code d'évaluation par défaut fourni par les auteurs, ou une implémentation standard dans une bibliothèque de référence comme [lm_eval](https://github.com/EleutherAI/lm-evaluation-harness) ou [lighteval](https://github.com/huggingface/lighteval). En revanche, si le code source de l'évaluation n'est pas fourni, je suis désolé pour vous, mais il est peu probable que vous puissiez reproduire les résultats avec précision. | |
Si vous voulez comprendre facilement quels types de divergences se produisent lors de l'utilisation de différentes implémentations, vous pouvez explorer cet [article de blog](https://huggingface.co/blog/fr/open-llm-leaderboard-mmlu) (en français) (⭐) que nous avons écrit avec l'équipe d'évaluation d'HuggingFace. Il étudie les différences que nous avons observées entre 3 implémentations courantes pour l'évaluation de MMLU (dans lm_eval, [helm](https://github.com/stanford-crfm/helm), et dans l'implémentation originale de l'auteur), et comment elles affectent les scores des modèles. | |
""", unsafe_allow_html=True) | |
st.info("""C'est précisément pour cette raison qu'une équipe d'Hugging Face a décidé de lancer l'[*Open LLM Leaderboard*](https://huggingface.co/spaces/open-llm-leaderboard/open_llm_leaderboard), pour obtenir des comparaisons unifiées et homogènes des scores des modèles afin de les comparer aux expériences internes.""") | |
st.markdown(""" """) | |
st.markdown(""" | |
##### Autres façons subtiles où l'implémentation peut être différente | |
Nous avons observé qu'il était facile de se tromper sur les points suivants, même en utilisant la même base de code : | |
- **Graine aléatoire différente** | |
Normalement, l'inférence est moins affectée par les graines aléatoires que l'entraînement. Cependant, elles peuvent affecter certaines opérations CUDA (voir la page sur la [reproductibilité](https://pytorch.org/docs/stable/notes/randomness.html) de PyTorch) et modifier les prédictions si vous utilisez une stratégie de génération [non *greedy*](https://huggingface.co/blog/how-to-generate). Elles peuvent également affecter l'instruction avec exemple, et certaines fonctions de pré/post-traitement. | |
→ Un changement minime peut entraîner une différence de quelques points. | |
- **Métrique différente** | |
Les métriques peuvent être différentes dans la pratique, même si elles portent le même nom. Quelques exemples : | |
- Vous n'obtiendrez pas les mêmes scores si l'implémentation originale est une « correspondance exacte via log vraisemblance » (log probabilités des différentes réponses possibles) mais que vous utilisez une « correspondance exacte via génération » (comparant la génération *greedy* avec la référence). | |
- Nous avons également vu, dans les bases de code d'évaluation, un certain nombre de tâches définies comme « correspondance exacte », mais qui étaient en fait des « correspondances exactes préfixes » (comparant uniquement le début de la génération avec la référence), ou des « correspondances exactes suffixes » (le contraire), ou des « correspondances quasi exactes » (correspondances exactes avec une normalisation).<br> | |
→ Vous ne pouvez donc pas vous fier uniquement au nom de la métrique pour déterminer ce qui se passe, et vous devez examiner le code. | |
- **Normalisation différente** | |
En poursuivant l'exemple précédent sur la « correspondance exacte », dans lm_eval v1, un certain nombre de tâches étaient simplement nommées « correspondance exacte via génération » : on pourrait en déduire que la prédiction est *comparée en tant que telle* à une référence. | |
En regardant le code, la prédiction passe en fait par une étape de normalisation (suppression de la ponctuation, homogénéisation des nombres, etc.) avant d'être comparée à la référence. Cela modifie évidemment beaucoup les résultats. | |
(La v2 de lm_eval inclut à présent le nom de la normalisation dans la plupart des noms des métriques.) | |
→ C'est l'une des sources d'erreurs la plus susceptible, en particulier pour les tâches qui nécessitent beaucoup de normalisation et de post-traitement des réponses. Notamment lors d'évaluations mathématiques où vous souhaitez extraire la réponse d'une explication générée. | |
""", unsafe_allow_html=True) | |
st.markdown(""" """) | |
st.markdown(""" """) | |
st.markdown(""" """) | |
st.markdown(""" | |
### Différences au niveau des instructions | |
3 éléments principaux peuvent entrer en jeu dans la variation au niveau des instructions. | |
##### L'instruction elle-même | |
Le format que vous utilisez pour l'instruction peut modifier et modifiera les scores de manière importante. | |
Par exemple, pour les réponses aux questions à choix multiples, certains formats courants incluent des variations très simples dans la présentation des choix, par exemple : | |
```markdown | |
Question: <texte de la question> | |
Choices: | |
| A. <Choice A> | (A) <Choice A> | <Choice A> | | |
| B. <Choice B> | (B) <Choice B> | <Choice B> | | |
| C. <Choice C> | (C) <Choice C> | <Choice C> | | |
| D. <Choice D> | (D) <Choice D> | <Choice D> | | |
Answer: | |
``` | |
et prédire soit `A`/`B`/`C`/`D` ou `<Choice A/B/C/D>`. | |
Ces instructions sont **sémantiquement équivalentes**, puisqu'ils contiennent exactement le même contenu, mais ils peuvent néanmoins donner lieu à une différence de *plusieurs points pour le même modèle*. Nous avons fait quelques expériences à ce sujet [ici](https://x.com/clefourrier/status/1777319187913875893/photo/1) et vous pouvez voir jusqu'à 7 points de différence pour le même modèle (image ci-dessous). Un [papier a observé des résultats similaires](https://arxiv.org/abs/2310.11324). | |
""", unsafe_allow_html=True) | |
st.image("""https://pbs.twimg.com/media/GKpMq9zXEAAf9fv?format=png&name=small""", use_container_width=True) | |
st.markdown(""" | |
Certaines tâches sont également précédées d'une instruction particuliere (par exemple : « Les questions suivantes portent sur le < sujet > »). Sa présence ou son absence affectera également les scores. | |
Cet [excellent papier](https://arxiv.org/abs/2407.07890) (⭐) met également en évidence un effet secondaire de ce phénomène : un certain nombre de modèles sont désormais entraînés à surapprendre les instructions et les formats de réponse des jeux d'évaluation, au prix d'une adaptation à d'autres instructions au moment de l'évaluation. | |
C'est quelque chose que nous avons observé sur l'*Open LLM Leaderboard 2* pour les modèles Llama3.1. Ils obtenaient de faibles scores bien que prédisaient les bonnes réponses à nos évaluations sur MATH-Hard. En effet, ils étaient incapables de s'adapter aux exemples fournis car ils ont surappris l'instruction et le format de réponse de GSM8K.""", unsafe_allow_html=True) | |
st.markdown(""" """) | |
st.markdown(""" """) | |
st.markdown(""" | |
##### *Prompt* système et format de chat | |
Les formats de chat ont généralement été soumis à un entraînement d'instruction/de préférence ou à un *finetuning*. À ce stade, ils ont appris à suivre des formats spécifiques lors de l'inférence. Par exemple, les modèles peuvent exiger de commencer les tours de dialogue par unz instruction générale (appelé `system prompt`) préfixé par des *tokens* spécifiques (généralement `System:`). Cette instruction est là pour fournir des instructions de haut niveau au modèle, comme le contenu d'un personnage, ou des instructions générales sur le style de réponse. Les dialogues peuvent également nécessiter l'ajout de mots clés préfixés au texte, comme `User` pour les requêtes et `Assistant` pour les réponses. | |
En *few shot*, vous devez également choisir si vous souhaitez que les exemples soient fournis à tour de rôle (en imitant les tours de l'utilisateur et de l'assistant) ou en une seule fois (dans une instruction unique de l'utilisateur). | |
Ne pas suivre le format de chat attendu par le modèle lors de l'inférence nuira à ses performances car le poussera en dehors de l'espace de probabilité sur lequel il a convergé. | |
""", unsafe_allow_html=True) | |
st.markdown(""" """) | |
st.markdown(""" """) | |
st.markdown(""" | |
##### Exemples | |
Comme plus haut, faites attention aux graines aléatoires. | |
Veilliez à utiliser le **même nombre d'échantillons** que la tâche de référence. | |
Vous devez aussi utiliser **les mêmes échantillons** lors de la comparaison de modèles car l'utilisation d'échantillons différents modifiera les résultats (ce qui n'est pas très surprenant, si nous supposons que certains échantillons expriment mieux la tâche que d'autres). | |
Plus surprenant peut-être : vous devez non seulement utiliser exactement les mêmes échantillons, mais aussi les présenter dans le **même ordre**. Varier l'ordre sur les mêmes échantillons nous a permis d'observer jusqu'à 3 points de différence sur certains sous-ensembles de MMLU (vous pouvez voir [quelques résultats ici](https://huggingface.co/blog/fr/evaluation-structured-outputs) (en français)). | |
""", unsafe_allow_html=True) | |
st.image("""https://pbs.twimg.com/media/GJ29DLNXAAAfJ2T?format=png&name=900x900""",use_container_width=True) | |
st.markdown(""" """) | |
st.markdown(""" """) | |
st.markdown(""" """) | |
st.markdown(""" | |
### Différences au niveau des paramètres de génération | |
Pour les évaluations de générations, les paramètres auxquels il faut prêter attention sont les suivants : | |
- s'assurer que vous utilisez le **même *token* de fin de phrase** | |
- s'assurer que vous autorisez votre modèle à **générer le même nombre de *tokens*** | |
- s'assurer, en cas d'échantillonnage, que vous utilisez les **mêmes paramètres température / graine aléatoire**. | |
""", unsafe_allow_html=True) | |
st.markdown(""" """) | |
st.markdown(""" """) | |
st.markdown(""" """) | |
st.markdown(""" | |
### Différences au niveau du chargement du modèle | |
Quelques sources de différences que nous avons observées : | |
- **matériels différents**<br>Pytorch n'assure pas la reproductibilité des opérations non déterministes à travers le matériel. | |
- **bibliothèques différentes**<br>Par exemple, si vous utilisez [transformers](https://github.com/huggingface/transformers) vs [vllm](https://github.com/vllm-project/vllm) comme *backend* pour l'inférence, les calculs de matrices ne sont pas gérés exactement de la même manière. | |
- **tailles de batch différentes**<br>Il a été démontré dans plusieurs bibliothèques d'évaluation et *backends* de modèles que l'utilisation de différentes tailles de batch modifie les résultats de l'inférence. Si vous souhaitez des évaluations parfaitement reproductibles, vous devez fixer la taille du batch, bien que cela ne soit pas toujours possible en raison de problèmes de mémoire. | |
- **précisions des poids différentes**<br>L'utilisation d'une précision plus faible peut réduire les coûts de mémoire et d'inférence mais modifiera également les résultats numériques puisque vous utilisez différentes versions des poids.""", unsafe_allow_html=True) | |
st.markdown(""" """) | |
st.markdown(""" """) | |
st.markdown(""" """) | |
col1, col2, col3= st.columns(3) | |
with col1: | |
if st.button('Section précédente', use_container_width=True): | |
switch_page("V.1._Dépanner l'inférence") | |
with col2: | |
if st.button("Accueil", use_container_width=True): | |
switch_page("Home") | |
with col3: | |
if st.button("Section suivante", use_container_width=True): | |
switch_page("V.3._Dépanner les problèmes mathématiques") |