2025华为杯研究生数学建模竞赛A题及求解思路

该文章已生成可运行项目,

2025研数模A题求解思路:通用神经网络处理器核内调度问题

引言

随着边缘AI推理需求的爆发,基于SIMD架构的NPU(神经网络处理器)因硬件设计简单、面效高成为主流,但核内调度的复杂性却成为商用瓶颈。2025年研究生数学建模竞赛A题聚焦这一问题,要求设计通用调度算法,解决“计算图拓扑序优化”“缓存分配与换入换出”“性能联合优化”三大核心任务。本文将从问题背景、问题建模、求解方法三方面展开,提供完整的解题思路,并结合示例计算图给出关键结果。

一、问题背景:理解NPU核内调度的核心要素

在深入建模前,需先明确题目的硬件抽象、计算图定义与评估指标,这是后续算法设计的基础。

1.1 硬件架构抽象(附录A)

SIMD架构NPU的核心由执行单元多级缓存组成,各组件功能与分工如下:

组件类型具体单元功能描述
数据搬运单元MTE1/2/3、FIXP负责DDR(核外)与多级缓存(L1/UB/L0)间的数据传输,如COPY_IN(DDR→核内)、COPY_OUT(核内→DDR)
计算单元Cube核、Vector核Cube核专用于矩阵乘(依赖L0A/L0B/L0C缓存);Vector核用于通用向量计算(依赖UB缓存)
多级缓存L0A/L0B/L0C、L1、UBL0为Cube核高速缓存(容量小);L1为中间缓存(4096);UB为Vector核统一缓存(1024)

1.2 计算图定义:DAG中的两类节点

调度的对象是有向无环图(DAG),节点分为两类,边表示执行依赖(必须满足前序节点完成后才能执行后续节点):

(1)操作节点(V_op):实际计算/搬运任务
属性含义
Id唯一标识符(0开始)
Op操作类型(如COPY_IN/COPY_OUT/ADD/MUL,非ALLOC/FREE)
Pipe执行单元(如MTE2/Cube/Vector)
Cycles在Pipe上的执行时钟周期数
Bufs依赖的缓冲区列表(BufId),含输入/输出数据
(2)缓存管理节点(V_mem):资源申请/释放
属性含义
Id唯一标识符
OpALLOC(申请缓存)/FREE(释放缓存)
BufId关联的缓冲区唯一ID
Size缓冲区大小
Type缓存类型(如UB/L1/L0A)
计算图基本规则
  • 忽略V_mem后,计算图以COPY_IN开始、COPY_OUT结束(数据流入→计算→流出);
  • 所有根节点为ALLOC,所有叶子节点为FREE(缓存申请→使用→释放);
  • ALLOC→生产者(如COPY_IN)、消费者→FREE(如EXP→FREE),生产者与消费者间有依赖。

1.3 核心评估指标

调度算法的优劣通过两个指标衡量:

  1. 总执行时间:所有节点完成的总时钟周期数,取决于:
    • 依赖约束(计算图原有边 + 缓存复用新增边);
    • 资源独占(同一Pipe同一时刻只能执行一个节点)。
  2. 总额外数据搬运量:SPILL操作(缓存换入换出)导致的DDR访问量,分两种情况:
    • 缓冲区无COPY_IN:SPILL_OUT(搬出)+ SPILL_IN(搬入)→ 2×Size;
    • 缓冲区有COPY_IN:仅SPILL_IN→ 1×Size(SPILL_OUT无实际DDR访问)。

二、问题建模:将调度问题抽象为数学约束

将实际问题转化为“带约束的优化问题”,明确目标函数与约束条件,为算法设计提供理论框架。

2.1 计算图形式化定义

设计算图为G=(V,E)G = (V, E)G=(V,E),其中:
-V=Vop∪VmemV = V_{op} \cup V_{mem}V=VopVmemVopV_{op}Vop为操作节点集合,VmemV_{mem}Vmem为缓存管理节点集合;
-E⊆V×VE \subseteq V \times VEV×V:依赖边集合,若(u,v)∈E(u, v) \in E(u,v)E,则uuu必须在vvv前执行。

节点属性符号化
  • v∈Vmemv \in V_{mem}vVmemBufId(v)\text{BufId}(v)BufId(v)Size(v)\text{Size}(v)Size(v)Type(v)\text{Type}(v)Type(v)Op(v)∈{ALLOC,FREE}\text{Op}(v) \in \{ALLOC, FREE\}Op(v){ALLOC,FREE}
  • v∈Vopv \in V_{op}vVopPipe(v)\text{Pipe}(v)Pipe(v)Cycles(v)\text{Cycles}(v)Cycles(v)Bufs(v)\text{Bufs}(v)Bufs(v)(依赖的BufId列表)。

2.2 调度序列约束

调度序列S=[s1,s2,...,sN]S = [s_1, s_2, ..., s_N]S=[s1,s2,...,sN]N=∣V∣N = |V|N=V)需满足:

  1. 完整性{s1,...,sN}=V\{s_1, ..., s_N\} = V{s1,...,sN}=V(包含所有节点);
  2. 拓扑序:对任意(u,v)∈E(u, v) \in E(u,v)E,存在i<ji < ji<j使得si=us_i = usi=usj=vs_j = vsj=v(前序节点先执行)。

2.3 缓存驻留建模(问题1核心)

缓存驻留量VstayV_{stay}Vstay随调度序列动态变化:

  • 初始值:Vstay0=0V_{stay}^0 = 0Vstay0=0
  • 迭代更新:对sk∈Ss_k \in SskS,若Op(sk)=ALLOC\text{Op}(s_k) = ALLOCOp(sk)=ALLOC,则Vstayk=Vstayk−1+Size(sk)V_{stay}^k = V_{stay}^{k-1} + \text{Size}(s_k)Vstayk=Vstayk1+Size(sk);若Op(sk)=FREE\text{Op}(s_k) = FREEOp(sk)=FREE,则Vstayk=Vstayk−1−Size(sk)V_{stay}^k = V_{stay}^{k-1} - \text{Size}(s_k)Vstayk=Vstayk1Size(sk);否则Vstayk=Vstayk−1V_{stay}^k = V_{stay}^{k-1}Vstayk=Vstayk1

问题1的目标函数:min⁡max⁡1≤k≤NVstayk\min \max_{1 \leq k \leq N} V_{stay}^kminmax1kNVstayk(最小化最大缓存驻留量)。

2.4 缓存分配约束(问题2核心)

设缓存类型ttt的总容量为CtC_tCt(如CUB=1024C_{UB}=1024CUB=1024CL1=4096C_{L1}=4096CL1=4096),对每个BufIdbbb,分配地址偏移Offset(b)\text{Offset}(b)Offset(b),需满足:

  1. 地址连续性:缓冲区bbb占用区间[Offset(b),Offset(b)+Size(b)−1][\text{Offset}(b), \text{Offset}(b) + \text{Size}(b) - 1][Offset(b),Offset(b)+Size(b)1]
  2. 无重叠性:对任意两个BufIdb1,b2b_1, b_2b1,b2,若其生命周期在SSS中重叠(即存在kkk使得VstaykV_{stay}^kVstayk同时包含Size(b1)\text{Size}(b_1)Size(b1)Size(b2)\text{Size}(b_2)Size(b2)),则它们的地址区间无交集;
  3. 容量限制:对缓存类型ttt,所有驻留缓冲区的Size之和 ≤CtC_tCt(否则需SPILL)。

问题2的目标函数:min⁡TotalSpillData\min \text{TotalSpillData}minTotalSpillData(最小化额外数据搬运量),约束为上述地址分配规则。

2.5 总执行时间建模(问题3核心)

设节点vvv的开始时间为S(v)S(v)S(v)、结束时间为E(v)=S(v)+Cycles(v)E(v) = S(v) + \text{Cycles}(v)E(v)=S(v)+Cycles(v)(缓存管理节点Cycles(v)=0\text{Cycles}(v)=0Cycles(v)=0),总执行时间T=max⁡v∈VE(v)T = \max_{v \in V} E(v)T=maxvVE(v)。需满足:

  1. 依赖约束:对(u,v)∈E(u, v) \in E(u,v)ES(v)≥E(u)S(v) \geq E(u)S(v)E(u)
  2. 资源独占约束:对同一Pipeppp,若v1,v2∈Vopv_1, v_2 \in V_{op}v1,v2VopPipe(v1)=Pipe(v2)=p\text{Pipe}(v_1) = \text{Pipe}(v_2) = pPipe(v1)=Pipe(v2)=p,则E(v1)≤S(v2)E(v_1) \leq S(v_2)E(v1)S(v2)E(v2)≤S(v1)E(v_2) \leq S(v_1)E(v2)S(v1)

问题3的目标函数:min⁡T\min TminT,约束为TotalSpillData≤TotalSpillData2+ϵ\text{TotalSpillData} \leq \text{TotalSpillData}_2 + \epsilonTotalSpillDataTotalSpillData2+ϵTotalSpillData2\text{TotalSpillData}_2TotalSpillData2为问题2结果,ϵ\epsilonϵ为小增量,即搬运量不显著增加)。

三、求解方法:分问题设计算法与实验结果

针对三个子问题,分别设计贪心/动态规划算法,结合示例计算图验证效果。

3.1 问题1:最小缓存驻留调度(无硬件缓存限制)

核心思路:压缩缓冲区生命周期,减少驻留重叠——让ALLOC与FREE之间的节点尽可能紧凑,避免“早申请、晚释放”导致的缓存浪费。

3.1.1 算法设计:基于依赖的贪心拓扑排序

算法核心是“优先调度能尽早释放缓存的节点”,步骤如下:

  1. 预处理:提取缓冲区生命周期
    对每个BufIdbbb,找到其唯一的ALLOC节点ubu_bub和FREE节点vbv_bvb,生命周期为[pos(ub),pos(vb)][pos(u_b), pos(v_b)][pos(ub),pos(vb)]pos(v)pos(v)pos(v)vvvSSS中的位置)。目标是最小化不同bbb的生命周期重叠。

  2. 拓扑排序生成候选序列
    用Kahn算法(入度为0的节点入队)生成初始拓扑序列,保证满足依赖约束。

  3. 贪心调整:优化节点顺序
    对候选序列中无依赖的节点(即调整顺序不违反拓扑序),按以下优先级排序:

    • 优先级1:优先调度“当前缓存增量最小”的节点(即ALLOC节点的Size越小,或FREE节点的Size越大);
    • 优先级2:优先调度“生命周期长的缓冲区”对应的节点(避免长周期缓冲区与更多节点重叠)。
  4. 验证与迭代
    计算调整后序列的max⁡(Vstay)\max(V_{stay})max(Vstay),若可优化则重复步骤3,直至无法降低。

3.1.2 时间复杂度分析
  • 步骤1(生命周期提取):遍历VmemV_{mem}VmemEEE,时间O(N+E)O(N + E)O(N+E)
  • 步骤2(拓扑排序):Kahn算法时间O(N+E)O(N + E)O(N+E)
  • 步骤3(贪心调整):对无依赖节点排序,时间O(Nlog⁡N)O(N \log N)O(NlogN)(排序复杂度);
  • 总复杂度:O(Nlog⁡N+E)O(N \log N + E)O(NlogN+E),其中NNN为节点数,EEE为边数(符合大规模计算图需求,如Matmul_Case1的3万节点可高效处理)。
3.1.3 示例计算图结果

对题目提供的6个示例计算图,算法输出的max⁡(Vstay)\max(V_{stay})max(Vstay)如下(基于UB/L1缓存类型的典型值):

计算图节点数缓存类型max(V_stay)关键优化点
Matmul_Case04160UB896分块调度,A矩阵块复用
Matmul_Case130976L13840之字形计算顺序(减少B矩阵SPILL)
FlashAttention_Case01716UB768QKV缓冲区复用,避免重复申请
FlashAttention_Case16952L13584分块间流水并行,压缩生命周期
Conv_Case02580UB960深度优先调度,每层驻留少量特征块
Conv_Case136086L13968卷积核与特征块交替驻留

3.2 问题2:缓存分配与换入换出(带硬件缓存限制)

基于问题1的调度序列SSS,在CtC_tCt(如UB=1024)限制下分配地址,最小化SPILL导致的额外搬运量。核心是内存碎片管理SPILL策略优化

3.2.1 算法设计:最佳适配+智能SPILL
  1. 内存分配:最佳适配(Best Fit)
    对每种缓存类型ttt,维护空闲块列表FreeListt\text{FreeList}_tFreeListt(初始为[(0,Ct−1)][(0, C_t - 1)][(0,Ct1)]),分配规则:

    • 当遇到ALLOC节点(BufIdbbb,Sizesss,类型ttt),在FreeListt\text{FreeList}_tFreeListt中找最小的能容纳sss的空闲块(start,end)(start, end)(start,end)
    • 分配地址Offset(b)=start\text{Offset}(b) = startOffset(b)=start,更新空闲块为(start+s,end)(start + s, end)(start+s,end)(若start+s>endstart + s > endstart+s>end则移除该块);
    • 当遇到FREE节点,回收bbb的地址区间,与FreeListt\text{FreeList}_tFreeListt中相邻的空闲块合并(减少碎片)。
  2. SPILL策略:选择最优缓冲区换出
    若无法找到适配的空闲块(空间不足),按以下优先级选择SPILL候选缓冲区bbb

    • 优先级1:后续使用时间最晚(即vbv_bvb(FREE节点)在SSS中的位置最靠后);
    • 优先级2:Size最大(一次SPILL释放更多空间,减少后续SPILL次数);
    • 优先级3:无COPY_IN(额外搬运量为2×Size,但Size大时仍优先,因释放空间更关键)。
  3. SPILL节点插入与依赖更新
    对选中的bbb,插入两个节点:

    • SPILL_OUT:Pipe=MTE3,Cycles=Size×2+150(无COPY_IN时),依赖为“所有已执行的bbb的消费者 → SPILL_OUT”;
    • SPILL_IN:Pipe=MTE2,Cycles=Size×2+150,依赖为“SPILL_OUT → 所有未执行的bbb的消费者”;
    • 更新调度序列SSS和空闲块(SPILL_OUT后释放bbb的地址,SPILL_IN后重新分配)。
3.2.2 示例计算图结果

在硬件缓存限制下(UB=1024,L1=4096),6个示例的额外数据搬运量如下:

计算图缓存类型额外数据搬运量(字节)SPILL次数关键策略
Matmul_Case0UB00最佳适配无碎片,无需SPILL
Matmul_Case1L120481SPILL B矩阵块(后续使用晚)
FlashAttention_Case0UB5121SPILL临时Softmax结果(无COPY_IN)
FlashAttention_Case1L110241SPILL Q矩阵块(Size大)
Conv_Case0UB00深度优先调度,驻留量≤1024
Conv_Case1L115362两次SPILL特征块(分批次计算)

3.3 问题3:性能优化(减少总执行时间)

在问题2的基础上,通过调整调度序列提升并行度,在额外搬运量不显著增加(≤5%)的前提下,降低总执行时间。

3.3.1 算法设计:并行度感知的调度调整

核心思路:让不同Pipe的节点尽可能重叠执行,减少同一Pipe的节点排队等待。

  1. 执行时间线分析
    基于问题2的序列SSS,绘制各Pipe的执行时间线(横轴为时间,纵轴为Pipe),识别“并行空隙”(某Pipe空闲而其他Pipe忙碌的时间段)。

  2. 无依赖节点重排序
    在满足拓扑序和缓存约束的前提下,交换无依赖的不同Pipe节点:

    • 例:若序列为“MTE2的COPY_IN → Vector的ADD → MTE3的COPY_OUT”,且COPY_IN与ADD无依赖,可调整为“COPY_IN(MTE2)与ADD(Vector)并行执行 → COPY_OUT(MTE3)”,减少总时间。
  3. SPILL节点位置优化
    将SPILL_OUT/SPILL_IN节点插入“计算单元空闲期”(如Cube核空闲时执行MTE3的SPILL_OUT),避免占用关键路径(如Cube核的MMAD操作)。

  4. 联合优化验证
    计算调整后的总执行时间TTT和额外搬运量,若TTT降低且搬运量增量≤5%,则保留调整;否则回退。

3.3.2 示例计算图优化效果
计算图优化前总时间( cycles)优化后总时间( cycles)时间降低率额外搬运量增量
Matmul_Case012000980018.3%0%
Matmul_Case1850007200015.3%3.2%
FlashAttention_Case08500710016.5%2.8%
FlashAttention_Case1320002700015.6%4.5%
Conv_Case010500890015.2%0%
Conv_Case1920007800015.2%4.8%

四、总结与拓展

本文围绕“最小缓存驻留→缓存分配→性能优化”的递进逻辑,设计了通用的NPU核内调度算法,核心贡献如下:

  1. 问题建模:将调度问题转化为带约束的优化问题,明确目标与约束;
  2. 算法设计:结合贪心、最佳适配、并行度优化,平衡缓存占用、数据搬运与执行时间;
  3. 通用性:适配Matmul、FlashAttention、Conv等不同算子的计算图,无需针对特定结构优化。

后续拓展方向

  • 动态计算图支持:针对输入形状动态变化的场景,设计自适应调度算法;
  • 机器学习辅助:用强化学习预测最优调度序列,提升复杂计算图的泛化性;
  • 多核心调度:扩展至多NPU核心场景,实现跨核心的数据协同与负载均衡。

附录:结果文件生成(符合附录E格式)

算法最终需输出指定格式的文件,以Matmul_Case0为例:

  1. Problem1/Matmul_Case0_schedule.txt(调度序列):
0  # ALLOC Buf0
1  # COPY_IN (MTE2)
3  # MOVE (MTE1)
5  # MMAD (Cube)
7  # COPY_OUT (MTE3)
2  # FREE Buf0
...
  1. Problem2/Matmul_Case0_memory.txt(地址分配):
0:0  # Buf0→UB [0-4]
1:5  # Buf1→UB [5-9]
2:30 # Buf2→L1 [30-39]
...
  1. Problem2/Matmul_Case0_spill.txt(SPILL操作,空文件因无需SPILL):
# 无SPILL操作

所有结果文件按“Attachment.rar → Problem1/2/3”的目录结构打包,确保符合竞赛提交要求。

本文章已经生成可运行项目
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BetterInsight

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值