共计 6312 个字符,预计需要花费 16 分钟才能阅读完成。
简介
既往的衰老研究主要聚焦于成年衰老时钟,这使得在理解覆盖整个生命周期的生物钟方面,特别是在婴幼儿和童年时期,存在一项关键空白。因此,这这开发了一种名为LifeClock的生物钟模型,该模型利用常规电子健康记录和实验室检测数据来预测所有生命阶段的生物学年龄。
作者整合了来自9,680,764个体的24,633,025次异质性纵向临床就诊记录的虚拟患者表征,并将其投影到一个潜在空间中。开发了一个基于时间序列Transformer的模型,EHRFormer,来高精度地分析发育与衰老动态,并开发出覆盖从婴儿期到老年期的精准生物钟。研究结果表明,不同生命阶段的生物钟模式存在显著差异。儿童期生物钟与儿童发育密切相关,并能准确预测主要儿科疾病的当前和未来风险,包括营养不良、生长和发育异常。成年期生物钟与衰老密切相关,并能准确预测主要年龄相关疾病的当前和未来风险,如糖尿病、肾功能衰竭、中风和心血管疾病。因此,本研究将儿童期发育与成年期衰老区分开来,并通过利用贯穿整个生命周期的常规临床数据,建立了一个旨在推进精准健康的创新框架。
方法
关于预测生物学衰老能实现什么我并不好奇,因此我们的目标主要集中在作者是如何处理海量临床数据并建模的。
数据预处理
作者收集了来自中国的五个队列十家医院的9,680,764名患者的EHR数据包含24,633,025次纵向临床就诊记录,将其中一个队列以及来自BioBank的数据作为外部验证。为每一位患者的全部就诊记录创建一个时序序列: S = {(X0, T0), (X1, T1), … , (XL, TL)} 其中Xi表示在第i次就诊时收集的临床变量向量(包括连续型和分类型实验室检测结果及临床测量值),Ti代表自首次就诊以来经过的时间(以天为单位),根据定义T0 = 0,L为该患者的就诊次数。
连续型临床变量根据公式:D(x) = ⌊ (x − Xmin)/(Xmax − Xmin) × dcont ⌋ 进行量化,其中⌊X⌋代表向下取整函数,Xmax为特征x的最大值,Xmin为特征x的最小值,dcont为离散区间的数量。这种离散化处理产生了介于0和dcont之间的整数值,超出定义范围的值被截断至最大边界1,缺失值则编码为-1。
- 定义Xmax和Xmax就是上下边界呗,在离散化之前先判断一下是否为极端值。如果先对非缺失值进行Z score,之后按照Z值划分离散区间并编码呢?这样似乎避免了人为定义截断值。 ↩︎
在每次就诊时,特征Xi被表示为分类变量与离散化连续变量的拼接:Xi = [Xcat; Xcont],其中Xcat ∈ NL×Ncat,Xcont ∈ NL×Ncont,L代表临床就诊次数,Ncat和Ncont分别为分类特征和连续特征的数量。
EHRFormer架构
EHRFormer是一个种编码器-解码器风格的transformer架构,包含一个编码器、一个时间嵌入、一个任务特定的解码器头(依据任务而定?)。
examination encoder 编码器
在前面的数据处理阶段,我们(其实是作者不是我)将连续变量分桶离散化了,然后与分类变量拼接,得到 Xi = [Xcat; Xcont] 。所以我们的所有变量都是事实上的分类变量。作者在这里借鉴BERT的想法,引入了双嵌入策略:词嵌入和类型嵌入,将二者相加就得到了既包含值信息也包含类型信息的融合嵌入。之后把得到的融合嵌入送入多层Transformer,通过自注意力机制、前馈神经网络等等最终得到了包含复杂语义的表示Evisit = encoder(Embed(Xi))。经过这样的一顿处理,我们就把一次就诊信息打包成了一个上下文化(contextualized,可以理解成融合了复杂的多项的检查结果的复杂非线性关系信息?)的语义表示。
总而言之言而总之,将人类看得懂的检查结果转换成了让机器看得懂的多维向量,同时在这个向量里也隐含了不同检查之间的深层次交互关系。
时间嵌入
在上一步的操作中,我们得到了对于每个患者的每次就诊的快照,但截至目前,这些快照都还是无序的,为了解决顺序问题,我们需要引入时间嵌入。我们计算同一个患者的某次就诊记录距离这位患者首次就诊时的天数Ti,将这个T输入线性位置嵌入层Timeembed(),得到了时间嵌入向量,之后将其与Evisit相加,得到了包含时序信息的就诊表示。将同一患者的按时序排布的包含时序信息的纵向就诊表示序列输入decoder,获得一个基于过去病史的、上下文相关的、预测性的表示:
Epatient = Decoder (Evisit + TimeEmbed (T))
Q&A:
Q: 为什么不是直接在原本N维的Evisit_i向量中加上一个T维度呢?
A: Evisit_i是经过了encoder深度处理的、包含复杂语义的高维向量,如果直接强行拓展一个维度,加上这个标量T,那就破坏了原有的向量空间的几何结构并且此维度难以与其他既有维度产生合理交互。同时数据维度的增加也迫使transformer模型的维度增加,增加了额外的计算成本。
Q: 既然时间很重要,为什么不从一开始就和类型、tooken一起嵌入呢?
A: 破坏就诊信息内部的语义独立性,并且绝对时间的临床意义有限,我们更看重的是就诊之间的相对时间。
task-specific decoders 任务特定的解码器头
结束了上一步,我们得到了基于既定的患者级别的纵向表示Epatient,现在我们希望模型能够根据不同的任务向外输出不同的预测结果,所以作者为不同任务设计了不同的通道,对于每一个任务通道,都执行一个:
yi = ReLU(WiT * Epatient, i)
其中Epatient, i是上一步时间嵌入层输出的直到第i次就诊为止的患者纵向信息表示,这使得我们不仅可以在最终状态Epatient, last进行预测,也可以在任意一个时间节点的中间状态进行预测。
WiT是一个投影层,可以将高维的Epatient,i投影到任务需求的维度。比如对于疾病编码预测任务,WiT就需要将Epatient,i投影到维度为“疾病编码类别数量”的向量上,之后再接上一个softmax输出预测概率;如果执行的是生物标志物数值、生物学年龄预测(本文的主题)等任务,则需要WiT将Epatient,i投影到一个标量上,得到的值就是要预测的值。
ReLU作为激活函数,保证了连续型变量预测任务时输出值非负?对于概率预测,因为已经接上了softmax,已经是非负的,relu对其无影响。
不同预测任务同时进行,损失函数一起反向传播作用于encoder和decoder,使得到的表示Epatient变得“万能”且稳定(鲁棒,莫名其妙的翻译)。
终于把数据预处理和EHRFormer的架构了解的差不多了。
训练流程
训练过程可分为预训练和微调两个过程,在与训练阶段,利用大量的无标签的纵向EHR数据进行自监督学习,构建稳健的表示。微调阶段将这些表示适配于特定的预测任务。
通过对抗性方法控制缺失和队列偏差
EHR中的缺失值我们在数据预处理阶段使用统一的特殊值表示,模型可能会在无意中学习依赖于缺失状态的偏差,而非特征表达值的真实临床含义。(比如学到没开CA199检查的患者都没肿瘤,我们不希望模型学习到这种依靠项目是否缺失来判断疾病的能力。而是希望模型学到根据检查结果情况来判断疾病的能力。)所以我们从GAN获得启发,设计了一个缺失判别器,把编码器输出的E_visit输入这个判别器(文章中没有表述判别器的结构,但是提供了模型代码,我还没看),判别器输出一个大小为M(变量的数量,也就是E_visit的维度数)的向量,每个维度通过sigmoid独立输出一个概率,表示该变量是否缺失。使用一个交叉熵损失函数:
Lmissing = -1/M ∑)Mj=1 ∑1m=0 zj,m log( ẑj,m
M是临床变量的数量。这个损失是对所有变量求平均。j:遍历每一个变量。m:遍历两种状态(0=存在,1=缺失)(文章采用one-hot编码)。zj, m: 是真实标签,它是一个one-hot向量,对于变量j,如果它存在,则 [zj,0=1, zj,1=0];如果缺失,则 [zj,0=0, zj,1=1]。ẑj, m: 是判别器的预测概率。对于变量j,它预测其为存在 ẑj,0 或缺失ẑj,1 的概率。
前向传播时,数据流过编码器,然后流入缺失判别器,判别器计算Lmissing。之后反向传播,Lmissing更新判别器。之后Lmissing继续向前传播,流入一个梯度反转层GRL,在这里将Lmissing乘上一个负数,之后这个被反转的Lmissing再反向传播到特征编码器。这样的操作使判别器愈发准确的同时,也使编码器的输出中“变量是否缺失”的信息最少化,使其能更好地在不同缺失值模式的数据集上进行泛化,最终提高临床结局预测的准确性和可靠性。
同样的,在多中心数据研究中,批次效应也是一个不可忽视的问题。与前面的方法类似,我们设计了一个队列判别器,旨在识别每个样本的队列标签,同时迫使编码器抑制队列特定信息。
Lcohort = −1i/N ∑Ni=1 ∑Dd=1 yi,d log( ŷ,d)
实现方法与缺失判别器相同,在此不再赘述。
预训练
在微调之前,我们让模型采用一种多个目标彼此互补的自监督学习方法,使模型能够学习到靠谱的表示。我们共引入了五个预训练任务:
- 掩码语言建模(masked language modeling):模仿BERT,随机遮盖一次就诊(以及它的下一次就诊)中50%的有效检验结果,然后训练模型去预测这些被遮盖的值。这强化了检查编码器学习临床变量间复杂依赖关系的能力,同时因为引入了“下一次就诊”,这也让模型学习到了疾病的演变模式,融入了时序动态。损失函数:模型预测值
vî, j与真实值vi, j之间的均方误差MSE。 - 变分推理与正则化
(ELBO):引入变分自编码器的思想,让模型学习一个规整、有意义的潜在空间。在这个空间里病情相似的患者会聚集在一起,病情的轻微变化会对应潜在空间的平滑移动。大大提升了表示的质量和泛化能力。损失函数:分为重构损失和KL散度两部分(我不懂这个概率的事,难过)LELBO = E[log pθ(x|z)] - DKL(qφ(z|x) || pθ(z|x)) - 前文提到的两个对抗模型
- 生理年龄预测:训练模型根据一次就诊的全部临床测量值(但已人工删除了所有明确与年龄相关的变量,如实际年龄、出生日期等),来预测病人的实际年龄。只使用健康个体的数据()来计算这个任务的损失。损失函数:
Lage = 1| N ∑Ni=0(âi − ai)2
最终的损失函数将上述的五个任务损失函数聚合:
Lpretrain = α1LMLM + α2LELBO - α3Lcohort - α4Lmissing + α5Lage
终于进入到了微调阶段啦!
使用已经预训练好的主干模型通过有监督学习来解决具体的预测任务啦!
- 任务一:判断患者当前是否为某种疾病的首次发作。要进行这个训练那我们得有对应的标签才能有监督学习呀,所以我们得先把“疾病首发”这个标签定义出来:
ci, d即对于这个患者的第i次就诊时d疾病是否首发。ci, d=0则非首发,ci, d=1即首发。ci, d=1需满足以下条件:1. 在第i次就诊时被诊断有d疾病。2. 在第i次就诊之前的所有就诊中都没有被诊断过d疾病。额外操作:为了让模型学习疾病的首发表现模式,而非稳定期及恢复期的模式,将首次诊断后的所有就诊后的所有就诊数据排除到训练数据之外。 - 任务二: 开放时间窗口的未来疾病预测。就是要预测不限制时间长度的未来的某种疾病的发病风险。这个标签怎么设置呢?让我来告诉你:
fi, d即future disease identification,fi, d =0代表在该患者的纵向EHR数据中每一次就诊都没有此疾病。fi, d =1需要满足两个条件:1.截止到此次就诊(包括本次)该患者都未被诊断该疾病。2. 在此次就诊之后的任意一次就诊,患者被诊断为该疾病。额外操作:作者没说,但是我觉得应该和上边类似,将确诊那次就诊及之后的就诊剔除。 - 任务三:固定时间窗口的未来疾病预测。在具体的未来时间窗口内(比如t=5年或10年)的某疾病患病风险。标签设置:
wi, dt = 1即在时间窗t内,患者确诊了d疾病,需满足:迄今为止未诊断过该疾病、在随访窗口t内的某次就诊时被诊断了该疾病。wi, dt =0 迄今为止为诊断过该疾病,并且在随访期t内也确认未诊断过该疾病。关键事项:严格的数据删失,随访不充分的患者应被排除。显而易见,不能因为没随访,就认为他没病或者有病。
因为这三个任务都大同小异嘛。主要就是差在了标签和数据上,算法没差别,所以损失函数的形式都是一样的:N是患者数,D是疾病种类的总数(多标签分类),LBCE就是二值交叉熵损失函数
L = 1/N ∑Ni=0 ∑Dd=1 LBCE(ŷi,d, yi,d)
训练细节
这块我就直接贴翻译了,没啥需要理解的地方。主要就是描述一些参数的选择:
我们使用了一个隐藏层维度为1024的24层transformer编码器作为检查编码器,用以处理单个检查事件;并使用了一个隐藏层维度为768的12层自回归transformer解码器作为时间编码器,用以捕捉检查序列中的纵向模式。该设计利用多头自注意力机制来理解每次检查内临床测量值之间的关系,同时采用因果掩码注意力机制对患者健康的时间进展进行建模。该模型使用PyTorch实现,并采用两阶段方法进行训练。在预训练阶段,我们使用Adam优化器训练模型200个周期,学习率设为10-3,权重衰减设为10-6。针对下游任务的后续微调阶段,我们使用Adam优化器进行了100个周期的训练,学习率降低至10-4,并保持相同的10-6权重衰减。对于预训练和微调,我们均使用了CHAI-Main数据集的子集(CHAI-Training和CHAI-Tuning)。内部验证结果使用CHAI-Internal进行报告,外部验证则使用两个独立队列进行:CHAI-External-1和UKB-External。为确保方法学严谨性,我们实施了一种患者级别的非重叠划分策略,将CHAI-Main数据集按8:1:1的比例随机划分,以分别生成CHAI-Training、CHAI-Tuning和CHAI-Internal子集。CHAI-Main中的健康参与者构成了用于BA计算和年龄差异分析的CHAI-Healthy Controls队列。UKB-External数据集包含来自UK Biobank队列的所有可用样本。
需要注意的是:作者在文章中描述的模型结构与其在Github上开源的代码中并不完全一样。
年龄差异计算
人的”生理年龄”并不总是等于”实际年龄”。有些人衰老得更快(生理年龄 > 实际年龄),有些人则更慢。EHRFormer的目标就是量化这种差异。首先,研究人员只在健康人群上训练模型来预测生理年龄。以此建立一个”纯净”的参考标准,排除了疾病干扰的正常衰老轨迹。
另外,生理年龄和实际年龄的关系不是简单的直线,而是一条复杂曲线。年轻人可能衰老得快一些,中年人相对稳定,老年人又加速衰老。LOWESS(局部加权散点图平滑)是一种能捕捉这种非线性关系的统计方法。它不像传统回归那样强加一个固定形状,而是根据每个点周围的数据密度来绘制平滑曲线。
计算个体偏离度:
对于每个病人,模型会预测他的生理年龄(比如模型判断他生理上是55岁),根据他的实际年龄(比如他实际只有45岁),在健康基准线上找到”45岁健康人的典型生理年龄”(假设是45岁)。计算差异:55岁(预测) – 45岁(期望) = 10岁(生理上比同龄健康人老10岁)。之后,将这个差异值标准化。如果整个人群的差异标准差是5岁,那么10岁的差异就相当于2个标准差。这样做的意义是:无论什么年龄段,+1.5都表示”比同龄人老1.5个标准差”,提供了统一的比较标准。很高级。
