--- license: cc-by-nc-4.0 library_name: pytorch pipeline_tag: image-classification datasets: - BreastDCEDL tags: - medical-imaging - breast-mri - dce-mri - pcr - cnn - from-scratch --- # Predicción de pCR en BreastDCEDL Pesos del modelo final de [ML_PrediccionpCR](https://github.com/Valdi183/ML_PrediccionpCR). A partir de una resonancia de mama con contraste (DCE-MRI) tomada **antes** de la quimioterapia, el modelo estima la probabilidad de **pCR**, es decir, de que tras el tratamiento no quede tumor invasivo. **Uso educativo, sin validez clínica.** ## Qué es - **CNN propia, entrenada desde cero**, sin nada preentrenado: 3 bloques convolucionales de 8, 16 y 32 filtros. Trabaja a 128 px dentro de la red y tiene **18.329 parámetros**. - **Conjunto de 5 redes**, una por fold de validación cruzada. La probabilidad de un corte es la media de las 5 sigmoides. - **Umbral 0,3635**, fijado en validación (pCR si la probabilidad es > 0,3635). - **Entrada:** un corte de 3 fases del contraste (PRE, EARLY, LATE, que no son RGB), cada una un PNG en gris de 256×256 dividido entre 255. La forma es `(N, 3, 256, 256)`, `float32`, en [0, 1]. El resto del preprocesado (la reducción a 128 px) va dentro de la red. - **Salida de cada red:** un logit; la sigmoide da p(pCR). ## Uso previsto y no previsto - **Previsto:** docencia e investigación. Sirve para estudiar el problema, reproducir los resultados y probar la web. - **No previsto:** cualquier uso clínico. **No sirve para diagnosticar ni para decidir tratamientos**, y no es un dispositivo médico. Un buen resultado retrospectivo no demostraría seguridad ni utilidad clínica, y este, además, no supera al azar en test. ## Datos y partición - **Dataset:** BreastDCEDL (Fridman et al., 2025, [arXiv:2506.12190](https://arxiv.org/abs/2506.12190)). Está construido a partir de las colecciones públicas I-SPY1, I-SPY2 y Duke Breast Cancer MRI y tiene licencia [CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/). Estos pesos derivan de él y se publican con la misma licencia, para uso no comercial y conservando la atribución. - **Tamaño:** 1.273 pacientes y 12.703 cortes; el 70,6 % son pCR=0. - Train: 1.097 pacientes (10.945 cortes). - Test: 176 pacientes (1.758 cortes). - **Partición por paciente:** ningún corte de una paciente aparece a la vez en entrenamiento y validación (5 folds) ni en train y test. - **Test usado una sola vez**, al final, con un plan fijado antes (pesos y su SHA-256, umbral y agregación). Nada se ajustó con él. ## Resultados - **Validación (5 folds):** AUC medio de todas las épocas, 0,551 ± 0,011. - **Test (evaluado una sola vez, por paciente, con la probabilidad media de sus cortes):** | Métrica | Valor | |---|---| | AUC | 0,544 [IC 95 %: 0,457-0,629] | | Sensibilidad | 0,038 | | Especificidad | 0,935 | Matriz de confusión (176 pacientes): | | Predicho pCR | Predicho no pCR | |---|---|---| | **pCR real** | VP 2 | FN 51 | | **No pCR real** | FP 8 | VN 115 | Los intervalos son bootstrap de pacientes (2.000 remuestreos). Fridman et al. 2025 obtienen 0,72 en el mismo test con un modelo preentrenado, así que no es comparable con una CNN desde cero. El detalle está en [docs/decisiones.md](https://github.com/Valdi183/ML_PrediccionpCR/blob/main/docs/decisiones.md). ## Limitaciones - **No se distingue del azar en test:** el IC 95 % del AUC incluye 0,5. Con el umbral elegido, detecta 2 de las 53 pCR. - **Un corte frente a un umbral por paciente:** el umbral se eligió con la media de los cortes de cada paciente (unos 10). Aplicado a un solo corte, como en la web, la decisión es menos fiable. - **EARLY saturado:** en la zona que más realza, más de la mitad de los píxeles están a 255 en EARLY en el 63 % de los cortes de train. La magnitud del realce no está en la imagen. Es una limitación de los PNG de 8 bits del dataset, no de este modelo. - **Diferencias entre cohortes:** las tres cohortes se procesaron de forma distinta. En test, el AUC por cohorte va de 0,351 (I-SPY1, 35 pacientes) a 0,650 (Duke, 42). - **TF32 frente a FP32:** las cifras oficiales se calcularon en GPU con TF32, el valor por defecto de PyTorch. En FP32, como calculan la web y `src.inferencia`, las probabilidades cambian hasta ~7e-4. ## Cómo cargarlos La arquitectura está en el repositorio de GitHub (`src/models/cnn.py`). Con el repositorio clonado, desde su raíz: ```python import torch from huggingface_hub import hf_hub_download from src.models.cnn import cargar REPO_HF = "Valdi183/ML_PrediccionpCR" NOMBRES = ["it6_3bloques_f0", "it6_3bloques_f1", "it8_3bloques_f2", "it8_3bloques_f3", "it8_3bloques_f4"] UMBRAL = 0.363489137 # cargar() usa torch.load(..., weights_only=True) y devuelve la red en modo evaluación redes = [cargar(hf_hub_download(REPO_HF, f"{n}.pt"))[0] for n in NOMBRES] x = torch.rand(1, 3, 256, 256) # PRE, EARLY, LATE en [0, 1] with torch.no_grad(): prob = torch.stack([torch.sigmoid(r(x)) for r in redes]).mean().item() print(prob, "pCR" if prob > UMBRAL else "no pCR") ``` Desde PNG reales: `python -m src.inferencia --pre X_PRE.png --early X_EARLY.png --late X_LATE.png` valida la entrada y comprueba el SHA-256 de cada peso. - **Web**, predicción en el navegador con el ONNX: - **Código, entrenamiento y resultados:** ## Ficheros | Fichero | Contenido | SHA-256 | |---|---|---| | `it6_3bloques_f0.pt` | red del fold 0 | `f1eb794abdee19ae3c8308727741a1d3db2b53c27e8112b1d241d6728e671862` | | `it6_3bloques_f1.pt` | red del fold 1 | `0c62d2e98b46ae493758c1670dbd56fcfd683d7e6f75074de00e02ff52e3a563` | | `it8_3bloques_f2.pt` | red del fold 2 | `b58239fd676a4d9050524933589dd80fb3f56d178e5f6dec5e3b56df4f5e29c8` | | `it8_3bloques_f3.pt` | red del fold 3 | `3c3826e3f1d07d3254b7ddf6a068c94e1ee24e791f04d981d38c9242afd47145` | | `it8_3bloques_f4.pt` | red del fold 4 | `e2d184a2ea3275a958630c1481be64dd3c9d751ed8c20e8e0e1d97d4db7ff1f3` | | `conjunto.onnx` | las 5 redes en un solo grafo (opset 17); devuelve `prob` (media) y `por_modelo` | `b6779db9769e1c62f61032dfec4c67215e862a0a4696fcd266f141382853413d` | La fuente de verdad de los hashes de los `.pt` es [results/test/plan.json](https://github.com/Valdi183/ML_PrediccionpCR/blob/main/results/test/plan.json); la del ONNX, [web/modelo.json](https://github.com/Valdi183/ML_PrediccionpCR/blob/main/web/modelo.json).