--- language: es license: apache-2.0 tags: - medical - clinical-nlp - abbreviation-detection - spanish - cardiology - llama metrics: - precision - recall - f1 --- # LLaMA 3.2-1B Medical Abbreviation Detector (Spanish) ## Descripción del Modelo Este modelo es una versión especializada de **LLaMA 3.2-1B Instruct** ajustada mediante fine-tuning para la **detección automática de abreviaciones médicas en textos clínicos en español**. Forma parte del sistema SimpliMed desarrollado para la simplificación de informes de alta hospitalaria en el ámbito de la cardiología. El modelo ha sido entrenado específicamente para identificar: - **Abreviaturas**: formas truncadas (ej: "a.c." = antes de comida) - **Siglas**: iniciales de palabras (ej: "EPOC" = enfermedad pulmonar obstructiva crónica) - **Acrnimos**: siglas lexicalizadas (ej: "DIU" = dispositivo intrauterino) - **Símbolos médicos**: notación clínica (ej: "mmHg", "mg", "cm") ### Formato de Salida ```json { "formas_abreviadas": ["HTA", "IAM", "FEVI", "EPOC"], "simbolos_medicos": ["mmHg", "mg/dl", "cm", "ml"] } ``` ## Rendimiento El modelo supera significativamente a los métodos basados en expresiones regulares: | Sistema | Precisión | Recall | F1 Score | |---------|-----------|--------|----------| | **SLM (este modelo)** | **0.8902** | **0.9283** | **0.9024** | | Expresiones regulares | 0.6271 | 0.7675 | 0.6704 | ## Entrenamiento ### Corpus de Entrenamiento - **Fuente**: Informes de alta hospitalaria del Hospital Universitario de Jaén (especialidad de cardiología) - **Anotación**: Automática con GPT-4o - **Diccionario de referencia**: 7,054 abreviaciones médicas del diccionario SEDOM (Sociedad Española de Documentación Médica) - **Tamaño del corpus**: 70% del total de informes disponibles ### Hiperparámetros ```python { "per_device_train_batch_size": 2, "per_device_eval_batch_size": 1, "num_train_epochs": 3, "eval_steps": 10, "save_steps": 500, "gradient_accumulation_steps": 4, "learning_rate": 1e-4, "seed": 42, "max_seq_length": 2048 } ``` ### Frameworks - PyTorch - Hugging Face Transformers - vLLM (para inferencia eficiente) ## Uso ```python import json import re from openai import OpenAI class ExtractorAbreviaciones: def __init__(self, ruta_modelo, ruta_prompt, base_url="http://localhost:8000/v1"): self.model_path = ruta_modelo self.prompt = self._cargar_prompt(ruta_prompt) self.client = OpenAI(base_url=base_url, api_key="token-abc123") def _cargar_prompt(self, ruta_prompt): with open(ruta_prompt, "r", encoding="utf-8") as file: return file.read() def _extraer_listas(self, texto): """Fallback para extraer listas si el JSON no parsea correctamente""" patrones = { "formas_abreviadas": re.compile(r'"formas_abreviadas": \[([^\]]+)\]'), "simbolos_medicos": re.compile(r'"simbolos_medicos": \[([^\]]+)\]') } datos = {"formas_abreviadas": [], "simbolos_medicos": []} for clave, patron in patrones.items(): coincidencia = patron.search(texto) if coincidencia: elementos = [x.strip().strip('"') for x in coincidencia.group(1).split(',')] datos[clave] = elementos return datos def extraer_abreviaciones(self, texto): """Extrae todas las abreviaciones (combinando ambas categorías)""" datos = self.extraer_abreviaciones_simbolos(texto) return list(set(datos["formas_abreviadas"]) | set(datos["simbolos_medicos"])) def extraer_abreviaciones_simbolos(self, text, temperature=0.0, max_new_tokens=128): """ Extrae abreviaciones y símbolos médicos de un texto. Args: text (str): El texto clínico a analizar temperature (float): Temperatura para la generación (0.0 = determinista) max_new_tokens (int): Número máximo de tokens a generar Returns: dict: {"formas_abreviadas": [...], "simbolos_medicos": [...]} """ try: messages = [ {"role": "system", "content": self.prompt}, {"role": "user", "content": text} ] response = self.client.chat.completions.create( model=self.model_path, messages=messages, max_tokens=max_new_tokens, temperature=temperature ) resp = response.choices.message.content # Intentar parsear como JSON try: return json.loads(resp) except json.JSONDecodeError: # Buscar inicio del JSON inicio_json = resp.find("{") if inicio_json != -1: json_str = resp[inicio_json:] try: return json.loads(json_str) except json.JSONDecodeError: return self._extraer_listas(resp) else: return self._extraer_listas(resp) except Exception as e: print(f"Error en la solicitud: {str(e)}") return {"formas_abreviadas": [], "simbolos_medicos": []} # Ejemplo de uso extractor = ExtractorAbreviaciones( ruta_modelo="lmolino/extractor_abreviaciones", ruta_prompt="prompt_abreviaciones.txt" ) texto = "Paciente con HTA e IAM previo. TA: 140/90 mmHg." resultado = extractor.extraer_abreviaciones_simbolos(texto) print(resultado) # {"formas_abreviadas": ["HTA", "IAM", "TA"], "simbolos_medicos": ["mmHg"]} ``` ## Limitaciones y Consideraciones 1. **Dominio específico**: El modelo ha sido entrenado principalmente con informes de cardiología, por lo que su rendimiento puede variar en otras especialidades médicas, aunque su diseño es generalista. 2. **Sensibilidad al formato**: El modelo puede tener dificultades con textos completamente en mayúsculas, donde pierde pistas tipográficas distintivas. 3. **Desambiguación contextual**: Para abreviaciones con múltiples significados (ej: "HTP" = hipertensin portal vs. hipertensión pulmonar), se requiere un módulo adicional de desambiguación basado en contexto clínico. 4. **Dependencia del diccionario SEDOM**: Las abreviaciones detectadas se validan contra el diccionario de 7,054 entradas del SEDOM. ## Casos de Uso - Preprocesamiento de informes médicos - Sistemas de simplificación de textos clínicos - Normalización de terminología médica - Asistencia en la comunicación médico-paciente - Análisis de calidad de documentación clínica ## Licencia Apache 2.0