
简介本资源是一个面向生物医药信息学研究者与AI医疗方向学习者的深度学习实践项目聚焦药物相互作用DDI预测这一关键临床安全问题适用于具备Python基础并希望掌握图神经网络、分子表征与多任务建模的中级开发者。压缩包共19个文件含13个核心Python脚本实现数据转换、模型训练、真实数据测试等全流程、3个Jupyter Notebook涵盖探索性分析、架构可视化与测试集验证、2张关键架构图及1份依赖说明整体仅621KB轻量但结构完整。已有191人下载学习资源以decagon1-master为根目录清晰呈现从SMILES编码、异构图构建、多标签预测到AUPRC评估的全链路实现配套requirements.txt与模块化utility工具便于快速复现、调试与二次开发是理解药物知识图谱与深度学习交叉应用的优质入门范例。 拿到“基于深度学习的药物相互作用预测.zip”这份项目包时我第一反应是先摸清楚它到底是哪个团队开源的框架还是自己攒的实验代码。这类压缩包在生物信息、医药AI圈子里很常见通常装着一套基于深度学习的模型代码用来预测两种药物一起吃的时候会不会产生不良反应、药效冲突或者代谢干扰。它解决的痛点很直白临床上多药联用太普遍了药物相互作用是实实在在的安全隐患传统实验测定费时费力用深度学习从已有数据里学规律则要高效得多。这篇文章就是我从解压这个zip开始到最终把模型跑通、看明白输出结果的完整记录既有环境配置和代码细节也有踩坑记录适合药学背景但想入门深度学习的同学也适合算法工程师想快速了解药物相互作用预测这个任务到底在做什么的读者。1. 项目包到手先别急着训练把压缩包和环境搞定1.1 校验Zip完整性很多人拿到压缩包后的第一件事是双击解压但在一台命令行环境为主的深度学习服务器上我更建议先用unzip或7z走一遍完整流程。项目包名字里带着“.zip”整个项目核心代码、数据、模型权重全部在这个文件里一旦解压出现问题后面所有工作都白搭。我实际拿到文件后先跑了unzip -t做完整性测试这一步能快速暴露常见的“file is not a zip file”和“invalid zip archive: could not find eocd”问题。如果你在解压时报could not find eocd意思是压缩包末尾缺少 End of Central Directory 记录zip文件结构不完整。最常见的原因是下载中断、传输过程中字节丢失或者文件后缀虽然是zip但实际格式是7z。可以用file命令确认真实格式然后决定是重新下载还是用7z x强制解压。还有一个容易被忽略的场景是分卷压缩比如下载到一半拿到的是xxx.z01和xxx.zip这时候不能单独解压必须把所有分卷放到同一目录然后用支持分卷的工具比如7-Zip按顺序合并解压。我在处理这类医药数据包时遇到过几次分卷丢失补齐分卷后基本都能正常解压。解压密码是另一个坑。如果项目包设置了密码而你手头没有密码文件常规思路是用zip密码恢复工具暴力破解但我的建议是优先找原始提供方要完整包。密码恢复对短密码可能有效但对复杂密码基本是碰运气而且涉及数据的合法使用边界开源项目通常不会刻意加密遇到加密包要多留个心眼。1.2 项目目录与依赖环境梳理解压完成后第一件事是看目录结构。一个正规的深度学习项目通常包含data/、src/、models/、scripts/、requirements.txt、README.md这几个部分。我建议先把README通读一遍搞清楚数据集的格式、模型的输入输出、训练命令是单机脚本还是支持分布式这会省掉后面大量试错时间。然后就是搭建运行环境。这类项目最常见的依赖是PyTorch或TensorFlow加上RDKit处理分子结构、NumPy、Pandas、scikit-learn。如果你在Ubuntu 22.04或24.04上操作先用conda新建一个独立环境不要直接用base环境去装否则很容易和系统自带的OpenCV、CUDA驱动打架。我在另一台机器上遇到过github下载的zip如何安装在conda base环境中的问题用pip install -e .或python setup.py install可以装成开发模式但如果你不熟悉依赖管理建议老老实实按 requirements.txt 来。安装前先检查Python版本和CUDA版本PyTorch对CUDA版本极敏感装错版本会在模型训练时报算子无法编译的错误。提示如果requirements.txt里写的是torch2.0.1先运行python -c import torch; print(torch.__version__)确认版本匹配不要盲目pip install -r。版本冲突是这种多依赖项目环境搭建中最大的时间黑洞。2. 药物相互作用预测任务定义与建模思路2.1 一句话说清楚问题药物相互作用Drug-Drug InteractionDDI预测直观理解就是给定两个药物模型判断它们联合用药时是否会产生不良反应以及具体是哪类相互作用。它和药物-靶点亲和力预测不一样输入是两个药物而不是药物和蛋白质输出也不是单一亲和力值而是一个类别标签或者多标签风险向量。在临床场景中DDI预测有两种典型任务形态二元分类只回答“有没有相互作用”而更细粒度的多分类任务则要预测相互作用类型比如药效增强、毒性叠加、代谢抑制、吸收减少等。我在这个项目里看到的是把DDI建模成一个多分类任务类别数取决于知识库的标注体系常见的有几十类甚至上百类。类别多带来的问题是类别不均衡比如“无相互作用”这类样本远多于“严重毒性”样本训练时如果直接拿原始分布算loss模型会严重偏向多数类后面必须处理。另外一个容易混淆的点是“药物”在不同数据源里的表示形式。有的数据集用药物名称有的用DrugBank ID有的用SMILES字符串有的用分子指纹。预测模型本身不关心药物叫什么名字它关心的是输入表示是否携带了足够的化学信息。这也直接决定了模型架构选型。2.2 为什么用深度学习而不是传统方法早期DDI预测方法基本依赖特征工程把药物的物理化学性质分子量、脂水分配系数logP、氢键供受体数和结构相似度、靶点谱信息拼在一起然后喂给随机森林、SVM、逻辑回归之类经典分类器。这类方法在小规模数据集上表现稳定解释性也强但有两个瓶颈一是特征设计依赖领域专家经验不同团队的数据集划分不同导致特征不可通用二是药物相互作用本质上是复杂非线性关系两个分子的结构特征在联合空间中会涌现出单独建模时看不到的模式线性模型或浅层模型往往抓不住。深度学习在这个任务上最大的优势是自动特征学习。你不需要手工决定“分子量差多少才算显著”模型可以从海量样本里学到高维交互模式。药物相互作用不是简单的“A有毒性B有毒性→联用毒性增加”它可能因为A抑制了CYP450酶导致B的血药浓度升高这个机制涉及代谢通路单靠一两个分子描述符很难充分表达。而深度模型可以从分子指纹、SMILES序列等原始输入中逐层抽象捕捉这种跨层级互动。举个例子CNN模型中的卷积层可以看成是滑动窗口在分子指纹或序列上扫描提取局部化学环境某个骨架、某个官能团池化层则将局部特征压缩成全局摘要保留“哪种官能团出现最多”这类信息。到了高层网络这些局部化学特征被组合成更抽象的交互证据。对比之下传统方法往往把每个特征独立地丢进分类器没有这种层层递进的组合能力。2.3 数据从哪来长什么样开源药物相互作用数据集主要来自DrugBank、DDI Corpus、TWOSIDES等。DrugBank是手工整理的药物数据库DDI标注信息相对准确但规模不大TWOSIDES是从FDA不良事件报告系统FAERS里挖掘出来的副作用关联规模大很多、但噪声也大。这个项目里我没有重新下载数据用的是包内自带的CSV文件结构大概是drug1_id, drug2_id, label三列另外附带一个SMILES字典用于把ID映射成分子结构。拿到数据后第一件事就是做去重和标签分布统计。我实测下来这类数据集的“无相互作用”样本占比往往超过60%如果项目包自带的划分方式不理想建议自己做一遍分层采样。还有一个隐蔽问题是数据泄露同一个药物对可能同时出现在训练集和测试集中如果模型在训练阶段见过这个药物对的相似变体测试指标就会虚高。最好按药物ID集合做划分保证训练集和测试集的药物没有重叠这样评估出的泛化能力才可信。3. 模型选型与关键结构设计3.1 药物输入的表示形式我目前看到的主流做法有三种分子指纹Molecular Fingerprint、SMILES字符串、图结构Molecular Graph。分子指纹是把分子结构编码成固定长度的二进制或计数向量典型的是1024位或2048位的MACCS、Morgan指纹。它的好处是输入维度固定、计算快适合直接喂给全连接网络缺点是丢失了分子结构中的连接信息指纹只记录“有哪些子结构”不记录“这些子结构怎么连在一起”。从深度学习角度看它更像一个预先做好的特征向量网络学习的是特征组合权重。SMILES是一种用 ASCII 字符串表达分子结构的线性表示比如乙醇是CCO。这类输入交给循环神经网络或Transformer处理网络需要先把字符序列嵌入成向量再通过注意力机制捕捉长距离依赖。它的优势是输入更接近原始分子结构训练得当可以学到序列语法背后的化学规律劣势是SMILES字符串存在许多等价写法同一个分子可能有多种SMILES表示尤其在模型预测环节字符串顺序敏感性是个隐患。图结构则把分子看作节点原子和边化学键用图神经网络GCN、GAT直接学习拓扑特征。这种方式在理论上是表示能力最强的因为分子天生就是图不丢失任何结构信息。但图模型的工程实现复杂度高另一个药物如果也用图表示两个图的交互建模会变得很麻烦多数时候还是要把图向量化为固定长度嵌入再做拼接或注意力。这个项目包里的复杂度不是很高用的是摩尔指纹加全连接好处是复现成本低跑通后再改进也方便。3.2 从两个药物到分类结果模型核心部分要解决一个问题给定两个药物的特征表示怎么把它们映射成一个相互作用类别。最常见的做法是向量拼接Concatenation即把两个药物的嵌入向量首尾相连送入MLP。这种做法的问题是它没有显式建模两个药物之间的交互强度而是把交互模式全部压进后续隐藏层的权重里在数据量充足时效果尚可在小数据集上泛化容易不足。一个更好的思路是引入注意力机制。具体来说给定药物A的特征向量计算药物B中哪个特征与A最相关反过来也一样。这样模型可以学习“药物A中的某个官能团与药物B中的某个官能团共同出现时强烈暗示某种代谢抑制”。这和人类判断相互作用的思路一致关键不在单个药物自身而在于两者之间的匹配关系。另一种值得考虑的做法是先算出两个药物嵌入的外积Outer Product或差分向量、点积把这些“交互候选特征”与原嵌入一起拼接。外积在数学上捕捉了特征之间的二阶组合信息量比单独拼接大得多代价是维度爆炸一般要用低秩近似的分解方式控制参数量。我在调优时通常把拼接、差向量、点积、外积这四类特征都算出来随后送入一个带Dropout的全连接层这样既保证交互建模的丰富性又不过分增加参数量。注意输入表示方式直接决定上层交互模型设计。如果你选了SMILES序列输入最好配合Transformer或BiLSTM来建模序列依赖如果选了分子指纹或图嵌入就适合走MLP或注意力池化的路线。不要混用不兼容的组合比如拿序列输入却只做简单平均池化会丢掉大量局部化学环境信息。3.3 损失函数与评估指标的选择多分类DDI预测的默认损失函数是交叉熵Cross Entropy但如果类别严重不均衡我会优先考虑带类别权重的交叉熵。权重可以按样本数的倒数设置比如第i类样本占比为 (p_i)权重设为 (1 / p_i) 或 (1 / \sqrt{p_i})。我实测过前者会把少数类权重抬得过高训练时容易出现震荡后者更平滑稳定得多。如果你不希望手动设权重Focal Loss也是个成熟选择它的核心是降低易分类样本的loss占比让模型更关注难分样本。评估指标上DDI任务里 AUCROC曲线下面积常常被当作默认指标但它有个众所周知的弱点对类别不平衡不敏感即使负样本占90%AUC也可能很高。更贴近实际场景的是 AUPRPrecision-Recall曲线下面积和F1分数尤其是当我们更关心“模型预测有相互作用、且它确实是相互作用”的准确率时AUPR更重要。项目包里的测试脚本同时输出AUC和AUPR我建议你在训练时用AUPR作为早停监控指标因为它的波动更真实地反映少数类的识别能力。另外不要只看平均指标。我做完一轮训练后习惯把混淆矩阵打印出来逐类看看是哪个相互作用类型特别容易被混淆。比如“代谢抑制”和“药效增强”如果经常被模型混淆说明数据里这两类的标注边界本身就不清晰这时候与其盲目调模型不如回头检查数据标注规范。4. 实操从数据预处理到训练完成4.1 数据预处理流程我拿到数据后按以下顺序做了清洗读入CSV检查缺失值。SMILES字符串缺失样本直接删除因为有结构信息才能生成指纹或序列。按药物ID去重用RDKit把SMILES转成RDKit分子对象转换失败的样本剔除。构建药物ID到特征向量的映射表。我用Morgan指纹生成2048位二进制向量半径设置为2这基本等价于ECFP4指纹是化学信息学里常用的标准配置。生成训练样本。如果原始数据里只有正样本有相互作用的药物对还需要从所有药物对里采样负样本。采样时注意不要让负样本总数碾压正样本我一般把正负比例控制在1:2到1:5之间保证模型见过足够多的负例又不至于偏移过头。RDKit生成指纹的代码段大致是from rdkit import Chem from rdkit.Chem import AllChem def mol_to_fingerprint(smiles, n_bits2048, radius2): mol Chem.MolFromSmiles(smiles) if mol is None: return None fp AllChem.GetMorganFingerprintAsBitVect(mol, radius, nBitsn_bits) arr np.zeros((n_bits,), dtypenp.float32) # 把BitVect转成0/1数组 for i in fp.GetOnBits(): arr[i] 1.0 return arr这里有个容易踩的坑RDKit版本更新后GetMorganFingerprintAsBitVect的行为可能会有细微变化不同版本生成的指纹不一定完全一致。如果项目包里已经附带了预生成的指纹缓存文件优先用缓存文件不要重新生成否则会因为指纹不一致导致模型预测结果发生偏移。数据划分上我用GroupShuffleSplit或StratifiedSplit来确保同一药物不会同时出现在训练集和测试集里。这一步很多人会忽略但它是模型评估可信度的关键尤其当药物总数不多时随机划分导致的数据泄露可以让测试AUC虚高好几个点。4.2 模型训练核心实现这个项目的网络结构不复杂我用PyTorch重新实现了一遍核心代码如下import torch import torch.nn as nn class DDIModel(nn.Module): def __init__(self, feat_dim2048, hidden_dim256, num_classes86): super().__init__() self.fc1 nn.Linear(feat_dim * 2, hidden_dim) self.bn1 nn.BatchNorm1d(hidden_dim) self.fc2 nn.Linear(hidden_dim, hidden_dim) self.dropout nn.Dropout(0.3) self.fc3 nn.Linear(hidden_dim, num_classes) self.relu nn.ReLU() def forward(self, drug1, drug2): diff torch.abs(drug1 - drug2) # 拼接原始特征和差分特征捕捉交互信息 x torch.cat([drug1, drug2, diff], dim1) x self.relu(self.bn1(self.fc1(x))) x self.dropout(x) x self.relu(self.fc2(x)) x self.dropout(x) return self.fc3(x)这里我额外拼入了两个药物指纹的差分绝对值它给模型提供了一个非常直接的对称交互信号如果两个药物在某一个指纹位上差异大可能意味着它们的结构特征互补这种互补在联合用药场景里往往比相似性更有意义。加不加这个差分特征我在实验里看到AUC大约有1到3个百分点的差异属于低成本高收益的调整。训练配置方面我使用Adam优化器初始学习率1e-3batch size 128训练最多50轮早停patience设为8。在代码里用PyTorch实现早停并不复杂核心逻辑是每个epoch结束后在验证集上算AUPR连续8个epoch没有上升就保存当前最佳权重并终止训练。这类多分类数据集的训练不要一味追求更多epoch因为类别多、噪声大时模型后期容易过拟合到训练集。我还特别关注了类别权重的设置方式。代码里使用了torch.nn.CrossEntropyLoss(weightclass_weights)class_weights的计算方式如下counts np.array([...]) # 每个类别的样本数 weights 1.0 / np.sqrt(counts) weights weights / weights.mean() # 归一化归一化这步很关键它避免了权重整体过小或过大导致学习率需要重新调整。如果不归一化大量小权重会让有效梯度过小训练极慢这个问题在类别数上百时尤其明显。4.3 实验结果与输出解读我在项目自带数据集上跑完一轮基线训练后的结果大致是验证集AUC 0.86左右AUPR 0.52。单独看AUC会觉得效果不错但AUPR只有0.52说明正类样本的精确率和召回率的调和平均还有很大提升空间模型对少数类的识别并不充分。这个现象在DDI数据集里很常见不奇怪。为了弄清模型在哪些类别上表现最差我打印了验证集的混淆矩阵发现“药效增强”和“代谢抑制”这两类互相混淆最严重。原因是这两类副作用在数据标注层面本身就有重叠一个药物对既可能被标注成药效增强也可能被标注成代谢抑制标注者之间的主观差异直接成了模型性能的天花板。遇到这种情况我建议算一下各类别的Micro-F1和Macro-F1然后去和数据集作者确认标注规范实在不行就考虑把这几个混淆严重的类别合并成一个粗粒度类别宁可宏观预测准确也不要微观上互掐。还要留意测试脚本输出的置信度分数。项目包里如果包含了predict.py它通常会把每个药物对的softmax概率输出到CSV。实际应用中不要直接取argmax而是设置一个“低置信度拒判”阈值比如最大概率低于0.6的样本标记为“待人工审核”。这个做法对医药场景特别重要因为模型预测错误的代价不是简单改个label而是可能影响临床安全决策。5. 实操中常见的坑与排查方法5.1 压缩包与数据文件层面的问题报错invalid zip archive: could not find eocd说明zip文件不完整或真实格式不是zip。先用file xxx.zip看真实类型再考虑重新下载或换工具解压。下载了分卷文件xxx.z01xxx.zip无法单文件解压必须用7-Zip在主zip所在目录打开主zip它会自动读取分卷。缺少任何一个分卷都会失败补齐后再解压。出现乱码文件名比如锟斤拷一般是zip包编码问题Windows下用中文编码打包Linux下按UTF-8解码导致的乱码。可以用unzip -O gbk指定编码或者用7-Zip打开后手动重命名。模型权重文件加载失败先检查文件md5是否和README一致。md5不匹配大概率是压缩包传输中损坏重新解压或下载才有用直接改代码绕过反而容易得到错误结果。5.2 模型训练层面的问题训练不收敛时我按以下顺序排查首先看loss曲线是否一直振荡不下降如果是先降低学习率一个数量级看是否稳定其次检查输入数据是否有NaN值我遇到过SMILES被RDKit转换后生成的指纹数组里出现NaN原因是个别特殊分子的原子类型编号超出预设范围再检查标签是否从0开始连续编码有的数据集类别从1开始而模型输出维度是类别总数如果标签和输出维度不对齐loss会直接报错或者默默学到错误映射。过拟合的典型表现是训练AUC涨到0.98、验证AUC只有0.75。这时候优先尝试加大Dropout、减小隐藏层维度、增加L2正则。如果数据量本身不足比如只有几千个阳性药物对再复杂的模型也没用建议先做特征降维或改用预训练的分子嵌入来提升数据效率。还有一个很容易被忽略的问题数据集划分时的药物重复。我之前接过一个外部药物相互作用数据集训练集和测试集共享了大量药物对结果测试AUC高达0.95我一度以为是模型效果好直到做了药物级别独立划分才发现真实性能缩水到0.82。所以任何预测类项目里数据划分方式决定了实验结论是否可信这个优先级高于模型结构。5.3 环境兼容性问题这类项目最容易出的环境坑就是CUDA和PyTorch不匹配。Ubuntu 22.04默认驱动版本较新如果你安装的PyTorch版本太老它会检测不到GPU或者反向报CUDA driver version is insufficient。我的建议是先跑nvidia-smi看驱动支持的CUDA版本然后按PyTorch官网对应版本安装编译好的轮子不要用源码编译费时且容易翻车。conda环境下还会遇到导入资源包失败 caused by: invalid zip archive这类报错。这不一定是你下载的包损坏而是conda缓存里的安装包损坏解决思路是清理conda缓存并重新安装而不是去卸载其他依赖包。另一个相关问题是zip包在Linux环境解压后某个Python包源码目录权限不对导致安装时找不到模块可以用chmod -R 755修复。如果你看到TensorFlow打印类似tf.Tensor: id91, shape(2,2), dtypeint32的输出这是框架正常执行时的张量调试信息不是报错。不要被这类冗长日志吓到真正的报错一般在堆栈跟踪末尾看Error或Traceback关键字后面几行即可定位。6. 一点实操后的心得我最大的体会是基于深度学习的药物相互作用预测真正难的不是模型结构而是数据处理和实验设计的严谨性。同样的数据、同样的模型如果划分方式不严谨测试指标可以差出几个百分点这在医疗相关场景里是不能容忍的。另外环境搭建阶段的zip解压、依赖版本匹配、Python环境隔离等基础操作看起来简单实际却在耗时占比里相当可观。如果你手头也有一个类似的模型包建议拿到手后先固化环境、再改模型逻辑把每一步操作记录清楚否则一旦踩坑想回溯是件很麻烦的事。本文还有配套的精品资源点击获取