RadFact é uma estrutura para a avaliação de relatórios radiológicos gerados por modelos, com base em um relatório verdadeiro, com ou sem fundamentação . Aproveitando os recursos de inferência lógica de grandes modelos de linguagem, o RadFact não é um número único, mas um conjunto de métricas, capturando aspectos de precisão e recuperação em níveis somente de texto e de texto e fundamentação.
RadFact foi introduzido no MAIRA-2: Grounded Radiology Report Generation. Aqui fornecemos uma implementação de código aberto da métrica para facilitar seu uso e desenvolvimento.
LLMEngine
para processamento paraleloPara executar o RadFact, você só precisa clonar este repositório e executar o seguinte comando:
pip install .
Isto instalará o pacote radfact
e todas as suas dependências.
Alternativamente, fornecemos um Makefile
para configurar um ambiente conda com todas as dependências. Você pode criar o ambiente com:
make miniconda
make mamba
make env
conda activate radfact
A primeira etapa instala o miniconda, a segunda instala o mamba para resolução rápida de dependências e a terceira cria um ambiente conda chamado radfact
com todas as dependências. Isso também instalará o pacote radfact no modo editável por padrão por meio da receita setup_packages_with_deps
(consulte Makefile). Por fim, ative o ambiente para execução do RadFact. Isso é altamente recomendado se você pretende contribuir com o projeto.
Para usar o RadFact, você precisa de acesso a um grande modelo de linguagem. Você precisa primeiro configurar os endpoints com autenticação e, em seguida, confirmar se eles estão se comportando conforme o esperado usando nosso script de teste.
O LLM deve estar disponível como um endpoint de API e ser suportado por langchain
(versão 0.1.4). Damos suporte a dois tipos de modelos: modelos AzureChatOpenAI e ChatOpenAI. O primeiro é adequado para modelos GPT disponíveis no Azure, enquanto o último é adequado para modelos implantados personalizados como o Llama-3 no Azure.
Oferecemos suporte aos seguintes métodos de autenticação:
API_KEY
como a chave API do endpoint. Usamos API_KEY
como nome da variável de ambiente padrão. Se você usar um nome diferente, poderá especificá-lo na configuração do endpoint por meio de api_key_env_var_name
. Isto é especialmente útil ao usar vários endpoints com diferentes chaves de API.config.json
no diretório raiz do projeto. Esta configuração deve ter chaves subscription_id
, resource_group
e workspace_name
. Ele pode ser baixado do espaço de trabalho do AzureML por meio do portal. Este arquivo é adicionado ao .gitignore
para evitar commits acidentais. Certifique-se de salvar o arquivo no diretório raiz do projeto com o nome config.json
conforme esperado pela classe do endpoint.key_vault_secret_name
na configuração do endpoint.azure_ad_token_provider
de um modelo AzureChatOpenAI
que permite a atualização automática do token. Isto só tem suporte para modelos AzureChatOpenAI
. Para saber mais sobre como integramos os enpoints no RadFact, consulte a classe LLMAPIArguments
em argumentos.py que consome um objeto endpoint da classe Endpoint
em endpoint.py.
Usamos Hydra para gerenciamento de configuração. As configurações do endpoint estão no caminho: configs/endpoints
.
Este é um exemplo de arquivo de configuração:
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"
e type: "AZURE_CHAT_OPENAI"
dependendo do endpoint do modelo usado. Para modelos GPT disponíveis no Azure, use type: "AZURE_CHAT_OPENAI"
. Para modelos implantados personalizados como Llama-3 no Azure, use type: "CHAT_OPENAI"
.url
e prováveis deployment_name
com os valores apropriados.keyvault_secret_name
é opcional e não é obrigatório se você definir a API por meio de uma variável de ambiente. Atualize api_key_env_var_name
se você usar um nome de variável de ambiente diferente para a chave de API do que o padrão "API_KEY"
. Ao usar vários endpoints, especifique api_key_env_var_name
diferente para cada endpoint.speed_factor
é usada quando mais de um endpoint está disponível. Isso permite especificar a velocidade relativa do endpoint em comparação com os outros, que é usada para fragmentar os dados entre os endpoints proporcionalmente.num_parallel_processes
é usada para especificar o número de processos paralelos a serem usados ao consultar um terminal específico. Todas as solicitações são processadas sequencialmente, a menos que num_parallel_processes
seja definido com um valor maior que 1, o que permite o processamento paralelo. Como acima, ao usar o RadFact para avaliação de relatórios não fundamentados , por exemplo, narrativos, o RadFact primeiro converte os relatórios em uma lista de frases. Usamos um LLM para esta etapa, mas não precisa ser o mesmo LLM usado para verificação de implicação. Você pode especificar qual endpoint (portanto, LLM) é usado para cada tarefa nas configurações a seguir, em override endpoints:
:
configs/report_to_phrases.yaml
– conversão de relatório em lista de frases. No MAIRA-2, usamos GPT-4 para isso, que pode ser consultado como um modelo AzureChatOpenAI.configs/radfact.yaml
– verificação de implicação. No MAIRA-2, usamos LLama-3-70B-Instruct
para isso, que pode ser consultado como um modelo ChatOpenAI. Diferentes LLMs de back-end podem se comportar de maneira diferente e produzir resultados de métricas diferentes. Em particular, um modelo com fraco desempenho na verificação de implicação não deve ser utilizado para RadFact. Para confirmar se a verificação de implicação está se comportando conforme esperado, execute python src/radfact/cli/run_radfact_test_examples.py
e confirme se os resultados são semelhantes aos esperados. Os resultados esperados foram obtidos utilizando o modelo LLama-3-70b-Instruct
.
Observe que isso não testa o comportamento da etapa report-to-phrases.
A classe LLMEngine
permite o processamento paralelo em vários endpoints. Se você tiver acesso a vários endpoints com taxa de transferência diferente, o mecanismo poderá fragmentar os dados entre os endpoints proporcionalmente à sua velocidade. O mecanismo também permite o processamento paralelo de solicitações para um único terminal. Isso é usado por padrão, independentemente do número de terminais. Consulte o arquivo de configuração dos endpoints para as opções speed_factor
e num_parallel_processes
. Além disso, o mecanismo cuida do processamento em lote e do cache intermediário dos resultados. Todos os resultados intermediários são armazenados no diretório outputs/radfact
em uma pasta run id marcada com o carimbo de data/hora inicial, por exemplo, outputs/radfact/run_20240814_075225
. A estrutura da pasta é a seguinte:
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
contém os resultados finais de todos os pontos de dados. progress.csv
contém o progresso do processamento para cada terminal. batch_outputs
contém os resultados intermediários por tamanho de lote. skipped
contém os pontos de dados que foram ignorados devido a erros.
Você pode consultar o caderno Getting_Started para ver como executar o RadFact em seus próprios dados. É altamente recomendável ler o notebook primeiro para entender o fluxo de trabalho do RadFact e como usá-lo. Também fornecemos um script para executar o RadFact em seus dados. Certifique-se de configurar os endpoints conforme descrito acima antes de executar o script. O comando run_radfact
executa o script python src/radfact/cli/run_radfact.py
nos bastidores. Você pode substituir o comportamento padrão por meio dos argumentos de linha de comando explicados abaixo executando run_radfact --help
. Você precisa ter o pacote instalado localmente para executar o 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 >
Consulte os arquivos de entrada de exemplo no diretório examples
para obter o formato esperado dos arquivos de entrada. Os arquivos de entrada devem estar no formato de um arquivo CSV para relatórios não fundamentados achados_generação_examples.csv e um arquivo JSON para relatórios fundamentados grounded_reporting_examples.json.
O script calcula intervalos de confiança para as métricas usando bootstrapping. O número de amostras de bootstrap pode ser controlado usando o argumento --bootstrap_samples
. O valor padrão é 500. Para desativar a inicialização, defina --bootstrap_samples 0
.
num_llm_failures
. O script imprimirá o número de consultas ignoradas no final da execução e as armazenará no diretório skipped
na pasta run id. Você também verá uma mensagem de aviso nos logs para cada consulta com falha. WARNING: No response for example {query_id}. Setting as NOT ENTAILED
.
Também fornecemos um script para converter relatórios em frases. Isto é útil quando você tem um relatório narrativo e deseja convertê-lo em uma lista de frases para avaliação RadFact. Você pode executar esta etapa off-line e usar o arquivo de saída como entrada para o RadFact. Certifique-se de configurar os endpoints conforme descrito acima antes de executar o script. O comando run_report_to_phrases
executa o script python src/radfact/cli/run_report_to_phrases.py
nos bastidores.
run_report_to_phrases dataset.csv_path= < your_path_to_cxr_reports >
Este script é configurável usando o arquivo de configuração report_to_phrases.yaml
. Você pode especificar o arquivo de entrada, o arquivo de saída e o terminal a ser usado para a conversão.
Se necessário, o RadFact primeiro divide os relatórios em frases individuais que descrevem no máximo uma descoberta. Em seguida, ele usa os recursos de inferência lógica de um modelo de linguagem grande para determinar se essas sentenças são logicamente suportadas ('incluídas') dado o relatório de referência. Calculamos isso em duas direções, primeiro usando o relatório real (original) como referência e vice-versa, usando o relatório gerado pelo modelo como referência. Isto permite a quantificação da exatidão e da integralidade.
No geral, o RadFact fornece seis medidas de qualidade de relatório (fundamentada):
Métrica | Definição | O que isso nos diz? | Aterramento? |
---|---|---|---|
Precisão lógica | A fração de sentenças geradas que são decorrentes do relatório de verdade. | Quão verdadeiras são as gerações do modelo: penaliza as gerações incorretas. | ❌ |
Recuperação lógica | A fração de sentenças verdadeiras que são decorrentes do relatório gerado. | Quão completo é o relatório gerado: penaliza as omissões. | ❌ |
Precisão de aterramento | A fração de sentenças geradas fundamentadas com implicação lógica que também são implicadas espacialmente. | Com que frequência as descobertas geradas corretamente também são fundamentadas corretamente? | ✔️ |
Recuperação de aterramento | A fração de sentenças de verdade fundamental fundamentadas logicamente implicadas que também são implicadas espacialmente. | Com que frequência as descobertas captadas corretamente também são fundamentadas corretamente? | ✔️ |
Precisão espacial | A fração de todas as sentenças geradas fundamentadas que são lógica e espacialmente implicadas. | Uma pontuação baixa significa que o modelo gerou caixas desnecessárias ou caixas para frases incorretas. | ✔️ |
Recordação espacial | A fração de todas as sentenças de verdade fundamentadas que são lógica e espacialmente implicadas. | Uma pontuação baixa significa que o modelo não conseguiu gerar caixas para descobertas na referência, potencialmente descrevendo a descoberta incorretamente ou nem descrevendo a descoberta. | ✔️ |
Espaciais {precisão, recordação} são menos imediatamente interpretáveis do que as outras métricas, mas as incluímos para controlar o denominador implícito na fundamentação {precisão, recordação}: se avaliarmos apenas a qualidade das caixas de sentenças logicamente implicadas, conforme medido pela fundamentação {precisão, recall}, não capturamos falhas de aterramento decorrentes de caixas estranhas associadas a sentenças incorretas (por exemplo, descobertas totalmente fabricadas) ou caixas faltantes associadas a descobertas perdidas.
RadFact usa LLMs em duas etapas. Em ambos os casos, usamos cerca de 10 exemplos de poucas cenas.
A verificação de implicação unidirecional (parte da etapa 2) funciona da seguinte forma:
Isso nos permite rotular cada frase como implicada logicamente (ou não) e implicada espacialmente (ou não) e, portanto, calcular as métricas RadFact listadas acima. Observe que a implicação espacial é definida apenas para sentenças com caixas.
Para conversão dos relatórios em sentenças individuais, geramos exemplos sintéticos no estilo dos relatórios MIMIC-CXR, utilizando a seção FINDINGS
. Os relatórios MIMIC originais são protegidos por um acordo de uso de dados que proíbe a redistribuição. Dividimos manualmente os relatórios narrativos em frases individuais. Os exemplos e a mensagem do sistema podem ser vistos em llm_utils.report_to_phrases.prompts
.
Para verificação de implicação, os exemplos de poucas tentativas são provenientes de um conjunto de dados privado ("USMix"). Cada exemplo contém frases de dois relatórios, que selecionamos como semelhantes, mas não idênticos, usando estatísticas tf-idf. Em colaboração com um radiologista consultor, nós os rotulamos manualmente com status de vinculação e evidências. Apesar de ser uma tarefa de inferência lógica, existe um certo grau de subjetividade na verificação de implicação, decorrente do rigor com que determinados conceitos são interpretados. Portanto, alguns desses exemplos poderiam ser contestados. Exemplos e mensagens do sistema estão disponíveis em llm_utils.nli.prompts
.
Para citar RadFact, você pode usar:
@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 é fornecido apenas para uso em pesquisa. RadFact não foi projetado, pretendido ou disponibilizado para uso no diagnóstico, prevenção, mitigação ou tratamento de uma doença ou condição médica, nem para desempenhar qualquer função médica, e o desempenho do RadFact para tais fins não foi estabelecido. Você é o único responsável por qualquer uso do RadFact, incluindo incorporação em qualquer produto destinado a fins médicos.
Este projeto aceita contribuições e sugestões. A maioria das contribuições exige que você concorde com um Contrato de Licença de Colaborador (CLA), declarando que você tem o direito de nos conceder, e realmente nos concede, os direitos de uso de sua contribuição. Para obter detalhes, visite https://cla.opensource.microsoft.com.
Quando você envia uma solicitação pull, um bot CLA determinará automaticamente se você precisa fornecer um CLA e decorará o PR adequadamente (por exemplo, verificação de status, comentário). Basta seguir as instruções fornecidas pelo bot. Você só precisará fazer isso uma vez em todos os repositórios usando nosso CLA.
Este projeto adotou o Código de Conduta de Código Aberto da Microsoft. Para obter mais informações, consulte as Perguntas frequentes sobre o Código de Conduta ou entre em contato com [email protected] com perguntas ou comentários adicionais.
Este projeto pode conter marcas registradas ou logotipos de projetos, produtos ou serviços. O uso autorizado de marcas registradas ou logotipos da Microsoft está sujeito e deve seguir as Diretrizes de Marcas Registradas e Marcas da Microsoft. O uso de marcas registradas ou logotipos da Microsoft em versões modificadas deste projeto não deve causar confusão nem implicar patrocínio da Microsoft. Qualquer uso de marcas registradas ou logotipos de terceiros está sujeito às políticas desses terceiros.