【训练营】小模型训练支持 - #232
Open
gavin-richie wants to merge 14 commits into
Open
【训练营】小模型训练支持#232gavin-richie wants to merge 14 commits into
gavin-richie wants to merge 14 commits into
Conversation
Add the Relu autograd function with forward/backward kernels for CPU and CUDA (fp32/bf16 via the elementwise dispatch helpers), a functional wrapper, and an nn::ReLU module, mirroring the existing Sigmoid operator.
Add the Conv2d autograd function supporting symmetric stride and padding with input, weight, and bias gradients, plus an nn::Conv2d module using the same default initialization as torch.nn.Conv2d (kaiming_uniform with a=sqrt(5)). CPU: im2col unfolding with row-major Eigen GEMMs and a col2im scatter for grad_input. CUDA: an im2col kernel, strided-batched cuBLAS GEMMs through the existing Gemm wrapper (weight broadcast via stride_b=0), an atomic col2im kernel, and per-channel bias reductions. Kernels cover the fp32 path required by the MNIST CNN training use case and reject other dtypes explicitly.
image_size_in_bytes_ was computed in the member initializer list against the original uint8 IDX payload, but the constructor then replaces the image tensor with a float32 copy. Every sample view therefore advanced by 784 bytes instead of 3136, so images were misaligned with their labels and training silently stagnated around chance accuracy. Recompute the per-sample stride once the conversion to float32 is done.
Add a --model flag (mlp|cnn, defaulting to the existing MLP) with a CNN classifier following Conv2d(1,16,3) -> ReLU -> Conv2d(16,32,3) -> ReLU -> Flatten -> Linear(18432, 10). The evaluation loop now runs under no_grad, per-step losses are reported, and the final test loss and accuracy are logged explicitly. A new --init_weights flag loads an InfiniTrain checkpoint as initial weights, enabling PyTorch-alignment runs.
Device-parameterized gtest coverage with PyTorch-derived reference vectors: ReLU elementwise forward/backward, Conv2d forward with and without bias across stride/padding combinations, Conv2d input, weight, and bias gradients, and module-level parameter, shape, and conv-relu-flatten-linear-cross-entropy training integration checks.
ReduceColumnsKernel summed along the wrong axis: it indexed the (bs, out_features) grad_output as if it were (out_features, bs), which happens to be correct only for bs == 1. Bias gradients on CUDA were therefore transposed sums and diverged from PyTorch for larger batches. The kernel now reduces rows within each column block for a row-major (num_rows, num_cols) input, and LinearBackwardBias passes (bs, out_features). Extend the linear backward test to check the bias gradient values, which previously only asserted the result size.
Add a --metrics_file flag that appends train and test metrics as JSON lines for visualization: a train_step line every 10 steps and an epoch_end line with train loss, test loss, and test accuracy after each epoch. Evaluation is extracted into an Evaluate() helper and now runs after every epoch under no_grad.
Upload the JSON lines written by the mnist demo's --metrics_file flag to SwanLab via the official swanlab package. The API key is read from the SWANLAB_API_KEY environment variable and is never stored in the repository.
Wire the mnist demo into the existing DDP stack: initialize the parallel environment from the RANK/LOCAL_RANK/WORLD_SIZE variables set by tools/infini_run, place each rank on its own CUDA device, create the data- parallel process group, wrap the model with DistributedDataParallel (zero_stage 0, bucketed gradient all-reduce), and shard the training data with DistributedDataLoader. Per-rank training losses are averaged with an AllReduce for logging, parameters are broadcast from the global-rank-0 process at startup, and rank-0-only logging/metrics keep single-process behavior unchanged when no parallel environment is set. The per-epoch step count is capped at the per-rank floor so every rank runs the same number of collectives; the strided DistributedDataLoader would otherwise hand one rank an extra batch and deadlock NCCL on the last all-reduce. Single-process 2-GPU verification (2x RTX 3090, CUDA 12.9/NCCL cu12): DDP with 2 ranks x batch 32 reproduces the single-process batch-64 loss trajectory exactly (max |diff| 2.6e-5 over 938 steps), and a 3-epoch DDP run reaches 97.08% test accuracy at ~236k samples/s.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
【训练营】小模型训练支持 — PR 描述
概述
扩展 InfiniTrain 的小模型训练能力:补齐 CNN 所需的 Module / 算子(从零实现 Conv2d 前向/反向,
CPU 与 CUDA 双后端),新增 ReLU 算子与 Flatten 模块,并在 MNIST 上完成端到端 CNN 训练 Demo,
支持 单卡 CPU / CUDA 训练与 DDP 多卡分布式训练,提供完整单元测试、SwanLab 训练可视化,
以及与 PyTorch 的逐点数值对齐验证。
最终训练流程:
MNIST Dataset → DataLoader → CNN → CrossEntropyLoss → Backward → Optimizer → Accuracy主要变更
1. Conv2d 算子(核心)
autograd::Conv2dFunction:支持 stride / padding 与 input / weight / bias 三路梯度,依据
needs_input_grad裁剪保存张量;接口对齐torch.nn.Conv2d的最小集合(dilation / groups 按项目要求不在范围内,非 fp32 显式报错)。
Gemm封装(strided-batch,stride_b=0广播共享权重)+ col2im(atomicAdd)+ 按 channel 的 bias 规约。
nn::Conv2d模块:默认初始化与 PyTorch 一致(KaimingUniform(a=√5) + bias U(±1/√fan_in))。2. ReLU / Flatten
autograd::Relu(CPU / CUDA fp32/bf16)+nn::ReLU+nn::functional::Relu。nn::Flatten(start_dim=1):基于Tensor::Flatten(View/NoOp,零拷贝,梯度透传)。3. MNIST CNN Demo(
example/mnist)--model mlp|cnn(默认 mlp,保持既有行为):Conv2d(1,16,3) → ReLU → Conv2d(16,32,3) → ReLU → Flatten → Linear(18432,10)。--init_weights:加载 InfiniTrain Checkpoint 格式的初始权重(PyTorch 导出,用于对齐)。--metrics_file:JSON Lines 指标输出(逐 step train loss + 逐 epoch train/test loss 与accuracy),配合
scripts/swanlab_upload.py上传 SwanLab 做训练可视化。NoGradGuard下);日志仅 rank 0。4. DDP 分布式训练
InitAllEnv(读取infini_run注入的 RANK/WORLD_SIZE)→每 rank 绑定各自 GPU → DP 进程组 →
DistributedDataParallel(zero_stage=0)(桶化梯度AllReduce,
Backward()零改动)→DistributedDataLoader数据分片 → 启动时 rank0 参数广播→ 训练 loss 跨 rank AllReduce 平均;仅 rank0 输出日志与指标。
DistributedDataLoader的交错分片会让一个 rank 多跑一次 collective 导致 NCCL 死锁,故丢弃尾部不完整的全局 batch。
./build/infini_run --nnodes=1 --nproc_per_node=2 ./build/mnist --model cnn --device cuda ...5. 修复的两个既有缺陷(对齐排查中发现)
example/mnist/dataset.cc:图像转 float32 后样本视图步长仍按 uint8 计算(784B vs 3136B),图像与标签错位,训练精度停滞在随机水平(约 10%)→ 转换后按 float32 重算步长。
infini_train/src/kernels/cuda/linear.cuLinearBackwardBias:ReduceColumnsKernel按转置索引读取梯度,bs=1 时恰好正确、bs>1 时 bias 梯度错误 → 修正归约轴,并在
test_autograd_linear_backward.cc增加 bias 梯度数值断言防止回归。6. CMake / 文档
--model/--init_weights/--metrics_file用法与 DDP 启动命令。单元测试(设备参数化,CPU / CUDA 各执行一遍)
test_autograd_conv2d_forward.cc/..._backward.cctest_autograd_relu.cctest_module_conv2d.cctest_autograd_linear_backward.cc(增强)回归:CPU 全量 251 项 100% 通过;CUDA 套件除 master 既有缺陷
AutogradElementwiseBackwardTest.ExpBackward(Release 构建段错误,已在 master 工作树复现确认,与本次改动无关)外全部通过。
结果
端到端训练(MNIST,CNN:Conv2d(1,16,3)→ReLU→Conv2d(16,32,3)→ReLU→Flatten→Linear)
Loss 随训练明显下降、Accuracy 逐步提升(SwanLab 曲线截图见项目报告)。
与 PyTorch 的数值对齐
方法:PyTorch 固定种子初始化后,将权重导出为 InfiniTrain Checkpoint 二进制格式;InfiniTrain 以
--init_weights加载;双方相同顺序 batch、相同超参。对齐阈值约定 |Δloss| ≤ 1e-3:复现
详细复现日志、对齐数据与排障记录见随报告提交的《小模型训练支持-详细结果日志》。