{"schemaVersion":1,"id":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production","title":"Privacidad Diferencial y Federated Learning: Arquitectura de Pipelines ML Sanitarios Conformes a HIPAA","description":"Budgets de epsilon, mecanismos de ruido, agregación segura y PySyft en la práctica, una arquitectura de pipeline de federated learning para imágenes médicas capaz de pasar auditorías HIPAA.","language":"es","datePublished":"2026-02-14","dateModified":null,"contentFormat":"text/markdown","content":"AI/ML\n\n# Privacidad Diferencial y Federated Learning: Arquitectura de Pipelines ML Sanitarios Conformes a HIPAA\n\n2026-02-147 min lectura\n\nLucio Durán\nEngineering Manager & AI Solutions Architect\n\nTambién disponible en: [English](<https://lucioduran.com/blog/differential-privacy-federated-learning-production>)\n\n## La Arquitectura\n\n```\nHospital A ──┐\nHospital B ──┤\nHospital C ──┼──→ [Servidor de Agregación Segura (AWS)] ──→ [Modelo Global]\nHospital D ──┤ ↑ solo gradientes encriptados\nHospital E ──┘ ↓ solo updates agregados\n```\n\nCada hospital corre un nodo de entrenamiento local. El servidor central nunca ve datos crudos, gradientes crudos ni updates de modelo individuales. Solo ve el resultado de la agregación segura, la suma encriptada de todos los updates.\n\n## Privacidad Diferencial: La Teoría que Realmente Se necesita\n\nLa privacidad diferencial es una definición matemática, no una técnica. Un algoritmo aleatorizado M satisface (ε, δ)-privacidad diferencial si para todos los datasets D y D' que difieren en un registro, y para todas las posibles salidas S:\n\n```\nP[M(D) ∈ S] ≤ e^ε · P[M(D') ∈ S] + δ\n```\n\nEn criollo: sacar o agregar los datos de cualquier paciente individual cambia la distribución de salida como máximo por un factor de e^ε, más una probabilidad de fallo δ despreciable.\n\nPara deep learning, aplicamos esto a través de **DP-SGD**:\n\n```python\nimport torch\nfrom opacus import PrivacyEngine\n\nmodel = PneumoniaResNet(pretrained=True)\noptimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)\ndata_loader = torch.utils.data.DataLoader(hospital_dataset, batch_size=64)\n\nprivacy_engine = PrivacyEngine()\nmodel, optimizer, data_loader = privacy_engine.make_private_with_epsilon(\n module=model,\n optimizer=optimizer,\n data_loader=data_loader,\n epochs=50,\n target_epsilon=8.0,\n target_delta=1e-5,\n max_grad_norm=1.0,\n)\n\nfor epoch in range(50):\n for batch in data_loader:\n images, labels = batch\n optimizer.zero_grad()\n output = model(images)\n loss = F.binary_cross_entropy_with_logits(output, labels)\n loss.backward()\n optimizer.step() # Opacus maneja clipping + ruido internamente\n\n epsilon = privacy_engine.get_epsilon(delta=1e-5)\n print(f\"Epoch {epoch}: ε = {epsilon:.2f}\")\n if epsilon > 8.0:\n print(\"Budget de privacidad agotado. Parando entrenamiento.\")\n break\n```\n\nLas decisiones clave de parámetros que requieren experimentación cuidadosa:\n\n- **max\\_grad\\_norm=1.0**: Muy bajo y clipeás señal útil. Muy alto y se necesita más ruido para lograr el mismo ε. Barrer de 0.1 a 10.0 típicamente arroja 1.0 como óptimo para arquitecturas ResNet.\n- **target\\_epsilon=8.0**: Una elección pragmática. ε=1.0 es el gold standard académico pero nos costaba 8% de accuracy. ε=8.0 dio garantías de privacidad significativas manteniendo accuracy dentro del 2% del baseline sin privacidad.\n- **target\\_delta=1e-5**: Práctica estándar, δ tiene que ser menor a 1/N donde N es el tamaño del dataset.\n\n## Rényi DP para Tracking de Budget\n\nEste es el punto donde la mayoría de los tutoriales cometen errores en la matemática. Si ejecutars DP-SGD por 100 epochs, el costo naive de privacidad es 100 × ε\\_por\\_paso. Esto se llama composición básica, y es dramáticamente pesimista.\n\n```python\nfrom opacus.accountants import RDPAccountant\n\naccountant = RDPAccountant()\n\nfor epoch in range(num_epochs):\n for step in range(steps_per_epoch):\n accountant.step(\n noise_multiplier=noise_multiplier,\n sample_rate=batch_size / len(dataset),\n )\n\n epsilon = accountant.get_epsilon(delta=1e-5)\n print(f\"Después de epoch {epoch}: ε = {epsilon:.2f} (RDP)\")\n```\n\nEn un pipeline representativo, composición básica da ε=12.4 después de 50 epochs. RDP dio ε=4.7 para la exacta misma corrida de entrenamiento. Eso no es una mejora menor, es la diferencia entre un resultado publicable y un paper rechazado.\n\n## Federated Learning con PySyft\n\n[PySyft](<https://github.com/OpenMined/PySyft>) provee la capa de federación. Cada hospital corre un ` DataSite ` que controla acceso a sus datos:\n\n```python\nimport syft as sy\n\nhospital_a = sy.orchestra.launch(\n name=\"hospital-a\",\n port=8081,\n dev_mode=False,\n reset=True,\n)\n\ndataset = sy.Dataset(\n name=\"chest-xray-hospital-a\",\n description=\"Radiografías de tórax de-identificadas, 2020-2025\",\n asset_list=[\n sy.Asset(\n name=\"images\",\n data=real_image_tensor, # Nunca sale de este nodo\n mock=generate_mock_images(), # Datos sintéticos para testing\n ),\n sy.Asset(\n name=\"labels\",\n data=real_labels,\n mock=generate_mock_labels(),\n ),\n ],\n)\nhospital_a.upload_dataset(dataset)\n```\n\nEl coordinador central orquesta el entrenamiento sin acceder a los datos:\n\n```python\nhospitals = [\n sy.login(url=\"https://hospital-a.internal:8081\", email=\"ml@coordinator.org\", password=\"...\"),\n sy.login(url=\"https://hospital-b.internal:8082\", email=\"ml@coordinator.org\", password=\"...\"),\n sy.login(url=\"https://hospital-c.internal:8083\", email=\"ml@coordinator.org\", password=\"...\"),\n sy.login(url=\"https://hospital-d.internal:8084\", email=\"ml@coordinator.org\", password=\"...\"),\n sy.login(url=\"https://hospital-e.internal:8085\", email=\"ml@coordinator.org\", password=\"...\"),\n]\n\n@sy.syft_function_single_use(\n images=hospitals[0].datasets[\"chest-xray-hospital-a\"][\"images\"],\n labels=hospitals[0].datasets[\"chest-xray-hospital-a\"][\"labels\"],\n)\ndef train_local(images, labels):\n import torch\n from opacus import PrivacyEngine\n\n model = load_global_model()\n optimizer = torch.optim.SGD(model.parameters(), lr=0.01)\n data_loader = make_loader(images, labels, batch_size=64)\n\n privacy_engine = PrivacyEngine()\n model, optimizer, data_loader = privacy_engine.make_private_with_epsilon(\n module=model, optimizer=optimizer, data_loader=data_loader,\n epochs=1, target_epsilon=0.5, target_delta=1e-5, max_grad_norm=1.0,\n )\n\n model.train()\n for batch_images, batch_labels in data_loader:\n optimizer.zero_grad()\n loss = F.binary_cross_entropy_with_logits(model(batch_images), batch_labels)\n loss.backward()\n optimizer.step()\n\n return extract_model_updates(model)\n```\n\n## Agregación Segura: La Pieza Faltante\n\nIncluso con privacidad diferencial en el update de cada hospital, el coordinador podría aprender algo sobre la distribución de datos de un hospital específico a partir de su gradient update individual. La agregación segura previene esto.\n\n```python\nimport numpy as np\n\ndef secure_aggregate(hospital_updates, threshold=3):\n \"\"\"\n Los hospitales secret-share máscaras pairwise para que el\n coordinador solo vea la suma de todos los updates, no los individuales.\n \"\"\"\n n = len(hospital_updates)\n masked_updates = []\n\n for i in range(n):\n mask = np.zeros_like(hospital_updates[i])\n for j in range(n):\n if i == j:\n continue\n shared_seed = derive_shared_seed(private_keys[i], public_keys[j])\n pairwise_mask = prng_from_seed(shared_seed, shape=mask.shape)\n\n if i < j:\n mask += pairwise_mask\n else:\n mask -= pairwise_mask\n\n masked_updates.append(hospital_updates[i] + mask)\n\n aggregate = sum(masked_updates) / n\n return aggregate\n```\n\nCuando el coordinador suma todos los updates enmascarados, las máscaras pairwise se cancelan perfectamente, dejando solo el promedio real de los updates de todos los hospitales.\n\n## El Problema Non-IID: Por Qué los Datos de Hospitales Son Raros\n\nLos datos reales de hospitales son wildly non-IID. Hospital A es un centro pediátrico, mayormente radiografías de chicos. Hospital C es un geriátrico, pacientes ancianos con comorbilidades. Hospital E es una clínica rural, equipamiento de imagen diferente, demografía diferente.\n\nFedAvg estándar se cae a pedazos con datos non-IID. Después de 10 rondas, veíamos modelos locales divergentes que promediados daban basura. La solución fue FedProx con un término proximal:\n\n```python\ndef train_local_fedprox(model, global_model, data_loader, mu=0.01):\n model.train()\n global_params = {name: param.clone() for name, param in global_model.named_parameters()}\n\n for batch_images, batch_labels in data_loader:\n optimizer.zero_grad()\n loss = F.binary_cross_entropy_with_logits(model(batch_images), batch_labels)\n\n # Término proximal: penaliza drift del modelo global\n proximal_loss = 0.0\n for name, param in model.named_parameters():\n proximal_loss += ((param - global_params[name]) ** 2).sum()\n loss += (mu / 2) * proximal_loss\n\n loss.backward()\n optimizer.step()\n```\n\nEste solo cambio llevó la convergencia de \"nunca\" a 30 rondas.\n\n## Resultados que Pasaron la Auditoría\n\nDespués de 50 rondas federadas con DP (ε=8.0 budget total por hospital):\n\n| Métrica | Centralizado | Federado (sin DP) | Federado + DP (ε=8) |\n| --- | --- | --- | --- |\n| AUC | 0.961 | 0.942 | 0.934 |\n| Sensibilidad | 0.923 | 0.911 | 0.897 |\n| Especificidad | 0.954 | 0.938 | 0.931 |\n| PPV | 0.891 | 0.872 | 0.858 |\n\nLa caída de 2.7% en AUC de centralizado a federado+DP es clínicamente aceptable para una herramienta de screening. El auditor de HIPAA específicamente destacó la garantía formal de privacidad (ε=8.0, δ=1e-5) como fortaleza, nunca habían visto una cota cuantitativa de privacidad, solo \"anonimizamos los datos\".\n\n## Testing de Ataques de Membership Inference\n\nCorrer ataques de membership inference contra el modelo entrenado valida las garantías de privacidad empíricamente:\n\n```python\nfrom ml_privacy_meter import run_population_metric_attack\n\nattack_results = run_population_metric_attack(\n target_model=federated_dp_model,\n population_data=held_out_data,\n member_data=training_data_sample,\n num_shadow_models=10,\n)\n\nprint(f\"Attack AUC: {attack_results.auc:.3f}\")\n# Sin DP: Attack AUC = 0.71 (el modelo está leakeando info de membership)\n# Con DP ε=8: Attack AUC = 0.53 (apenas mejor que adivinar al azar)\n# Con DP ε=1: Attack AUC = 0.51 (esencialmente random)\n```\n\nCon ε=8.0, el ataque de membership inference logró solo 53% de AUC, apenas arriba del baseline random de 50%.\n\n## Lecciones Prácticas\n\n**Los costos de comunicación dominan.** Cada ronda federada manda model updates (~180 MB para un ResNet-50) desde cinco hospitales por canales encriptados. Son casi 1 GB por ronda. Comprimir gradientes con top-k sparsification reduce la comunicación a ~5 MB por ronda.\n\n**Los departamentos de IT de hospitales son el cuello de botella real.** La ingeniería de ML típicamente toma 6 semanas. Conseguir que cinco departamentos de IT de hospitales abran puertos de firewall, aprueben containers Docker y asignen recurse es GPU puede tomar 10 semanas. Arrancar el proceso de procurement de IT el día uno es esencial.\n\nEste tipo de pipeline corre en producción, reentrenándose mensualmente con datos frescos de todos los hospitales participantes. Ningún dato de paciente sale jamás de la red del hospital. El modelo mejora con el tiempo a medida que encuentra case es más diversos. Y la garantía de privacidad es matemáticamente demostrable, no solo una promesa en una política de privacidad.\n\n## Preguntas frecuentes\n\n### ¿La privacidad diferencial puede garantizar que los datos de un paciente específico no se pueden extraer del modelo?\n\nLa privacidad diferencial provee una cota matemática sobre cuánto cualquier registro individual puede influir en la salida del modelo. Con epsilon=1.0, un atacante gana como máximo e^1 ≈ 2.7x de ventaja para distinguir si un paciente específico estaba en el set de entrenamiento. No hace la extracción imposible, la hace probablemente acotada.\n\n### ¿Cuánta accuracy se pierde con federated learning comparado con entrenamiento centralizado?\n\nEn un pipeline representativo, el entrenamiento federado con 5 nodos de hospital logró 94.2% AUC comparado con 96.1% para entrenamiento centralizado en los mismos datos pooled. La brecha de 1.9% es mayormente por heterogeneidad de datos entre hospitales (distribuciones non-IID), no por los mecanismos de privacidad. Agregar privacidad diferencial lo bajó otro 0.8% a 93.4%.\n\n### ¿PySyft está listo para producción?\n\nPySyft 0.9+ es significativamente más estable que versiones anteriores, pero no lo llamaría production-ready para healthcare mission-critical sin testing extensivo. Lo ideal es envolverlo en una capa de orquestación custom con health checks, recovery automático y fallback a entrenamiento local si la federación falla.\n\n## Tips\n\n1. **Tip:** No configurar epsilon abajo de 1.0 en producción sin medir la pérdida real de utilidad en tu validation set. Los papers académicos aman epsilon=0.1 pero en la práctica tu accuracy de modelo se degrada significativamente. Comenzar con epsilon=8.0 y ajustá gradualmente monitoreando F1 scores.\n2. **Tip:** Utilizar Rényi Differential Privacy (` RDP `) para trackear tu budget de privacidad a través de rondas de entrenamiento en vez de composición naive. Con composición básica, 100 rondas a epsilon=0.1 cada una te da epsilon=10.0. Con RDP, las mismas 100 rondas dan epsilon≈3.2. La matemática es accuracy gratis.\n3. **Tip:** Aplicar siempre clipping a los gradientes per-sample antes de agregar ruido. Si se omite el clipping, un solo registro de paciente outlier puede dominar el gradient update, y el ruido que agregars no va a estar calibrado a la sensitividad real. Utilizar ` opacus.PrivacyEngine ` con ` max_grad_norm=1.0 ` como punto de partida.\n4. **Tip:** Los budgets de privacidad son de ida. Una vez que gastás epsilon, se fue para siempre para ese dataset. Es común quemar presupuesto significativo durante hyperparameter tuning. Lo ideal es hacer todo el tuning con datos sintéticos y solo correr el entrenamiento final con datos reales.\n\n- privacidad-diferencial\n- federated-learning\n- pysyft\n- ml-salud\n- privacidad\n- agregacion-segura\n\n[Volver al Blog](<https://lucioduran.com/es/blog>)","headings":[{"level":1,"text":"Privacidad Diferencial y Federated Learning: Arquitectura de Pipelines ML Sanitarios Conformes a HIPAA","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#title"},{"level":2,"text":"La Arquitectura","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#la-arquitectura"},{"level":2,"text":"Privacidad Diferencial: La Teoría que Realmente Se necesita","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#privacidad-diferencial-la-teora-que-realmente-se-necesita"},{"level":2,"text":"Rényi DP para Tracking de Budget","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#rnyi-dp-para-tracking-de-budget"},{"level":2,"text":"Federated Learning con PySyft","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#federated-learning-con-pysyft"},{"level":2,"text":"Agregación Segura: La Pieza Faltante","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#agregacin-segura-la-pieza-faltante"},{"level":2,"text":"El Problema Non-IID: Por Qué los Datos de Hospitales Son Raros","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#el-problema-non-iid-por-qu-los-datos-de-hospitales-son-raros"},{"level":2,"text":"Resultados que Pasaron la Auditoría","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#resultados-que-pasaron-la-auditora"},{"level":2,"text":"Testing de Ataques de Membership Inference","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#testing-de-ataques-de-membership-inference"},{"level":2,"text":"Lecciones Prácticas","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#lecciones-prcticas"},{"level":2,"text":"Preguntas frecuentes","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#questions"},{"level":3,"text":"¿La privacidad diferencial puede garantizar que los datos de un paciente específico no se pueden extraer del modelo?","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#question-1"},{"level":3,"text":"¿Cuánta accuracy se pierde con federated learning comparado con entrenamiento centralizado?","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#question-2"},{"level":3,"text":"¿PySyft está listo para producción?","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#question-3"},{"level":2,"text":"Tips","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#article-tips"}],"sections":[{"heading":"Privacidad Diferencial y Federated Learning: Arquitectura de Pipelines ML Sanitarios Conformes a HIPAA","level":1,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production","content":"AI/ML"},{"heading":"Privacidad Diferencial y Federated Learning: Arquitectura de Pipelines ML Sanitarios Conformes a HIPAA","level":1,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#title","content":"2026-02-147 min lectura\n\nLucio Durán\nEngineering Manager & AI Solutions Architect\n\nTambién disponible en: [English](<https://lucioduran.com/blog/differential-privacy-federated-learning-production>)"},{"heading":"La Arquitectura","level":2,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#la-arquitectura","content":"```\nHospital A ──┐\nHospital B ──┤\nHospital C ──┼──→ [Servidor de Agregación Segura (AWS)] ──→ [Modelo Global]\nHospital D ──┤ ↑ solo gradientes encriptados\nHospital E ──┘ ↓ solo updates agregados\n```\n\nCada hospital corre un nodo de entrenamiento local. El servidor central nunca ve datos crudos, gradientes crudos ni updates de modelo individuales. Solo ve el resultado de la agregación segura, la suma encriptada de todos los updates."},{"heading":"Privacidad Diferencial: La Teoría que Realmente Se necesita","level":2,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#privacidad-diferencial-la-teora-que-realmente-se-necesita","content":"La privacidad diferencial es una definición matemática, no una técnica. Un algoritmo aleatorizado M satisface (ε, δ)-privacidad diferencial si para todos los datasets D y D' que difieren en un registro, y para todas las posibles salidas S:\n\n```\nP[M(D) ∈ S] ≤ e^ε · P[M(D') ∈ S] + δ\n```\n\nEn criollo: sacar o agregar los datos de cualquier paciente individual cambia la distribución de salida como máximo por un factor de e^ε, más una probabilidad de fallo δ despreciable.\n\nPara deep learning, aplicamos esto a través de **DP-SGD**:\n\n```python\nimport torch\nfrom opacus import PrivacyEngine\n\nmodel = PneumoniaResNet(pretrained=True)\noptimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)\ndata_loader = torch.utils.data.DataLoader(hospital_dataset, batch_size=64)\n\nprivacy_engine = PrivacyEngine()\nmodel, optimizer, data_loader = privacy_engine.make_private_with_epsilon(\n module=model,\n optimizer=optimizer,\n data_loader=data_loader,\n epochs=50,\n target_epsilon=8.0,\n target_delta=1e-5,\n max_grad_norm=1.0,\n)\n\nfor epoch in range(50):\n for batch in data_loader:\n images, labels = batch\n optimizer.zero_grad()\n output = model(images)\n loss = F.binary_cross_entropy_with_logits(output, labels)\n loss.backward()\n optimizer.step() # Opacus maneja clipping + ruido internamente\n\n epsilon = privacy_engine.get_epsilon(delta=1e-5)\n print(f\"Epoch {epoch}: ε = {epsilon:.2f}\")\n if epsilon > 8.0:\n print(\"Budget de privacidad agotado. Parando entrenamiento.\")\n break\n```\n\nLas decisiones clave de parámetros que requieren experimentación cuidadosa:\n\n- **max\\_grad\\_norm=1.0**: Muy bajo y clipeás señal útil. Muy alto y se necesita más ruido para lograr el mismo ε. Barrer de 0.1 a 10.0 típicamente arroja 1.0 como óptimo para arquitecturas ResNet.\n- **target\\_epsilon=8.0**: Una elección pragmática. ε=1.0 es el gold standard académico pero nos costaba 8% de accuracy. ε=8.0 dio garantías de privacidad significativas manteniendo accuracy dentro del 2% del baseline sin privacidad.\n- **target\\_delta=1e-5**: Práctica estándar, δ tiene que ser menor a 1/N donde N es el tamaño del dataset."},{"heading":"Rényi DP para Tracking de Budget","level":2,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#rnyi-dp-para-tracking-de-budget","content":"Este es el punto donde la mayoría de los tutoriales cometen errores en la matemática. Si ejecutars DP-SGD por 100 epochs, el costo naive de privacidad es 100 × ε\\_por\\_paso. Esto se llama composición básica, y es dramáticamente pesimista.\n\n```python\nfrom opacus.accountants import RDPAccountant\n\naccountant = RDPAccountant()\n\nfor epoch in range(num_epochs):\n for step in range(steps_per_epoch):\n accountant.step(\n noise_multiplier=noise_multiplier,\n sample_rate=batch_size / len(dataset),\n )\n\n epsilon = accountant.get_epsilon(delta=1e-5)\n print(f\"Después de epoch {epoch}: ε = {epsilon:.2f} (RDP)\")\n```\n\nEn un pipeline representativo, composición básica da ε=12.4 después de 50 epochs. RDP dio ε=4.7 para la exacta misma corrida de entrenamiento. Eso no es una mejora menor, es la diferencia entre un resultado publicable y un paper rechazado."},{"heading":"Federated Learning con PySyft","level":2,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#federated-learning-con-pysyft","content":"[PySyft](<https://github.com/OpenMined/PySyft>) provee la capa de federación. Cada hospital corre un ` DataSite ` que controla acceso a sus datos:\n\n```python\nimport syft as sy\n\nhospital_a = sy.orchestra.launch(\n name=\"hospital-a\",\n port=8081,\n dev_mode=False,\n reset=True,\n)\n\ndataset = sy.Dataset(\n name=\"chest-xray-hospital-a\",\n description=\"Radiografías de tórax de-identificadas, 2020-2025\",\n asset_list=[\n sy.Asset(\n name=\"images\",\n data=real_image_tensor, # Nunca sale de este nodo\n mock=generate_mock_images(), # Datos sintéticos para testing\n ),\n sy.Asset(\n name=\"labels\",\n data=real_labels,\n mock=generate_mock_labels(),\n ),\n ],\n)\nhospital_a.upload_dataset(dataset)\n```\n\nEl coordinador central orquesta el entrenamiento sin acceder a los datos:\n\n```python\nhospitals = [\n sy.login(url=\"https://hospital-a.internal:8081\", email=\"ml@coordinator.org\", password=\"...\"),\n sy.login(url=\"https://hospital-b.internal:8082\", email=\"ml@coordinator.org\", password=\"...\"),\n sy.login(url=\"https://hospital-c.internal:8083\", email=\"ml@coordinator.org\", password=\"...\"),\n sy.login(url=\"https://hospital-d.internal:8084\", email=\"ml@coordinator.org\", password=\"...\"),\n sy.login(url=\"https://hospital-e.internal:8085\", email=\"ml@coordinator.org\", password=\"...\"),\n]\n\n@sy.syft_function_single_use(\n images=hospitals[0].datasets[\"chest-xray-hospital-a\"][\"images\"],\n labels=hospitals[0].datasets[\"chest-xray-hospital-a\"][\"labels\"],\n)\ndef train_local(images, labels):\n import torch\n from opacus import PrivacyEngine\n\n model = load_global_model()\n optimizer = torch.optim.SGD(model.parameters(), lr=0.01)\n data_loader = make_loader(images, labels, batch_size=64)\n\n privacy_engine = PrivacyEngine()\n model, optimizer, data_loader = privacy_engine.make_private_with_epsilon(\n module=model, optimizer=optimizer, data_loader=data_loader,\n epochs=1, target_epsilon=0.5, target_delta=1e-5, max_grad_norm=1.0,\n )\n\n model.train()\n for batch_images, batch_labels in data_loader:\n optimizer.zero_grad()\n loss = F.binary_cross_entropy_with_logits(model(batch_images), batch_labels)\n loss.backward()\n optimizer.step()\n\n return extract_model_updates(model)\n```"},{"heading":"Agregación Segura: La Pieza Faltante","level":2,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#agregacin-segura-la-pieza-faltante","content":"Incluso con privacidad diferencial en el update de cada hospital, el coordinador podría aprender algo sobre la distribución de datos de un hospital específico a partir de su gradient update individual. La agregación segura previene esto.\n\n```python\nimport numpy as np\n\ndef secure_aggregate(hospital_updates, threshold=3):\n \"\"\"\n Los hospitales secret-share máscaras pairwise para que el\n coordinador solo vea la suma de todos los updates, no los individuales.\n \"\"\"\n n = len(hospital_updates)\n masked_updates = []\n\n for i in range(n):\n mask = np.zeros_like(hospital_updates[i])\n for j in range(n):\n if i == j:\n continue\n shared_seed = derive_shared_seed(private_keys[i], public_keys[j])\n pairwise_mask = prng_from_seed(shared_seed, shape=mask.shape)\n\n if i < j:\n mask += pairwise_mask\n else:\n mask -= pairwise_mask\n\n masked_updates.append(hospital_updates[i] + mask)\n\n aggregate = sum(masked_updates) / n\n return aggregate\n```\n\nCuando el coordinador suma todos los updates enmascarados, las máscaras pairwise se cancelan perfectamente, dejando solo el promedio real de los updates de todos los hospitales."},{"heading":"El Problema Non-IID: Por Qué los Datos de Hospitales Son Raros","level":2,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#el-problema-non-iid-por-qu-los-datos-de-hospitales-son-raros","content":"Los datos reales de hospitales son wildly non-IID. Hospital A es un centro pediátrico, mayormente radiografías de chicos. Hospital C es un geriátrico, pacientes ancianos con comorbilidades. Hospital E es una clínica rural, equipamiento de imagen diferente, demografía diferente.\n\nFedAvg estándar se cae a pedazos con datos non-IID. Después de 10 rondas, veíamos modelos locales divergentes que promediados daban basura. La solución fue FedProx con un término proximal:\n\n```python\ndef train_local_fedprox(model, global_model, data_loader, mu=0.01):\n model.train()\n global_params = {name: param.clone() for name, param in global_model.named_parameters()}\n\n for batch_images, batch_labels in data_loader:\n optimizer.zero_grad()\n loss = F.binary_cross_entropy_with_logits(model(batch_images), batch_labels)\n\n # Término proximal: penaliza drift del modelo global\n proximal_loss = 0.0\n for name, param in model.named_parameters():\n proximal_loss += ((param - global_params[name]) ** 2).sum()\n loss += (mu / 2) * proximal_loss\n\n loss.backward()\n optimizer.step()\n```\n\nEste solo cambio llevó la convergencia de \"nunca\" a 30 rondas."},{"heading":"Resultados que Pasaron la Auditoría","level":2,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#resultados-que-pasaron-la-auditora","content":"Después de 50 rondas federadas con DP (ε=8.0 budget total por hospital):\n\n| Métrica | Centralizado | Federado (sin DP) | Federado + DP (ε=8) |\n| --- | --- | --- | --- |\n| AUC | 0.961 | 0.942 | 0.934 |\n| Sensibilidad | 0.923 | 0.911 | 0.897 |\n| Especificidad | 0.954 | 0.938 | 0.931 |\n| PPV | 0.891 | 0.872 | 0.858 |\n\nLa caída de 2.7% en AUC de centralizado a federado+DP es clínicamente aceptable para una herramienta de screening. El auditor de HIPAA específicamente destacó la garantía formal de privacidad (ε=8.0, δ=1e-5) como fortaleza, nunca habían visto una cota cuantitativa de privacidad, solo \"anonimizamos los datos\"."},{"heading":"Testing de Ataques de Membership Inference","level":2,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#testing-de-ataques-de-membership-inference","content":"Correr ataques de membership inference contra el modelo entrenado valida las garantías de privacidad empíricamente:\n\n```python\nfrom ml_privacy_meter import run_population_metric_attack\n\nattack_results = run_population_metric_attack(\n target_model=federated_dp_model,\n population_data=held_out_data,\n member_data=training_data_sample,\n num_shadow_models=10,\n)\n\nprint(f\"Attack AUC: {attack_results.auc:.3f}\")\n# Sin DP: Attack AUC = 0.71 (el modelo está leakeando info de membership)\n# Con DP ε=8: Attack AUC = 0.53 (apenas mejor que adivinar al azar)\n# Con DP ε=1: Attack AUC = 0.51 (esencialmente random)\n```\n\nCon ε=8.0, el ataque de membership inference logró solo 53% de AUC, apenas arriba del baseline random de 50%."},{"heading":"Lecciones Prácticas","level":2,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#lecciones-prcticas","content":"**Los costos de comunicación dominan.** Cada ronda federada manda model updates (~180 MB para un ResNet-50) desde cinco hospitales por canales encriptados. Son casi 1 GB por ronda. Comprimir gradientes con top-k sparsification reduce la comunicación a ~5 MB por ronda.\n\n**Los departamentos de IT de hospitales son el cuello de botella real.** La ingeniería de ML típicamente toma 6 semanas. Conseguir que cinco departamentos de IT de hospitales abran puertos de firewall, aprueben containers Docker y asignen recurse es GPU puede tomar 10 semanas. Arrancar el proceso de procurement de IT el día uno es esencial.\n\nEste tipo de pipeline corre en producción, reentrenándose mensualmente con datos frescos de todos los hospitales participantes. Ningún dato de paciente sale jamás de la red del hospital. El modelo mejora con el tiempo a medida que encuentra case es más diversos. Y la garantía de privacidad es matemáticamente demostrable, no solo una promesa en una política de privacidad."},{"heading":"Preguntas frecuentes","level":2,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#questions","content":""},{"heading":"¿La privacidad diferencial puede garantizar que los datos de un paciente específico no se pueden extraer del modelo?","level":3,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#question-1","content":"La privacidad diferencial provee una cota matemática sobre cuánto cualquier registro individual puede influir en la salida del modelo. Con epsilon=1.0, un atacante gana como máximo e^1 ≈ 2.7x de ventaja para distinguir si un paciente específico estaba en el set de entrenamiento. No hace la extracción imposible, la hace probablemente acotada."},{"heading":"¿Cuánta accuracy se pierde con federated learning comparado con entrenamiento centralizado?","level":3,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#question-2","content":"En un pipeline representativo, el entrenamiento federado con 5 nodos de hospital logró 94.2% AUC comparado con 96.1% para entrenamiento centralizado en los mismos datos pooled. La brecha de 1.9% es mayormente por heterogeneidad de datos entre hospitales (distribuciones non-IID), no por los mecanismos de privacidad. Agregar privacidad diferencial lo bajó otro 0.8% a 93.4%."},{"heading":"¿PySyft está listo para producción?","level":3,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#question-3","content":"PySyft 0.9+ es significativamente más estable que versiones anteriores, pero no lo llamaría production-ready para healthcare mission-critical sin testing extensivo. Lo ideal es envolverlo en una capa de orquestación custom con health checks, recovery automático y fallback a entrenamiento local si la federación falla."},{"heading":"Tips","level":2,"url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#article-tips","content":"1. **Tip:** No configurar epsilon abajo de 1.0 en producción sin medir la pérdida real de utilidad en tu validation set. Los papers académicos aman epsilon=0.1 pero en la práctica tu accuracy de modelo se degrada significativamente. Comenzar con epsilon=8.0 y ajustá gradualmente monitoreando F1 scores.\n2. **Tip:** Utilizar Rényi Differential Privacy (` RDP `) para trackear tu budget de privacidad a través de rondas de entrenamiento en vez de composición naive. Con composición básica, 100 rondas a epsilon=0.1 cada una te da epsilon=10.0. Con RDP, las mismas 100 rondas dan epsilon≈3.2. La matemática es accuracy gratis.\n3. **Tip:** Aplicar siempre clipping a los gradientes per-sample antes de agregar ruido. Si se omite el clipping, un solo registro de paciente outlier puede dominar el gradient update, y el ruido que agregars no va a estar calibrado a la sensitividad real. Utilizar ` opacus.PrivacyEngine ` con ` max_grad_norm=1.0 ` como punto de partida.\n4. **Tip:** Los budgets de privacidad son de ida. Una vez que gastás epsilon, se fue para siempre para ese dataset. Es común quemar presupuesto significativo durante hyperparameter tuning. Lo ideal es hacer todo el tuning con datos sintéticos y solo correr el entrenamiento final con datos reales.\n\n- privacidad-diferencial\n- federated-learning\n- pysyft\n- ml-salud\n- privacidad\n- agregacion-segura\n\n[Volver al Blog](<https://lucioduran.com/es/blog>)"}],"links":[{"text":"English","url":"https://lucioduran.com/blog/differential-privacy-federated-learning-production"},{"text":"PySyft","url":"https://github.com/OpenMined/PySyft"},{"text":"Volver al Blog","url":"https://lucioduran.com/es/blog"}],"structuredData":[{"@context":"https://schema.org","@graph":[{"@type":"BlogPosting","@id":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production#article","mainEntityOfPage":{"@type":"WebPage","@id":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production"},"headline":"Privacidad Diferencial y Federated Learning: Arquitectura de Pipelines ML Sanitarios Conformes a HIPAA","description":"Budgets de epsilon, mecanismos de ruido, agregación segura y PySyft en la práctica, una arquitectura de pipeline de federated learning para imágenes médicas capaz de pasar auditorías HIPAA.","datePublished":"2026-02-14","author":{"@type":"Person","@id":"https://lucioduran.com/#person","name":"Lucio Durán","url":"https://lucioduran.com"},"publisher":{"@type":"Person","@id":"https://lucioduran.com/#person","name":"Lucio Durán","url":"https://lucioduran.com"},"image":"https://statics.lucioduran.com/images/lucioduran-social-card.jpg","url":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production","inLanguage":"es","isPartOf":{"@id":"https://lucioduran.com/blog#blog"},"articleSection":"AI/ML","keywords":"privacidad-diferencial, federated-learning, pysyft, ml-salud, privacidad, agregacion-segura","wordCount":1239,"timeRequired":"PT7M","workTranslation":[{"@type":"BlogPosting","inLanguage":"en","url":"https://lucioduran.com/blog/differential-privacy-federated-learning-production"}]},{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Inicio","item":"https://lucioduran.com/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https://lucioduran.com/es/blog"},{"@type":"ListItem","position":3,"name":"Privacidad Diferencial y Federated Learning: Arquitectura de Pipelines ML Sanitarios Conformes a HIPAA","item":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production"}]},{"@type":"FAQPage","mainEntity":[{"@type":"Question","name":"¿La privacidad diferencial puede garantizar que los datos de un paciente específico no se pueden extraer del modelo?","acceptedAnswer":{"@type":"Answer","text":"La privacidad diferencial provee una cota matemática sobre cuánto cualquier registro individual puede influir en la salida del modelo. Con epsilon=1.0, un atacante gana como máximo e^1 ≈ 2.7x de ventaja para distinguir si un paciente específico estaba en el set de entrenamiento. No hace la extracción imposible, la hace probablemente acotada."}},{"@type":"Question","name":"¿Cuánta accuracy se pierde con federated learning comparado con entrenamiento centralizado?","acceptedAnswer":{"@type":"Answer","text":"En un pipeline representativo, el entrenamiento federado con 5 nodos de hospital logró 94.2% AUC comparado con 96.1% para entrenamiento centralizado en los mismos datos pooled. La brecha de 1.9% es mayormente por heterogeneidad de datos entre hospitales (distribuciones non-IID), no por los mecanismos de privacidad. Agregar privacidad diferencial lo bajó otro 0.8% a 93.4%."}},{"@type":"Question","name":"¿PySyft está listo para producción?","acceptedAnswer":{"@type":"Answer","text":"PySyft 0.9+ es significativamente más estable que versiones anteriores, pero no lo llamaría production-ready para healthcare mission-critical sin testing extensivo. Lo ideal es envolverlo en una capa de orquestación custom con health checks, recovery automático y fallback a entrenamiento local si la federación falla."}}]}]}],"contentHash":"5068ccc39b59f541466dab1420c111647f43ccd90aa3347cf1bd4497fcca4f0a","provenance":{"method":"Deterministic serialization of the server-rendered main element","source":"https://lucioduran.com/es/blog/differential-privacy-federated-learning-production","hashAlgorithm":"sha256","hashScope":"JSON document fields before contentHash and provenance","sourceHTMLBytes":68664,"contentBytes":13710}}
