Skip to content

[2026春季][T2-2-1]ChaoticLuna - #188

Open
ChaoticLuna wants to merge 7 commits into
InfiniTensor:masterfrom
ChaoticLuna:2026-spring-ChaoticLuna-T2-2-1
Open

[2026春季][T2-2-1]ChaoticLuna#188
ChaoticLuna wants to merge 7 commits into
InfiniTensor:masterfrom
ChaoticLuna:2026-spring-ChaoticLuna-T2-2-1

Conversation

@ChaoticLuna

@ChaoticLuna ChaoticLuna commented Jul 12, 2026

Copy link
Copy Markdown

赛题报告.pdf
HONOR_CODE.md
REFERENCE.md

2026 春季人工智能大赛赛题报告

一、设计与实现

下文按照赛题《【2026 春季人工智能大赛】Generator 抽象选题》的任务拆解,依次说明 Generator 抽象与状态管理、CPU/CUDA 后端实现、默认 Generator 与统一随机种子,以及随机算子的接入方式。每一部分同时说明与 PyTorch 的语义对应和当前实现边界。

下图概览 Generator 句柄如何经由 CPU/CUDA 后端向随机 kernel 提供状态,并由 Dispatcher 按设备完成分发。

image

1. Generator 抽象与状态管理

1.1 接口

对外暴露的接口集中在 infini_train/include/generator.h。底层抽象为 GeneratorImpl 基类,其中 seed/state 是纯虚接口,device()clone() 由基类提供通用实现。

名称 声明与实现 PyTorch 对应语义 用途/与 PyTorch 对齐度
Generator(类) infini_train/include/generator.h
infini_train/src/generator.cc
at::Generator,底层为 c10::GeneratorImpl 用户侧句柄,值类型,浅拷贝共享底层 GeneratorImplclone() 用于深拷贝。句柄与 clone 语义基本对齐,智能指针分别为 std::shared_ptrc10::intrusive_ptr
Generator::set_current_seed() / Generator::current_seed() GeneratorImpl 纯虚接口,infini_train/include/generator.h
CPU:infini_train/src/core/runtime/cpu/cpu_generator_impl.cc
CUDA:infini_train/src/core/runtime/cuda/cuda_generator_impl.cc
at::Generator::set_current_seed() / at::Generator::current_seed() 设置和获取当前种子。核心语义对齐。
Generator::seed() GeneratorImpl 纯虚接口,infini_train/include/generator.h
CPU:infini_train/src/core/runtime/cpu/cpu_generator_impl.cc
CUDA:infini_train/src/core/runtime/cuda/cuda_generator_impl.cc
at::Generator::seed() 生成一个非确定的新种子,并用它重置 Generator。核心语义对齐。
Generator::get_state() / Generator::set_state() GeneratorImpl 纯虚接口,infini_train/include/generator.h
CPU:infini_train/src/core/runtime/cpu/cpu_generator_impl.cc
CUDA:infini_train/src/core/runtime/cuda/cuda_generator_impl.cc
at::Generator::get_state() / at::Generator::set_state() 保存和恢复随机序列的推进位置。接口语义对齐,state 的二进制布局不同。
Generator::device() infini_train/include/generator.h
头文件内联实现
at::Generator::device() 查询 Generator 所属设备。语义对齐。
Generator::clone() infini_train/include/generator.h
基类 GeneratorImpl::clone() 在头文件内联实现;后端通过 clone_impl() 实现深拷贝
at::Generator::clone() 创建具有独立随机状态的 Generator。语义对齐。
Generator::mutex() infini_train/include/generator.h
头文件内联实现
at::Generator::mutex() 取得底层 Generator 的互斥锁;跨多个 Generator 操作需要原子化时由调用方加锁。两边均公开锁,但 PyTorch 更明确要求调用方为非只读操作持锁。
infini_train::CreateGenerator() infini_train/include/generator.h
infini_train/src/generator.cc
at::make_generator<Impl>(),后端的 createCPUGenerator() / createCUDAGenerator() 按设备创建 Generator,调用方无需包含后端 Impl 头文件。创建目的对齐,PyTorch 的创建入口按后端拆分。
infini_train::GetDefaultGenerator()(见下文) infini_train/include/generator.h
infini_train/src/generator.cc
at::globalContext().defaultGenerator(Device) 获取对应设备的默认 Generator。按设备获取和延迟创建语义对齐。
infini_train::manual_seed()(见下文) infini_train/include/generator.h
infini_train/src/generator.cc
torch.manual_seed() 重置所有已启用设备的默认 Generator 种子。影响范围与 PyTorch 的全局设种子入口对齐。

1.2 设计说明

Generator 是上层可持有的轻量句柄,只保存一个 std::shared_ptr<GeneratorImpl>。因此复制 Generator 不会复制随机状态,两个句柄会继续消费同一条随机流;调用 clone() 才会得到状态独立、初始内容相同的 Generator。这个语义把“共享同一随机流”和“复制出一条新随机流”区分为两个显式操作。

GeneratorImpl 负责定义不同设备 Generator 共有的状态接口,CPU 和 CUDA 分别提供派生实现。随机算子只接收 Generator,不直接依赖某个后端的实现类型。后端类和相关头文件放在 src/core/runtime/ 下,普通调用路径无需接触 std::mt19937、Philox 或 curand 等随机引擎细节。

创建 Generator 时,CreateGenerator 根据 Device 选择相应后端实现,调用方不需要包含后端 Impl 头文件。后续接入新的设备类型时,可以增加对应的 GeneratorImpl 派生类和创建分支,而无需改变上层随机算子的 Generator 参数形式。

实现中将 seed 与 state 分开处理。set_current_seed() 用于重新初始化随机流,get_state()set_state() 用于保存和恢复已经推进到的位置;随机算子每次使用 Generator 后都会推进其状态。state 的具体编码由后端自行维护,因此公共接口只传递状态对象,不依赖某一种随机引擎的内部表示。

互斥锁归属于 GeneratorImpl。Uniform、Normal 和 Dropout 的 kernel 在消费同一 Generator 时持锁,避免并发调用同时推进同一份状态;如果调用方需要将多个 Generator 操作作为一个原子过程执行,则需要通过 Generator::mutex() 自行界定加锁范围。

1.3 对齐与差异

以下比较基于 2026-08-01 拉取的 PyTorch main(85728e11a5a98c344c4596880855e35046db81b0)中的 ATen/core/Generator.hc10/core/GeneratorImpl.h 及 CPU/CUDA Generator 实现。

  1. 基本一致的行为:两边都采用“用户侧 Generator 句柄 + 设备相关 GeneratorImpl”的多态结构,普通句柄复制共享同一 Impl,clone() 才创建独立状态,Impl 的 Copy/Move 均被删除。set_current_seed()current_seed()seed()get_state()set_state()device() 的核心用途相同;默认 Generator 都按设备维护并延迟创建。公开的 state 载体也都是 CPU 字节 Tensor,而不是裸字节数组。

  2. 未对齐的行为:InfiniTrain 用 std::shared_ptr,PyTorch 用 c10::intrusive_ptr,因此没有 unsafeReleaseGeneratorImpl()getIntrusivePtr() 等所有权和运行时集成接口。两边的 state 二进制布局不同:本实现使用后端 magic、CPU engine 序列化或 CUDA subsequence,PyTorch CPU 使用固定大小 POD,CUDA 使用 seed 与 Philox offset;本实现没有显式 version 字段,公共检查也未验证 state 连续性。线程语义也不完全一致,PyTorch 要求调用方为非只读 Generator 操作持有 mutex,而本实现仅对已接入的 Uniform、Normal、Dropout kernel 自动加锁,直接变更状态或组合多个操作仍由调用方协调。此外,PyTorch 提供 set_offset()get_offset()philox_state() 和 CUDA Graph 的 graph-safe state 接口;本实现通过内部 philox_subsequence() 满足普通 CUDA kernel 的区间预留需求,这些超出赛题范围的扩展能力未纳入当前实现。

2. CPU 与 CUDA 后端 Generator

2.1 接口

CPU 和 CUDA 后端都继承 GeneratorImpl,对外统一实现 seed/state/device/clone 接口。为了服务上层 kernel,两个后端还暴露了一些后端专用方法,这些方法只在 src/ 内部使用。

名称 声明与实现 PyTorch 对应语义 用途/与 PyTorch 对齐度
CPUGeneratorImpl(类) infini_train/src/core/runtime/cpu/cpu_generator_impl.h
infini_train/src/core/runtime/cpu/cpu_generator_impl.cc
at::CPUGeneratorImpl CPU 后端实现,基于 std::mt19937。后端角色与 seed/state 语义对齐,具体 engine 类型不同。
CUDAGeneratorImpl(类) infini_train/src/core/runtime/cuda/cuda_generator_impl.h
infini_train/src/core/runtime/cuda/cuda_generator_impl.cc
at::cuda::CUDAGeneratorImpl CUDA 后端实现,基于 Philox。普通 kernel 的随机区间管理语义基本对齐,PyTorch 额外支持 CUDA Graph。
CPUGeneratorImpl::get_state() / CPUGeneratorImpl::set_state() infini_train/src/core/runtime/cpu/cpu_generator_impl.h
infini_train/src/core/runtime/cpu/cpu_generator_impl.cc
at::CPUGeneratorImpl::get_state() / set_state() 序列化或恢复 engine、seed 与 Normal 缓存。保存与恢复语义对齐,PyTorch 使用固定大小 state,本实现为可变长度序列化。
CUDAGeneratorImpl::get_state() / CUDAGeneratorImpl::set_state() infini_train/src/core/runtime/cuda/cuda_generator_impl.h
infini_train/src/core/runtime/cuda/cuda_generator_impl.cc
at::cuda::CUDAGeneratorImpl::get_state() / set_state() 序列化或恢复 magic、seed 与 Philox subsequence。保存与恢复语义对齐,PyTorch 以 Philox offset 表示推进位置。
CPUGeneratorImpl::random() / CPUGeneratorImpl::random64() infini_train/src/core/runtime/cpu/cpu_generator_impl.h
infini_train/src/core/runtime/cpu/cpu_generator_impl.cc
at::CPUGeneratorImpl::random() / random64() 返回 32/64 位随机数,供 CPU distribution 使用。接口目的对齐。
CPUGeneratorImpl::next_float_normal_sample() / set_next_float_normal_sample()
next_double_normal_sample() / set_next_double_normal_sample()
infini_train/src/core/runtime/cpu/cpu_generator_impl.h
infini_train/src/core/runtime/cpu/cpu_generator_impl.cc
at::CPUGeneratorImpl 的同名 float/double 缓存接口 缓存 Box-Muller 算法的第二个样本。float 与 double 两类缓存语义对齐。
CUDAGeneratorImpl::philox_subsequence() infini_train/src/core/runtime/cuda/cuda_generator_impl.h
infini_train/src/core/runtime/cuda/cuda_generator_impl.cc
at::cuda::CUDAGeneratorImpl::philox_cuda_state(increment) 为一次 kernel 调用预留一段 Philox subsequence,并推进内部计数器。用途相近,但 PyTorch 使用 offset 并兼顾 CUDA Graph 捕获。

上层 kernel 不直接引用 CPUGeneratorImplCUDAGeneratorImpl,而是通过 check_generator<T>()get_generator_or_default<T>() 在内部转换。

2.2 设计说明

CPU 后端使用 std::mt19937。构造时将 64 位 seed 的高、低 32 位同时交给 std::seed_seq 初始化 engine,避免直接调用 std::mt19937(seed) 时高 32 位被截断。CPU 的 Uniform 和 Normal 通过 distributions_helper.h 消费 engine;Normal 采用 Box-Muller,并把尚未消费的第二个样本缓存到 Generator 中。因此,CPU state 除 engine 以外,还需要保存 seed 和 float/double 两种缓存。

image

CUDA 后端不保存每个元素的 curandState,而是保存 seed 和下一段可分配的 Philox subsequence。一次随机 kernel 启动前,在锁保护下调用 philox_subsequence(n) 预留区间;kernel 随后以 curand_init(seed, subsequence + index, 0, &state) 为各元素构造独立状态。这样后续调用从新的 subsequence 开始,不会与已经启动的 kernel 重用随机区间。

image

两个后端都将 state 作为 CPU UINT8 Tensor 返回。set_state() 先检查该公共载体,再由后端检查长度和 magic,因此 CPU/CUDA state 会相互拒绝,长度、dtype、设备或 magic 不符合要求的 state 也会失败。CPU 还会检查 engine 序列化内容和缓存标志;CUDA 的固定字段格式不对 seed 与 subsequence 的数值额外作完整性校验。当前 state 使用 backend magic 区分来源,但没有显式 version 字段;CUDA state 也不编码 device index,因此同一 CUDA backend 的 state 可以恢复到另一张 CUDA 卡。state 格式属于后端私有实现,不保证跨版本兼容。

2.3 对齐与差异

  1. 基本一致的行为:CPU 使用 Mersenne Twister、CUDA 使用 Philox;CUDA 默认 Generator 按设备维度独立维护。两边都不要求 CPU 与 CUDA 在相同 seed 下生成逐元素一致的结果。

  2. 未对齐的行为:PyTorch CPU state 是固定大小的 POD 结构,本实现将 engine 序列化为字符串,因此大小可变。PyTorch CUDA 的常规 state 使用 seed 与 Philox offset,本实现使用带 magic 的 seed 与 subsequence。PyTorch 还提供公开的 offset 控制和 CUDA Graph 相关接口;本实现通过内部 philox_subsequence() 满足普通 CUDA kernel 的区间预留需求,未覆盖这些超出赛题范围的扩展能力。

3. 默认 Generator 与全局随机种子

3.1 接口

名称 声明与实现 PyTorch 对应语义 用途/与 PyTorch 对齐度
infini_train::GetDefaultGenerator(Device) infini_train/include/generator.h
infini_train/src/generator.cc
at::globalContext().defaultGenerator(Device) 返回指定设备的默认 Generator。按设备返回默认状态来源的语义对齐。
infini_train::manual_seed() infini_train/include/generator.h
infini_train/src/generator.cc
torch.manual_seed() 重置 CPU 默认 Generator 和所有 CUDA 设备的默认 Generator。全局默认状态的设种子语义对齐。

3.2 设计说明

默认 Generator 是框架持有的随机状态来源。CPU 维护一个进程级单例;CUDA 按设备索引维护默认 Generator,首次请求该设备时才创建。GetDefaultGenerator(Device) 根据设备类型与 CUDA 设备索引分派并返回对应句柄,因此重复获取同一设备会共享同一份随机状态,不同 CUDA 设备的默认状态彼此独立。

随机算子的 Generator 参数为可选项。调用方传入已定义的 Generator 时,算子直接使用该句柄,不会消耗默认 Generator;未传入参数或传入未定义的 Generator{} 时,算子根据目标 Tensor 所在设备取得默认 Generator。显式 Generator 仍会校验后端类型,CPU Generator 不能用于 CUDA kernel,反之亦然。

manual_seed(uint64_t) 是统一的显式设种子入口。它先重置 CPU 默认 Generator,再初始化并逐个重置所有可见 CUDA 设备的默认 Generator。重置过程在各自的 mutex 保护下进行。该函数只影响默认 Generator,不会改变调用方通过 CreateGenerator() 创建的独立 Generator;在相同种子、设备与随机算子调用顺序下,默认路径可稳定复现。

3.3 对齐与差异

  1. 基本一致的行为:PyTorch 通过 at::globalContext().defaultGenerator(Device) 获取设备默认 Generator,CPU 与 CUDA 后端再分别维护对应实例。本实现的 GetDefaultGenerator(Device) 采用相同的按设备获取语义。两边的 manual_seed 都会重置 CPU 默认 Generator 与当前可见 CUDA 设备的默认 Generator,显式传入的 Generator 也都会优先于默认路径使用。

  2. 未对齐的行为:PyTorch 的 Context 可以通过 accelerator hooks 路由到更多设备后端,本实现当前只覆盖 CPU 与 CUDA。PyTorch 的默认 Generator 获取主要位于 Context 与后端内部接口中,本实现将 GetDefaultGenerator(Device) 作为直接的公共入口。全局设种子只覆盖框架默认状态,不会替显式创建的 Generator 改种子,这一边界与 PyTorch 一致;若后续接入新的设备后端,需要补充对应的默认 Generator 管理与 manual_seed 路径。

4. 随机算子接入

4.1 接口

名称 声明与实现 PyTorch 对应语义 用途/与 PyTorch 对齐度
infini_train::nn::init::Uniform() infini_train/include/nn/init.h
infini_train/src/nn/init.cc
torch.nn.init.uniform_() 对已有 Tensor 做均匀分布初始化。初始化语义对齐,均支持显式 Generator。
infini_train::nn::init::Normal() infini_train/include/nn/init.h
infini_train/src/nn/init.cc
torch.nn.init.normal_() 对已有 Tensor 做正态分布初始化。初始化语义对齐,均支持显式 Generator。
infini_train::nn::init::KaimingUniform() infini_train/include/nn/init.h
infini_train/src/nn/init.cc
torch.nn.init.kaiming_uniform_() 计算 Kaiming uniform 边界后调用 Tensor::Uniform()。计算 fan、gain 和边界的目标语义对齐。
Tensor::Uniform() infini_train/include/tensor.h
infini_train/src/tensor.cc
Tensor.uniform_() Tensor 成员方法,转发到 nn::init::Uniform()。原地均匀填充语义对齐。
infini_train::nn::function::Rand() infini_train/include/nn/functional.h
infini_train/src/nn/functional.cc
torch.rand() 创建并返回均匀分布的新 tensor。创建语义和可选 Generator 参数对齐。
infini_train::nn::function::Randn() infini_train/include/nn/functional.h
infini_train/src/nn/functional.cc
torch.randn() 创建并返回正态分布的新 tensor。创建语义和可选 Generator 参数对齐。
infini_train::nn::function::Dropout() infini_train/include/nn/functional.h
infini_train/src/nn/functional.cc
torch.nn.functional.dropout() Dropout 前向,training 时按概率丢弃元素。前向随机语义对齐,但 InfiniTrain 额外暴露可选 Generator 参数,PyTorch 公共接口使用默认 Generator。

上述接口均以 std::optional<Generator> 接收可选 Generator。未传入参数或传入未定义的 Generator{} 时,后端回退到目标 Tensor 设备的默认 Generator。

4.2 设计说明

初始化与训练期随机算子共用同一条 Generator 接入路径。RandRandn 创建目标 Tensor 后,分别转发到 UniformNormalKaimingUniform 先根据 fan 和 gain 计算边界,再调用 Tensor::Uniform。这些上层接口只传递可选 Generator,并通过 Dispatcher::Instance().Call 进入按设备注册的 CPU 或 CUDA kernel,不直接依赖 std::mt19937、curand 或 Philox 的具体类型。

后端 kernel 通过 get_generator_or_default() 解析可选参数。CPU kernel 取得 Generator 后持锁,逐样本消费 std::mt19937 engine;CUDA kernel 在持锁范围内读取 seed 并按 Tensor 元素数预留 Philox subsequence,随后在 kernel 中以 curand_init(seed, subsequence + index, 0, &state) 初始化每个元素的随机状态。一次实际抽样会推进所选 Generator 的状态,因而相同 seed、设备、Tensor 形状和调用顺序能够复现同一后端上的结果。并发调用虽受 mutex 保护,但锁竞争顺序本身不构成可复现的调用顺序。

Dropout 将可选 Generator 保存在 autograd::Dropout 中,并交给 DropoutForward kernel 生成输出与 UINT8 mask。mask 被标记为不可微并保存到上下文,反向阶段由 DropoutBackward 依照同一 mask 缩放梯度,不再消耗随机状态。training=falsep=0p=1 或空 Tensor 不进行实际抽样。CPU/CUDA 的 distribution 和 Dropout kernel 均覆盖 FLOAT16BFLOAT16FLOAT32FLOAT64 四种浮点 dtype。

4.3 对齐与差异

  1. 基本一致的行为:UniformNormalKaimingUniformRandRandn 都可选择显式 Generator 或设备默认 Generator,语义对应 PyTorch 初始化函数及 torch.randtorch.randn 的 generator 参数。两边的 Dropout 都在前向阶段生成并保存 mask,反向阶段复用该 mask;CPU 与 CUDA 的随机算法不同,因此只承诺各后端在相同调用条件下可复现,不承诺跨设备逐元素一致。

  2. 未对齐的行为:本实现将 std::optional<Generator> 直接暴露给 Dropout,方便训练代码显式控制随机流;PyTorch 的 torch.nn.functional.dropout 公共接口没有 generator 参数,通常使用当前设备默认 Generator。本实现的 Dropout 没有 inplace 选项,随机初始化覆盖范围也只包含本题接入的 Uniform、Normal 和 KaimingUniform,未扩展到 PyTorch 的全部随机算子与初始化策略。后续新增随机算子时,可沿用可选 Generator 参数、后端校验和 kernel 内状态预留这条接入路径。

二、其他改动与后续工作

DDP 构造阶段参考 PyTorch 的初始化同步语义,由 rank 0 将模块参数和 buffer 原地广播到其余 rank,使各卡在训练开始前持有一致的模型状态。目前的实现不试图改变单进程多线程训练时共享 CPU 默认 Generator 的语义。多个 rank 对默认随机流的消费顺序受线程调度影响,因此即使重复相同操作,也不保证跨次运行得到完全相同的随机序列。后续可考虑两条路线:采用类似 torchrun 的一 GPU 一进程启动方式,使各 rank 拥有独立进程内 RNG;或参考 Megatron 的思路,为不同线程提供隔离的局部随机流。后者会扩展全局默认 Generator 的设计边界,因此未纳入本题实现范围。

三、验证与复现

3.1 验证环境

本节正式结果来自租用的 7 卡 CUDA 服务器,运行日志见后文图片。配置如下。

项目 配置
GPU NVIDIA RTX 4090 D,7 张
CUDA Toolkit 12.8
CMake 3.31.4
NCCL 2.25.1
C++ 编译器 /usr/bin/g++-13
CUDA 架构 CMAKE_CUDA_ARCHITECTURES=89
构建选项 USE_CUDA=ONUSE_NCCL=ONBUILD_TEST=ON

3.2 测试内容与结果

Generator 测试位于 tests/generator/test_generator_cputest_generator_cuda 由同一套参数化 gtest 源码生成;本次分别通过 --gtest_filter='CPU/*'--gtest_filter='CUDA/*' 选择对应参数实例。因此两行覆盖的用例互不重复,可以合并阅读。

可执行文件 本次结果 覆盖内容
test_generator_cpu 17 passed,2 skipped,2454 ms CPU 参数实例。两条仅适用于 CUDA 的用例按条件跳过。
test_generator_cuda 17 passed,2 skipped,5719 ms CUDA 参数实例。两条仅适用于 CPU 的用例按条件跳过;7 卡默认 Generator 独立性与 CUDA Generator 跨卡使用用例实际通过。
test_generator_ddp 1 passed,1603 ms DDP 构造后将 rank 0 参数广播到其余 GPU 的测试。7 卡环境实际执行并通过。

两组 Generator 测试共 34 条通过、4 条按后端条件跳过,没有失败用例。CPU 筛选跳过 CUDA 专用项,CUDA 筛选跳过 CPU 专用项;由于服务器有 7 张 GPU,所有需要至少 2 张 GPU 的用例均实际运行。

核心测试覆盖了本题的四类功能。test_generator_core.cc 验证 Generator 的句柄和 state 语义、默认 Generator 与显式 Generator 的选择、CPU/CUDA 后端不匹配时的拒绝,以及初始化入口的可复现性;test_generator_random_ops.cc 验证 RandRandnDropout 的固定随机脚本重放、默认状态不受显式 Generator 消耗、四种浮点 dtype、非连续 view 的写入范围、Dropout mask 与反向计算,以及非法参数的失败路径。DDP 用例是附带验证,关注多 GPU 环境中模块参数的初始同步,不改变 Generator 的公共语义。

image image image ### 3.3 复现步骤

在仓库根目录配置并构建测试:

cmake -S . -B build \
  -DCMAKE_CXX_COMPILER=/usr/bin/g++-13 \
  -DCMAKE_CUDA_HOST_COMPILER=/usr/bin/g++-13 \
  -DUSE_CUDA=ON \
  -DUSE_NCCL=ON \
  -DBUILD_TEST=ON \
  -DCMAKE_POLICY_VERSION_MINIMUM=3.5
cmake --build build -j$(nproc)

进入构建目录后运行 Generator 测试。若运行环境未为 glog 或 CUDA 配置动态库搜索路径,可先设置 LD_LIBRARY_PATH

cd build
export LD_LIBRARY_PATH="$PWD/third_party/glog:/usr/local/cuda/lib64${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"

./tests/generator/test_generator_cpu --gtest_filter='CPU/*'
./tests/generator/test_generator_cuda --gtest_filter='CUDA/*'
./tests/generator/test_generator_ddp

CPU 筛选会跳过 CUDA 专用用例,CUDA 筛选会跳过 CPU 专用用例。若机器少于两张 GPU,CUDA 的跨卡 Generator、各设备默认 Generator 独立性和 DDP 测试还会按条件跳过。多卡服务器若无法由 CMake 自动探测架构,可在配置命令中额外传入 -DCMAKE_CUDA_ARCHITECTURES=89,用于 RTX 4090 D。


2026 春季启元人工智能大赛诚信守则(Honor Code)

本人作为 2026 春季启元人工智能大赛(以下简称“比赛”)的参赛选手,郑重承诺严格遵守比赛规则及本诚信守则,秉持诚信、公正、廉洁的参赛原则,自觉维护比赛的公平性与严肃性。本人充分理解并认可,违反本准则将导致参赛资格被取消、比赛成绩作废等相应后果,且愿意承担由此产生的一切责任。

一、参赛诚信承诺

  1. 本人保证所提交的赛题PR(Pull Request)中包含的算子实现代码及相关文档,均为本人(及参赛团队,如为团队参赛)在比赛期间独立完成或在明确标注参考来源的基础上进行开发,不存在任何欺诈、抄袭、作弊行为。

  2. 本人承诺主动、全面、真实地披露赛题实现过程中所有参考的外部资源,尤其是开源代码资源,不隐瞒任何可能影响比赛公平性的信息。

  3. 本人保证不采用任何不正当手段获取比赛优势,包括但不限于窃取其他参赛选手的代码成果、利用非比赛允许的工具或技术、与他人串通作弊等。

二、参考资源说明

本人确认已按比赛要求,将本次赛题实现过程中涉及的参考资源信息单独撰写至REFERENCE.md文件中,该文件将与本诚信守则一同作为PR附件提交。REFERENCE.md需根据实际参考情况,按以下要求完整填写,信息不完整或虚假填写将视为违反本准则:

情况1:无参考外部开源代码及核心实现思路

REFERENCE.md中需明确声明:“本次赛题提交的算子代码、核心算法逻辑及实现方案均为本人(及参赛团队)独立设计与开发,未参考任何外部开源项目、技术文档中的核心代码片段或实现思路,未接受任何第三方的技术指导或代码支持。”

情况2:有参考外部开源代码及相关资源

对每个参考资源提供以下信息陈述:

  1. 参考开源项目/资源名称

  2. 参考资源链接(GitHub/Gitee/论文/技术文档等)

  3. 参考的具体内容(请明确说明参考的代码片段、算法逻辑、实现思路等,需标注对应资源的具体位置,如文件路径、代码行数等)

  4. 本人对参考内容的修改与优化说明:(请详细说明在参考基础上,本人所做的独立开发、修改、优化工作,体现自身技术贡献)

  5. 若是开源项目,提供参考资源的开源协议类型:(如MIT、Apache 2.0、GPL等)

  6. 其他需要补充说明的信息

三、禁止行为确认

本人明确知晓并承诺避免以下违反比赛公平性的行为,若存在以下任一情况,自愿接受比赛组委会的相应处罚:

  1. 未经授权复制、抄袭他人(包括其他参赛选手、开源项目、商业代码)的代码、算法或技术方案,且未进行明确标注;

  2. 隐瞒或虚假披露参考资源信息,包括遗漏重要参考来源、伪造参考内容说明等;

  3. 与其他参赛选手或第三方串通,进行代码共享、成果交换等违规协作;

  4. 利用比赛平台漏洞、技术缺陷或非比赛允许的工具获取不正当利益;

  5. 伪造比赛相关证明材料、提交虚假信息;

  6. 其他违反比赛规则及公序良俗的不诚信行为。

四、责任与确认

  1. 本人充分理解,比赛组委会将对所有提交的PR进行代码溯源、参考信息核查等公平性审查,若发现本人存在违反本准则的行为,有权随时取消本人的参赛资格、作废比赛成绩,情节严重的将在比赛相关平台进行公示。

  2. 若因本人违反本准则导致比赛争议或第三方权益受损(如开源协议侵权等),本人将独立承担全部法律责任及相关损失,与比赛组委会无关。

  3. 本人确认已仔细阅读并完全理解本诚信守则的全部内容,自愿签署本准则,接受比赛组委会的监督与审查。

五、签署信息

参赛选手姓名(团队参赛需填写所有成员姓名)
李源,王柯翰,狄凡瑞

签署日期
2026年7月12日


REFERENCE

本项目在比赛提供的 InfiniTrain 代码库上完成。实现时参考了 PyTorch 对随机数状态、默认 Generator 和训练期随机算子的公开语义与实现思路;代码结合 InfiniTrain 现有的 TensorDeviceDispatcher、Autograd 和构建结构独立完成。

PyTorch Generator、随机算子与 DDP

资源: PyTorch

主要参考:

  • Generator 接口与实现CPU GeneratorCUDA Generator。参考句柄与后端实现分离、默认 Generator、seed 和 state 的语义,以及 CUDA 中按设备维护独立随机状态的做法。
  • 随机分布辅助实现CPU 分布 kernel。参考 Generator 负责提供和推进随机状态、Uniform 与 Normal kernel 消费随机数、Normal 缓存第二个 Box-Muller 样本的组织方式。
  • CUDA Dropout。参考训练期前向生成随机 mask、反向复用该 mask,以及前向调用推进随机状态的语义。
  • 随机性说明Generator 文档。参考显式传入 Generator、默认 Generator 和设置统一 seed 后可复现的使用语义。
  • PyTorch DistributedDataParallel 的初始化同步语义。参考由 rank 0 将模块参数和 buffer 同步到其他 rank 的行为,用于本项目 DDP 构造后的模块状态同步。

本项目没有复制 PyTorch 的实现。CPU 后端使用 std::mt19937 保存随机序列状态,CUDA 后端以 seed 和 Philox subsequence 管理 kernel 所需的随机区间;两者通过 InfiniTrain 的 Dispatcher 注册并分发 CPU/CUDA kernel。项目目标是保持 Generator 的使用和可复现语义,不要求 CPU 与 CUDA 在相同 seed 下产生逐位一致的随机数,也未覆盖 CUDA Graph 等扩展接口。

AI 工具

资源名称:OpenAI Codex,Claude Code

资源链接:https://openai.com/codex

参考内容:用于协助整理实验记录、分析 benchmark 结果、撰写报告,并辅助生成小范围代码改动方案。

修改与优化:最终代码与实验决策均由参赛团队确认;

协议:不涉及开源代码复用。

@kilinchange
kilinchange requested a review from chen2021673 July 13, 2026 08:33

@chen2021673 chen2021673 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在修改逻辑细节前建议先完成以下整体整理:

  1. 收敛 PR 范围。 删除 benchmark 、Tokenizer、MNIST、Tensor::To、Exp backward 等无关修改(如觉得必要可以单独PR修复);
  2. 清理个人开发环境内容例如 .gitignore 文件;
  3. 不要引入第二套 distribution_stubs 体系。 仓库已有 dispatcher,应优先复用现有机制;
  4. 现在创建 CPU/CUDA Generator 必须包含 src/..._generator_impl.h,建议提供公共的 CreateGenerator(Device, seed) 等接口,隐藏具体 Impl;
  5. 统一注释与 include 规范。 新增 C++ 注释统一改成简洁英文,删除“比赛要求”“仿 PyTorch XX 行”及“//用struct能记录”等开发期说明。做一次 header self-contained/IWYU 检查及格式检查;
  6. 如果声明支持 FP16/BF16/FP32/FP64,请补充测试。
  7. 整理提交历史,自行 Review 代码,确认逻辑清晰简洁,尽量达到可合入标准。

@ChaoticLuna
ChaoticLuna force-pushed the 2026-spring-ChaoticLuna-T2-2-1 branch from 4eda57f to 41cb406 Compare July 26, 2026 21:46
@ChaoticLuna

ChaoticLuna commented Jul 26, 2026

Copy link
Copy Markdown
Author

感谢 review,已完成整理:

  1. 已按照要求收敛PR范围,删除了与赛题无关的修改内容(benchmarkTokenizerMNISTTensor::ToExp backward 等)。
  2. 已清除个人开发环境的冗余文件
  3. 随机分布与 Dropout 统一复用仓库现有的Dispatcher分发宏和注册宏,并参考官方代码格式,定义别名宏,统一调用REGISTER_KERNEL完成核函数的分发注册,具体调用侧则直接使用Dispatcher::Instance().Call
  4. 新增 infini_train::CreateGenerator(Device, seed) / GetDefaultGenerator(Device) / manual_seed(seed)generator.h),CPU/CUDA Impl 头文件全部收回 src/ 内部,调用方无需知晓 *_generator_impl.h
  5. 新增/修改注释已统一为简洁英文,无关注释已删除;已完成 header self-contained 与 IWYU 检查
  6. 已补 FP16/BF16/FP32/FP64 四 dtype 的 Uniform/Normal/Dropout 前反向测试
  7. 提交历史重新整理为 6 个线性 commit。

另外,本仓库还做了额外的修改:

  1. cpu侧的mt引擎现在不再直接截断成32bit,而是64bit都参与计算。
  2. 参考官方代码风格,现在DropoutForward 改为显式返回 {output, mask} 元组。
  3. state加入了8字节的magic头,跨后端 state 双向拒绝,截断/错误 dtype/错误设备的损坏 state 显式失败。保留负载头和缓存。
  4. 仿照pytorch,支持ddp rank0向其他卡广播。但是对于单进程多线程的情况,若想要两次ddp复刻同一个操作则极有可能失败,因此解决方法1、使用类似torchrun的方式启动多进程而非多线程。2、参考megatron的实现,利用局部的RNG来隔离不同线程的默认generator,由于似乎有点偏离赛道,因此可以作为后续考虑的方向。
  5. 重新进行了多卡测试,环境如下:
CMake   3.31.4
NCCL    2.25.1
CMAKE_CUDA_ARCHITECTURES	89
CMAKE_CXX_COMPILER=/usr/bin/g++-13
4090-d * 7

命令:

cmake -S . -B build \
  -DCMAKE_CXX_COMPILER=/usr/bin/g++-13 \
  -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc \
  -DCMAKE_CUDA_HOST_COMPILER=/usr/bin/g++-13 \
  -DCMAKE_CUDA_ARCHITECTURES=89 \
  -DUSE_CUDA=ON \
  -DUSE_NCCL=ON \
  -DBUILD_TEST=ON \
  -DCMAKE_POLICY_VERSION_MINIMUM=3.5
cd build
export LD_LIBRARY_PATH="$PWD/third_party/glog:/usr/local/cuda/lib64:${LD_LIBRARY_PATH:-}"

./tests/generator/test_generator_cpu --gtest_filter='CPU/*'
./tests/generator/test_generator_cuda --gtest_filter='CUDA/*'
./tests/generator/test_generator_ddp
image image image

@ChaoticLuna
ChaoticLuna requested a review from chen2021673 July 26, 2026 22:56

} // namespace

void Uniform(const std::shared_ptr<Tensor> &tensor, double from, double to, const std::optional<Generator> &gen) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里注册的函数参数为 const std::optional<Generator>& generator),但现有 Dispatcher 的调用逻辑中,ArgsT... 按值推导,调用的应该是 std::optional<Generator>,这两个函数指针类型不相同。直接修改这里的类型即可。

@ChaoticLuna ChaoticLuna Aug 1, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已按现有 Dispatcher 的按值调用约束,将本 PR 中注册的随机 kernel 的 std::optional 统一改为按值传递,见 383657e
不过同时注意到 KernelFunction::Call 已有“支持自动推导返回值和参数类型”的 TODO。当前的类型擦除调用无法保留注册函数的精确引用类型,仓库既有部分 kernel 的引用参数也有同样的限制如ScatterForward、GatherForward;根治需要调整 Dispatcher 的注册与调用机制,超出本 PR 范围,因此本次未改动既有 kernel。感谢指出。

@chen2021673

Copy link
Copy Markdown
Contributor

赛题报告如有和代码不符的地方请尽快更新。

@ChaoticLuna
ChaoticLuna force-pushed the 2026-spring-ChaoticLuna-T2-2-1 branch from 3ea06c8 to 383657e Compare August 1, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants