ARTICLE · 1066271
华为机考AI方向9月23日笔试题与解析
写在前面
本次给大家带来2026年9月23日华为AI方向笔试题的2道题,本套题涉及到的岗位:AI算法工程师,AI应用开发工程师,AI数据科学工程师等以AI为开头的岗位,统一笔试,不区分部门。
需要我整理的AI机考速成攻略&题单可访问文章底部左侧:阅读原文
选择题(15*6分 + 5*12分
1、用 RANSAC 拟合直线时,外点占比约 70%。若希望模型仍有较大概率被正确估出,应优先采取哪一措施?
改用最小二乘直接拟合全部点 把最小样本集规模再加大 换用更高次多项式去“吃掉”外点 提高随机采样的迭代轮数
2、关于数据并行(Data Parallel)中各卡上的模型与数据,正确的是
每张 GPU 只保存模型的部分层,处理同一批数据 每张 GPU 保存完整模型副本,处理同一批数据 每张 GPU 保存完整模型副本,各自处理不同数据批次 每张 GPU 只保存模型的部分层,各自处理不同数据批次
3、用 PSNR 评估扩散模型生成图质量,得到 5 个样本: 。该样本的样本标准差为(保留两位小数)
1.15 1.20 1.18 1.12
4、要判断 是否为凸函数,可检查其 Hessian 矩阵是否为:
正交矩阵 负定矩阵 对角矩阵 正定或半正定矩阵
5、RAG 流水线里,检索模块主要负责什么?
更新生成模型的权重 从外部知识库取出相关文档/片段 持久化用户画像 调整网络拓扑
6、CNN 中“感受野”通常指
卷积核边长 池化窗口边长 特征图上某点所对应的输入图像区域 全连接层入口维度
7、若两向量点积等于 0,则二者
模长相同 同向 反向 互相垂直
8、已知 , , ,则
0.50 0.40 0.25 0.20
9、用牛顿法求方程 的单根时,局部收敛阶通常是:
线性收敛 一阶收敛 三阶收敛 二阶收敛(平方收敛)
10、若 ,则 大约为
0.50 0.95 0.84 0.68
第2题-激活检查点放置(150分)
题目描述
在大模型训练中,前向传播会留下大量中间激活,反向传播时还要用到它们。当 GPU 显存吃紧时,激活重计算(Gradient Checkpointing)是一种常见的「用时间换空间」做法:只在若干「检查点」层保存激活,其余层在反向阶段再算一遍。本题要求:在给定显存预算下,求出最优的 Checkpoint 放置方案。
模型共有 层(编号为 到 ),按前向顺序依次执行。给定两个长度为 的正整数数组:
forward_time[i]( ):第 层前向传播的耗时; memory[i]( ):在第 层保存激活(打 Checkpoint)所需的额外显存。
固定边界:
第 层(输入层)的激活常驻显存,不计入额外开销,它是天然的起始 Checkpoint; 第 层是终点:不必在第 层再存额外激活,也不占用 Checkpoint 显存。
操作:你可以在某些中间层 ( )打 Checkpoint。在第 层打 Checkpoint 会占用 memory[c-1] 的显存(第 层对应数组下标 )。所有 Checkpoint 的显存占用之和不得超过 。
重计算代价:设两个相邻 Checkpoint 位置为 与 ( ,中间没有别的 Checkpoint)。反向传播经过该区间时,需要从第 层的激活出发,重新前向计算以恢复中间层激活。由于反向是逐层推进的,层 只需重算一次(从 前向到 ),层 需要重算两次,以此类推。因此该区间的重计算代价为:
其中 是第 层的前向耗时, 是该层被重复计算的次数。若 (相邻 Checkpoint),代价为 。
目标:在显存预算 内选择 Checkpoint 放置方案,使整网总重计算代价最小。总代价等于所有相邻 Checkpoint 对之间的代价之和(隐含起点 与终点 )。
样例1
输入
5 35 10 5 10 201 2 1 3 1输出
15解题思路
核心思路
本题是在显存预算约束下,选择若干中间层打 Checkpoint,使重计算总代价最小。相邻两个 Checkpoint(含隐式起点 与终点 )之间的代价为
可先用前缀和 ,由递推 、 在 内预处理全部区间代价。
实现方法
令 表示「最后一个 Checkpoint 打在位置 ,已用显存恰好为 」时的最小代价( 为起点, )。对 ,枚举上一个 Checkpoint :
终点 不占显存,答案为 。
python代码(C++和JAVA代码见在线OJ网址)
INF = 10**18def min_recompute(n, max_mem, f, mem): # 前缀和,便于 O(1) 递推区间代价 s = [0] * (n + 1) for i in range(1, n + 1): s[i] = s[i - 1] + f[i - 1] cost = [[0] * (n + 1) for _ in range(n + 1)] for c in range(n): for d in range(c + 2, n + 1): # 终点从 d-1 扩到 d:区间内每层多重算一次 cost[c][d] = cost[c][d - 1] + (s[d - 1] - s[c]) dp = [[INF] * (max_mem + 1) for _ in range(n + 1)] dp[0][0] = 0 for i in range(1, n): mi = mem[i - 1] for j in range(i): for w in range(max_mem + 1): if dp[j][w] >= INF: continue nw = w + mi if nw > max_mem: continue val = dp[j][w] + cost[j][i] if val < dp[i][nw]: dp[i][nw] = val ans = INF for j in range(n): for w in range(max_mem + 1): if dp[j][w] < INF: # 终点 N 不占显存 ans = min(ans, dp[j][w] + cost[j][n]) return ansdef main(): n, max_mem = map(int, input().split()) f = list(map(int, input().split())) mem = list(map(int, input().split())) print(min_recompute(n, max_mem, f, mem))if __name__ == "__main__": main()第3题-NPU梯度任务均衡调度(300分)
题目描述
在大模型分布式训练场景下,要把若干梯度更新任务分配到多张 NPU 上。目标是让各卡的「梯度计算总耗时」尽量均衡(即最小化「最大卡总耗时」),再按学习率衰减规则汇总总训练成本。
规则如下:
任务分配:将 划分成 个子集(一张 NPU 对应一个子集)。每个任务必须分到恰好一个子集;在所有划分中,取「子集总和的最大值」最小的那些划分。 成本计算:记 为各卡总耗时的最大值, 为第 张卡的总耗时。则 第 张卡学习率: ; 第 张卡训练成本: ; 总训练成本:所有卡成本之和。
样例1
输入
8,5,4,3,3,2,1;3;0.1;0.8输出
9,2.4400解题思路
每个梯度任务都要分到恰好一张卡上。直接枚举:第 个任务依次尝试 张卡,用数组记下各卡当前耗时。如果某张卡加上这个任务后,耗时已经大于目前找到的最小「最大耗时」,这一支就不用再搜。搜完得到最小的 ,以及一组达到它的各卡负载,再按
把各卡成本加起来,保留四位小数。
实现方法
按 ;拆开输入,读出耗时数组、、基础学习率和衰减系数。递归枚举每个任务的去向,维护当前最小的最大耗时和对应负载。 用上面的公式累加成本并输出。
暴力dfs做法(95%通过率)
python代码(C++和JAVA代码见在线OJ网址)
def parse_line(s): parts = s.strip().split(";") times = [int(x) for x in parts[0].split(",") if x != ""] k = int(parts[1]) base = float(parts[2]) decay = float(parts[3]) return times, k, base, decaydef solve(times, k, base, decay): n = len(times) loads = [0] * k best_m = None best_loads = None def dfs(i): nonlocal best_m, best_loads if i == n: m = max(loads) if best_m is None or m < best_m: best_m = m best_loads = loads[:] return for b in range(k): loads[b] += times[i] if best_m is None or loads[b] <= best_m: dfs(i + 1) loads[b] -= times[i] dfs(0) total = 0.0 for s in best_loads: total += s * base * (decay ** (best_m - s)) return best_m, totaldef main(): times, k, base, decay = parse_line(input().strip()) m, total = solve(times, k, base, decay) print(f"{m},{total:.4f}")if __name__ == "__main__": main()刷题练习:CodeFun2000.com