做机器学习这些年,我见过最拧巴的需求就是这一种:模型要从一方跑到另一方,数据却被死死卡在“不能出医院”这条红线里。IJCAI 2019 上,第四范式等机构把这个问题摆上台面,推的是一类隐私保护新算法,目标很直接——让医疗这类敏感数据也能参与模型训练,但训练方从头到尾看不到病人的原始记录。听起来像既要鱼又要熊掌,但这类算法还真不是玄学,而是把加密、分布式计算、统计噪音这几样东西重新组合了一遍。
这篇内容要说的,不是某个躺在论文 PDF 里的公式推导,而是把这类隐私保护算法拆开来看:它到底解决什么问题、用了哪些核心手段、我实际搭建验证环境时会怎么选型、以及最容易在那里翻车。想给医疗 AI 项目做合规建模的工程师、做数据平台的技术负责人,或者只是好奇“加密之后怎么还能训练模型”的朋友,都可以在这篇里找到能直接上手的思路。
1. 先搞清楚 IJCAI 2019 这次工作到底解决什么问题
1.1 不是所有算法问题都值得上论文,但这个值得
IJCAI 是人工智能领域的老牌顶会,能在这里出现的工作,一般不是简单调参刷点,而是提出一类可以被复用、被验证的方法。这篇围绕“隐私保护新算法”的工作,讽刺的地方在于:医疗行业的数据恰恰是 AI 最需要的,但恰恰也是最难拿出来的。
医院里存着大量结构化病历、影像、检验指标、用药记录,这些数据如果能汇聚起来训练一个诊断辅助模型,价值非常大。可问题在于,医院不敢给,患者也不愿意给,监管更不允许随便给。以往我们把数据脱敏后交给第三方训练,去掉姓名、身份证号,看上去没问题,但研究早就证明,所谓匿名数据结合少量外部信息,能被重新识别出具体个人。
所以这次工作关心的不是“模型准不准”这个单一目标,而是“模型要准,同时数据不能裸奔”。以前这两件事是分开谈的,现在必须放在同一个算法框里一起解决。
1.2 医疗数据为什么比普通业务数据更敏感
我在工业界做过不少风控、营销类的建模项目,数据敏感度确实有,但医疗是另一个量级。病历数据不仅包含疾病信息,还包含遗传信息、生活习惯、精神状况,这些一旦泄露,影响的可能不只是一个账号,而是人的社会关系、就业可能、保险定价。
更重要的是医疗数据的关联性极强。一个人的心电图、血常规、影像切片,看着是离散的几条记录,但拼在一起就能刻画出一个人的健康全貌。哪怕只泄露其中一项指标,结合其他渠道的数据,也能拼出完整画像。这就是为什么数据合规里,医疗数据常被单列出来,适用远比其他行业更严格的要求。
传统的集中式训练办法,让所有数据拷贝到同一个训练集群里,然后跑 TensorFlow 或者 PyTorch。这在内部政务、企业数据上偶尔还能操作,但在医疗场景基本走不通。因为“离开医院”这个动作本身就是违规的,不管数据脱不脱敏。
1.3 一个能落地的合理目标到底是什么
隐私保护算法要建立的共识是:数据使用权和数据所有权可以分离。医院保留数据所有权,不对外复制和移交;但算法可以通过特定方式行使使用权,学到数据里的统计规律,从而更新模型参数。
这件事不是靠一纸协议做到的,而是靠技术约束。算法层面要保证三点:单个样本信息不泄露、中间结果不可逆、最终模型参数不反推原始数据。注意“不泄露”不是绝对意义上的不可能,而是指在合理的计算复杂度和隐私预算下,攻击者拿不到有效信息。
第四范式这类机构把算法推到 IJCAI,真正的目的是给产业界一个信号:隐私保护不是论文里的未来概念,已经有可计算、可验证、可落地的路线。医院可以安心把数据留在本地,AI 公司带着算法进来,双方在加密或者分布式的框架下协作。
2. 隐私保护算法的技术构成,到底有哪些底牌
2.1 差分隐私:给统计规律加一层可控噪音
差分隐私可能是这几个技术里最容易理解的一个。它不改变数据的存储方式,也不对模型做特殊处理,而是在计算过程中注入噪声,让攻击者无法通过输出结果判断某个具体个体是否在数据集中。
听起来很玄,举个生活中的例子:一群人在房间里投票,问的是“你有没有得过某类疾病”。如果每个人如实回答,主持人很容易知道谁患病。但我们换一种回答方式:每个人先抛硬币,抛到正面就答真话,抛到反面就说反话。大量人一起回答后,主持人统计出患病比例仍然近似准确,但单个回答无法指认任何具体的人。噪声让单个样本的存在性被模糊掉了。
在机器学习里,差分隐私通常加在梯度更新上。每次计算梯度后,往梯度里加入随机扰动,再拿去更新模型。加了噪声之后,模型整体趋势还是向正确方向走,但任何一条具体训练样本的梯度贡献都被噪声掩盖。这里有一个关键参数叫隐私预算,用希腊字母 ε 表示。ε 越小,隐私保护越强,但噪声也越大,模型精度可能明显下降。
需要澄清一点,差分隐私适合回答“整体规律是什么”的问题,但如果某个模型要记住稀有病例的极度细节,那困难就大了。我在实际项目中会把差分隐私当作最后一道防线,而不是唯一的依赖手段。
2.2 同态加密:在密文上做计算,就像戴着厚手套做手术
同态加密是另一种思路。传统加密只能保证数据存储和传输安全,一旦要计算,必须先解密。而同态加密允许我们直接在密文上进行加减乘除,结果解密后与明文计算结果一致。用通俗的话说,就是戴着厚手套做手术,手摸不到病人,但手术效果照样出来。
2019 年前后,真正能工程化的主要是半同态加密,比如 Paillier 加密只支持同态加法,或者少数支持乘法同态的方案。这意味着不能对密文直接跑一个完整的神经网络,但可以对梯度做安全的聚合。比如多个医院各自在本地算好模型更新量,把这些更新量加密后发给协调方,协调方在密文上做加法求和,解密后得到所有医院更新的总和,再平均更新全局模型。整个过程里,协调方看不到任何一家医院的具体更新量。
同态加密最大的代价是计算性能和密文膨胀。我做过对比测试:一个 32 位浮点数的梯度,加密后通常会膨胀到原来的几十倍甚至上百倍,运算速度比明文慢好几个数量级。所以做工程的时候,不会把整个训练过程都塞进密文里,而是在关键节点加密,剩下的在明文域跑。
这里还要提醒一点,同态加密虽然能保护数据机密性,但没法防止模型本身被恶意投毒。如果某个参与方故意提交异常的加密梯度,协调方也无法判断这是正常统计波动还是恶意攻击。所以后来很多方案会配合可信执行环境做辅助校验,单纯靠同态加密并不能解决所有安全问题。
2.3 安全多方计算:让几个互不信任的机构协作计算
安全多方计算解决的是另外一类问题:多个参与方手里各有一份数据,大家想联合算出某个结果,但谁也不想把自己的原始数据交给别人。最经典的例子是百万富翁问题:两个富翁想知道谁更有钱,但都不愿意暴露自己的具体身家。
在医疗场景里,这个需求同样真实。两家医院想联合统计某种疾病的发病率关联因素,但各自有各自的患者数据,数据不能出本院的边界。安全多方计算通过把每个数据分成多个随机碎片,分发给不同参与方,每个参与方只看到无意义的碎片,但各方共同执行一个协议,最终能算出正确结果。
假设医院 A 有一个数值 x,医院 B 有一个数值 y,两方想算 x+y。A 可以把 x 拆成 x1 和 x2,自己留 x1,把 x2 送给 B;B 也把 y 拆成 y1 和 y2,自己留 y1,把 y2 送给 A。然后 A 在手上有 x1 和 y2,可以本地算一个中间结果,B 手上有 x2 和 y1,也算一个中间结果,两个中间结果汇总后,就能恢复出 x+y。而 A 和 B 各自拿到的碎片中,没有任何关于对方原始数据的信息。
安全多方计算的通信开销通常不小,因为每次计算都要交换中间碎片。2019 年这类技术已经在一些金融反洗钱、医疗联合建模里尝试落地,但距离大规模工程化还有距离。它和同态加密的区别在于,同态加密依赖一个统一的计算方,多方计算则强调多个参与方通过协议协作,更适合互相不信任的多机构环境。
2.4 实际使用的算法组合,不是单挑而是排兵布阵
刚才讲了三种方法,分着看都各有短板,但放到真实方案里往往是这样组合的:本地训练用明文,参数交换用安全聚合,最终模型加差分隐私,整体流程用安全多方计算做协议保障。
用一个场景串起来就清楚了。某省级医疗平台要做糖尿病并发症预测模型,参与的是几家医院。每家医院在自己本地用患者数据训练一个本地模型,这个过程不出数据、不加密,速度很快。训练到某一轮后,各医院把模型梯度打包、量化、加密,通过同态加密或秘密分享的方式汇总到一个可信协调方。协调方在密文上计算梯度总和和梯度平均,更新全局模型,再把新的全局模型分发给各医院。每一轮训练都重复这个过程。
这里还有一层,全局模型发布给医院的途中,可以加入差分隐私噪声,保证即使有人截获了模型参数,或者通过黑盒接口反复查询,也无法推断出特定患者的信息。这样就形成了纵深防御:数据不出域由本地训练保证,传输过程由加密保证,模型反推由差分隐私兜底。
我把几种方法的权衡整理成一个对照表,方便大家做技术选型:
| 方法 | 保护的数据对象 | 主要代价 | 适合步骤 | 成熟度 |
|---|---|---|---|---|
| 差分隐私 | 训练样本的存在性 | 模型精度损失 | 最终模型发布、查询接口 | 高 |
| 同态加密 | 密文数据的计算结果 | 计算开销大、通信数据膨胀 | 梯度聚合、统计汇总 | 中 |
| 安全多方计算 | 多方联合计算中的原始碎片 | 通信轮次高、协议复杂 | 多机构联合统计 | 中 |
| 联邦学习 | 原始数据不出本地 | 数据异构性影响收敛 | 整体训练框架 | 高 |
没有一种方法能包打天下,这正是隐私保护算法到现在仍然值得持续研究的原因。
3. 从论文到工程:搭建一个隐私保护训练的最小验证
3.1 最小验证环境该怎么搭
理解了理论,还是要动手走一遍。我不建议一上来就搭完整的多方计算环境,那涉及网络拓扑、协议调度、密钥管理,复杂度太高。先在一台机器上模拟两家医院和一个协调方,用 Python 把数据分片、加密、聚合、更新整个链路跑通。
2019 年那会儿常用的库有 PySyft、PySEAL、phe,现在的话 TenSEAL、OpenMined 的生态更齐全。我习惯用 phe 做 Paillier 半同态加密演示,它依赖少、接口清晰,适合验证逻辑。
先模拟两个数据源,各有一份小规模样本:
import numpy as np from phe import PaillierKeypair, PaillierPublicKey, EncryptedNumber # 模拟两家医院本地计算好的梯度 gradient_a = np.array([0.02, -0.15, 0.33]) gradient_b = np.array([0.03, 0.11, -0.27]) # 生成密钥对,协调方持有私钥 pub_key, priv_key = PaillierKeypair.generate_keypair() # 两家医院分别加密各自的梯度 encrypted_a = [pub_key.encrypt(float(g)) for g in gradient_a] encrypted_b = [pub_key.encrypt(float(g)) for g in gradient_b]这里pub_key是可以公开的,医院拿它加密梯度,加密后连医院自己也无法在本地修改数据,因为改任何一个字节都会导致解密失败。这跟通常的加密不太一样,也正是同态加密有意思的地方。
3.2 服务端聚合为什么能保住隐私
接下来是协调方的工作。协调方只有私钥,它收到两家医院发来的密文梯度后,直接在密文域做加法聚合:
# 协调方在密文域计算梯度总和 encrypted_sum = [] for ea, eb in zip(encrypted_a, encrypted_b): encrypted_sum.append(ea + eb) # 协调方解密得到梯度总和 sum_array = np.array([priv_key.decrypt(v) for v in encrypted_sum]) avg_array = sum_array / 2.0 print("聚合后的平均梯度:", avg_array)这里有一个非常重要的细节:协调方看到的是encrypted_a和encrypted_b,它无法判断某一个具体的值来自哪家医院。它只能把两个密文相加,再利用私钥解密出总和。如果只有一家医院发来梯度,理论上协调方解密后是可以反推该医院梯度的,这也是隐私泄露的口子。所以实际方案里,参与方至少要两家以上,而且要约定最少参与人数。否则“隐私保护”就是纸糊的。
真实系统还会给每个参与方的梯度加上一个可加掩码,掩码只有参与方自己知道,聚合时所有参与方协同去除掩码,这样即使协调方看到密文也无法用减法反推单家梯度。这种技术叫盲化或掩码聚合,和秘密分享的思路一脉相承。
3.3 模型训练流程里的三个关键节点
隐私保护不是只保护梯度聚合那一步,而是要覆盖训练全流程。我实际在项目里会把训练分成三个关键节点分别检查。
第一个节点是数据预处理。各家医院在本地完成缺失值填充、归一化、特征编码,保证送出来参与聚合的数据已经是标准化之后的张量,不再携带可直接识别的患者字段。这里要格外小心,有些文本特征比如现病史描述,即使编码成 ID,也可能通过 ID 映射关系反查。如果非要使用文本特征,最好在本地完成特征嵌入后再参与加密训练,而不是传送 ID。
第二个节点是参数交换。无论是梯度还是模型参数,只要离开参与方边界,一律走加密通道。常见做法是梯度先量化为固定位数的整数,再做 Paillier 加密,这样既能压缩密文体积,也能避免浮点数加密精度损失。量化范围通常取 ±5 就够了,因为深度学习梯度很少超出这个范围,除非某批样本出现极端异常。
第三个节点是模型发布。模型训练完成后,在真正开放接口给临床使用之前,需要做差分隐私处理。具体做法是评估整个模型在某个隐私预算下的敏感度,然后向模型权重或输出加噪声。这一步不是可选项。我见过不少团队把加密训练做完就以为万事大吉,结果模型接口对外开放后,攻击者通过大量构造查询,能从输出中反推出训练集里是否存在某类患者。差分隐私把这个口子堵上。
3.4 评估一个隐私保护方案,不能只看模型精度
跑通了训练流程,还要回答一个问题:这个方案到底值不值得用?评估维度不能只有 AUC 或者准确率,还得看隐私强度、通信开销、训练耗时。我把评估拆成四个部分。
模型效果评估最容易做,和普通模型一样画 ROC 曲线、计算混淆矩阵,但要额外记录“隐私保护前后”的指标差异。如果加入加密和差分隐私后,模型从 AUC 0.85 掉到 0.70,那就说明噪声预算给得太狠,或者训练超参没有适配加密环境,而不是“隐私保护必然导致效果差”。
通信开销评估要看单轮聚合的数据量。明文训练可能一个批次只要几百 KB,加密之后可能变成几十 MB。如果医院之间网络带宽有限,训练速度会被通信拖死。这时候就要权衡是减少同步轮次、增大参与方本地 batch size,还是改用秘密分享方案降低通信负载。
计算耗时评估要分别统计本地训练、加密传输、服务端聚合三个环节的耗时占比。我实测过,Paillier 加密单个浮点数的耗时在毫秒级,但如果一个模型有上百万个参数,每一轮加密就是几百秒的量级。所以实操中常常只加密梯度的一小部分子集,或者先对梯度做稀疏化,只取绝对值较大的分量参与聚合。这样能在不影响模型收敛的前提下大幅压缩计算开销。
隐私强度评估需要量化攻击面的变化。常见的评估方式叫成员推理攻击测试:训练一个攻击模型,尝试判断某个样本是否在训练集中。如果攻击成功率接近随机猜测,说明当前方案的隐私保护是有效的;如果攻击成功率明显偏高,就说明某个环节泄了信息,需要回溯排查。
4. 踩坑记录:隐私保护训练九个常见问题
4.1 密文范围溢出:加密世界的“爆内存”
第一批坑永远来自密文范围控制。Paillier 加密要求明文是整数范围固定,如果梯度里有 NaN、无穷大,或者数值超过模数范围,加密直接报错或者解密出来乱七八糟。我一开始在模拟环境里跑了一个含稀疏特征的模型,某一轮梯度出现了一个巨大的离群值,加密后聚合时模数溢出,解密后的数值完全对不上。
解决办法很简单,但不注意就会踩:在加密前对所有参与聚合的数值做 clip 和缩放,同时记录缩放因子,解密侧再还原。这个缩放因子要不要保密?看场景。如果攻击者知道缩放因子,理论上可以通过暴力枚举反推梯度范围,所以一般建议把缩放因子也隐藏在多方协议里,或者使用一个公共但不敏感的固定缩放倍数。
4.2 训练不收敛:噪声把有效信号盖掉了
加了差分隐私之后,最常见的问题是模型发散或者不收敛。很多人第一反应是隐私预算设得太小,其实还有一个容易被忽略的原因:噪声是逐次累积的,每一轮都往梯度上加独立噪声,累计到几十轮之后,梯度方向已经完全失真。
我的经验是对噪声做衰减。具体来说,训练初期隐私保护可以稍弱,让模型先学到全局结构,后期再逐步增强噪声,保护稀有样本。这不是论文里的标准做法,但我在多个数据集上试下来,收敛速度和最终精度都有明显改善。当然,这需要在实验记录里明确说明隐私预算的分配策略,否则后期审计的时候会被挑战。
4.3 数据异构性:各家医院的分布完全不一样
医疗数据的分布差异比我预想的严重得多。三甲医院收治的重症患者多,社区医院多是慢病随访,如果直接把两边的样本拿来做联邦训练,全局模型的收敛就会很慢,甚至出现某一方模型精度急剧下降的情况。
解决这个问题要用个性化的聚合策略。最简单的适配方法是按参与方数据量为模型聚合加权,数据多的医院权重高。但遇到极端不平衡,我建议把模型拆成两部分,一部分是全局共享的表示学习层,另一部分是各家本地的分类头。全局层参与加密聚合,本地头各自保留,这样既能利用多方数据,又不会被分布差异拖垮。
4.4 “梯度泄露”的伪装者:加密之后还会丢隐私
常见误解是数据加密了就不会泄露,其实加密只能保证传输和计算过程中的保密,模型输出本身可能携带训练数据信息。很多团队把注意力放在通信链路上,却忽略了最终模型可以成为攻击媒介。
比如攻击者拿到全局模型,可以反向训练一个辅助模型来推断参与方数据中是否包含某个特定个体。这种做法不需要破解密码学,只需要大量合理构造的查询。所以我在做隐私保护方案时,一定会配合成员推理攻击测试。如果攻击成功率居高不下,就算加密做得再完美,整个方案也谈不上安全。
4.5 密钥管理:私钥放在哪里都是问题
私钥是整个系统的命门。协调方持有私钥,一旦被攻破,所有密文都会变成明文。医院端持有公钥,理论上说得过去,但如果公钥被篡改,医院就会把数据加密到攻击者指定的密钥下,导致定向泄露。
在实际工程中,我会把私钥存放在硬件安全模块或者独立密钥管理服务里,并且严格审计私钥使用日志。还要定期轮换密钥,防止长期使用同一对密钥带来的累积风险。轮换密钥不是重发一遍就完事,需要同时规划存量密文的重加密方案。
4.6 小医院算力不足:隐私保护不是大机构专属
小医院最大的障碍不是意愿,而是基础设施。跑一个加密梯度聚合,对内存和 CPU 都有要求。很多基层医疗机构的服务器还停留在几年前的配置,跑不动繁重的同态加密运算。
如果合作伙伴里包含小规模机构,可以引入“代理加密”或者“轻量参与方模式”。小医院只做本地数据预处理和明文模型推理,把中间结果交给一个具备算力的中转方做加密聚合。中转方需要是可信第三方。这种设计牺牲了一部分去信任化程度,但换来了参与门槛的大幅降低,实际落地时往往更顺利。
4.7 模型版本与隐私版本的耦合问题
训练过程中模型每更新一轮,理论上都消耗了新的隐私预算。如果需要频繁发布新模型,就需要考虑隐私预算的累计问题。同一条数据被反复用于不同版本的模型训练,攻击者可以通过比较不同版本来推断更多信息。
实操上,我给每个患者样本设一个生命周期:在某段时间内,这条样本最多参与 N 次训练轮次,超过之后自动从训练池中移除。这个策略牺牲了一部分训练数据量,但换来了可验证的隐私上限,在合规审计时非常加分。
4.8 合规审计缺失:光有算法还不够
隐私保护算法做完了,最终还要面对监管和审计。审计人员可能不懂密码学,但他们要能看到完整的证据链:谁在什么时间访问过什么数据、模型训练使用了哪些数据批次、加密协议版本是什么、隐私预算消耗了多少。
我建议从项目开始第一天就记录审计日志,而不是等做完了再补。加密结构天然会掩盖一部分操作痕迹,如果没有对应的审计日志,出了问题很难定位责任。现在不少框架支持可验证计算,让第三方在不看到原始数据的情况下验证计算结果是否正确,这类工具在医疗场景里会越来越重要。
4.9 过度设计:不是所有医疗数据都需要三层加密
最后一条经验听起来有点反直觉,但很重要:不要在不需要保护的地方过度加密。有些医疗数据是已经公开的统计资料,有些是科研数据集,本身经过严格脱敏且授权明确,强行套上同态加密和多方计算,只会让项目速度拖慢十倍,收益却微乎其微。
我通常会在项目初期做一次数据分级:一级数据是直接标识符,绝不允许出现在任何训练流程;二级数据是高敏感临床记录,必须采用加密训练;三级数据是聚合统计指标,可以明文参与分析。分级之后,算力资源集中用在高价值高敏感的数据路径上,整体效率和安全性都能兼顾。
5. 写在最后:我在实操中的一点体会
把 IJCAI 2019 那个题目重读一遍,你会发现“医疗敏感数据也能合理学”这句话的落点其实在“合理”两个字上。数据不可能完全锁死不用,也不应该毫无防备地流转,隐私保护算法给了我们中间那条可行的通道。
我自己踩过不少坑,最大的一条还是心态上的:别把隐私保护当成一个可以后期加装的功能。如果在模型架构设计的时候没有考虑加密、聚合、噪声这些因素,等到数据管道都搭好了,再回头包装一层隐私保护,基本等于推到重来。
如果你现在正要启动一个跨机构合作的数据项目,我的建议很简单:先把参与方最少、数据量最小、模型最简单的端到端流程跑通,确认加密训练链路没有问题,再逐步扩大规模。不要在一个 PoC 上追求极致的密码学方案,也不要一开始就选最重的同态加密框架。真实场景里,能落地的方案永远是在安全强度、计算代价、模型效果三者之间反复权衡之后才能定下来的。