Ubuntu下fused与upfirdn2d模块缺失?CUDA扩展编译全攻略
发布时间:2026/10/26 4:18:43 锦皓数字建站

1. 这个报错到底在说什么如果你在 Ubuntu 上跑过一些图像生成、超分辨率或者风格迁移相关的开源项目大概率见过这两行红字ModuleNotFoundError: No module named fused和ModuleNotFoundError: No module named upfirdn2d。第一次遇到的人往往会愣一下因为去 PyPI 上搜这两个名字基本搜不到什么正经的包pip install fused装出来的东西跟项目要的完全不是一回事。这两个模块不是通用依赖而是特定项目里自带的CUDA 扩展算子通常以fused_act、upfirdn2d这样的目录形式躺在源码里需要现场编译才能用。我在 Ubuntu 上部署这类项目不下十几次从 18.04 到 22.04 都踩过这两个报错几乎每次都会出现而且报错信息极其简短不给任何线索。它本质上不是缺一个包而是缺一个编译好的动态库。你pip install再多东西也没用因为 Python 解释器在sys.path里找不到名为fused或upfirdn2d的模块而这两个模块本应由项目自带的setup.py编译生成.so文件后才会出现。这篇文章面向的是所有在 Linux 环境下折腾这类项目的人不管你是刚接触 CUDA 编译的新手还是已经能看懂nvcc报错但被这两个模块卡住的老手。我会把这两个模块是什么、为什么缺、编译时为什么会失败、失败后怎么一步步排查讲透最后给出一套可以直接照着敲的完整流程。核心关键词就三个fused模块缺失、upfirdn2d模块缺失、CUDA 扩展编译。读完之后你应该能做到看到这个报错不再慌知道先查什么、再改什么、最后怎么验证。需要先说明一点这两个模块的编译强依赖本机的 CUDA 工具链和 PyTorch 版本匹配情况所以下面的方案里我会反复强调先确认环境再动手因为绝大多数编译失败都源于版本错配而不是代码本身有问题。2. 先搞清楚这两个模块是什么来头2.1 fused 模块融合激活函数的 CUDA 实现fused在多数项目里对应的是fused_act或fused_act.py它实现的是一个融合了 LeakyReLU 的激活操作通常叫FusedLeakyReLU。为什么叫融合因为在生成对抗网络这类模型里激活函数后面经常跟着一个偏置项或者缩放操作如果分成两步做就要多读写一次显存把它们合并成一个 CUDA kernel一次算完显存带宽省下来了速度也就上去了。这个模块的源码结构一般是这样一个fused_act.py负责 Python 侧的接口和torch.autograd.Function的定义一个fused_bias_act.cpp和fused_bias_act_kernel.cu负责 C 与 CUDA 的具体实现再加一个setup.py把它们编译成fused_act_cuda这样的扩展。Python 侧通过from torch.utils.cpp_extension import load或者直接import fused_act_cuda来加载。关键点在于这个模块不是 pip 包是随项目源码分发的。所以报No module named fused说明要么项目里根本没有编译产物要么编译产物放错了位置要么 Python 找不到它。2.2 upfirdn2d 模块上采样与滤波的联合算子upfirdn2d这个名字拆开看就明白了up上采样、fir有限冲激响应滤波、down下采样、2d二维。它实现的是一个二维信号处理里的经典操作——先对图像做零插值上采样再用一个 FIR 滤波器做卷积最后按需下采样。在 StyleGAN 系列及其衍生项目里这个算子被用来做高质量的重采样比普通的双线性插值效果更细腻。它的源码结构和fused类似upfirdn2d.py是 Python 接口upfirdn2d.cpp和upfirdn2d_kernel.cu是底层实现setup.py负责编译。同样地它也不是能从 PyPI 装到的包。2.3 为什么这两个模块总是成对出现因为它们通常来自同一个代码库比如某些图像生成项目的op/目录下会同时放着fused_act和upfirdn2d两个子目录共用一个顶层setup.py或者各自有独立的编译脚本。项目作者把这两个性能敏感的算子抽出来用 CUDA 重写其余部分用纯 PyTorch所以你在requirements.txt里看不到它们但跑起来就缺。注意有些项目会把编译好的.so文件一起打包进仓库这种情况下你直接跑可能不报错但一旦换了 CUDA 版本或者 PyTorch 版本加载旧.so会报 undefined symbol 之类的错反而更难查。所以我的习惯是拿到项目先删掉所有预编译产物自己重新编一遍。3. 报错背后的四类真实原因3.1 原因一压根没编译源码目录里只有 .py 没有 .so这是最常见的情况。你 clone 下来的仓库里fused_act目录下只有fused_act.py、fused_bias_act.cpp、fused_bias_act_kernel.cu和setup.py没有任何.so文件。Python 执行import fused_act时解释器在目录里找不到fused_act.so或fused_act.cpython-*.so于是报模块不存在。判断方法很简单进到模块目录里ls一下ls -la op/fused_act/如果只看到.py、.cpp、.cu、setup.py没有.so那就是没编译。这时候你需要手动执行编译而不是去 pip 装东西。3.2 原因二编译了但装错了位置有些人跑过python setup.py install或者pip install .编译是成功了但产物被装进了当前 Python 环境的site-packages里而项目代码是通过相对路径from op import fused_act来导入的两边对不上照样报错。还有一种情况是编译产物生成在了build/目录下但项目期望它在源码目录同级。这种编了但没放对地方的问题最迷惑人因为你会看到编译日志全是成功的但运行还是报错。3.3 原因三CUDA 工具链缺失或版本不匹配编译 CUDA 扩展需要本机有nvcc而且nvcc的版本要和 PyTorch 编译时用的 CUDA 版本大致匹配。如果你装的是 CPU 版 PyTorch那torch.utils.cpp_extension根本没法编译 CUDA 代码会直接报错说找不到 CUDA。如果 PyTorch 是 cu118 编译的而你本机nvcc是 11.3编译时可能能过但加载时会报符号不匹配。确认方法nvcc --version python -c import torch; print(torch.version.cuda); print(torch.__version__)两个版本号要能对上大版本比如都是 11.8 或者都是 12.1。差一个小版本通常没事差一个大版本基本必挂。3.4 原因四gcc/g 版本过高导致编译报错Ubuntu 22.04 默认的 gcc 是 11 或 12而一些老项目的 CUDA 代码在 gcc 10 以上会报各种语法错误典型的是error: identifier AT_CHECK is undefined或者跟std::相关的模板报错。这类错误会让编译中途失败.so根本没生成于是运行时表现为模块缺失。这种情况的迷惑性在于报错发生在编译阶段但如果你没仔细看编译日志只看到最后运行时的No module named就会误以为是导入问题。4. 编译前的环境自查清单动手之前先把下面这几项确认一遍能省掉后面一大半的排查时间。我把它整理成表格你逐项打勾就行。检查项命令期望结果不满足时的处理nvcc 是否存在which nvcc输出路径如/usr/local/cuda/bin/nvcc安装 CUDA Toolkitnvcc 版本nvcc --version与 PyTorch CUDA 版本大版本一致调整 CUDA 或换 PyTorchPyTorch 是否 CUDA 版python -c import torch; print(torch.cuda.is_available())输出True重装 CUDA 版 PyTorchPyTorch CUDA 版本python -c import torch; print(torch.version.cuda)与 nvcc 匹配同上gcc 版本gcc --version一般不高于 10老项目安装低版本 gcc 并切换显卡驱动nvidia-smi正常输出显卡信息更新驱动这里重点说 gcc 那一项。很多教程不提这个但它是老项目编译失败的头号元凶。Ubuntu 22.04 上装 gcc-9 的命令是sudo apt install gcc-9 g-9然后编译时通过环境变量指定CCgcc-9 CXXg-9 python setup.py build_ext --inplace这样就不用动系统默认的 gcc避免影响其他软件。提示如果你不确定项目对 gcc 版本的要求先用默认 gcc 编一次看报错里有没有gcc相关的版本提示。CUDA 11.x 官方支持到 gcc 10CUDA 12.x 支持到 gcc 12超出范围就容易出问题。5. 手把手编译 fused 与 upfirdn2d5.1 找到正确的编译入口先确认项目结构。典型的布局是项目根目录下有一个op文件夹里面分fused_act和upfirdn2d两个子目录每个子目录有自己的setup.py。也有项目在根目录放一个统一的setup.py通过参数区分。你先find一下find . -name setup.py -not -path */node_modules/*找到跟fused_act或upfirdn2d同级的那个setup.py那就是编译入口。如果两个模块各有各的setup.py就分别进目录编译。5.2 编译 fused_act进入fused_act目录先看一眼setup.py内容确认它用的是CUDAExtensionfrom setuptools import setup from torch.utils.cpp_extension import BuildExtension, CUDAExtension setup( namefused_act_cuda, ext_modules[ CUDAExtension(fused_act_cuda, [ fused_bias_act.cpp, fused_bias_act_kernel.cu, ]) ], cmdclass{build_ext: BuildExtension} )确认无误后执行python setup.py build_ext --inplace--inplace是关键它让编译产物直接生成在当前目录而不是装到site-packages。编译成功后你会看到fused_act_cuda.cpython-38-x86_64-linux-gnu.so这样的文件出现在当前目录。如果项目用的是load()方式动态编译有些代码在fused_act.py里直接调load(namefused_act, sources[...])那第一次 import 时就会自动编译编译缓存放在~/.cache/torch_extensions/下。这种方式的好处是不用手动跑 setup坏处是编译错误被吞在 import 里不好看日志。我一般会先手动跑一次 setup 确认能编过再让代码走load()。5.3 编译 upfirdn2d流程完全一样进目录后python setup.py build_ext --inplace产物是upfirdn2d_cuda.cpython-*.so。这里有个细节要注意upfirdn2d的 CUDA kernel 里经常用到at::cuda::getCurrentCUDAStream()这类 API如果 PyTorch 版本较新某些旧写法会报 deprecated 警告甚至错误。遇到这种情况通常需要把源码里的旧 API 换成新写法或者降 PyTorch 版本。具体换法我在第 6 节讲。5.4 验证编译结果编译完别急着跑主程序先单独验证模块能不能导入python -c import fused_act_cuda; print(fused ok) python -c import upfirdn2d_cuda; print(upfirdn2d ok)注意这里导入的是带_cuda后缀的扩展名而不是fused或upfirdn2d。因为 Python 侧的fused_act.py会去 import 这个扩展你直接 import 扩展能过说明编译产物没问题。如果这一步报ImportError: libcudart.so.11.0: cannot open shared object file那是动态库路径没配好需要把 CUDA 的 lib 目录加进LD_LIBRARY_PATHexport LD_LIBRARY_PATH/usr/local/cuda/lib64:$LD_LIBRARY_PATH5.5 让项目正确找到模块编译产物在op/fused_act/下而项目代码可能写的是from op import fused_act。这时候fused_act.py里的import fused_act_cuda能不能找到.so取决于.so是否和fused_act.py在同一目录。--inplace保证了这一点所以通常没问题。但如果你遇到ModuleNotFoundError: No module named fused_act_cuda说明.so没生成在预期位置。检查两点一是编译时是否真的加了--inplace二是fused_act.py里 import 的名字和setup.py里CUDAExtension的第一个参数是否一致。名字对不上是最常见的低级错误。6. 编译报错逐条排查实录6.1 nvcc 找不到No CUDA runtime is found完整报错通常是OSError: No CUDA runtime is found或者CUDA_HOME environment variable is not set。这说明torch.utils.cpp_extension找不到 CUDA。先确认nvcc在 PATH 里如果不在手动指定export CUDA_HOME/usr/local/cuda export PATH$CUDA_HOME/bin:$PATH然后再编译。如果nvcc确实装了但还是报这个可能是 PyTorch 装成了 CPU 版torch.version.cuda输出None那就只能重装 CUDA 版 PyTorch。6.2 gcc 版本过高unsupported GNU version报错长这样error: #error -- unsupported GNU version! gcc versions later than 10 are not supported!。这是 CUDA 头文件里的版本检查。解决办法有两个装低版本 gcc 并用CC/CXX指定或者给 nvcc 加-allow-unsupported-compiler参数。后者不推荐因为可能编出运行时崩溃的库。稳妥做法还是装 gcc-9sudo apt install gcc-9 g-9 CCgcc-9 CXXg-9 python setup.py build_ext --inplace6.3 符号未定义undefined symbol编译能过但 import 时报undefined symbol: _ZN2at6detail...。这几乎一定是 PyTorch 版本和编译时用的版本不一致导致的。比如你用 PyTorch 2.0 编译但运行环境里是 1.13ABI 对不上。解决办法是确保编译和运行在同一个 Python 环境、同一个 PyTorch 版本下进行。用 conda 或 venv 隔离环境能有效避免这个问题。6.4 显存不足out of memory during compilation编译 CUDA kernel 时nvcc会吃不少内存尤其是upfirdn2d这种模板展开多的代码小内存机器比如 8G 的云主机可能直接 OOM 被 kill。表现是编译进程突然消失没有任何错误信息。解决办法是加 swap或者用MAX_JOBS1限制并行编译数MAX_JOBS1 python setup.py build_ext --inplace这个参数很多人不知道但它在低配机器上非常管用能把峰值内存压下来。6.5 常见问题速查表报错关键词大概率原因快速处理No module named fused没编译或产物不在路径进目录build_ext --inplaceNo module named upfirdn2d同上同上No CUDA runtime is foundCUDA_HOME 未设或 CPU 版 PyTorch设 CUDA_HOME换 PyTorchunsupported GNU versiongcc 过高装 gcc-9 并指定 CC/CXXundefined symbolPyTorch 版本不一致统一编译与运行环境Killed编译 OOM加 swap 或MAX_JOBS1libcudart.so not found动态库路径缺失设LD_LIBRARY_PATH7. 几个容易忽略的实操细节7.1 编译缓存要清干净torch.utils.cpp_extension会把编译中间产物缓存在~/.cache/torch_extensions/下。如果你改了源码或者换了 CUDA 版本旧缓存可能导致编译结果不对。我的习惯是每次大改环境后先清缓存rm -rf ~/.cache/torch_extensions/然后再编译。不清缓存有时候会出现明明改了代码但行为没变的诡异现象。7.2 虚拟环境隔离是底线这类项目对 PyTorch 和 CUDA 版本极其敏感千万别在系统 Python 里直接装。用 conda 建一个独立环境把 PyTorch 版本锁死编译和运行都在这个环境里做。我见过太多人因为系统里同时装了多个 PyTorch 版本编译时用了一个、运行时用了另一个排查半天查不出原因。7.3 源码里的旧 API 要顺手改如果编译时报AT_CHECK is deprecated或者Tensor.data is deprecated说明源码用的是老版 PyTorch API。新版 PyTorch 里AT_CHECK换成了TORCH_CHECKdata换成了data_ptr。这些改动量不大但必须改否则编译不过。改的时候注意保持参数顺序一致别改出新 bug。7.4 编译成功不等于运行成功.so生成只是第一步真正跑起来还可能遇到 kernel 启动失败、显存越界等问题。建议编译完后先用一个极小的输入跑一次前向比如torch.randn(1, 3, 8, 8).cuda()确认算子能正常执行再上完整模型。这样能把编译问题和模型逻辑问题分开排查。8. 我踩过的坑与经验总结最早一次遇到这个报错是在一台 Ubuntu 20.04 的机器上当时第一反应是pip install fused装完发现是个完全无关的包浪费了半小时。后来才明白这类模块必须从源码编译。这个教训让我养成了一个习惯拿到任何项目先看setup.py和op/目录确认有没有需要现场编译的扩展而不是无脑pip install -r requirements.txt。第二个坑是 gcc 版本。有次在 Ubuntu 22.04 上编译报了一堆看不懂的模板错误查了半天才发现是 gcc 12 太新。装了 gcc-9 之后一次过。从那以后我编译任何 CUDA 扩展前都会先gcc --version看一眼超过 10 就先装低版本备用。第三个坑是编译 OOM。在一台 8G 内存的云主机上编upfirdn2d进程直接被 kill日志里啥也没有。后来加了 4G swap 并用MAX_JOBS1才顺利编完。所以低配机器上编译 CUDA 扩展内存和 swap 要提前规划好。最后一个体会是这两个报错看着吓人其实本质就是编译没做或编译没做对。把环境对齐、把编译跑通、把产物放对位置问题就解决了。真正花时间的不是解决本身而是定位到底是哪一环出了问题。所以我建议你按第 4 节的清单逐项确认再按第 5 节编译最后用第 6 节的速查表对照报错基本能覆盖九成以上的情况。剩下的一成多半是源码本身跟你的 PyTorch 版本不兼容那就得具体问题具体改了。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。