Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
build/
/build-cpu/
/build-cuda/
/build-ddp/
/runs/
.cache/
.vscode/

Expand Down
13 changes: 12 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ endif()

if(USE_CUDA)
add_compile_definitions(USE_CUDA=1)
set(CMAKE_CUDA_STANDARD 20)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
set(CMAKE_CUDA_ARCHITECTURES "75;80;90")
endif()
enable_language(CUDA)
find_package(CUDAToolkit REQUIRED)
include_directories(${CUDAToolkit_INCLUDE_DIRS})
Expand All @@ -115,7 +120,7 @@ if(USE_CUDA)
file(GLOB_RECURSE CUDA_KERNELS ${PROJECT_SOURCE_DIR}/infini_train/src/*.cu)

add_library(infini_train_cuda_kernels STATIC ${CUDA_KERNELS})
set_target_properties(infini_train_cuda_kernels PROPERTIES CUDA_ARCHITECTURES "75;80;90")
set_target_properties(infini_train_cuda_kernels PROPERTIES CUDA_ARCHITECTURES "${CMAKE_CUDA_ARCHITECTURES}")

target_link_libraries(infini_train_cuda_kernels
PUBLIC
Expand Down Expand Up @@ -240,6 +245,12 @@ add_executable(mnist
)
link_infini_train_exe(mnist)

add_executable(mnist_align
example/mnist/align.cc
example/mnist/net.cc
)
link_infini_train_exe(mnist_align)

add_executable(gpt2
example/gpt2/main.cc
example/common/tiny_shakespeare_dataset.cc
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,23 @@ The generated files can be passed directly to the corresponding executables:

##### MNIST

The MNIST example uses a two-layer CNN:
`Conv2d(1,16,3) → ReLU → Conv2d(16,32,3) → ReLU → Flatten → Linear(18432,10)`.
It accepts flattened DataLoader batches or NCHW images and returns raw logits.
See [MNIST CNN architecture and tests](docs/mnist_cnn.md) for details.
The reproducible CPU/CUDA training configuration and measured results are in
[MNIST end-to-end training](docs/mnist_training.md).
For one-process-per-GPU NCCL training and real two-GPU integration tests, see
[MNIST distributed training](docs/mnist_ddp.md).

```bash
./build/mnist \
--device cpu \
--dataset data/mnist
--dataset data/mnist \
--bs 64 \
--num_epoch 3 \
--lr 0.05 \
--output_dir runs/mnist-cpu
```

##### GPT-2 124M
Expand Down
8 changes: 8 additions & 0 deletions cmake/FindNCCL.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,12 @@ find_package_handle_standard_args(NCCL
if (NCCL_FOUND)
set(NCCL_INCLUDE_DIRS ${NCCL_INCLUDE_DIR})
set(NCCL_LIBRARIES ${NCCL_LIBRARY})
# Honor NCCL_ROOT for both headers and linkage instead of resolving bare
# -lnccl against an unrelated system installation.
if(NOT TARGET nccl)
add_library(nccl UNKNOWN IMPORTED)
set_target_properties(nccl PROPERTIES
IMPORTED_LOCATION "${NCCL_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${NCCL_INCLUDE_DIR}")
endif()
endif()
96 changes: 96 additions & 0 deletions docs/cnn_basic_support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# CNN 基础训练能力(任务第一步)

依据:[项目要求:小模型训练支持](https://gxtctab8no8.feishu.cn/docx/QiMHdE5w4omePTx9KBicX6gZnSd),任务拆解第 1 项。

第二步的网络搭建与 MNIST 示例接入见 [MNIST CNN 网络说明](mnist_cnn.md)。

## 已实现接口

| 能力 | 接口 | 范围 |
| --- | --- | --- |
| 卷积模块 | `nn::Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, bias=true, device=Device())` | 方形卷积核,整数步长、对称零填充,可选偏置 |
| 卷积函数 | `nn::function::Conv2d(input, weight, bias=nullptr, stride=1, padding=0)` | 权重为 OIHW;函数也支持矩形卷积核 |
| 激活 | `nn::ReLU`、`nn::function::ReLU(input)` | 非原地操作,零点导数为 0 |
| 展平模块 | `nn::Flatten(start_dim=1, end_dim=-1)` | 支持负维度,复用 `Tensor::Flatten` 的变形与自动求导 |

卷积与 ReLU 支持 CPU/CUDA 上的 FP32。卷积输入为连续的 `[N,C,H,W]`,权重为 `[C_out,C_in,K_h,K_w]`,执行与 PyTorch Conv2d 相同的互相关计算。当前不提供 groups、dilation、其他 padding 模式、混合精度或非连续张量接口。卷积要求正的 batch、通道与空间尺寸;Flatten 要求合法的非标量维度区间。

输出高度为 `(H + 2 * padding - K_h) / stride + 1`,采用整数向下取整,宽度同理。输入 rank、通道、dtype、设备、bias 形状、stride/padding 和可用空间均在计算前检查。

## 框架接入

- `nn::Conv2d` 注册可训练的 `weight` 和可选 `bias`,复用 Kaiming/Uniform 初始化、参数枚举、设备迁移和优化器。
- `autograd::Conv2d` 保存反向所需张量,通过 Dispatcher 调用后端,计算输入、权重和偏置梯度,并跳过不需要的梯度输出。
- CPU 使用直接卷积,前向、输入梯度和权重梯度可使用 OpenMP;CUDA 每个线程负责一个输出或梯度元素,使用框架当前 stream、DeviceGuard 和 launch 错误检查。无 CPU 回退和浮点原子累加。
- CPU/CUDA 共享标量索引计算,单元测试使用独立的双精度参考实现验证;该实现优先保证正确性,尚未做 im2col/GEMM 或 cuDNN 性能优化。
- 新源码和测试接入项目原有的 CMake 源码收集规则。新增文件后需要重新运行 CMake 配置。
- CUDA 使用 C++20,允许通过 `CMAKE_CUDA_ARCHITECTURES` 指定 GPU 架构;未指定时保留原默认值 `75;80;90`。

必要头文件:

```cpp
#include "infini_train/include/nn/modules/convolution.h"
#include "infini_train/include/nn/modules/activations.h"
#include "infini_train/include/nn/modules/flatten.h"
#include "infini_train/include/nn/functional.h"
```

```cpp
auto conv = std::make_shared<nn::Conv2d>(1, 16, 3);
auto relu = std::make_shared<nn::ReLU>();
auto flatten = std::make_shared<nn::Flatten>(); // 保留 batch 维
auto features = (*flatten)((*relu)((*conv)({input})))[0];
// [N,1,28,28] -> [N,16,26,26] -> [N,10816]
```

与框架现有模块保持一致,参与设备迁移或参数枚举的模块使用 `std::shared_ptr` 管理。

## 测试与复现

测试源文件:`tests/autograd/test_autograd_cnn.cc`,测试组:`CnnTest`。

覆盖内容:

1. 手算卷积前向、输入/权重/bias 梯度及非均匀上游梯度。
2. 多 batch、多输入/输出通道、矩形输入/卷积核、stride/padding、有无 bias。前向与独立双精度参考计算比较;三类梯度逐元素做中心有限差分检查。
3. 全部七种可训练输入/权重/bias 组合,无 bias 模块、1×1 卷积。
4. ReLU 的正负数、零点导数、非原地行为和 NaN/无穷值前向。
5. Flatten 的默认/负维度/局部/全维展平、数值顺序与反向形状恢复。
6. 两层 Conv2d + ReLU + Flatten + Linear + CrossEntropyLoss 的四步 SGD。检查六组参数的梯度非零、有限,每个元素满足 SGD 更新公式,loss 下降且 ZeroGrad 生效。
7. NoGrad 推理、重复反向的梯度累积,以及非法参数失败检查。

前向及参数更新比较使用绝对误差 `1e-5`,有限差分步长 `1e-4`、梯度绝对误差 `2e-5`。测试数据采用可精确表示的二进制小数以降低参考输入转换误差。

在 Linux/WSL 中,从项目根目录运行:

```bash
# 若使用 Git checkout,先补齐仓库声明的 third_party 子模块。
git submodule update --init --recursive

cmake -S . -B build-cpu -DUSE_CUDA=OFF -DUSE_NCCL=OFF \
-DUSE_OMP=ON -DBUILD_TEST=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build-cpu --target test_autograd_cpu -j 6
OMP_NUM_THREADS=2 ./build-cpu/tests/autograd/test_autograd_cpu --gtest_filter='*CnnTest*'

cmake -S . -B build-cuda -DUSE_CUDA=ON -DUSE_NCCL=OFF \
-DUSE_OMP=ON -DBUILD_TEST=ON -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CUDA_ARCHITECTURES=native
cmake --build build-cuda --target test_autograd_cuda -j 6
OMP_NUM_THREADS=2 ./build-cuda/tests/autograd/test_autograd_cuda --gtest_filter='CUDA/CnnTest.*'
```

CMake 4.x 配合较早版本的第三方依赖时,可增加 `-DCMAKE_POLICY_VERSION_MINIMUM=3.5`。未在 PATH 中的 nvcc 可用 `-DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc` 指定。CUDA 参数错误测试复用 CPU 检查并在 CUDA 测试组中跳过,避免 fork 已初始化的 CUDA context。

本次工作止于基础算子、模块与训练链路单测;MNIST 网络改造、完整数据集训练和 PyTorch 端到端对齐属于文档后续任务。

## 本机验证记录

验证环境:WSL Ubuntu 26.04、GCC 15.2、CMake 4.2.3、CUDA 13.3,GPU 为 NVIDIA GeForce RTX 5060 Laptop GPU(编译参数 `CMAKE_CUDA_ARCHITECTURES=120`),启用 OpenMP。

原压缩包中的第三方目录为空,本机从原依赖上游补齐了 glog 0.7.1、gflags 2.2.2、GoogleTest 1.17.0 和 InfiniTensor/eigen-mirror(5.0.1-dev),未修改这些依赖的源码。

- CPU 独立构建成功,新增 CNN 测试 8/8 通过。
- CPU 自动求导回归:141 项中 140 项通过,1 项原有 BF16 测试按现有条件跳过,无失败。
- CUDA 构建和链接成功,包含新增 Conv2d/ReLU 内核及测试程序。
- 本机曾因 Windows 驱动与 CUDA 13.3 运行库不兼容而无法执行 GPU 测试。最终验收改在驱动 570.124.06、CUDA 12.8、RTX 4090 服务器上完成。
- 服务器实测:CPU 的 8 项 `CnnTest` 全部通过;CUDA 的 7 项计算/训练测试全部通过,1 项非法参数测试因与 CPU 共用校验逻辑按设计跳过。没有失败项。
81 changes: 81 additions & 0 deletions docs/mnist_cnn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# MNIST CNN 网络(任务第二步)

依据:[小模型训练支持项目要求](https://gxtctab8no8.feishu.cn/docx/QiMHdE5w4omePTx9KBicX6gZnSd),任务拆解第 2 项。网络直接采用文档中的两层卷积结构,并复用第一步的基础能力。

## 网络结构

| 模块名 | 配置 | 输出形状 |
| --- | --- | --- |
| 输入 | FP32,像素除以 255 | `[N,1,28,28]` |
| `conv1` | Conv2d(1,16,3),stride=1,padding=0,bias=true | `[N,16,26,26]` |
| `relu1` | ReLU | `[N,16,26,26]` |
| `conv2` | Conv2d(16,32,3),stride=1,padding=0,bias=true | `[N,32,24,24]` |
| `relu2` | ReLU | `[N,32,24,24]` |
| `flatten` | Flatten(1,-1) | `[N,18432]` |
| `fc` | Linear(18432,10),bias=true | `[N,10]` |

共 **189,130** 个可训练参数,分为 `conv1.weight/bias`、`conv2.weight/bias`、`fc.weight/bias` 六组。输出为原始 logits,直接交给现有 CrossEntropyLoss;网络末尾不额外使用 Softmax。预测时取 logits 最大值对应的类别。

`example/mnist/net.h` / `net.cc` 中的 `MNIST` 类保留原名称,替换原 MLP。网络接受两种批量输入:

- `[N,784]`:适配现有 DataLoader,在模型入口通过可求导的 View 恢复为 NCHW。
- `[N,1,28,28]`:直接用于图像输入和后续参考实现对齐。

其他形状、非 FP32 输入和空 batch 会明确报错。batch 大小不固定,支持末批数量不足的情况。参数初始化沿用 Conv2d/Linear 的默认实现。

## 示例接入与必要修复

- `example/mnist/main.cc` 使用 `shared_ptr<MNIST>` 管理网络,使参数枚举、设备迁移与优化器正常工作;通过模块调用接口执行前向。
- 测试集前向使用 `NoGradGuard`。读取设备回传的指标前同步,避免异步拷贝后提前访问数据。
- 修复 `MNISTDataset` 的图片切片步长:IDX 中每张图片占 784 字节,但归一化成 FP32 后占 3136 字节。以前仍按 784 字节偏移读取,会错误读取第二张及后续图片;现在按实际 FP32 大小切片。
- 保留通用 DataLoader 的原有行为,将图像形状适配局限于 MNIST 网络入口。

使用示例:

```cpp
auto network = std::make_shared<MNIST>();
network->To(device);
infini_train::optimizers::SGD optimizer(network->Parameters(), 0.001f);
infini_train::nn::CrossEntropyLoss loss_fn;
optimizer.ZeroGrad();
auto logits = (*network)({images})[0];
auto loss = loss_fn({logits, labels})[0];
loss->Backward();
optimizer.Step();
```

这里的 `images` 是已归一化的 FP32 Tensor,`labels` 是类别索引 Tensor,两者已位于所选设备;构建网络之后先迁移设备,再创建优化器。

## 验证与运行

新增 `tests/mnist/test_mnist.cc`,CMake 注册 `test_mnist_cpu` / `test_mnist_cuda`。测试覆盖逐层输出尺寸、六组参数名称及总量、batch=1/2/3、两种输入布局的结果一致性、原始 logits、无梯度推理、完整模型的 Loss/Backward/SGD、非法输入,以及真实 IDX 格式的合成文件与末批数据接入。

```bash
cmake -S . -B build-cpu -DUSE_CUDA=OFF -DUSE_NCCL=OFF \
-DBUILD_TEST=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build-cpu --target mnist test_mnist_cpu -j 6
OMP_NUM_THREADS=2 ctest --test-dir build-cpu -R MnistCnnTest --output-on-failure

# 准备好真实 MNIST 数据后,可继续使用原示例入口。
OMP_NUM_THREADS=2 ./build-cpu/mnist --device cpu --dataset data/mnist --bs 64 --num_epoch 1 --lr 0.01
```

完整数据集训练采用 `batch_size=64`、`epochs=3`、`lr=0.05`、`seed=42`,配置与结果见 [MNIST 端到端训练](mnist_training.md)。CMake 4.x 配合较旧依赖时需额外传入 `-DCMAKE_POLICY_VERSION_MINIMUM=3.5`。

CUDA 构建及环境要求见 [CNN 基础能力说明](cnn_basic_support.md)。已有 CUDA 构建目录可执行:

```bash
cmake -S . -B build-cuda
cmake --build build-cuda --target mnist test_mnist_cuda -j 6
OMP_NUM_THREADS=2 ./build-cuda/tests/mnist/test_mnist_cuda --gtest_filter='CUDA/*'
```

真实 MNIST 已在 CPU 和 CUDA 上完成端到端训练;PyTorch 数值对齐也已在同一 CUDA 环境完成。第二步的合成数据检查仍只用于验证网络接入,不作为准确率结果。

## 本机验证记录

验证环境沿用第一步的 WSL / GCC / CUDA 环境。CPU 版 `mnist` 已成功构建,并用三张合成 IDX 图片、batch=2、1 epoch、lr=0.001 跑完训练和评估,覆盖末批大小为 1 的情况,loss 有限、程序正常退出。该检查只证明入口可运行,不代表真实手写数字识别精度。

CPU 的 5 项 `MnistCnnTest` 均经 CTest 运行通过:逐层尺寸/参数、输入布局/批量大小、完整网络反向与 SGD、IDX 读取/末批接入、非法输入检查。反向测试确认全部六组参数梯度有限且非零,更新逐元素符合 SGD 公式,更新后的同批次 loss 下降。

最终在驱动 570.124.06、CUDA 12.8、RTX 4090 服务器上完成 GPU 验收。CPU 的 7 项 `MnistCnnTest` 全部通过;CUDA 的 6 项计算/训练测试通过,1 项非法输入测试因与 CPU 共用校验逻辑按设计跳过。相同 seed 和超参数下,CPU/CUDA 都完成 3 个 epoch 的真实 MNIST 训练并达到 97.88% 测试准确率,详见 [MNIST 端到端训练](mnist_training.md)。
87 changes: 87 additions & 0 deletions docs/mnist_ddp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# MNIST CNN 单机多卡 DDP

在已有 CPU/CUDA CNN 上复用框架的 `DistributedDataParallel`、`ProcessGroup`、
NCCL 和 `infini_run`,采用一进程一卡,支持 bucketed 和逐参数两条梯度归约路径。
本 Demo 支持单机多卡;不支持多节点、ZeRO、混合精度或训练中断续训。
checkpoint 可在单卡或双卡上仅评估。

## 构建与启动

需要 CUDA、NCCL 开发库和至少两张可见 GPU。RTX 5090 使用 CUDA 12.8 以上,
`CMAKE_CUDA_ARCHITECTURES=120`;其他 GPU 可设置为 `native`。

```bash
cmake -S . -B build-ddp -DUSE_CUDA=ON -DUSE_NCCL=ON \
-DBUILD_TEST=ON -DBUILD_MNIST_DDP_TESTS=ON -DUSE_OMP=ON -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CUDA_ARCHITECTURES=120
cmake --build build-ddp --target mnist mnist_align infini_run \
test_mnist_ddp test_mnist_cpu test_mnist_cuda test_autograd_cpu test_autograd_cuda -j 8

# --bs 是每个 rank 的 batch;此处 global batch = 32 * 2 = 64。
OMP_NUM_THREADS=2 ./build-ddp/infini_run --nproc_per_node=2 ./build-ddp/mnist \
--ddp=true --device=cuda --dataset=data/mnist --bs=32 \
--num_epoch=3 --lr=0.05 --seed=42 --threads=8 --output_dir=runs/mnist-ddp

# 与上述训练使用相同的全局 batch、初始权重、样本集合和学习率。
./build-ddp/mnist --device=cuda --dataset=data/mnist --bs=64 \
--num_epoch=3 --lr=0.05 --seed=42 --threads=8 --output_dir=runs/mnist-single
```

使用独立 NCCL 安装时设置 `-DNCCL_ROOT=/path/to/nccl`,该目录包含 `include/nccl.h`
和 `lib/libnccl.so`。切换已有 build 的 NCCL 版本时先清除 CMake 缓存中的旧路径:
`cmake -S . -B build-ddp -U NCCL_INCLUDE_DIR -U NCCL_LIBRARY -DNCCL_ROOT=/path/to/nccl`。
运行 PyTorch 参考脚本时也将对应 `lib` 目录放在 `LD_LIBRARY_PATH` 首位。

## 训练语义

- `--ddp=false` 默认保持原有 CPU/单卡行为。多进程启动必须显式传 `--ddp=true`。
- `--ddp_buckets=true` 默认复用框架 bucket reducer;设为 `false` 使用逐参数 AllReduce。
- `infini_run` 提供 `RANK/WORLD_SIZE/LOCAL_RANK/LOCAL_WORLD_SIZE` 和独立 rendezvous ID。
`LOCAL_RANK` 映射可见 GPU,进程组使用 DP 轴,不创建 TP/PP 组。
- 先在 CPU 确定性初始化,迁移到本卡,再将 rank 0 的全部参数广播到所有 rank。
- 每个 epoch 使用同一 `seed+epoch` 生成全局排列,rank r 读取位置 r、r+world_size 等样本。
训练只丢弃总样本数对 world_size 的余数,每个 rank 样本数相等。
不足 `--bs` 的本地尾批仍执行;各卡尾批大小相同,NCCL 平均本地 mean-loss 梯度,
因而等价于全局 batch 的 mean-loss 梯度,学习率不额外乘除卡数。
- MNIST 60,000 个训练样本在双卡上不丢弃也不重复;每卡 30,000 个,最后本地 batch=16,
全局尾批=32。每个 epoch 938 次 SGD,3 epochs 共 2,814 次。
- 测试集不截断、不补齐;允许不等长或空评估分片。FP64 AllReduce 汇总 loss_sum、correct、
samples,再计算全局均值,避免平均每卡 accuracy/loss 引入偏差。
- 只由 rank 0 输出全局 JSONL 与 checkpoint;每个 rank 输出独立配置。结束前广播参数副本,
校验所有 189,130 个参数有限且与 rank 0 逐字节相等,写入 `rank*/replica_check.txt`。
所有 rank 在保存完成后同步退出。非空输出目录会报错。

## 测试

```bash
OMP_NUM_THREADS=2 ctest --test-dir build-ddp -R '^mnist_ddp_' --output-on-failure -V
./build-ddp/tests/autograd/test_autograd_cpu --gtest_filter='CPU/CnnTest.*'
./build-ddp/tests/autograd/test_autograd_cuda --gtest_filter='CUDA/CnnTest.*'
./build-ddp/tests/mnist/test_mnist_cpu --gtest_filter='CPU/MnistCnnTest.*:MnistDistributedSampler.*'
./build-ddp/tests/mnist/test_mnist_cuda --gtest_filter='CUDA/MnistCnnTest.*'
```

两个 DDP CTest 均实际启动两个进程/两张 GPU,分别验证 bucket 与逐参数路径。
测试故意用不同 seed 初始化两个 rank,验证参数广播;使用 batch=6、2、6 连续三步,
检查 logits、全局 loss、输入梯度、六组参数梯度、SGD 后参数,并覆盖不均匀/空评估分片。
数值判据为 `abs(candidate-reference) <= atol + rtol*abs(reference)`:logits 为
`1e-5/1e-4`,梯度为 `1e-6/1e-3`,更新参数为 `1e-6/1e-5`。
采样器单测验证确定性、分片互斥、截断策略、尾批及全评估集覆盖。
这些测试仅在 `BUILD_MNIST_DDP_TESTS=ON` 时注册(默认 OFF,避免影响单 GPU 的普通 CTest)。
无双卡环境应只运行 CPU/单卡测试,不将其当作已验证的 DDP。

项目报告随附的 `validate_ddp.py`(PR 外)可一键运行上述测试、3 类固定 fixture 的
PyTorch 单卡/DDP 数值对齐、MNIST 全量训练、双卡重复训练与 checkpoint 重新评估。
输入梯度没有 DDP 参数 hook,因此导出时除以 world_size,转换为全局 mean-loss 的导数。
完整训练不要求与单卡逐位相同:不同矩阵 batch 形状和归约次序存在 FP32 舍入差异。
固定短轨迹的阈值对齐与相同配置的独立重复运行分别检验正确性与可复现性。

```bash
./build-ddp/infini_run --nproc_per_node=2 ./build-ddp/mnist \
--device=cuda --ddp=true --dataset=data/mnist --bs=32 --eval_only=true \
--checkpoint=runs/mnist-ddp/checkpoint --output_dir=runs/mnist-ddp-eval
```

常见错误:缺少 `USE_NCCL` 时重建;`LOCAL_RANK` 超出 GPU 数量时检查 `CUDA_VISIBLE_DEVICES`;
训练样本少于卡数时减少卡数;出现 NCCL 错误时开启 `NCCL_DEBUG=INFO` 并核对动态库实际版本。
不要用跳过多卡测试或禁用梯度同步替代修复通信环境。
Loading