Créer un radiologue IA multimodal russe : ViT + ruGPT-3 Guide Kaggle
Développer des solutions d'IA médicale en russe souffre d'un manque d'outils et de datasets prêts à l'emploi. Cet article présente un cas pratique d'assemblage et d'entraînement d'un modèle VisionEncoderDecoder pour générer des rapports médicaux à partir de radiographies, en combinant l'encodeur visuel ViT avec le modèle de langage ruGPT-3.
Choix architecturaux et modifications du modèle
Construire un modèle multimodal de zéro exige une puissance de calcul massive. Une approche plus intelligente consiste à combiner des composants pré-entraînés via l'architecture VisionEncoderDecoderModel de Hugging Face. Nous avons choisi google/vit-base-patch16-224-in21k comme encodeur pour extraire les caractéristiques visuelles. Le décodeur est le modèle en russe ai-forever/rugpt3small_based_on_gpt2.
Défi principal : ruGPT-3 ne supporte pas nativement l'attention croisée pour recevoir les données de l'encodeur. La solution passe par une modification de la configuration avant initialisation :
from transformers import AutoConfig, AutoModelForCausalLM, AutoModel
encoder = AutoModel.from_pretrained("google/vit-base-patch16-224-in21k")
decoder_config = AutoConfig.from_pretrained("ai-forever/rugpt3small_based_on_gpt2")
decoder_config.is_decoder = True
decoder_config.add_cross_attention = True
decoder = AutoModelForCausalLM.from_pretrained("ai-forever/rugpt3small_based_on_gpt2", config=decoder_config)
Une fois assemblé, le modèle initialise de nouveaux poids pour les couches d'attention croisée et de projection, qui seront affinés pendant l'entraînement.
Préparation et traitement des données
Aucun dataset russe prêt n'associe images de radiographies et rapports médicaux, nous avons donc innové. Nous avons utilisé le dataset anglais Indiana University Chest X-Ray (IU X-Ray) avec ~7 500 images et rapports. Les rapports ont été traduits en russe via le modèle Helsinki-NLP/opus-mt-en-ru directement dans l'environnement Kaggle.
La gestion des fichiers sur Kaggle a ses particularités. Les chargeurs d'images standards ne voient souvent que les aperçus miniatures. Pour un mapping correct, nous scannons en profondeur le système de fichiers :
import os
file_map = {}
for root, dirs, files in os.walk('/kaggle/input'):
for file in files:
if file.lower().endswith(('.png', '.jpg', '.jpeg')):
base_name = os.path.splitext(file)[0]
file_map[base_name] = os.path.join(root, file)
Cela garantit un lien fiable entre les identifiants CSV et les chemins d'images réels.
Processus d'entraînement et dépannage
L'entraînement s'est déroulé sur deux GPU NVIDIA T4 avec précision mixte (fp16) et accumulation de gradients (gradient_accumulation_steps=4) pour un batch virtuel de 32 de manière efficace.
Problèmes courants et solutions :
- Crash lors de la sauvegarde des checkpoints : Seq2SeqTrainer échoue sur certains modèles composites personnalisés. Solution : Désactiver les sauvegardes intermédiaires (save_strategy="no") et gérer manuellement les paramètres de génération via GenerationConfig avant la sauvegarde finale.
- Timeouts de session Kaggle : Éviter l'arrêt automatique pendant un entraînement long en exécutant un snippet JavaScript simple dans la console du navigateur pour simuler des clics périodiques.
Résultats, inférence et déploiement
Après 15 époques, le modèle génère des rapports médicaux russes cohérents, utilisant correctement la terminologie professionnelle. Il identifie des motifs de base comme des poumons sains, des signes de pneumothorax et une cardiomégalie. Le petit dataset entraîne des hallucinations occasionnelles, comme mentionner des dispositifs médicaux absents.
Exemple d'inférence basique :
import torch
from transformers import VisionEncoderDecoderModel, ViTImageProcessor, AutoTokenizer
from PIL import Image
model_id = "livadies/Russian-Radiologist-ruGPT-ViT"
model = VisionEncoderDecoderModel.from_pretrained(model_id)
feature_extractor = ViTImageProcessor.from_pretrained(model_id)
tokenizer = AutoTokenizer.from_pretrained(model_id)
image = Image.open("xray.jpg").convert("RGB")
pixel_values = feature_extractor(images=image, return_tensors="pt").pixel_values
generated_ids = model.generate(pixel_values, max_length=128, num_beams=4)
print(tokenizer.decode(generated_ids[0], skip_special_tokens=True))
Une démo Gradio tourne sur Hugging Face Spaces en CPU, avec des temps de génération de 10–15 secondes. Le code source complet — incluant pipelines de données et notebooks d'entraînement — est dans le repo public.
Enseignements clés
- Architecture hybride : Fusion réussie d'un encodeur visuel ViT pré-entraîné et du modèle de langage ruGPT-3 via ajouts d'attention croisée par tweaks de config.
- Contournements de données : Surmonté le manque de datasets médicaux russes en traduisant des datasets anglais et en naviguant les bizarreries de fichiers Kaggle.
- Solutions pratiques : Désactivé les auto-sauvegardes buggées de Seq2SeqTrainer et prévenu les timeouts de session pour un entraînement long fiable.
- Preuve de concept : Modèle sur petit dataset valide l'architecture Vision + Langage pour la génération de texte médical russe structuré.
- Ouvert et accessible : Code complet et démo interactive publics pour étude, tests et extensions par la communauté.
— Editorial Team
Aucun commentaire pour le moment.