切片计算与求和

枚举切片取值、并行执行并汇总结果,以及切片对总计算量和内存的影响。

本页目录

计算每个切片,再把结果相加

确定路径和切片 index 后,才开始实际的数组计算。每组 index 取值对应一个子任务:从输入张量中取出相应的数据,再按方案中的收缩路径得到该片结果。所有切片计算完后,将结果逐元素相加,得到原网络的收缩结果。

例如,一个维度为 2 的内部 index 被切片后,计算两个结果 R0R_0、R1R_1,最终结果为 R=R0+R1R=R_0+R_1。这就是“按切片方案执行收缩”,不是再次搜索路径。

两个切片 index 的取值组合。连续编号分为一组;组内顺序累加,组间并行执行,最后按组编号合并结果。
rust
use arctn::contract_network_sliced;

let output = contract_network_sliced(
    &net, &tensors, &ssa_path, &sliced_legs
)?;

并行计算与结果求和

原生执行器把连续编号的切片分成若干组(chunk)。每组按切片编号顺序累加,Rayon 并行处理不同组;完成后再按组编号依次合并部分和。分组只依赖切片数和输出元素数,不依赖线程数。

项目 具体行为
分组数上限 最多 256,并受部分输出的元素数预算限制
线程变化 改变各组的完成时机,不改变分组和最终合并顺序
无切片 index 直接调用 contract_network
并发内存 同时执行的每个切片都有自己的输入副本和中间结果

线程数独立的归并顺序用于稳定单机浮点结果;它不意味着 MPI Allreduce 在不同 rank 数下也逐位相同。

总工作量与内存

若切片数为 NN,全部切片的二元收缩工作量为

Ftotal=NFslice,log⁡10Ftotal=log⁡10Fslice+log⁡10N.\begin{aligned} F_{\mathrm{total}}&=NF_{\mathrm{slice}},\\ \log_{10}F_{\mathrm{total}}&=\log_{10}F_{\mathrm{slice}}+\log_{10}N. \end{aligned}

切片可能降低单片最大结果,同时因重复计算使总 FLOPs 上升;模型计数不含最终跨片求和的额外加法。

随切片增加通常下降 随切片增加通常上升
单片最大中间结果 完整执行的切片数
单个子任务的路径模型内存 总 FLOPs 和输入读取

target_size 只限制单片的二元收缩结果,单张量网络则检查最终输出。原始输入、一元预处理、转置临时量、后端工作区、部分和以及同时执行的其他切片都会增加实际 RSS。控制总内存时,还需考虑执行并行度。

三条执行路线

路线 切片任务调度 单片收缩 结果累加
Rust / Python native Rust 按固定分组,用 Rayon 并行 ArcTN Rust CPU 执行器 组内、组间均按编号顺序累加
Python 外部后端 Python 按固定顺序串行枚举 复用一个 opt_einsum.contract_expression 在所选数组后端上相加
tnmpi 各进程执行不同的连续切片区间 ArcTN Rust CPU 执行器;--dtype 支持四种实数 / 复数类型,见 MPI 执行 MPI Allreduce

三条路线使用相同的数学分解,但任务调度、同步和浮点归并顺序不同。性能测试应注明执行路线。