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
{
"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
{
"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
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
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.
Sensibilidad al formato: El modelo puede tener dificultades con textos completamente en mayúsculas, donde pierde pistas tipográficas distintivas.
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.
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
- Downloads last month
- 11