RadFact est un cadre pour l'évaluation de rapports de radiologie générés par un modèle, à partir d'un rapport de vérité sur le terrain, avec ou sans mise à la terre . Tirant parti des capacités d'inférence logique des grands modèles de langage, RadFact n'est pas un nombre unique mais une suite de métriques, capturant les aspects de précision et de rappel aux niveaux du texte uniquement et du texte et de la base.
RadFact a été introduit dans MAIRA-2 : Grounded Radiology Report Generation. Nous proposons ici une implémentation open source de la métrique pour faciliter son utilisation et son développement.
LLMEngine
pour le traitement parallèlePour exécuter RadFact, il vous suffit de cloner ce référentiel et d'exécuter la commande suivante :
pip install .
Cela installera le package radfact
et toutes ses dépendances.
Alternativement, nous fournissons un Makefile
pour configurer un environnement conda avec toutes les dépendances. Vous pouvez créer l'environnement avec :
make miniconda
make mamba
make env
conda activate radfact
La première étape installe miniconda, la seconde installe mamba pour une résolution rapide des dépendances et la troisième crée un environnement conda appelé radfact
avec toutes les dépendances. Cela installera également le package radfact en mode modifiable par défaut via la recette setup_packages_with_deps
(voir Makefile). Enfin, activez l'environnement pour exécuter RadFact. Ceci est fortement recommandé si vous avez l’intention de contribuer au projet.
Pour utiliser RadFact, vous devez accéder à un grand modèle de langage. Vous devez d'abord configurer les points de terminaison avec l'authentification, puis confirmer qu'ils se comportent comme prévu à l'aide de notre script de test.
Le LLM doit être disponible en tant que point de terminaison d'API et être pris en charge par langchain
(version 0.1.4). Nous prenons en charge deux types de modèles : les modèles AzureChatOpenAI et ChatOpenAI. Le premier convient aux modèles GPT disponibles sur Azure, tandis que le second convient aux modèles déployés personnalisés comme Llama-3 dans Azure.
Nous prenons en charge les méthodes d'authentification suivantes :
API_KEY
sur la clé API du point de terminaison. Nous utilisons API_KEY
comme nom de variable d'environnement par défaut. Si vous utilisez un nom différent, vous pouvez le spécifier dans la configuration du point de terminaison via api_key_env_var_name
. Ceci est particulièrement utile lors de l'utilisation de plusieurs points de terminaison avec différentes clés API.config.json
dans le répertoire racine du projet. Cette configuration doit avoir les clés subscription_id
, resource_group
et workspace_name
. Il peut être téléchargé depuis l’espace de travail AzureML via le portail. Ce fichier est ajouté au .gitignore
pour éviter les validations accidentelles. Assurez-vous d'enregistrer le fichier dans le répertoire racine du projet sous le nom config.json
comme prévu par la classe de point de terminaison.key_vault_secret_name
dans la configuration du point de terminaison.azure_ad_token_provider
d'un modèle AzureChatOpenAI
permettant l'actualisation automatique du jeton. Ceci est uniquement pris en charge pour les modèles AzureChatOpenAI
. Pour en savoir plus sur la façon dont nous intégrons les points de terminaison dans RadFact, veuillez vous référer à la classe LLMAPIArguments
dans arguments.py qui consomme un objet point de terminaison de la classe Endpoint
dans endpoint.py.
Nous utilisons Hydra pour la gestion de la configuration. Les configurations des points de terminaison se trouvent dans le chemin : configs/endpoints
.
Ceci est un exemple de fichier de configuration :
ENDPOINT_EXAMPLE : type : " CHAT_OPENAI " url : "" deployment_name : " llama3-70b " api_key_env_var_name : "" keyvault_secret_name : "" speed_factor : 1.0 num_parallel_processes : 10
type: "CHAT_OPENAI"
et type: "AZURE_CHAT_OPENAI"
selon le point de terminaison du modèle utilisé. Pour les modèles GPT disponibles sur Azure, utilisez type: "AZURE_CHAT_OPENAI"
. Pour les modèles déployés personnalisés comme Llama-3 sur Azure, utilisez type: "CHAT_OPENAI"
.url
et probablement deployment_name
avec les valeurs appropriées.keyvault_secret_name
est facultatif et n'est pas obligatoire si vous définissez l'API via une variable d'environnement. Mettez à jour api_key_env_var_name
si vous utilisez un nom de variable d'environnement différent pour la clé API que le nom de variable d'environnement par défaut "API_KEY"
. Lorsque vous utilisez plusieurs points de terminaison, spécifiez api_key_env_var_name
différent pour chaque point de terminaison.speed_factor
est utilisée lorsque plusieurs points de terminaison sont disponibles. Cela vous permet de spécifier la vitesse relative du point de terminaison par rapport aux autres, qui est utilisée pour partager proportionnellement les données entre les points de terminaison.num_parallel_processes
est utilisée pour spécifier le nombre de processus parallèles à utiliser lors de l'interrogation d'un point de terminaison spécifique. Toutes les demandes sont traitées séquentiellement sauf si num_parallel_processes
est défini sur une valeur supérieure à 1, ce qui permet un traitement parallèle. Comme ci-dessus, lors de l'utilisation de RadFact pour l'évaluation de rapports non fondés , par exemple narratifs, RadFact convertit d'abord les rapports en une liste d'expressions. Nous utilisons un LLM pour cette étape, mais il n'est pas nécessaire qu'il s'agisse du même LLM que celui utilisé pour la vérification des implications. Vous pouvez spécifier quel point de terminaison (donc LLM) est utilisé pour chaque tâche dans les configurations suivantes, sous override endpoints:
:
configs/report_to_phrases.yaml
-- conversion du rapport en liste de phrases. Dans MAIRA-2, nous avons utilisé pour cela GPT-4 qui peut être interrogé en tant que modèle AzureChatOpenAI.configs/radfact.yaml
-- vérification des implications. Dans MAIRA-2, nous avons utilisé pour cela LLama-3-70B-Instruct
qui peut être interrogé en tant que modèle ChatOpenAI. Différents LLM back-end peuvent se comporter différemment et produire des résultats métriques différents. En particulier, un modèle qui fonctionne mal lors de la vérification des implications ne doit pas être utilisé pour RadFact. Pour confirmer que la vérification d'implication se comporte comme prévu, exécutez python src/radfact/cli/run_radfact_test_examples.py
et confirmez que les résultats sont similaires à ceux attendus. Les résultats attendus ont été obtenus à l'aide du modèle LLama-3-70b-Instruct
.
Notez que cela ne teste pas le comportement de l’étape de rapport aux phrases.
La classe LLMEngine
permet un traitement parallèle sur plusieurs points de terminaison. Si vous avez accès à plusieurs points de terminaison avec des débits différents, le moteur peut partager les données entre les points de terminaison proportionnellement à leur vitesse. Le moteur permet également le traitement parallèle des requêtes vers un seul point de terminaison. Ceci est utilisé par défaut quel que soit le nombre de points de terminaison. Reportez-vous au fichier de configuration des points de terminaison pour les options speed_factor
et num_parallel_processes
. De plus, le moteur prend en charge le traitement par lots et la mise en cache intermédiaire des résultats. Tous les résultats intermédiaires sont stockés dans le répertoire outputs/radfact
sous un dossier d'identification d'exécution marqué avec l'horodatage de début, par exemple outputs/radfact/run_20240814_075225
. La structure des dossiers est la suivante :
outputs/radfact/run_20240814_075225
├── batch_outputs
│ ├── outputs_0_100.json
| ├── .
| ├── .
| ├── .
│ └── outputs_1000_1100.json
├── progress
│ ├── subset_0_240.csv
| ├── .
| ├── .
| ├── .
│ └── subset_800_1100.csv
├── skipped
│ ├── subset_0_240.csv
| ├── .
| ├── .
| ├── .
│ └── subset_800_1100.csv
├── outputs.json
├── progress.csv
└── skipped.csv
outputs.json
contient les résultats finaux pour tous les points de données. progress.csv
contient la progression du traitement pour chaque point de terminaison. batch_outputs
contient les résultats intermédiaires par taille de lot. skipped
contient les points de données qui ont été ignorés en raison d'erreurs.
Vous pouvez vous référer au notebook getting_started pour voir comment exécuter RadFact sur vos propres données. Nous vous recommandons fortement de lire d'abord le cahier pour comprendre le flux de travail RadFact et comment l'utiliser. Nous fournissons également un script pour exécuter RadFact sur vos données. Assurez-vous d'avoir configuré les points de terminaison comme décrit ci-dessus avant d'exécuter le script. La commande run_radfact
exécute le script python src/radfact/cli/run_radfact.py
sous le capot. Vous pouvez remplacer le comportement par défaut via les arguments de ligne de commande expliqués ci-dessous en exécutant run_radfact --help
. Vous devez avoir le package installé localement pour pouvoir exécuter le script.
$ run_radfact --help
usage: run_radfact [-h] [--radfact_config_name RADFACT_CONFIG_NAME] [--phrases_config_name PHRASES_CONFIG_NAME] --input_path INPUT_PATH [--is_narrative_text] [--output_dir OUTPUT_DIR] [--bootstrap_samples BOOTSTRAP_SAMPLES]
Compute RadFact metric for a set of samples and saves the results to a json file.
options:
-h, --help show this help message and exit
--input_path INPUT_PATH
The path to the csv or json file containing the samples to compute RadFact for. For finding generation samples, the csv file should have columns ' example_id ' ,
' prediction ' , and ' target ' similar to the example in ` examples/findings_generation_examples.csv ` . For grounded reporting samples, provide a json file in the
same format as ` examples/grounded_reporting_examples.json ` .
--is_narrative_text Whether the input samples are narrative text or not. If true, the input samples are expected to be narrative text, otherwise they are expected to be grounded
phrases.
--radfact_config_name RADFACT_CONFIG_NAME
The name of the config file for RadFact processing. We use the default config file but you can provide a custom config. Make sure the config follows the same
structure as ` configs/radfact.yaml ` and is saved in the ` configs ` directory. This is necessary for hydra initialization from the ` configs ` directory.
--phrases_config_name PHRASES_CONFIG_NAME
The name of the config file for reports to phrases conversion. We use the default config file but you can provide a custom config. Make sure the config follows
the same structure as ` configs/report_to_phrases.yaml ` and is saved in the ` configs ` directory. This is necessary for hydra initialization from the ` configs `
directory.
--output_dir OUTPUT_DIR
Path to the directory where the results will be saved as a json file.
--bootstrap_samples BOOTSTRAP_SAMPLES
Number of bootstrap samples to use for computing the confidence intervals. Set to 0 to disable bootstrapping.
run_radfact --input_path < path_to_input_file.csv > --is_narrative_text
run_radfact --input_path < path_to_input_file.json >
Reportez-vous aux exemples de fichiers d'entrée dans le répertoire examples
pour connaître le format attendu des fichiers d'entrée. Les fichiers d'entrée doivent être au format d'un fichier CSV pour les rapports non fondés Findings_Generation_examples.csv et d'un fichier JSON pour les rapports fondés Grounded_reporting_examples.json.
Le script calcule les intervalles de confiance pour les métriques à l'aide du bootstrapping. Le nombre d'échantillons bootstrap peut être contrôlé à l'aide de l'argument --bootstrap_samples
. La valeur par défaut est 500. Pour désactiver l'amorçage, définissez --bootstrap_samples 0
.
num_llm_failures
. Le script imprimera le nombre de requêtes ignorées à la fin de l'exécution et les stockera dans le répertoire skipped
sous le dossier identifiant d'exécution. Vous verrez également un message d'avertissement dans les journaux pour chaque requête ayant échoué. WARNING: No response for example {query_id}. Setting as NOT ENTAILED
.
Nous fournissons également un script pour convertir les rapports en phrases. Ceci est utile lorsque vous disposez d'un rapport narratif et que vous souhaitez le convertir en une liste d'expressions pour l'évaluation RadFact. Vous pouvez exécuter cette étape hors ligne, puis utiliser le fichier de sortie comme entrée dans RadFact. Assurez-vous d'avoir configuré les points de terminaison comme décrit ci-dessus avant d'exécuter le script. La commande run_report_to_phrases
exécute le script python src/radfact/cli/run_report_to_phrases.py
sous le capot.
run_report_to_phrases dataset.csv_path= < your_path_to_cxr_reports >
Ce script est configurable à l'aide du fichier de configuration report_to_phrases.yaml
. Vous pouvez spécifier le fichier d'entrée, le fichier de sortie et le point de terminaison à utiliser pour la conversion.
Si nécessaire, RadFact divise d'abord les rapports en phrases individuelles décrivant au plus un résultat. Il utilise ensuite les capacités d'inférence logique d'un grand modèle de langage pour déterminer si ces phrases sont logiquement prises en charge (« impliquées ») compte tenu du rapport de référence. Nous calculons cela dans deux directions, d'abord en utilisant le rapport de vérité terrain (original) comme référence, et vice versa, en utilisant le rapport généré par le modèle comme référence. Cela permet de quantifier à la fois l’exactitude et l’exhaustivité.
Dans l'ensemble, RadFact fournit six mesures de la qualité (fondée) des rapports :
Métrique | Définition | Que nous dit-il ? | Mise à la terre ? |
---|---|---|---|
Précision logique | La fraction des phrases générées qui sont impliquées par le rapport de vérité sur le terrain. | Quelle est la véracité des générations modèles : cela pénalise les générations incorrectes. | ❌ |
Rappel logique | La fraction de phrases de vérité terrain impliquées par le rapport généré. | Le degré de complétude du rapport généré : il pénalise les omissions. | ❌ |
Précision de mise à la terre | La fraction de phrases générées fondées logiquement et qui sont également impliquées spatialement. | À quelle fréquence les résultats générés correctement sont- ils également correctement fondés ? | ✔️ |
Rappel de mise à la terre | La fraction de phrases de vérité terrain logiquement impliquées qui sont également impliquées spatialement. | À quelle fréquence les résultats correctement saisis sont- ils également correctement fondés ? | ✔️ |
Précision spatiale | La fraction de toutes les phrases générées fondées qui sont à la fois logiquement et spatialement impliquées. | Un score faible signifie que le modèle a généré des cases inutiles ou des cases pour des phrases incorrectes. | ✔️ |
Rappel spatial | La fraction de toutes les phrases fondées sur la vérité terrain qui sont à la fois logiquement et spatialement impliquées. | Un score faible signifie que le modèle n'a pas réussi à générer des cases pour les résultats dans la référence, potentiellement en décrivant les résultats de manière incorrecte ou pas du tout. | ✔️ |
Les {précision, rappel} spatiales sont moins immédiatement interprétables que les autres métriques, mais nous les incluons pour contrôler le dénominateur implicite dans la mise à la terre {précision, rappel} : si nous évaluons uniquement la qualité des cases de phrases logiquement impliquées telle que mesurée par la mise à la terre {précision, rappel}, nous ne capturons pas les échecs de mise à la terre résultant de cases superflues associées à des phrases incorrectes (par exemple, des découvertes entièrement fabriquées), ou des cases manquantes associées à des découvertes manquées.
RadFact utilise les LLM en deux étapes. Dans les deux cas, nous utilisons une dizaine d’exemples en quelques prises de vue.
La vérification de l'implication unidirectionnelle (partie de l'étape 2) fonctionne comme suit :
Cela nous permet d'étiqueter chaque phrase comme étant logiquement impliquée (ou non) et spatialement impliquée (ou non), et donc de calculer les métriques RadFact répertoriées ci-dessus. Notez que l'implication spatiale n'est définie que pour les phrases avec des cases.
Pour la conversion des rapports en phrases individuelles, nous avons généré des exemples synthétiques dans le style des rapports MIMIC-CXR, en utilisant la section FINDINGS
. Les rapports MIMIC originaux sont protégés par un accord d'utilisation des données qui interdit la redistribution. Nous divisons manuellement les rapports narratifs en phrases individuelles. Les exemples et le message système peuvent être consultés sous llm_utils.report_to_phrases.prompts
.
Pour la vérification des implications, les quelques exemples proviennent d'un ensemble de données privé (« USMix »). Chaque exemple contient des phrases de deux rapports, que nous avons sélectionnés comme étant similaires mais non identiques à l'aide des statistiques tf-idf. En collaboration avec un radiologue consultant, nous les avons ensuite étiquetés manuellement avec leur statut d'implication et leurs preuves. Bien qu'il s'agisse d'une tâche d'inférence logique, il existe un certain degré de subjectivité dans la vérification des implications, qui découle de la manière dont certains concepts sont interprétés de manière stricte. Certains de ces exemples pourraient donc être contestés. Des exemples et des messages système sont disponibles sous llm_utils.nli.prompts
.
Pour citer RadFact, vous pouvez utiliser :
@article { Bannur2024MAIRA2GR ,
title = { MAIRA-2: Grounded Radiology Report Generation } ,
author = { Shruthi Bannur and Kenza Bouzid and Daniel C. Castro and Anton Schwaighofer and Sam Bond-Taylor and Maximilian Ilse and Fernando P'erez-Garc'ia and Valentina Salvatelli and Harshita Sharma and Felix Meissen and Mercy Prasanna Ranjit and Shaury Srivastav and Julia Gong and Fabian Falck and Ozan Oktay and Anja Thieme and Matthew P. Lungren and Maria T. A. Wetscherek and Javier Alvarez-Valle and Stephanie L. Hyland } ,
journal = { arXiv } ,
year = { 2024 } ,
volume = { abs/2406.04449 } ,
url = { https://arxiv.org/abs/2406.04449 }
}
RadFact est fourni uniquement à des fins de recherche. RadFact n'est pas conçu, prévu ou mis à disposition pour être utilisé dans le diagnostic, la prévention, l'atténuation ou le traitement d'une maladie ou d'un problème médical, ni pour remplir une fonction médicale, et les performances de RadFact à ces fins n'ont pas été établies. Vous êtes seul responsable de toute utilisation de RadFact, y compris son incorporation dans tout produit destiné à un usage médical.
Ce projet accueille les contributions et suggestions. La plupart des contributions nécessitent que vous acceptiez un contrat de licence de contributeur (CLA) déclarant que vous avez le droit de nous accorder, et que vous nous accordez effectivement, le droit d'utiliser votre contribution. Pour plus de détails, visitez https://cla.opensource.microsoft.com.
Lorsque vous soumettez une pull request, un robot CLA déterminera automatiquement si vous devez fournir un CLA et décorera le PR de manière appropriée (par exemple, vérification du statut, commentaire). Suivez simplement les instructions fournies par le bot. Vous n’aurez besoin de le faire qu’une seule fois pour tous les dépôts utilisant notre CLA.
Ce projet a adopté le code de conduite Microsoft Open Source. Pour plus d’informations, consultez la FAQ sur le code de conduite ou contactez [email protected] pour toute question ou commentaire supplémentaire.
Ce projet peut contenir des marques ou des logos pour des projets, des produits ou des services. L'utilisation autorisée des marques ou logos Microsoft est soumise et doit respecter les directives relatives aux marques et aux marques de Microsoft. L'utilisation des marques ou logos Microsoft dans les versions modifiées de ce projet ne doit pas prêter à confusion ni impliquer le parrainage de Microsoft. Toute utilisation de marques ou de logos tiers est soumise aux politiques de ces tiers.