
入手RTX 5090那一刻我以为接下来就是快乐的“跑大模型”环节。结果装好驱动、部署好环境、用transformers加载Qwen2.5-7B一前向就报错CUDA error: no kernel image is available for execution on the device。查了日志发现是sm_120没有被当前PyTorch和FlashAttention的预编译库覆盖。这一句话把我从“新卡到手”直接变成“显卡调试员”。尤其是FlashAttention这个几乎是大模型长文本标配的优化工具在sm_120上如果不重新编译它根本不干活。这篇文章是我把RTX 5090 sm_120 FlashAttention组合从零调到能稳定跑通Qwen2.5-7B的全过程包括架构背景、版本搭配、源码编译、报错排查和性能观察。如果你也刚入手50系卡或者想在本地部署大模型这篇应该能帮你少走不少弯路。1. sm_120 到底卡了多少人的脖子架构背景与支持现状1.1 Blackwell 消费级 GPU 的计算能力sm_120 是什么NVIDIA 的架构代号和计算能力Compute Capability是两套系统。RTX 5090 用的是 Blackwell 架构但 Blackwell 本身是一个庞大的家族数据中心里的 B200、GB200 是 sm_100/sm_110而消费级的 RTX 50 系列则对应 sm_120。这个 sm_120 就是编译器眼里“RTX 5090 的指令集版本”。CUDA 代码编译的时候不能只写一个“架构名”而要明确到具体的 sm 版本比如 sm_80Ampere、sm_90Hopper、sm_120Blackwell消费级。为什么这么麻烦因为不同 sm 版本之间Tensor Core 的排列、指令调度方式、显存寻址粒度、甚至 warp 大小相关的组合都有差异。用通俗的话说同样一道菜有的是平底锅炒有的是铁锅炒火候和颠勺的手法是不同的。你不能拿一份专门为 A100sm_80编译好的 kernel 直接塞到 RTX 5090sm_120上硬要跑就会遇到“no kernel image”的错误或者更隐蔽的性能下降。很多人会把 compute capability 和 CUDA 版本混在一起。其实 compute capability 12.0 是 GPU 硬件能力等级CUDA 12.8 是软件工具链版本。只有软件版本足够高、且编译时把 sm_120 作为目标架构加入硬件能力才可能被用起来。1.2 你的 PyTorch 可能根本不认识这张卡我折腾的时候官方稳定版 PyTorch 预编译包主要覆盖 sm_70/sm_75/sm_80/sm_86/sm_90没有 sm_120。这导致torch.cuda.is_available()返回 Trueget_device_name()也正常但一执行矩阵乘法就报错。原因是 PyTorch 里没有为该算子的 sm_120 生成机器码运行时不知道把什么加载进 GPU。类似地FlashAttention 的 prebuilt wheel 也可能只覆盖到 sm_80/sm_90。于是你装了最新版 flash_attnimport 不报错一用就崩。所以第一步不是去改模型代码而是先确认环境里有没有 sm_120 的原生支持。最简单的验证import torch print(torch.__version__) print(torch.version.cuda) print(torch.cuda.get_device_capability(0)) print(torch.cuda.get_arch_list())如果 arch_list 里没有sm_120那你后面大概率会遇到编译或运行错误。我这里重装之后输出里能看到sm_120所以跑通一切顺利。1.3 判断工具链是否支持 sm_120 的快速方法除了上面还可以做一个矩阵乘法测试。用torch.randn创建两个矩阵在 GPU 上做乘法a torch.randn(2048, 2048, devicecuda) b torch.randn(2048, 2048, devicecuda) c a b torch.cuda.synchronize() print(c.sum().item())如果报错RuntimeError: CUDA error: no kernel image is available for execution on the device说明当前 torch 包不包含 sm_120 的 kernel。相反如果能正常算出结果说明至少 torch 原生算子能跑了。判断 FlashAttention 是否支持则直接用一个前向测试import torch from flash_attn import flash_attn_func q torch.randn(1, 2, 128, 64, dtypetorch.bfloat16, devicecuda) k torch.randn(1, 2, 128, 64, dtypetorch.bfloat16, devicecuda) v torch.randn(1, 2, 128, 64, dtypetorch.bfloat16, devicecuda) out flash_attn_func(q, k, v) print(out.shape)如果没有报错才说明编译产物可用。这个做法比只看import是否成功靠谱得多因为很多 wheel 没编译对应架构时 import 也可能正常。2. 环境搭建的版本组合驱动、CUDA、PyTorch 的“三角关系”2.1 驱动与 CUDA 版本先装对底层再谈编译我用的系统是 Ubuntu 22.04显卡是 RTX 5090。驱动方面请使用支持 Blackwell 的 570.xxx 或更新版本。不要偷懒用发行版源里那个老驱动那不是为 50 系准备的。安装后nvidia-smi输出类似----------------------------------------------------------------------------- | NVIDIA-SMI 570.124.06 Driver Version: 570.124.06 CUDA Version: 12.8 | ----------------------------------------------------------------------------- | 0 NVIDIA GeForce RTX 5090 On | 00000000:01:00.0 Off | N/A |其中 CUDA Version 12.8 是驱动支持的最大运行时版本并不代表你安装了 CUDA Toolkit。接下来为了源码编译 FlashAttention 和 PyTorch需要安装完整的 CUDA Toolkit 12.8并确保nvcc指向正确版本nvcc --version如果显示的是老版本需要检查PATH和LD_LIBRARY_PATH。通常安装完 CUDA Toolkit 后会在/usr/local/cuda-12.8下可以这样设置export PATH/usr/local/cuda-12.8/bin:$PATH export LD_LIBRARY_PATH/usr/local/cuda-12.8/lib64:$LD_LIBRARY_PATH这个“三角关系”里面驱动决定硬件能不能被操作系统找到CUDA Toolkit 决定编译出来的代码用什么指令级别PyTorch 决定运行时算子库和自动求导图。三层必须版本匹配。如果驱动太老即使装了新 CUDA Toolkit也会在运行时报driver is too old如果 CUDA Toolkit 版本不够编译时就不会生成 sm_120 的代码。2.2 PyTorch 的两种选择Nightly 轮子还是源码编译在 5090 刚出的那段时间官方 stable pip 包还不带 sm_120。两条路摆在你面前等 stable 更新或者用 nightly如果 nightly 也没有就自己编译。我自己先用 nightly 试试pip install --pre torch --index-url https://download.pytorch.org/whl/nightly/cu128装完再跑torch.cuda.get_arch_list()看到sm_120说明 torch 部分已经解决。如果你只需要跑推理到这里 PyTorch 就够用了。但如果你还需要 torchvision记得装同 source 的版本pip install --pre torch torchvision --index-url https://download.pytorch.org/whl/nightly/cu128如果 nightly 的包仍然没有sm_120或者你在生产环境需要固定版本不能追新再考虑源码编译。源码编译 PyTorch 很费时间我试过一次光是下载依赖和编译就用掉了半个下午期间还遇到 NCCL 版本和 cuDNN 版本不匹配的问题。后来我决定python 层用 nightlyCUDA C 层用源码编译 FlashAttention。选择逻辑是torch 本身作为底座nightly 已经覆盖了 sm_120没必要自己造轮子而 FlashAttention 是额外的扩展官方 wheel 没有覆盖新架构必须自己编译。这是实操中最经济的一条路。2.3 安装其他依赖时的连带坑这里要提transformers和accelerate。如果旧版本不支持新模型的 attention 类型加载时会警告 fallback 到 eager attention导致 FlashAttention 不生效。建议安装最新版pip install -U transformers accelerate sentencepiece对于 Qwen2.5 系列我用的是transformers4.45基本没问题。另外注意einops有时是 FlashAttention 的依赖但有些环境下没有自动装上运行时会报ModuleNotFoundError: No module named einops。建议直接pip install einops还有一个小坑在 Python 环境里之前如果装过旧版flash_attn后面源码编译前一定要先pip uninstall flash-attn否则 import 时加载的还是旧包容易让你误以为“重新编译没用”。干净环境永远比 patch 环境省时间。3. FlashAttention 源码编译与 sm_120 适配全记录3.1 拉源码前必须搞清的分支和版本矩阵FlashAttention 官方仓库的 README 其实写得很清楚不是所有分支都支持所有架构。旧版本如 v2.5.x 主要支持 Ampere 和 Hopper对 Blackwell 的 sm_120 支持是在后面的版本才加入的。我用的命令git clone https://github.com/Dao-AILab/flash-attention.git cd flash-attention git checkout v2.7.1 # 或者直接使用 main 分支拉完源码之后别急着编译先看setup.pygrep -n sm_120\|compute_120 setup.py我当时用 v2.6.3 检查时没有输出切到 v2.7.1 后就有了。如果你当前分支没有可以先去 GitHub 的 issue 搜sm_120通常会在新 tag 里修复。这个检查能帮你避免白跑几个小时的编译。3.2 TORCH_CUDA_ARCH_LIST 和 MAX_JOBS 的调参心得源码编译的核心就是通过环境变量告诉编译器目标架构。对 RTX 5090就是要设置export TORCH_CUDA_ARCH_LIST12.0 export MAX_JOBS8这里有人会问为什么不写sm_120而是12.0因为 PyTorch 的构建系统期望的是 compute capability 的数字表示12.0会自动映射到sm_120/compute_120。如果你还要兼容后续驱动对 PTX 的 JIT可以写成12.0PTX不过这会增加编译产物大小。我只在本机用所以就12.0。MAX_JOBS控制的是 Ninja 并行编译的 job 数。它和 CPU 核心数、内存大小都有关系。我的机器是 16 核 64GB 内存设置成 8 编译大概 20 多分钟如果设置成 2可能要等一个多小时。但如果你内存只有 32GB并行太多容易把内存打满被 OOM killer 杀掉。实际编译命令python setup.py build之后安装pip install .推荐先用build单独编译看日志比pip install .更直接。3.3 我遇到的编译报错和解决办法我不是第一次就编译成功的整个过程遇到三个比较典型的错误。第一个Unsupported gpu architecture compute_120。原因就是源码包版本太旧setup.py里没有 12.0 这个架构选项。这时候不需要硬改而是去更新源码分支。第二个fatal error: cudnn.h: No such file or directory。因为我虽然装了 CUDA Toolkit 12.8但 cuDNN 没装或者CUDNN_ROOT没设置。FlashAttention 编译时需要 cuDNN所以我按官方文档装了一遍 cuDNN 8.9/9.x并让CUDNN_ROOT指向正确路径export CUDNN_ROOT/usr/local/cuda-12.8第三个编译过程中ninja: build stopped: subcommand failed但完整日志被刷掉了。我把编译输出重定向到文件再翻日志python setup.py build build.log 21 tail -n 100 build.log最后定位到是 gcc 版本和-march参数冲突换用 gcc-12 后解决。需要强调这些报错不一定每个人全遇到但思路是通用的先确认架构列表再确认依赖路径最后分步排查日志。最忌讳的是报错后重新编译也不看日志直接把整台机器 reset。3.4 验证 FlashAttention 没有“假编译”编译安装结束后我按 1.3 里的小脚本跑了一遍确认输出正常。然后在真实模型里启用model AutoModelForCausalLM.from_pretrained( model_dir, torch_dtypetorch.bfloat16, attn_implementationflash_attention_2, device_mapcuda )如果加载时没有警告说“FlashAttention 不可用回退到 eager”说明已经生效。为了进一步确认我还会用torch.profiler抓一次前向在 kernel 列表里能看到和flash相关的算子。看到它这颗“定心丸”才算吃下去。4. 跑通 Qwen2.5-7B推理性能、显存占用和稳定性实测4.1 下载模型与加载方式ModelScope 替代 HuggingFace现在到大模型实际运行环节。我选了 Qwen2.5-7B-Instruct它对中文友好而且 70 亿参数在单卡 5090 上很从容。模型获取方面如果网络环境方便可以直接用 HuggingFace如果不方便我会用 ModelScope 的命令行工具或 Python 接口下载from modelscope import snapshot_download model_dir snapshot_download(Qwen/Qwen2.5-7B-Instruct)下载完成后加载模型时建议直接用model_dir。用torch_dtypetorch.bfloat16是因为 RTX 50 系的新卡更适合 bf16而且 Qwen 权重本身就是 bf16 预训练。加载方式from transformers import AutoModelForCausalLM, AutoTokenizer import torch tokenizer AutoTokenizer.from_pretrained(model_dir) model AutoModelForCausalLM.from_pretrained( model_dir, torch_dtypetorch.bfloat16, attn_implementationflash_attention_2, device_mapcuda, ) model.eval()4.2 实际跑推理的显存/速度数据然后写一个简单生成函数input_text 你好请介绍一下你自己。 inputs tokenizer(input_text, return_tensorspt).to(cuda) out model.generate( **inputs, max_new_tokens256, do_sampleFalse, ) print(tokenizer.decode(out[0], skip_special_tokensTrue))这个代码跑通后我顺手统计了一下输入 512 token、输出 256 token 的普通问答BF16 权重加载后初始显存约 15GB生成过程中峰值约 18GBRTX 5090 的 32GB 完全够甚至还能再开几个并发但你要控制 KV cache。速度上平均 45~55 tokens/s具体跟电源状态和散热有关但整体比朋友的 4090 要快一些。这里补充一个对比场景原生 SDPA (不使用FlashAttention)FlashAttention 2峰值显存(2048 ctx)约22GB约18GB生成速度(512 ctx, 256 output)约32 tokens/s约48 tokens/sGPU 利用率稳定性波动较大更稳定这组数据是基于我单卡测试的大概值不同驱动/BIOS 下会有差异。但能明显看出 FlashAttention 在长上下文和吞吐上的收益。4.3 从“能跑”到“跑好”FA3、量化、vLLM 的后续选择跑通单模型后我尝试了三个进阶方向。第一个是 FlashAttention 3。它针对 Hopper/Blackwell 有更强的 Tensor Core 优化但当时在 sm_120 上的支持还比较挑版本需要切源码分支并且对某些 PyTorch nightly 版本有限制。如果你只是做推理FA2 已经够用想做训练/长序列可以保持关注。第二个是 4bit 量化。用bitsandbytes加载时显存能降到 9GB 左右但注意 bitsandbytes 对 Blackwell 的适配也需要时间。如果你遇到CUDA error: no kernel image is available很可能是量化算子没有 sm_120 版本这时候可以回退到 bf16或者换用AutoGPTQ等方案。第三个是 vLLM 服务化。vLLM 对并发请求吞吐更适合但它内部也会调 FlashAttention所以同样的先确保 sm_120 支持。我在本地试过一次vllm serve吞吐更高但配置更复杂适合把所有代码逻辑跑通后再上。4.4 稳定性问题总结与最终配置清单最后整理一下踩过的稳定性坑。第一显存不足并不代表物理显存不够很多情况下是因为 attention 没有用 FlashAttention导致 KV cache 占用被放大。先把attn_implementation设置对再谈优化。第二生成过程中偶发device-side assert triggered通常是 tokenizer 或模型版本不一致。升级 transformers 和模型仓库代码后明显减少。第三一定不要忽略环境变量的持久化。编译完 FlashAttention 后我把TORCH_CUDA_ARCH_LIST和MAX_JOBS写进了 shell 的~/.bashrc这样后续重新编译不会忘记。同时也把已安装的 python 包 freeze 到 requirements 文件里pip freeze requirements_5090.txt最终配置清单如下组件版本/参数操作系统Ubuntu 22.04 LTS显卡驱动570.124.06CUDA Toolkit12.8PyTorch2.7.0.dev (nightly cu128)FlashAttention2.7.1 本地编译TORCH_CUDA_ARCH_LIST12.0transformers4.45模型Qwen/Qwen2.5-7B-Instruct最后分享一个小习惯跑通后立刻把当前环境 freeze 下来这不难但能让你三周后重装环境时少走很多弯路。这次折腾 RTX 5090 最大的收获不是那几十 tokens/s 的生成速度而是真正搞清楚了新硬件出来之后工具链的适配往往比显卡本身更值得提前关注。希望这份记录能帮到你。