【训练营】小模型训练支持 - #220
Open
accelerator-llc wants to merge 15 commits into
Open
【训练营】小模型训练支持#220accelerator-llc wants to merge 15 commits into
accelerator-llc wants to merge 15 commits into
Conversation
Implemented inline (im2col + GEMM) rather than exposing a public operator since the MNIST CNN is the only consumer. Scoped to square kernel, stride 1, padding 0, optional bias, and FP32 to meet the project need without covering the full Conv2d parameter space. Uses PyTorch cross-correlation semantics (no kernel flip) to keep numerical alignment with torch.nn.functional.conv2d.
Add autograd::ReLU function (forward with clamp_min semantics, backward with threshold_backward semantics) and nn::ReLU module, following the existing activation pattern. CPU and CUDA elementwise kernels preserve the exact NaN and negative-zero behavior of PyTorch, verified bit-exact against PyTorch (fixed seed). Includes forward, backward, end-to-end training chain and Flatten gradient tests.
The MNIST dataset loader computed the per-sample byte stride from the on-disk UINT8 element size, but the image tensor is normalized to FLOAT32 in the constructor. Sample views after the first therefore read from a wrong, overlapping byte range, so most training images are misaligned mixes of real pixels and the network cannot learn. Use the FLOAT32 element size when computing the stride. Validated: MNIST MLP and CNN training reach >=95% test accuracy.
Add MnistCnn (Conv2d(1,16,3)->ReLU->Conv2d(16,32,3)->ReLU->Flatten->Linear(18432,10)) alongside the existing MLP. A --model=mlp|cnn flag (default cnn) selects the network; the CNN restores the (N,1,28,28) spatial layout from the flattened [N,784] input with Tensor::View. Hold the loss in a shared_ptr to match the other examples. Tune the default --num_epoch/--lr (3 / 0.1) so the default CNN demo reaches ~97.8% test accuracy. Training converges after the MNIST dataset loader's per-sample stride is fixed to use the normalized FLOAT32 element size (older stride misaligned the image views).
Launch with infini_run to shard MNIST batches across processes: each process selects its GPU from LOCAL_RANK, wraps the network with DistributedDataParallel, broadcasts rank-0 parameters before training, and averages the per-step loss for global logging. Single-process behavior is unchanged; document --model and the multi-process launch in the README.
Cover non-square grad_output shapes whose per-element values separate the sample-dimension sum from a row sum, and the bf16 branch whose grad_bias is promoted to fp32.
Route the training and test loops through Module::operator() instead of calling Forward directly, matching the gpt2 example and the hook design doc: operator() is the entry that runs module hooks. No hook consumers exist yet, so outputs are unchanged.
Fold the *_cuda_* conv test files into their CPU counterparts so each test definition instantiates on every available device, matching the test infrastructure design and leaving no ONLY_ macros in the merged files. The CUDA-only empty-batch cases are device-independent and carry over, and the negative-value check in the extreme-values forward case now also runs on CUDA.
Forward and backward-input dispatched one cuBLAS call per image with batch_count=1, while the Gemm interface already exposes a strided-batched path that Matmul uses. Both now issue a single strided-batched GEMM with the weight shared via stride 0, and backward-input runs one col2im launch for the whole batch. The CPU kernels zero-initialized their im2col scratch right before overwriting every element; allocate it uninitialized instead. Single-GPU MNIST CNN throughput: 16582 -> 32802 samples/s per epoch.
The train pair duplicated the same end-to-end SGD step per device, leaving a *_cuda_* file behind after the forward/backward merge. Fold them into one parameterized body that inspects loss, gradients and parameters through host copies, with parameter snapshots taken into freshly allocated host buffers so they survive the in-place update.
Drop the unused Gemm declaration header from the CUDA conv kernel, add the missing <cstdint> to the CPU ReLU kernel, and remove the copy-and- keep-in-sync note above the CUDA ReLU block-size helper.
accelerator-llc
force-pushed
the
feat/small-model-cnn
branch
from
September 11, 2026 15:24
502f2bd to
badbb9f
Compare
Run the full test set after each epoch instead of only once at the end of training, so a single run shows the test loss falling and the test accuracy rising. The evaluation runs under no_grad: a forward-only graph leaves each parameter's grad accumulator with a dependency count that the next backward pass cannot satisfy, silently stopping its gradient accumulation. The training progress line now carries an explicit 1-based [step k/total] field next to the samples consumed so far.
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.
Summary
This PR adds small-model (CNN) training support to InfiniTrain: Conv2d / ReLU
operators for both CPU and CUDA backends (kernel + autograd + nn::Module, three
coherent layers), an MNIST CNN training demo, and distributed data-parallel
training wired through the framework's existing DDP components. The operator
interfaces follow PyTorch conventions; the implementation scope covers what the
CNN demo needs (Conv2d with stride=1 / padding=0, leaving room for future
extensions).
What is included
backward-input issued as single strided-batched GEMMs).
(NaN propagation on forward and backward).
LinearBackwardBiasdefectwas found independently while developing this branch (
LinearBackwardBiasreadthe row-major
(bs, out_features)gradient transposed and reduced over thewrong dimension; for constant-valued inputs the row sums happen to equal the
column sums, and the existing test asserted only the output count, so the bug
was never exposed). Master has since fixed the same defect (
a684567), so thisPR carries no kernel change for it; what it contributes is three numeric
regression tests (non-square repro shape, random pattern, BF16 branch) pinning
the sample-dimension reduction.
MnistCnn(Conv2d(1,16,3)→ReLU→Conv2d(16,32,3)→ReLU→Flatten→Linear);
--model cnn|mlpkeeps the existing MLP path. DDP is enabled automatically by the environment
variables that
infini_runinjects (one GPU per process via LOCAL_RANK, rank-0parameter broadcast at construction, per-step loss AllReduce for global
logging). Test metrics are reported after every epoch (evaluation runs under
no_grad), and the progress line prints an explicit step counter.and removal of redundant im2col scratch initialization; single-GPU MNIST CNN
throughput 1.98× (16582 → 32802 samples/s on a 4090D).
empty batch, kernel == spatial size, non-square regression shapes, torch
golden), ReLU cases, Linear backward numeric assertions; full suite
CPU 276 / CUDA 10, all passing on the current tree.
a header-only addition to the existing
mnisttarget, andtests/collectsits sources via glob, so re-running cmake picks up the new test files.
--modelusage and the multi-processinfini_runlaunch example.
Verification
hyper-parameters): forward logits 5.2e-8, loss 1.3e-9, gradients 4.3e-8,
one optimizer step 1.5e-8, 10-step trajectory 2.4e-7 (thresholds 6e-5 / 2e-6).
AllReduce averaging — overall max_abs 1.863e-8; two-process end-to-end 3-epoch
run shows bitwise-identical loss curves and identical accuracy (97.57%).
Distributed runs were taken on a 2×4090D machine on this branch's pre-rebase
tree. Rebasing onto current master picked up master's reworked sharded loader
(per-rank batch count derived from the global batch size, trailing partial
batch dropped per epoch), so the demo's old divisibility guard was removed —
per-rank step equality is now a construction-time invariant of the loader
itself. The distributed path has not been re-run on 2 GPUs since the rebase
and the evaluation-timing change.
accuracy sweep in the project report, submitted separately).
@kilinchange please review, thank you!