最近帮某实验室收拾一批服务器环境,里面就有一台 Intel B60 GPU 服务器。上手之前,团队里几个人习惯性按 NVIDIA 那套流程来:装 CUDA、配 cuDNN、对着nvidia-smi看状态。结果发现这条路完全走不通——Intel GPU 的 Linux 环境搭建逻辑跟 CUDA 生态根本是两个世界。这篇东西是我从零把 B60 这台机器在 Ubuntu 22.04 上跑通的全过程,覆盖硬件确认、系统安装、驱动栈、oneAPI、PyTorch 适配、验证链路和踩坑记录。适合刚拿到 Intel 系列 GPU 服务器、准备在上面跑 AI 推理或 HPC 任务的运维和算法同学参考。
我会尽量把“为什么这么做”也讲清楚,而不是只丢命令。毕竟环境搭建这件事,真正卡住人的往往不是命令本身,而是对软件栈结构的理解。
1. 先把家底摸清楚:B60整机硬件确认与BIOS要点
1.1 与NVIDIA服务器不同的第一印象
B60 这台机器,从外观和定位上就和常见的 NVIDIA GPU 服务器有区别。拿我这台来说,整机是标准 2U 服务器形态,上面装的是 Intel B60 加速卡,属于新一代 Xe 架构,配了 16GB 显存。你手里那台具体规格可能不一样,但整个排查思路是通用的。
开机后先用系统命令确认硬件,不要凭感觉:
lspci | grep -i display lscpu sudo dmidecode -t memory | grep -E "Size|Type"lspci里看到 VGA 兼容控制器是 Intel 的 ID,说明主板层面已经识别到这张卡。如果这里就空着,后面系统层面大概率也会有问题。内存和 CPU 信息顺手记一下,后面做性能基线、跑 AI 推理时有用。B60 这类卡在服务器里通常是辅助计算角色,所以主机内存带宽、PCIe 通道数都会直接影响到最终能跑多快。
1.2 进系统前我给你列的三项检查
很多人在这一步着急,插上显卡就装系统,结果后面反复折腾。我在装系统前做过三次检查,你可以照着做:
第一项:确认固件和启动模式。Ubuntu 22.04 对 UEFI 支持很成熟,建议直接用 UEFI 模式装。Legacy BIOS 模式在部分主板上会跟显卡的 Option ROM 冲突,虽然概率不高,但没必要冒险。
第二项:Resizable BAR。这是很多人忽略的一点。B60 有 16GB 显存,如果主板没开 Resizable BAR,CPU 访问显存时只能按 256MB 窗口寻址,性能损失非常明显。具体路径通常在 BIOS 的 PCIe 或 Advanced 菜单里,各家的叫法不一样,搜Resizable BAR、Re-Size BAR Support或Above 4G Decoding。记住一个原则:能开就开。
第三项:Secure Boot。如果你的服务器主要用于内部实验,我建议先把 Secure Boot 关掉。倒不是说 Secure Boot 本身不好,而是 Ubuntu 对第三方驱动模块的签名链处理比较繁琐,缺一个环节就加载失败,排查起来很费时间。生产环境如果强制要求开,也能做,但需要在模块签名上多花功夫,后面第 6 节我会提到。
这三项检查完,再进系统,可以省掉后面一多半的坑。BIOS 设置这种东西没有标准答案,但方向是对的:让系统尽量裸奔式地识别硬件,先把环境跑通,再逐步加安全加固。
2. Ubuntu 22.04安装、内核升级与驱动模块准备
2.1 为什么锁定22.04而不是最新版本
Intel 这套 GPU 软件栈有一个特点:对内核版本敏感。太老的内核不认识新卡,太新的内核又可能跟某些用户态组件步调不一致。Ubuntu 22.04 LTS 是当前最主流的服务器发行版之一,Intel 官方对它的适配投入也最多,所以锁定 22.04 是稳妥选择。
但要注意,22.04 刚发布时默认内核是 5.15,对于 B60 这种较新的 Xe 架构卡来说,5.15 大概率认不全。解决方式不是换发行版,而是把内核升级到 HWE(Hardware Enablement)版本。HWE 内核相当于把新硬件支持反向移植到 LTS 版本上,这比整个系统滚动升级可控得多。
2.2 装完系统后的内核与固件动作
系统安装过程本身不复杂,ISO 写入 U 盘后,分区、网络、用户这些按常规流程走就行。有一点建议:如果你的服务器不跑图形界面,干脆别装 GNOME 等桌面环境,省下的内存都给计算任务。
装完系统后,第一件事不是装驱动,而是把内核和固件升到合理版本:
sudo apt update && sudo apt upgrade -y sudo apt install -y linux-generic-hwe-22.04 linux-firmware sudo reboot重启后用uname -r确认内核版本。我这边升级完是 6.5 系列,B60 已经被内核正确识别。linux-firmware这个包必须装,Intel GPU 的 GUC/HUC 固件都在这里面。缺了它,驱动能加载但硬件起不来,那种状态非常隐蔽。
2.3 驱动模块的选择:i915还是xe
Intel GPU 在 Linux 内核里有两条驱动路径:老的i915和新的xe。i915覆盖范围广、历史久,但主要是为核显和旧款独显设计的;xe是专门为新一代 Xe 架构准备的,B60 这类卡应该走xe驱动。
你不需要手动卸载谁,Ubuntu 会根据 PCI ID 自动选择加载哪个模块。有时可能需要显式声明一下,在/etc/modprobe.d/下建一个配置文件:
echo "options xe force_probe=xxxx" | sudo tee /etc/modprobe.d/xe.confxxxx是你从lspci -nn里看到的 Intel 设备 ID。这条配置的作用是让xe驱动主动接管 B60,避免系统默认走i915。实际操作中我这边不加也能识别,但如果你发现内核日志里一直出现i915但不认卡,可以试试这个办法。
内核这一步做完,系统层面已经能看到硬件。但别急着高兴,CPU 能看到显卡和真正能用它做计算,中间还隔着好几层软件。
3. 装齐GPU运行时:Level Zero、OpenCL与媒体驱动
3.1 先把Intel GPU软件栈的分层讲明白
如果你只用过 NVIDIA 的机器,第一次接触 Intel GPU 会很不习惯。NVIDIA 那套是驱动、CUDA runtime、cuBLAS 等一整套闭环;Intel 这边则是内核态驱动、固件、用户态 runtime、编译器、数学库各自独立安装协同工作。
简单来说,内核里的xe模块只是让操作系统把 B60 当成一个 PCIe 设备管起来,真正要执行计算,还需要用户在系统层面提供三样东西:
- Level Zero:Intel GPU 的底层计算接口,类似 CUDA Runtime 的角色,是高性能路径。
- OpenCL ICD:通用并行计算接口,偏兼容性和通用性。
- 媒体驱动/VA-API:视频编解码要用的栈,如果只跑 AI 计算可以暂时不装,但做多模态、视频数据处理时会用到。
这三样跟内核驱动的关系,可以类比成:内核驱动是普通话的发音规则,用户态 runtime 是新华字典。系统光会发音不够,得有一本字典才能把字组合成词。
3.2 添加官方软件源并安装运行时组件
Ubuntu 自带仓库里也有一些 Intel 图形相关的包,但版本往往比较老。建议添加 Intel 官方 GPU 软件源,用官方打包好的版本。操作流程是:下载官方 GPG key、写入 sources 配置、更新索引、安装包。具体仓库地址以 Intel 官方文档当时给出的为准,但配置逻辑大致如下:
wget -qO - https://repos.intel.com/gpu/ubuntu/ | sudo gpg --dearmor -o /usr/share/keyrings/intel-gpu-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/intel-gpu-archive-keyring.gpg] https://repos.intel.com/gpu/ubuntu jammy unified" | sudo tee /etc/apt/sources.list.d/intel-gpu.list sudo apt update然后安装核心组件:
sudo apt install -y intel-opencl-icd intel-level-zero-gpu intel-gpu-tools intel-media-driverintel-gpu-tools里的intel_gpu_top是后面排查性能问题时必须用的工具。安装过程如果遇到依赖冲突,先确认是否开了多个第三方源,比如某些源把libigc或libigfxcmrt的版本拉高了,导致兼容性检查失败。这种问题在混合源环境下很常见,处理方式是固定用 Intel 官方源,或临时把不相关源注释掉。
3.3 装完后的第一轮验证:设备节点与内核实测
装完运行时组件,先做一次快速冒烟测试:
ls -l /dev/dri正常输出应该是两个设备节点:card0和renderD128。card0对应显示输出,renderD128是通用计算节点,应用程序主要走这个。如果只有card0没有renderD128,说明 GPU 的计算引擎没被正确初始化,大概率是固件问题,后面踩坑部分会展开说。
接着看内核日志:
sudo dmesg | grep -i xe正常能看到类似xe 0000:..: [drm] Xe device ... initialized的日志。如果这里报固件加载失败或初始化超时,就要回到固件环节排查。
这一层验证通过后,系统层面已经“看到”并能“驱动”B60 了。但这时候你还没法跑 PyTorch——AI 框架还需要另一套更上层的软件栈。
4. 搭AI推理环境:oneAPI Base Toolkit与PyTorch/IPEX
4.1 Intel GPU不认CUDA,那AI训练靠什么
这是很多算法工程师最困惑的地方。习惯了 CUDA,拿到 Intel GPU 后第一反应是找 NVIDIA 的 CUDA 生态适配层,但 Intel GPU 不支持 CUDA,也不会去兼容 CUDA。Intel 走的是 oneAPI 这条路:用 SYCL 作为跨平台编程模型,用 oneDNN、oneMKL 这类库提供底层算子和数学能力。
对于 PyTorch 用户,好消息是官方和 Intel 社区一起维护了一个扩展包intel-extension-for-pytorch,简称 IPEX。装上之后,PyTorch 里会多出xpu这种设备类型,你可以像写cuda一样写xpu,大部分算子会自动调度到 B60 上。
这套关系的理解方式很简单:oneAPI 是 Intel GPU 的“生态底座”,IPEX 是 PyTorch 用户接触这个底座的最小切口。如果你不做底层 kernel 开发,不需要学 SYCL 语法,但至少要知道掉到深层问题时往哪查。
4.2 安装oneAPI Base Toolkit的完整操作
oneAPI Base Toolkit 包含编译器、数学库、通信库等一堆东西,体积不小。如果只跑 PyTorch 推理,其实不需要全装,但建议装一份,因为后续用sycl-ls验证设备、编译 SYCL 程序、跑官方样例都会用到。
安装方式走 apt 源比较省事:
wget -O- https://apt.repos.intel.com/oneapi/setup.sh | sudo bash sudo apt install -y intel-basekit装完后执行:
source /opt/intel/oneapi/setvars.sh sycl-lssycl-ls能列出当前系统里所有 SYCL 设备。B60 正常出现的话,输出里会有[ext_oneapi_level_zero:gpu:0]这一行。看到这个,说明 oneAPI 层面的设备枚举已经打通。
注意setvars.sh只在当前 shell 生效。如果你不想每次登录都手动 source,可以把source /opt/intel/oneapi/setvars.sh写进用户的.bashrc。但如果是多人在服务器上共用环境,我建议别写进全局配置,免得一个人改环境影响所有人,宁可让使用者自己 source。
4.3 PyTorch与IPEX版本匹配那点事
PyTorch 和 IPEX 是强耦合的,版本必须匹配,否则 import 阶段就报错。常见匹配关系大致如下:
| PyTorch | IPEX | 适用场景 |
|---|---|---|
| 2.0.x | 2.0.x | 老项目,能用但建议升级 |
| 2.1.x | 2.1.x | 稳定性较好 |
| 2.2.x | 2.2.x | 目前跑 LLM 推理比较推荐的组合 |
| 2.3.x | 2.3.x | 新特性多,注意算子覆盖 |
具体版本组合要以 IPEX 官方发布说明为准,因为 Intel 社区更新节奏很快。安装时最好建一个干净的 Python 虚拟环境,避免污染系统 Python:
python3 -m venv ~/b60env source ~/b60env/bin/activate pip install torch torchvision intel-extension-for-pytorch如果服务器上有多个 Python 版本,注意python3指向哪个。虚拟环境一旦建好,用pip list核对版本号,确保 torch 和 IPEX 的版本前缀一致。
4.4 多卡环境需要的附加配置
如果你这台 B60 服务器是双卡甚至四卡配置,还需要关注设备亲和性和分布式通信。IPEX 在多个 GPU 之间做数据并行时,主要通过 Level Zero 底层和 oneCCL 通信库实现。oneAPI Base Toolkit 自带 oneCCL,不需要额外安装。
多卡环境下的一个关键环境变量是ZE_AFFINITY_MASK,它控制哪些 GPU 对应用户可见。比如双卡机器,你只想让 0 号卡被任务看到:
export ZE_AFFINITY_MASK=0要让两张卡都被看到:
export ZE_AFFINITY_MASK=0,1这个变量在跑分布式推理和单进程多卡场景时特别重要。之前遇到过应用明明运行成功,但性能完全不对,后来发现进程被固定在某一张卡上,另一张卡全程闲置,问题就出在没设置硬件亲和。后面第 6 节会再细说。
5. 从驱动到跑通模型:一条验证链路跑到底
5.1 四层验证法:内核、设备、运行时、算力
环境装完不能直接上头跑大模型,得按层级验证。我习惯按四层来检查,每一层都有对应命令:
内核层:确认xe或i915模块已加载,固件初始化成功。
lsmod | grep xe sudo dmesg | grep -i xe设备层:确认/dev/dri/renderD128存在,用户有访问权限。
ls -l /dev/dri/renderD128运行时层:用sycl-ls确认 Level Zero 能看到 B60。
source /opt/intel/oneapi/setvars.sh sycl-ls算力层:真正跑一个小程序验证 GPU 在计算。这一层最实在,也最容易被跳过。
这个顺序像剥洋葱,从外到里逐层透视。如果某一层卡住了,不需要怀疑下面一层。比如sycl-ls看不到设备,那肯定不是 PyTorch 的问题,而是运行时或内核层出了问题。
5.2 PyTorch在B60上跑矩阵乘法的实操
算力层的第一个程序,我用一个最简单的矩阵乘法,确认 PyTorch 能通过 IPEX 把算子放到 B60 上:
import torch import intel_extension_for_pytorch as ipex x = torch.randn(2048, 2048, device="xpu") w = torch.randn(2048, 2048, device="xpu") y = x @ w torch.xpu.synchronize() print("xpu matmul ok, result device =", y.device)运行后如果打印出xpu matmul ok,说明 PyTorch、IPEX、Level Zero、内核驱动整条链路已经打通。你还可以顺手做个性能对比:
import time def bench(device, repeat=10): x = torch.randn(2048, 2048, device=device) w = torch.randn(2048, 2048, device=device) torch.xpu.synchronize() if device == "xpu" else torch.cuda.synchronize() ts = [] for _ in range(repeat): t0 = time.time() y = x @ w if device == "xpu": torch.xpu.synchronize() ts.append(time.time() - t0) return sum(ts) / len(ts) print("CPU time:", bench("cpu")) print("XPU time:", bench("xpu"))对比 CPU 和 XPU 的耗时,能直观感受到 B60 在矩阵运算上的优势。如果 XPU 和 CPU 差不多甚至更慢,先别急着骂硬件,看看是不是显存带宽受限、内核没升够版本,或者是温度墙/功耗墙压住了频率。
5.3 一次7B量级对话模型的推理实验
矩阵乘法跑通后,再往里走一步:跑一个实际模型。我用一个 7B 参数量的开源对话模型做实验,推理框架沿用 transformers + IPEX:
import torch import intel_extension_for_pytorch as ipex from transformers import AutoModelForCausalLM, AutoTokenizer model_name = "some-open-dialogue-7b" model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.bfloat16) model = model.to("xpu") model.eval() model = ipex.optimize(model, dtype=torch.bfloat16) tokenizer = AutoTokenizer.from_pretrained(model_name) inputs = tokenizer("你好,请简单介绍一下自己。", return_tensors="pt").to("xpu") with torch.no_grad(): outputs = model.generate(**inputs, max_new_tokens=100) print(tokenizer.decode(outputs[0], skip_special_tokens=True))跑这个实验前,建议检查一下显存占用,避免 OOM。B60 有 16GB 显存,7B 模型用 bfloat16 加载大概 14GB 上下,比较接近上限。如果 OOM,可以改用 4bit 量化或者换更小的模型。
推理过程跑起来后,我会同时开两个终端:一个跑intel_gpu_top -l看实时利用率,另一个跑xpu-smi stats看功耗和温度。如果 GPU 利用率超过 80%、温度处于 70 到 80 摄氏度之间,说明模型确实在 B60 上计算。如果利用率一直很低,多半是数据加载或 tokenizer 部分成了瓶颈,可以通过增大 batch 或使用DataLoader改善。
6. 环境搭建中绕不开的坑位记录
6.1 默认内核不认识B60,升级HWE后才看到设备
这是我踩的第一个坑,也很有代表性。系统装完是 Ubuntu 22.04,默认内核 5.15。lspci能看到 B60 这个设备,但dmesg里没有任何xe或i915的初始化日志,/dev/dri下只有card0没有renderD128。
当时第一反应是驱动没装,满世界找显卡驱动包,折腾了半天没有任何效果。后来才意识到是内核根本不认识这个设备。装上linux-generic-hwe-22.04升级到 6.5 内核后,重启直接识别。
这条经验再强调一遍:B60 这种新卡,关键不在驱动,而在内核。遇到不识别,先看内核版本,不要急着装各种外部驱动包。
6.2 SecureBoot导致模块加载失败
中间有次手贱把 BIOS 里的 Secure Boot 打开了,结果重启后系统正常起来,但dmesg里出现模块验证失败,xe驱动加载不了。这是因为启用了 Secure Boot 后,内核只加载有合法签名的模块,Ubuntu 自带内核模块虽然有签名,但某些第三方或后续升级的模块不在白名单里。
解决方式有两个:简单粗暴的就是进 BIOS 关掉 Secure Boot;讲究一点的话,用mokutil把模块签名注册进系统。我这边是实验环境,直接关了。生产环境如果要做到既开 Secure Boot 又能加载驱动,需要走完整的 DKMS 签名流程,工作量不小。
6.3 缺固件导致只有card没有render节点
还有一次是什么都没改,重装了一版系统,结果/dev/dri下只有card0,死活没有renderD128。查dmesg看到核心报错是固件加载失败,文件路径对应xe驱动的 GUC 固件缺失。
原因是我在安装系统时图快,跳过了linux-firmware的安装。处理办法就是补装:
sudo apt install -y linux-firmware sudo reboot补装后/dev/dri/renderD128正常出现。这个坑很隐蔽,因为系统不会主动提醒你少装固件,只有 GPU 初始化失败时才会在dmesg里暴露。
6.4 容器里访问不了GPU
B60 环境跑通后,打算把推理服务容器化,结果容器起来后 PyTorch 一直报设备不存在。排查下来是容器里没有 B60 的设备节点,也没有对应的用户态 runtime。
Docker 启动时要把/dev/dri设备挂进去,同时把用户组权限交给容器:
docker run --rm -it \ --device /dev/dri \ --group-add video \ --group-add render \ --ipc host \ my-pytorch-image这里有两个很容易漏的细节:--group-add video和--group-add render。内核设备节点有用户组权限控制,容器默认只继承 root 的权限,但/dev/dri/renderD128的属组是render,不把宿主机的 render 组加进去,容器里的普通进程就没有访问权限。另外运行时组件要装在镜像里,或用官方带 oneAPI 和 IPEX 的 PyTorch 镜像,否则容器里还是找不到 Level Zero 库。
6.5 多卡环境下的显存误判与亲和性设置
最后这个坑,在双卡机器上特别容易踩。我以为两张卡都空闲,跑推理时选了个 7B 模型,结果提示显存不足。用xpu-smi info一看,发现两张卡的显存占用情况完全不一样,0 号卡被之前残留的进程占了一部分,1 号卡才是真正全空。
多卡机器管理起来,别只靠眼睛。建议养成两个习惯:
- 每次跑任务前用
xpu-smi info和xpu-smi stats看一眼当前显存、利用率、温度。 - 需要指定卡时,用
ZE_AFFINITY_MASK明确绑定,比如只用 1 号卡就设:
export ZE_AFFINITY_MASK=1如果不设置,Level Zero 通常会默认枚举所有设备,应用的默认行为可能跟你想的不一样,尤其是有多个进程同时跑的时候,互相干扰很难查。先通过环境变量把设备范围控制住,再调具体的模型并行策略,会省心很多。