把一批一万个配体扔给 AutoDock-Vina-GPU 2.1,和扔给常规的 CPU 版 Vina,用户体验完全不是一回事。我在实验室里第一次跑完 GPU 版之后,直接把排队的虚拟筛选脚本全部改掉,不是因为它“快了多少倍”的纸面数据,而是同样的任务不再需要等一个周末;它把配体构象采样和打分函数评估拆成了海量并行任务,批任务几乎是“扫”着跑完。
但说回这款软件的安装,很多人真正卡住的不是编译那几分钟,而是底层环境里驱动、OpenCL/CUDA、CMake 之间互相不对付。尤其是第一次装的人,经常在一个看似无关紧要的依赖上消耗一下午。这篇文章就写我怎么把这个 2.1 GPU 版从一台相对干净的新机器上装起来、跑通、再挂进批量筛选流程的全过程,适合做结构生物学、药物化学、分子对接方向的同学,也适合手里有张显卡但不想花太多时间折腾驱动的人。
1. 为什么值得折腾 GPU 版:加速来源和适用边界
刚开始接触分子对接的人往往会问一个问题:Vina 不是已经有 CPU 版了吗?为什么还要单独维护一个 GPU 版,安装的时候还多出这么多变量?
答案很简单:AutoDock Vina 这类基于打分函数和随机搜索的软件,整个计算过程由两个高开销部分组成——打分函数计算和构象空间搜索。一个配体有大量可旋转键时,构象搜索的采样点数目会指数上升。CPU 版在这部分只能靠有限的线程轮流算,而 GPU 版则把“评价一批构象的分数”这件事改造成可以同时上千个线程执行的并行任务。
AutoDock-Vina-GPU 2.1 不是换了个壳的旧程序。它基于 Vina 1.2 时代的评分模型,把能量项计算和优化过程移植到 GPU kernel 上,同时保留 Vina 的搜索算法框架。也就是说,你原来熟悉的 receptor.pdbqt、ligand.pdbqt、盒子中心这些概念依然成立,只是底层计算引擎换了。
1.1 GPU 到底把时间花在哪一步省了下来
我自己的使用感受是:加速收益最明显的是“配体数量大、单个配体构象空间中等”的场景。比如一个虚拟筛选任务里有几十万个小分子,每个分子几万次构象评估,这个规模是最适合 GPU 的。CPU 版在这一步通常是逐一处理配体、逐代进化、反复打分,GPU 版则可以一次同时评估多组构象。
GPU 版跑批任务时,CPU 主要负责文件解析、网格映射、逻辑控制和 I/O,打分和局部优化放在 GPU 上。所以你会观察到:命令行启动后,有一个短暂的 CPU 高占用阶段,那是它在做格点预计算和准备输入;紧接着 GPU 利用率拉满,CPU 占用反而掉下来,这个阶段就是真正的并行打分。
对单个配体做单次对接时,GPU 版的启动和初始化成本会被摊薄得不明显,如果机器本身比较老,单任务甚至未必比 CPU 快多少。但只要你把任务数堆积起来,让它持续“吃饱”,收益就会变得非常直观。我习惯把 GPU 版比喻成一个流水线工厂,CPU 版是一个大师傅,活少的时候大师傅更灵活,活一多,流水线的吞吐量优势就完全压不住了。
1.2 什么样的算力水平适合上 GPU 版
先给一个非常主观的结论:如果你手头的任务是单个靶点、几十个配体的课堂作业,CPU 版已经够用,没必要折腾 GPU。但如果你要跑 >5000 个配体的筛选,或者你的靶点需要反复调盒子、换构象做多轮对接,那么 GPU 版能帮你把任务从“按天等”变成“按小时等”。
硬件方面,显存并不是越大越好,但确实有个舒适下限。绝大多数常规靶点、配体分子量在 500 以内的任务,2GB 显存基本能跑,4GB 以上会比较从容。因为 Vina 的搜索需要把格点图和相关数据结构放进显存,盒子设得越大、体系原子数越多,显存占用上升越快。如果是超大体系,比如把整个蛋白二聚体都框进很大的盒子里,8GB 显存也可能紧张。
图形卡和专业计算卡都能跑。NVIDIA 的 GTX/RTX 系列、AMD 的 Radeon 系列都有人在实际用。真正影响安装选择的不是显卡品牌,而是你准备用哪套后端。
1.3 CUDA 还是 OpenCL:先想清楚再动手
AutoDock-Vina-GPU 2.1 的源码里通常同时提供两套后端:CUDA 和 OpenCL。选择后端这件事最好在装驱动之前就定下来,因为它直接影响你要不要装 CUDA Toolkit。
- CUDA 后端:只支持 NVIDIA 显卡,性能通常更稳定,官方维护和社区讨论也多。缺点是必须装 CUDA Toolkit,且 Toolkit 版本和驱动版本之间有小范围的兼容窗口。
- OpenCL 后端:兼容 NVIDIA、AMD、Intel 等各类显卡,只要显卡驱动能提供 OpenCL runtime 就可以编译。安装依赖相对轻,不过不同厂商驱动的 OpenCL 实现质量参差不齐,偶尔会遇到同样的代码在不同卡上性能差距很大。
我个人的建议是:如果你是 NVIDIA 卡且主要跑自己的计算任务,优先用 CUDA 后端;如果你手头的机器可能是 AMD 卡,或者你需要在一台机器上兼容后续换卡的可能,就选 OpenCL。编译两套并不冲突,但没必要一开始就两套都折腾,一套跑通再加另一套。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 安装前的环境扫雷:驱动、OpenCL 与编译工具链
很多安装教程会直接让你跳到一个 git clone、cmake .. && make,仿佛只要敲完这几行就能出结果。但根据我在不同机器上的安装经历,90% 的失败都不是代码本身,而是底层环境没对齐。
编译 Vina-GPU 需要三类东西:能识别的显卡与驱动、对应后端的运行库、以及足够新的编译工具链。这三类中任何一项版本不一致,都可能让你在编译阶段或运行阶段遇到看起来莫名其妙的报错。
2.1 先确认显卡型号、驱动版本和 ICD 路径
这一步千万别跳过。我见过有人在一台只有核显的服务器上照着教程装了半天,最后发现根本没有可用的 GPU;也有人双显卡机器上默认驱动没装好,nvidia-smi 都输出不了信息。
在 Linux 下先跑:
bash复制nvidia-smi
如果输出正常,说明 NVIDIA 驱动已经在工作。看右上角的 “Driver Version” 和 “CUDA Version”,这个 CUDA Version 表示当前驱动支持的最高 CUDA 版本,不等于你已经安装了 CUDA Toolkit。
如果是 AMD 卡或 Intel 核显,用:
bash复制clinfo
没有 clinfo 就先安装:
bash复制sudo apt install clinfo
clinfo 会列出平台和所有 OpenCL 设备。如果提示找不到 platform,说明 OpenCL runtime 没装好,这时候先不要急着编译 Vina-GPU,因为编译能过,运行也一定会挂在初始化设备这一步。
2.2 OpenCL 运行库是 Linux 上最隐蔽的坑
很多 Linux 发行版默认没有安装 OpenCL 的 ICD loader。NVIDIA 驱动虽然会给显卡提供 OpenCL 实现,但系统里没有 loader 时,程序找不到 OpenCL 平台。
Debian/Ubuntu 系通常需要:
bash复制sudo apt install ocl-icd-libopencl1 opencl-headers
装完后检查:
bash复制ls /etc/OpenCL/vendors/
如果里面有 nvidia.icd、amdocl64.icd 这类文件,说明驱动侧的 OpenCL 注册信息在。此时再跑 clinfo 就应该能列出设备了。
AMD 显卡在 Ubuntu 下的 OpenCL 有两种来源:一种是 AMDGPU 驱动自带的 ROCm OpenCL runtime,另一种是某些 APU 用的 Mesa 实现。很多人刚接触时 apt 装了一堆东西,机器上也确实有显卡驱动,但 OpenCL 就是枚举不出来,最终多半是缺了对应的 ICD 注册文件。
还有一个容易忽视的细节:OpenCL 头文件的版本和运行库版本不需要严格一致,但如果你自己下载了很老的 OpenCL SDK,编译时可能因为头文件缺失某些 API 而失败。直接用发行版的 opencl-headers 通常最省心。
2.3 CMake、编译器与 CUDA Toolkit 需要配套
编译 Vina-GPU 的代码需要 CMake 和一个支持 C++17 的编译器。Ubuntu 20.04 以上自带的 gcc 基本都够用,如果系统比较老,建议先把 CMake 升到 3.15 以上。我这里倒没有遇到 CMake 高版本带来的兼容问题,反而是低版本在解析 CUDA 目标时容易报错。
如果选 CUDA 后端,还要单独装 CUDA Toolkit。这里有个反复出现的误区:有人以为安装了显卡驱动就等于装好了 CUDA。不是的。驱动是运行期需要的,nvcc 编译器在 CUDA Toolkit 里。
确认 nvcc:
bash复制nvcc --version
如果提示找不到命令,说明你确实没有装 Toolkit。装完 CUDA Toolkit 之后还要把路径加进 shell:
bash复制export PATH=/usr/local/cuda/bin:$PATH
同时要注意驱动版本对 CUDA Toolkit 版本有硬限制。驱动支持的 CUDA 版本如果低于你装的 Toolkit 版本,程序编译也许能过,但运行时加载 CUDA runtime 会直接报 CUDA driver version is insufficient。这种错误一般不是代码问题,是驱动和 Toolkit 版本不匹配。
3. 从源码到可执行文件:两个后端的编译实录
环境准备做完,真正编译的过程其实不长。以我在 Ubuntu 22.04 上编译 OpenCL 后端的完整操作来看,顺利的话十分钟内就能出可执行文件。
3.1 获取源码并确认目录结构
Vina-GPU 的源码托管在公开的 GitHub 仓库里,clone 的时候注意版本 tag。我一般指定到 2.1 的发布版本,避免默认分支和我熟悉的行为不一致。
bash复制git clone https://github.com/ccsb-scripps/AutoDock-Vina-GPU.git
cd AutoDock-Vina-GPU
git checkout 2.1.0
如果仓库中有子模块引用,顺手执行:
bash复制git submodule update --init --recursive
这一步不一定每次都需要,但做了没坏处。
切到 2.1 之后你会看到目录下有区分后端的子目录,比较典型的结构是 cuda/ 和 opencl/ 各自有独立的 CMakeLists.txt。不要直接在整个仓库根目录执行 cmake,先确定自己要走哪个后端,再进入对应目录。
3.2 OpenCL 后端的编译命令与 cmake 参数
进入 opencl 目录后的标准流程:
bash复制cd opencl
mkdir build && cd build
cmake ..
make -j"$(nproc)"
如果上面 OpenCL 头文件和运行库都装好了,CMake 大概率能自动找到依赖。但实际总有例外,比如系统里有多个 OpenCL 实现,或者头文件路径是非标准位置。这时候手动指定路径更直接:
bash复制cmake .. \
-DOPENCL_LIBRARY=/usr/lib/x86_64-linux-gnu/libOpenCL.so \
-DOPENCL_INCLUDE_DIR=/usr/include/CL
编译完成后,在当前目录或源码目录下会生成可执行文件。不同版本对可执行文件的命名不太一样,有些叫 vina,有些叫 vina_gpu。用 ls 找一下,然后直接执行:
bash复制./vina --help
如果输出正常,说明 OpenCL 后端已经完成编译,而且程序已经能正确加载 OpenCL 库。
3.3 CUDA 后端的编译与算力参数
CUDA 后端的目录通常是 cuda/。进入后先确认 nvcc 可用:
bash复制nvcc --version
然后进行编译:
bash复制cd cuda
mkdir build && cd build
cmake .. \
-DCMAKE_CUDA_COMPILER=$(which nvcc) \
-DCMAKE_CUDA_ARCHITECTURES=75
make -j"$(nproc)"
CMAKE_CUDA_ARCHITECTURES 这里填的是你显卡的 compute capability。75 对应 Turing 架构,也就是 RTX 20 系列;如果你是 RTX 30 系列,填 86;RTX 40 系列填 89;A100 填 80。
不确定显卡算力的话,用 nvidia-smi 查询:
bash复制nvidia-smi --query-gpu=compute_cap --format=csv
输出类似 8.9,那 CMAKE_CUDA_ARCHITECTURES 就填 89。这一步非常重要,填错或漏填会导致编译出来的 kernel 不兼容你的显卡,运行时会直接提示找不到匹配的设备。
3.4 编译阶段常见的报错和处理方向
我积累的几个高频编译期报错和处理方向:
- 如果提示找不到 OpenCL headers,检查是否安装了
opencl-headers,或者手动指定OPENCL_INCLUDE_DIR。 - 如果 CMake 提示找不到 OpenCL 库,先
ldconfig -p | grep OpenCL看库文件是否存在,不存在就装ocl-icd-libopencl1。 - 如果 CUDA 后端编译时报
fatal error: cuda_runtime.h: No such file or directory,说明 CMake 没有找到 CUDA 路径,可以设置CMAKE_CUDA_COMPILER,并把/usr/local/cuda/include加入CPLUS_INCLUDE_PATH。 - 如果
make过程中卡死或者报内存不够,多半是-j参数开得太大,编译并行任务太多吃满了内存,改成make -j4试试。
4. 第一次真正跑通:参数文件、命令行与结果验证
能编译出可执行文件只是第一步。第一次运行如果直接报错或者算出来的结果明显不合理,很多人会怀疑是不是安装出了问题,其实更多时候问题出在输入文件准备和参数理解上。
4.1 受体和配体先转成规范的 PDBQT
Vina-GPU 读取的是 PDBQT 格式。这个格式在普通 PDB 的基础上增加了原子类型、电荷、ROOT 分支等信息,是 AutoDock 家族通用的输入格式。你不能直接拿一个从 RCSB 下载的 PDB 文件丢给它运行。
受体的准备通常用 MGLTools 或者 ADFR 套件里的 prepare_receptor4.py:
bash复制python prepare_receptor4.py -r receptor.pdb -o receptor.pdbqt -A hydrogens -U nphs_lps
这里 -A hydrogens 表示加氢,-U nphs_lps 表示合并非极性氢并删除孤对电子。对 Vina 来说,极性氢需要保留,非极性氢合并到碳原子上是标准做法。
配体准备可以用 prepare_ligand4.py,也可以用 Open Babel:
bash复制obabel ligand.sdf -O ligand.pdbqt -p 7.4
-p 7.4 是指定 pH 7.4 下加氢。配体的三维结构最好先通过能量最小化或者构象生成确认合理,直接拿一个没有正确加氢的 2D 结构转出的 PDBQT,即使能跑,对接结果也没有参考价值。
4.2 配置文件和命令行示例
Vina 系列支持把盒子中心、尺寸等参数写进配置文件。这样做的好处是同一个靶点多轮筛选时,文件可复用,不会因为命令行历史容易丢失而忘记某个参数。
下面是一个典型的 Vina-GPU 2.1 运行方式,具体开关名可能随小版本略有差异,可以用 ./vina --help 确认:
bash复制./vina \
--receptor receptor.pdbqt \
--ligand ligand.pdbqt \
--center_x 27.5 --center_y 53.2 --center_z 9.8 \
--size_x 22.5 --size_y 22.5 --size_z 22.5 \
--exhaustiveness 32 \
--num_modes 9 \
--seed 2024 \
--out result.pdbqt \
--log result.log
盒子中心和尺寸应该根据你对接的活性位点来设定,而不是随便给一个全蛋白的大盒子。盒子越大,需要计算的格点越多,搜索空间也越大,耗时成倍增加。做对接之前先用 PyMOL 或者 Chimerax 查看目标蛋白的已知活性口袋坐标,比盲目设一个大盒子要靠谱得多。
exhaustiveness 控制搜索的充分程度,建议值在 8 到 64 之间。初次验证流程可以用较小的值快速测试,正式筛选再调大。
4.3 怎么判断输出结果是可信的
跑完后打开 result.log,会看到类似下面的信息:
text复制mode | affinity | dist from best mode
| (kcal/mol) | rmsd l.b.| rmsd u.b.
-----+------------+----------+----------
1 | -8.2 | 0.000 | 0.000
2 | -7.9 | 1.542 | 2.109
第一列是结合模式序号,第二列是预测的结合自由能,单位是 kcal/mol。数值越负,代表预测结合越强。
拿到结果后我建议做两件事验证流程是否正常:
第一,用同一个受体配体对在 CPU 版 Vina 上跑一次,对比 top 结合模式的能量排序。GPU 版本与原版评分函数一致的情况下,两者结果不会逐位完全相同,但前几个模式应该基本吻合。如果连能量范围都差出好几个数量级,那就要检查是不是输入文件或者盒子设置出了问题。
第二,把输出的 PDBQT 用 PyMOL 打开,和目标蛋白活性位点的关键残基目测检查一下,看配体是不是真的落在盒子区域里,有没有明显的原子碰撞。这一步虽然原始,但能最快暴露盒子中心设置错误这类低级问题。
5. 批量虚拟筛选时怎么调用最稳
单任务跑通之后,你很快会面对真正的需求:一批配体全部要做对接。这时候怎么调用 GPU 版,直接决定任务能不能稳定跑完。
5.1 单进程批处理比多进程并行更省心
有的同学习惯写一个循环,把 GPU 命令在 shell 里并行跑十几份,以为这样能榨干显卡。实际表现往往是:显存不够、驱动报错、最终结果文件互相覆盖。
GPU 资源不适合像 CPU 任务那样用一堆进程来堆吞吐。Vina-GPU 在处理多个配体时本身就有连续处理的能力,更合理的方式是让一个 GPU 进程持续工作。你可以把配体文件按要求准备好,让程序按批次读取。如果 2.1 版本提供了批处理模式,优先用批处理;没有的话,用脚本串行循环处理也比盲目并行的稳定性好。
5.2 小规模试跑、日志拆分与断点续跑
正式跑大库之前,一定先抽 50-100 个配体做小规模试跑,目的有三个:
一是估算总耗时。比如 100 个配体跑了 15 分钟,那 2 万个配体大概就是 50 小时左右,据此决定要不要分配成多个子任务。
二是确认没有哪个配体格式特殊,会让程序中途退出。
三是验证输出文件能正常写出、日志能记录下来。
批量任务处理时,日志最好拆到每个任务文件里。一个简单的方式是每跑一个配体,就把标准输出重定向到独立日志:
bash复制./vina --receptor receptor.pdbqt \
--ligand "lig_${i}.pdbqt" \
--config conf.txt \
--out "out_${i}.pdbqt" > "log_${i}.txt" 2>&1
这样万一中间某个配体导致程序异常,你能精确定位是哪一个,处理完这个坏文件后直接从断点继续,而不是从头再来。
5.3 显存占用与任务拆分的平衡
一个容易忽略的事实是:配体分子量大、可旋转键多的情况下,单个任务占用的显存和时间都远超普通分子。有些大配体甚至比一个小分子慢几十倍,这会拖慢整个批处理进度。
我的做法是先按配体分子量或可旋转键数目做预分组,把简单的任务和复杂的任务分开跑。这样简单的上千个配体能快速完成,复杂分子单独跑时也不会把日志文件搅在一起,排查问题会清晰很多。
另外,如果你的机器有多张显卡,建议明确指定设备后再跑。双卡机器如果不指定,程序可能默认选到一张性能较差的卡或非目标卡。查看当前 OpenCL 设备列表可以用:
bash复制clinfo -l
然后根据 Vina-GPU 2.1 提供的设备参数指定。如果有多个 CUDA 设备,也可以用类似 CUDA_VISIBLE_DEVICES 的方式限定可见设备,但这只对 CUDA 后端有效,OpenCL 后端要看程序本身是否支持平台/设备索引。
6. 安装到运行路上最容易踩的几个坑
最后把这些年帮别人排查时反复遇到的问题集中写一遍。这些问题本身不难解决,但如果你没有经验,可能会在错误的方向上绕很久。
6.1 找不到 OpenCL 平台或设备
编译没问题,运行时却提示找不到平台/设备,这是 OpenCL 环境的老大难。
优先检查 /etc/OpenCL/vendors/ 目录下有没有 ICD 文件。如果目录为空或者文件缺失,驱动没有正确把自己注册为 OpenCL 实现。此时先不要慌着重装驱动,尝试:
bash复制sudo apt install --reinstall ocl-icd-libopencl1
对于 NVIDIA 卡,也可以查一下驱动包是否完整,部分精简安装的驱动不带 OpenCL 支持。确认 ICD 文件存在后,再跑 clinfo,通常就能看到设备。
6.2 GPU 结果与 CPU 版对不上
这不算 bug。GPU 版的打分内核和 CPU 版虽然源自同一套评分模型,但浮点计算顺序不同、随机数生成和并行归约方式不同,结果有微小差异是正常的。真正要关注的是整体分布和排名稳定性。
如果 GPU 跑出来的绝对能量和 CPU 版系统性差了一大截,比如差 2-3 个 kcal/mol 以上,那我建议重点检查是不是没有正确指定格点盒子,或者输入 PDBQT 文件有细微差异。你可以把两个版本跑同一个配体的输出文件用脚本提取打分,按序排名,再看排名的一致性。
6.3 盒子和配体库太大导致静默失败
所谓静默失败,就是程序跑着跑着突然退出,或者某个配体毫无输出了。这类情况大多和显存不够有关。GPU 分配显存失败时,很多程序不会像 CPU 程序一样给出清晰的 out of memory,而是直接终止,甚至表现为段错误。
排查时可以实时看显存占用:
bash复制nvidia-smi -l 2
如果批量任务跑到一半 GPU 显存突然占满然后程序退出,就要缩小盒子、降低单次批处理量,或者把特别大的体系单独处理。
6.4 多卡机器上的默认设备选择
多卡机器上最迷惑人的现象是:程序能跑,但速度和你预期的 GPU 型号完全不符。这是因为设备选择策略可能默认选了第一块卡,而那块卡可能是集显或者低端卡。
解决思路是先确认你的目标卡在设备列表里的编号,然后通过 Vina-GPU 2.1 的设备参数指定。如果程序不支持直接指定 OpenCL 设备索引,还有一种粗方法:临时把其他设备的 ICD 文件移走,只保留目标卡。这个方法比较暴力,但在某些老旧版本上确实有效。跑完后记得恢复文件。
最后再分享一个我自己的习惯:每次大任务跑完,第一件事不是看结果汇总,而是检查日志里有没有退出码异常、GPU 利用率是否出现过长时间为 0。GPU 利用率掉到 0 通常意味着程序卡在了 CPU 侧的转换或 I/O 上,这种时候与其加 GPU,不如检查输入文件解析和磁盘读写。把工具链从安装到验证的每一步都跑稳了,Vina-GPU 2.1 才会真正变成你虚拟筛选流程里的那把快刀。
