ML_PrediccionpCR / README.md
Valdi183's picture
Mover los pesos y la tarjeta a la ra铆z
9a84fd8 verified
|
Raw History Blame Contribute Delete
6.52 kB
metadata
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. 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). 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. 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.

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:

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.

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; la del ONNX, web/modelo.json.