Spaces:
Running
Running
| import streamlit as st | |
| st.set_page_config(layout="wide") | |
| from streamlit_extras.switch_page_button import switch_page | |
| st.markdown("""# Panorama 2024""") | |
| st.markdown(""" """) | |
| st.success("""Ce panorama 2024 est extrêmement redondant avec ce que vous avez déjà pu lire dans ce guide. Il s'agit de l'[article de blog de Clémentine](https://huggingface.co/blog/clefourrier/llm-evaluation) qui lui a servi de base dans sa réflexion pour rédaction du guide. Vous pouvez ainsi ou pas lire ce panorama ou bien passer directement à celui de 2025.""") | |
| st.markdown(""" """) | |
| st.markdown("""## Parlons de l'évaluation des LLM | |
| Étant donné que mon équipe travaille sur l'évaluation et les benchmarks à Hugging Face, à l'ICLR 2024, beaucoup de gens ont voulu me demander mon avis sur le sujet (ce qui était très inattendu, merci beaucoup à tous ceux qui étaient intéressés). | |
| Grâce à toutes ces discussions, j'ai réalisé qu'un certain nombre de choses que je tiens pour acquises en termes d'évaluation sont 1) des idées peu répandues 2) apparemment intéressantes. | |
| Alors, partageons la conversation plus largement ! | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" """) | |
| st.markdown(""" """) | |
| st.markdown(""" """) | |
| st.markdown(""" | |
| ### Comment faisons-nous l'évaluation LLM ? | |
| Tout d'abord, posons quelques définitions. Il y a, à ma connaissance, à l'heure actuelle, 3 façons principales de faire de l'évaluation : les benchmarks automatisés, l'évaluation humaine, et l'utilisation via des modèles (*LLM-as-a-judge*). Chaque approche a sa propre raison d'être, ses utilisations et ses limites. | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" """) | |
| st.markdown(""" | |
| #### Benchmarks | |
| Les benchmarks automatisés fonctionnent généralement de la manière suivante : vous aimeriez savoir comment votre modèle se comporte sur quelque chose. Il peut s'agir d'une **tâche** concrète bien définie, telle que « Dans quelle mesure mon modèle peut-il classer le spam des e-mails non spam ? », ou d'une **capacité** plus abstraite et générale, telle que « Quelle est la qualité de mon modèle en mathématiques ? ». | |
| À partir de là, vous construisez une évaluation, généralement composée de deux choses : | |
| - une collection d'*échantillons*, donnés en entrée au modèle pour voir ce qui en sort, parfois couplé à une référence (appelée or) à laquelle comparer. Les exemples sont généralement conçus pour essayer d'émuler ce sur quoi vous voulez tester le modèle. Par exemple, si vous examinez une classification d'e-mails, vous créez un jeu de données d'e-mails désirables et indésirables, essayez d'inclure des cas limites difficiles, etc. Pour les LLM, les deux tâches principales sont l'évaluation de la génération (comparaison du texte généré avec une référence après normalisation) ou le choix multiple (comparer les probabilités logarithmiques relatives des continuations possibles après une invite). | |
| - une *métrique*, qui est un moyen de calculer un score pour le modèle. Par exemple, avec quelle précision votre modèle peut-il classer le spam (score de l'échantillon bien classé = 1, mal classé = 0). | |
| C'est plus intéressant à faire sur des données qui n'ont pas été incluses dans le jeu d'entraînement du modèle, car vous voulez tester si cela se généralise bien. Vous ne voulez pas d'un modèle qui ne peut classer que les emails qu'il a déjà « vus », ce ne serait pas très utile ! | |
| """, unsafe_allow_html=True) | |
| st.info(""" | |
| Un modèle qui ne peut que bien prédire sur ses données d'entraînement (et qui n'a pas appris de manière latente des modèles généraux de haut niveau) est dit **surentraîné**. Dans les cas moins extrêmes, vous souhaitez tout de même tester si votre modèle est capable de généraliser à des modèles de données qui n'étaient pas dans la distribution de l'ensemble d'entraînement (par exemple, classez les spams concernant les produits de « santé » après n'avoir vu que des spams concernant de fausses banques). | |
| """) | |
| st.markdown(""" | |
| Cela fonctionne assez bien pour des tâches très bien définies, où les performances sont « faciles » à évaluer et à mesurer : lorsque vous testez littéralement votre modèle sur de la classification des spams, vous pouvez dire « le modèle a correctement classé n % de ces échantillons ». Pour les benchmarks de LLM, certains problèmes peuvent survenir, tels que les modèles [favorisant des choix spécifiques basés sur l'ordre dans lequel ils ont été présentés pour les évaluations à choix multiples](https://arxiv.org/abs/2309.03882), et les évaluations génératives reposant sur des normalisations qui peuvent facilement [être injustes si elles ne sont pas bien conçues](https://huggingface.co/blog/fr/open-llm-leaderboard-drop), mais dans l'ensemble, elles fournissent toujours un signal au niveau de la tâche. | |
| Pour les capacités, cependant, il est difficile de les décomposer en tâches bien définies et précises : que signifie « bon en mathématiques » ? Bon en arithmétique ? à la logique ? capable de raisonner sur des concepts mathématiques ? | |
| Dans ce cas, les gens ont tendance à faire des évaluations plus « holistiques », en ne décomposant pas la capacité dans des tâches réelles, mais en supposant que la performance sur des échantillons généraux sera un **bon indicateur** de ce que nous visons à mesurer. Par exemple, le jeu GSM8K est composé de problèmes mathématiques réels de lycée, qui nécessitent tout un ensemble de capacités pour être résolus. Cela signifie également que l'échec et le succès sont très difficiles à interpréter. Certaines capacités ou sujets, tels que « ce modèle est-il bon pour écrire de la poésie ? » ou « les résultats du modèle sont-ils utiles ? » sont encore plus difficiles à évaluer avec des mesures automatiques. Et en même temps, les modèles semblent maintenant avoir de plus en plus de capacités **généralistes**, nous devons donc évaluer leurs capacités de manière plus large. Par exemple, il y a eu un débat dans la communauté scientifique sur la question de savoir si les LLM [peuvent dessiner](https://arxiv.org/abs/2303.12712) des licornes [ou non](https://twitter.com/DimitrisPapail/status/1719119242186871275). Très probablement pas à ce stade, mais clairement un point important à étudier. | |
| Les benchmarks automatisés ont également tendance à avoir un autre problème : une fois qu'ils sont publiés publiquement en texte brut, ils sont très susceptibles de se retrouver (souvent accidentellement) dans les jeux de données d'entraînement des modèles. Certains créateurs de benchmarks, comme les auteurs de BigBench, ont essayé d'atténuer cela en ajoutant une « chaîne canari » (une combinaison très spécifique de caractères) pour que les gens puissent la rechercher et la supprimer des ensembles d'entraînement, mais tout le monde n'est pas conscient du mécanisme ni n'essaie de faire cette suppression. Il existe également une quantité non négligeable de benchmarks, de sorte que la recherche de copies accidentelles d'absolument tous ces benchmarks dans les données est coûteuse. D'autres options incluent la fourniture de benchmarks sous une [forme cryptée](https://arxiv.org/pdf/2309.16575), ou derrière un [système de contrôle](https://huggingface.co/datasets/Idavidrein/gpqa). Cependant, lors de l'évaluation de modèles fermés derrière des API de boîte noire, il n'y a aucune garantie que les données fournies ne seront pas utilisées ultérieurement en interne pour l'entraînement ou le finetuning. | |
| Le cas où un jeu de données d'évaluation se retrouve dans le jeu d'entraînement s'appelle la **contamination**, et un modèle qui a été contaminé aura une performance de référence élevée qui ne se généralise pas bien à la tâche sous-jacente (une description détaillée de la contamination peut être trouvée [ici](https://aclanthology.org/2023.findings-emnlp.722/), et voici une façon amusante de [la détecter](https://arxiv.org/abs/2311.06233)). Une façon de lutter contre la contamination est d'exécuter des [**benchmarks dynamiques**](https://arxiv.org/abs/2104.14337) (évaluations sur des données qui sont régulièrement actualisées pour fournir des scores sur de nouvelles données systématiquement invisibles), mais cette approche est coûteuse à long terme. | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" """) | |
| st.markdown(""" | |
| #### L'humain comme juge | |
| Une solution à la fois à la contamination et à une évaluation plus ouverte consiste à demander aux humains d'évaluer les résultats du modèle. | |
| Cela se fait généralement en demander à des humains d'interroger des modèles puis de noter une réponse de modèle ou de classer plusieurs résultats selon des directives. Utiliser des humains comme juges permet d'étudier des tâches plus complexes, avec plus de flexibilité que les mesures automatisées. Cela permet également d'éviter la plupart des cas de contamination, puisque les instructions écrites sont (espérons-le) nouvelles. Enfin, il est bien corrélé avec la préférence humaine, puisque c'est littéralement ce qui est évalué ! | |
| Différentes approches existent pour évaluer les modèles avec des humains dans la boucle. | |
| **Vibes-checks** est le nom donné aux évaluations manuelles effectuées individuellement par certains membres de la communauté, généralement sur des instructions non divulguées, pour obtenir une « sensation » globale de la performance des modèles sur de nombreux cas d'utilisation, qui vont du codage à la qualité des écrits. | |
| Souvent partagés sur Twitter et Reddit, ils constituent pour la plupart des preuves anecdotiques et ont tendance à être très sensibles au biais de confirmation (en d'autres termes, les gens ont tendance à trouver ce qu'ils cherchent). Cependant, certaines personnes ont essayé de faire des évaluations plus méthodiques ; par exemple, l'utilisateur *Wolfram Ravenwolf* partage ses résultats de comparaisons de modèles de manière très systématique à travers des blogs (voir [ici](https://huggingface.co/blog/wolfram/llm-comparison-test-llama-3) pour un exemple). | |
| L'utilisation des commentaires de la communauté pour établir des classements massifs de modèles est ce que nous appelons une **arène**. Un exemple bien connu est l'arène des chatbots LMSYS(https://huggingface.co/spaces/lmsys/chatbot-arena-leaderboard), où les utilisateurs sont invités à discuter avec des modèles jusqu'à ce qu'ils trouvent que l'un est meilleur que l'autre. Les votes sont ensuite agrégés dans un classement Elo (un classement de matchs) pour sélectionner quel modèle est « le meilleur ». Le problème évident d'une telle approche est la grande subjectivité. Il est difficile d'imposer une notation cohérente à de nombreuses personnes en utilisant des directives générales, d'autant plus que les préférences des annotateurs ont tendance à être [culturellement liées](https://arxiv.org/abs/2404.16019v1) (avec différentes personnes privilégiant différents sujets de discussion, par exemple). On peut espérer que cet effet est atténué par l'ampleur des votes, par un effet de « sagesse de la foule » (cet effet a été constaté par un statisticien nommé Galton, qui a observé que les réponses individuelles essayant d'estimer une valeur numérique, comme le poids d'un porc, pouvaient être modélisées comme une distribution de probabilité centrée autour de la réponse réelle). | |
| La dernière approche est les annotations systématiques, où vous fournissez des directives extrêmement spécifiques aux annotateurs sélectionnés rémunérés, afin d'éliminer autant que possible le biais de subjectivité (c'est l'approche utilisée par [ScaleAI](https://scale.com/guides/data-labeling-annotation-guide#hight-quality-data-annotations), et la plupart des sociétés d'annotation de données). Cependant, cela peut rapidement devenir extrêmement coûteux, car vous devez continuer à faire des évaluations de manière continue et non automatique pour chaque nouveau modèle que vous souhaitez évaluer, et il peut toujours être la proie de préjugés humains (cette [étude](https://arxiv.org/abs/2205.00501) a montré que les personnes ayant des identités différentes ont tendance à évaluer la toxicité des réponses du modèle très différemment). | |
| Des [travaux récents](https://arxiv.org/pdf/2309.16349) ont également montré que les évaluateurs humains ont tendance à estimer la qualité des réponses en se basant sur les premières impressions, plutôt que sur la réalité ou la fidélité. Les annotateurs sont notamment très sensibles au ton et sous-estiment le nombre d'erreurs factuelles ou logiques dans une réponse affirmée. En d'autres termes, si un modèle dit des choses fausses sur un ton confiant, les évaluateurs humains sont beaucoup moins susceptibles de le remarquer, ce qui pourrait biaiser les évaluations en faveur des modèles les plus affirmés. | |
| Les annotateurs experts sont moins susceptibles d'être la proie de ces biais. Ce type de biais humain a été confirmé dans un autre [article](https://arxiv.org/pdf/2310.13548) : les humains sont plus susceptibles de préférer des réponses qui font appel à leurs opinions ou s'alignent sur leurs opinions ou erreurs, plutôt que des réponses qui sont factuellement correctes. | |
| Ces biais ne sont pas inattendus, mais ils doivent être pris en compte : tous les cas d'utilisation ne doivent pas reposer sur l'utilisation d'annotateurs humains, en particulier ceux qui sont issus du *crowdsourcing* et qui ne sont pas experts - toute tâche nécessitant des faits (comme l'écriture de code, l'évaluation de la connaissance du modèle, etc.) doit inclure un autre type d'évaluation, plus robuste, pour compléter le benchmark. | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" """) | |
| st.markdown(""" | |
| #### *Model-as-a-judge* | |
| Pour atténuer le coût des annotateurs humains, certaines personnes ont envisagé d'utiliser des modèles ou des artefacts dérivés (de préférence alignés sur les préférences humaines) pour évaluer les résultats des modèles. Cette approche n'est pas nouvelle, car vous pouvez trouver des techniques pour mesurer la qualité de la synthèse à partir de [d'embeddings de modèles](https://arxiv.org/abs/1904.09675) en 2019. | |
| Il existe deux approches pour la notation : l'utilisation de [modèles généralistes à haute capacité](https://arxiv.org/abs/2306.05685v4) ou l'utilisation de [petits modèles spécialisés](https://arxiv.org/pdf/2405.01535) entraînés spécifiquement pour distinguer les données de préférence. La première approche donne des résultats bien corrélés avec la préférence humaine, mais la plupart des modèles suffisamment solides ont tendance à être à source fermée, donc sujets à changement derrière les API et ininterprétables. | |
| Les LLM en tant que juges ont plusieurs fortes limites : ils ont tendance à [favoriser leurs propres résultats](https://arxiv.org/abs/2404.13076) lors de la notation des réponses, sont [mauvais pour fournir des plages de scores cohérentes](https://twitter.com/aparnadhinak/status/1748368364395721128) (bien que vous puissiez améliorer cela en demandant au modèle d'expliquer son raisonnement [avant de fournir un score](https://twitter.com/seungonekim/status/1749289437165769177)), et ne sont en fait pas si cohérents [avec les humains classements](https://arxiv.org/pdf/2308.15812). | |
| Mon principal reproche avec l'utilisation de cette approche est que ces modèles introduisent un biais très subtil et ininterprétable dans la sélection des réponses. J'ai l'impression que, tout comme lorsque vous faites trop de croisements dans les études génétiques, vous vous retrouvez avec des animaux ou des plantes dysfonctionnels, en utilisant des LLM pour sélectionner et entraîner des LLM, nous sommes tout aussi susceptibles d'introduire des changements infimes qui auront des répercussions plus importantes dans quelques générations. Je pense que ce type de biais est moins susceptible de se produire dans des modèles plus petits et plus spécialisés en tant que juges (tels que les classifieurs de toxicité), mais cela reste à tester et à prouver rigoureusement. | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" """) | |
| st.markdown(""" """) | |
| st.markdown(""" """) | |
| st.markdown(""" | |
| ### Pourquoi faisons-nous de l'évaluation de LLM ? | |
| Maintenant que nous avons vu comment nous faisons de l'évaluation, à quoi cela sert réellement ? | |
| Je crois fermement qu'il y a 3 raisons principales pour lesquelles les gens font de l'évaluation, qui ont tendance à être confondues, mais qui sont en fait **très différentes**, et chacune répond à une question distincte. | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" """) | |
| st.markdown(""" | |
| #### 1) Mon modèle s'entraîne-t-il bien ? Ma méthode d'entraînement est-elle solide ? : Tests de non-régression | |
| Un test de non-régression est un concept qui vient de l'industrie du logiciel, pour s'assurer que de petits changements n'ont pas cassé l'approche globale. | |
| L'idée est la suivante : lorsque vous ajoutez une nouvelle fonctionnalité à votre logiciel, ou que vous corrigez un problème dans la base de code, avez-vous cassé quelque chose d'autre ? C'est à cela que servent les tests de non-régression : s'assurer que le comportement attendu et de haut niveau de votre logiciel n'est pas soudainement interrompu par un changement (apparemment sans rapport). | |
| Lorsque vous sélectionnez une configuration pour entraîner des modèles, vous voulez tester quelque chose de très similaire et vous assurer que vos modifications (choix de données d'entraînement, d'architecture, de paramètres différents, etc.) n'ont pas « cassé » les performances attendues pour un modèle de ces propriétés. | |
| Pour donner un exemple concret, on s'attendrait à ce qu'un LLM de base 7B obtienne entre 50 et 65 sur MMLU (à choix multiples) après l'entraînement, et d'autre part des performances fluctuant entre 20 et 30 indiquent qu'aucun apprentissage n'a eu lieu. | |
| Pour l'évaluation « non-régression », vous devez regarder 1) les scores d'évaluation **trajectoires** (est-ce que la performance est meilleure maintenant qu'au début de l'entraînement), 2) les **plages** des scores d'évaluation (c'est la performance dans ce qui est attendu). En fait, vous ... ne se soucient pas du score précis eux-mêmes ! | |
| Cette évaluation n'est donc pas là pour vous dire quoi que ce soit sur les capacités réelles du modèle, mais plutôt pour confirmer que votre approche d'entraînement est « aussi solide » que l'autre, et que votre modèle se comporte de manière similaire. Je crois que même certaines évaluations portant simplement sur les changements dans la perplexité (probabilités) du texte pourraient être suffisantes pour cette étape, mais vous voulez généralement des points de référence qui ont un rapport « signal sur bruit » élevé, ou en d'autres termes, vous voulez vous assurer qu'un grand changement dans le score reflète un grand changement dans votre modèle. | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" """) | |
| st.markdown(""" | |
| #### 2) Quel est le meilleur modèle ? Mon modèle est-il meilleur que le vôtre ? : Classements | |
| Le rôle suivant de l'évaluation consiste simplement à trier les modèles pour trouver et sélectionner les meilleures architectures et approches globales. Si vous avez un classement, que vous prenez le meilleur modèle et qu'il ne fonctionne pas sur votre cas d'utilisation, il est peu probable que le meilleur modèle suivant fonctionne. Dans [leur article](https://arxiv.org/pdf/2404.02112) sur les leçons apprises sur l'analyse comparative et la conception de jeux de données de l'ère ImageNet, les auteurs soutiennent que, puisque les scores sont susceptibles d'être instables, la seule façon robuste d'évaluer les modèles est d'utiliser les classements. Plus précisément de trouver de grands groupes d'évaluations qui fournissent des classements cohérents et stables. | |
| Je crois que la recherche de la stabilité d'un classement est en effet une approche extrêmement intéressante pour l'analyse comparative des modèles, car nous avons montré que les *scores* des LLM sur les benchmarks automatisés sont extrêmement sensibles aux [changements infimes du *prompt*](https://huggingface.co/blog/fr/evaluation-structured-outputs), et que les évaluations humaines ne sont pas plus cohérentes. Les *classements* sont en fait plus stables lors de l'utilisation de méthodes d'évaluation robustes. | |
| Si les scores, en eux-mêmes, ne sont pas si pertinents que cela, l'utilisation de l'ordre relatif des modèles pourrait-elle nous dire quelque chose de valeur à la place ? | |
| Lors de la séance plénière d'évaluation d'ICLR 2024, Moritz Hardt a comparé l'ajout de perturbations à l'*Open LLM Leaderboard* (par une modification minuscule du score, bien dans les fourchettes de scores) et sur l'arène du chatbot (en ajoutant un mauvais concurrent à l'arène pour voir comment cela a affecté le classement Elo). Ces benchmarks ne fournissent pas non plus de classements stables et cohérents à l'heure actuelle. Nous ne manquerons pas d'explorer cet aspect avec les futures versions de l'Open LLM Leaderboard ! | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" """) | |
| st.markdown(""" | |
| #### 3) Où en sommes-nous, en tant que domaine, en termes de capacités de modèle ? Mon modèle peut-il faire X ? | |
| « Comment savez-vous si les modèles peuvent faire X ? » est une question qui revient souvent, et je pense que c'est une question très valable. | |
| Cependant, pour toute capacité complexe, nous ne pouvons pas pour l'instant simplement dire « ce modèle est le meilleur dans ce domaine », mais plutôt « ce modèle est le meilleur sur cette tâche que nous espérons être un bon proxy pour cette capacité, sans aucune garantie ». | |
| Nous manquons cruellement de bonnes définitions et de cadres sur ce qu'est une capacité pour un modèle d'apprentissage automatique, en particulier pour ceux qui entourent le raisonnement et la théorie de l'esprit. Cependant, ce n'est pas spécifique à l'apprentissage machine ! Dans les études humaines et animales, il est également assez difficile de définir ce qui constitue une « capacité », et les mesures qui tentent de fournir des scores précis (QI et QE par exemple) sont vivement débattues et controversées, à juste titre. | |
| Nous pourrions vouloir nous tourner vers les sciences sociales pour réfléchir à l'évaluation des capacités, car dans ces domaines, les gens sont habitués à réfléchir sérieusement aux facteurs de confusion dans la collecte et l'analyse des données. Cependant, je crois aussi qu'il est probable que 1) nous ne pouvons pas du tout définir ces grandes capacités, puisque nous ne pouvons pas les définir chez les humains et les animaux pour le moment, 2) les cadres conçus avec l'humain/l'animal à l'esprit ne seront pas bien transférés aux modèles, car les comportements et les hypothèses sous-jacents ne sont pas les mêmes. | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" """) | |
| st.markdown(""" """) | |
| st.markdown(""" """) | |
| st.markdown(""" | |
| ### Conclusion | |
| L'évaluation d'un LLM se fait aujourd'hui de la manière suivante : | |
| - En utilisant des benchmarks automatisés, affectés par la contamination et le manque de « généralité » (ce dernier n'étant pas forcément une mauvaise chose, tant les évaluations spécialisées sont intéressantes). | |
| - En utilisant des évaluateurs humains, qui ont tendance à souffrir d'un manque de reproductibilité à petite échelle, et les biais psychologiques en général (tels que la préférence pour les réponses flagorneuses), bien que l'on puisse espérer que certains des biais soient lissés à grande échelle. | |
| - En utilisant des modèles, ce qui présente des biais très subtils lors de l'évaluation, susceptibles de passer inaperçus mais d'introduire des perturbations en aval. | |
| Cependant, tout n'est pas perdu : l'évaluation, dans ses limites, est toujours en mesure de fournir un signal sur les nouvelles méthodes d'entraînement ou les jeux de données qui semblent prometteurs ou non, à la fois en examinant comment les performances se situent dans les plages attendues (tests de non-régression) et comment les modèles sont classés globalement (avec des évaluations suffisamment stables). Nous pouvons également espérer que la combinaison de suffisamment de points de données entre les sujets et les tâches nous fournira suffisamment de signal pour nous faire une idée des performances globales du modèle, sans toutefois supposer quoi que ce soit sur des capacités plus « générales ». | |
| Contrairement au battage médiatique, nous ne pouvons pas vraiment évaluer les « capacités générales d'un modèle » pour le moment, tout d'abord parce que nous n'avons pas défini ce que cela signifie. Cependant, l'évaluation du LLM, en tant que domaine de recherche, n'en est qu'à ses balbutiements à l'heure actuelle, et il y a beaucoup à faire, ce qui est très excitant ! L'inspiration peut être puisée dans de nombreux domaines, de l'apprentissage automatique (https://transformer-circuits.pub/2024/scaling-monosemanticity/index.html) à la sociologie, afin de définir de nouvelles métriques et tâches. Le travail interdisciplinaire ouvrira probablement de très nouvelles directions intéressantes pour le domaine ! | |
| """, 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("Panorama 2023") | |
| 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("Panorama 2025") |