华为AI方向机考10月14日笔试题与解析
- 轮次
- 笔试
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
一、选择题(共 20 题:15 题 × 6 分 + 5 题 × 12 分)
-
某 Transformer 层在张量并行度为 2 时要做一次 All-Reduce,待同步张量大小为 80MB。网络带宽为 40GB/s,忽略延迟,通信时间约为多少?(0.2ms;20ms;0.02ms;2ms)
-
一组测量值中混有少量极端大的尖峰。若要反映数据的中心位置,且不希望被这些尖峰明显拉动,应优先采用哪个统计量?(方差;众数;算术平均值;中位数)
-
将模型权重从 BF16 量化为 INT8,主要压缩的是:(网络层数;词表长度;单个权重所占的比特数;注意力头数)
-
模型训练中用 float32 替代 float64,主要是为了:(提高计算精度;避免过拟合;降低显存占用,并加快运算;简化模型结构)
-
某分类模型训练集准确率为 97%,测试集准确率为 58%。这表示模型处于什么状态?(欠拟合;数据不足;过拟合;良好拟合)
-
某二分类模型的混淆矩阵为 TP=28、TN=52、FP=8、FN=12,准确率约为多少?(0.70;0.90;0.85;0.80)
-
合同检索用 BPE 对中英混合文本分词后,法条编号、机构专名和条款缩写被拆成大量子词,检索召回明显变差。最合理的改法是:(提高向量检索的 top-k,多取一些碎片片段;改为字符级分词,让稀有词不再被拆开;加大文档切分长度,减弱子词碎片的影响;在分词词表中加入领域词,使法条编号、机构专名和条款缩写各成为一个完整 token)
-
计算 f(x)=√(x²+9)−√x 时,若 x 很大,控制舍入误差最有效的方法是:(按原式直接相减;只把浮点位数加长;先做分子有理化;把绝对值很小的项直接丢掉)
-
对抗样本一般是如何构造的?(给输入叠一层幅度很小、肉眼基本看不出来的改动,使分类结果出错;必须改变输入的语义,扰动才会生效;只对图像模型有效,文本模型不会出现;在输入上叠加大量随机噪声,使模型完全认不出原内容)
-
某分类器测试集混淆矩阵为 TP=50、FP=10、FN=15、TN=25,其 F1 分数是多少?(0.833;0.769;0.75;0.8)
二、编程题:轻量化推理引擎中的 Masked Fused RMSNorm 模块实现(150 分)
在轻量化大模型推理引擎中,Transformer 的隐藏状态会在多个子模块之间不断传递。为了减少内存读写、提升推理效率,实际工程中常把多个操作融合进同一个算子,例如残差连接 Residual Add、RMSNorm 归一化、逐元素缩放 Scale、逐元素偏置 Bias 以及 Padding Mask 处理。本题要求按下述步骤实现一个简化版的 Masked Fused RMSNorm 模块。
计算步骤:对于第 k 个输入样本向量 xₖ,给定残差向量 rₖ、残差系数 αₖ、有效长度 lₖ、缩放向量 γ、偏置向量 β、数值稳定项 ε:
- 残差融合:hₖᵢ = xₖᵢ + αₖ · rₖᵢ
- 有效部分的 RMS 与 energy:仅前 lₖ 个位置为有效位置,后续位置视为 padding,不参与 RMS 与 energy 计算。energyₖ = Σᵢ₌₁^lₖ hₖᵢ²,RMSₖ = √(energyₖ / dₖ + ε),其中 dₖ = max(lₖ, 1)
- 归一化输出:对输出向量 yₖ,有效位置(1 ≤ i ≤ lₖ)为 yₖᵢ = γᵢ · hₖᵢ / RMSₖ + βᵢ;无效位置(lₖ < i ≤ n)为 yₖᵢ = 0
任务说明:给定 m 个样本,对每个样本计算并输出 Masked Fused RMSNorm 后的结果向量 yₖ、该样本有效部分的 RMSₖ、该样本有效部分的平方和 energyₖ。
输入描述:
- 第 1 行:三个数 m n eps,分别表示样本数、向量维度、数值稳定项。
- 第 2 行:n 个浮点数,缩放向量 γ。
- 第 3 行:n 个浮点数,偏置向量 β。
- 接下来 m 行:每行先给 l alpha,再依次给出 x 的 n 个值和 r 的 n 个值。
输出描述:对每个样本输出一行 y_1 y_2 … y_n | RMS | energy,同一行用单个空格分隔,| 两侧各有一个空格。浮点保留两位小数,采用标准四舍五入(恰好满五时远离零);绝对值小于 0.005 的数一律写成 0.00(这样不会出现 -0.00)。注意不要用 C++ 的 printf(“%.2f”)、Python 的 format 或 Java 的 String.format(“%.2f”),它们对能精确表示的 0.125、1.125 会走银行家舍入,印成 0.12、1.12。
样例输入:
2 3 0.01
1.0 0.5 -1.0
0.0 1.0 0.0
2 0.5 -1.0 1.0 -1.0 2.0 -2.0 1.0
3 1.0 3.0 4.0 0.0 0.0 0.0 0.0 0.0
样例输出:
0.00 1.00 0.00 | 0.10 | 0.00
1.04 1.69 0.00 | 2.89 | 25.00
《参考解析》
第 1 题:选 2ms
这题只考量纲换算。80MB = 80×10⁶ 字节,40GB/s = 40×10⁹ 字节/秒,时间 = 80×10⁶ ÷ 40×10⁹ = 2×10⁻³ 秒 = 2ms。两个易错点:把 GB/s 里的 G 当成 10⁹ bit(差 8 倍),以及忘记 MB 与 GB 之间是 10³ 而非 10²⁴ 关系。补充一句工程直觉:如果这题问的是 ring all-reduce 实际传输量而非题面给的待同步张量大小,总通信量约为 2×(N−1)/N 倍,结果会翻倍到约 4ms。
第 2 题:选中位数
中位数只看排序后的中间位置,把某个极端值从 100 改成 10¹² 也不改变它,稳健性(breakdown point 达 50%)最好。算术平均值给每个观测值相同权重,一个尖峰就能把它拉走;方差是二阶矩、对极端值更敏感;众数只反映最高频取值,连续数据里未必唯一,也未必落在数据中心。数据带离群值时,用中位数或截尾均值替代均值是标准做法。
第 3 题:选单个权重所占的比特数
BF16 每个权重占 16 bit,INT8 占 8 bit,量化后权重矩阵的存储量约减半;额外开销只有每个量化分组(per-tensor 或 per-channel)的 scale 与 zero-point,量级可忽略。网络层数、注意力头数、词表长度都是结构超参,改量化位宽不会动它们。注意区分:权重量化压的是权重存储,激活/KV Cache 量化是另一条线。
第 4 题:选降低显存占用,并加快运算
FP64 每个数 8 字节,FP32 只要 4 字节,同模型同 batch 下参数、梯度、激活的显存都减半;而且主流 GPU(尤其消费级)的 FP64 吞吐往往被裁到 FP32 的 1/32 甚至更低,换用 FP32 会明显更快。代价是尾数位从 52 位降到 23 位、精度略降,深度学习对这么高的精度本就不敏感,实践中再叠 BF16 混合精度也够用。
第 5 题:选过拟合
训练 97%、测试 58%,近 40 个百分点的泛化 gap 属于典型过拟合:模型把训练集的噪声和个例也记住了,换到没见过的数据就塌。欠拟合的表现是两边都差;良好拟合是两边都高且接近。对应手段是加正则(weight decay、dropout)、做数据增强或扩量、早停、降模型容量——但先要确认这 58% 不是切分或标签泄露等数据问题造成的。
第 6 题:选 0.80
准确率 = (TP+TN) / (TP+TN+FP+FN) = (28+52) / (28+52+8+12) = 80/100 = 0.80。这里正例 40 个、负例 60 个,类别大致均衡,所以准确率还能反映真实水平;一旦类极不平衡(如负例占 99%),全猜负类也能拿高准确率,此时必须改用精确率、召回率、F1 或 AUC 来判断。
第 7 题:选在分词词表中加入领域词
根因是低频串被 BPE 按字/子词切碎,一个语义单元散成多个 token,检索时无法对齐。把这批法条编号、机构专名、条款缩写作为完整 token 补进词表(继续训练 tokenizer 或加自定义词表),它们就各占一个 token。改字符级分词会丢掉词边界、序列变长、召回未必更好;提高 top-k 只是多捞碎片;加大切分长度是稀释问题而非解决。
第 8 题:选先做分子有理化
考点是相近数相减的灾难性消去:两个几乎相等的量直接相减时,前面的有效数字互相抵消,结果的相对误差被放大到 eps·(a/|a−b|) 量级。分子有理化把 a−b 改写成 (a²−b²)/(a+b),分子变成可精确计算的多项式、分母是量级更大的加法,相对误差回到正常乘除级别。单纯加长浮点位宽只是延后问题,直接丢掉小项则改变了数学结果。
第 9 题:选给输入叠一层幅度很小、肉眼基本看不出来的改动
对抗样本是刻意优化的微小扰动(FGSM、PGD 沿损失对输入的梯度方向走一步或多步),扰动的 L∞ 范数被限制在 ε 内,人看内容没变,模型却分类出错。所以它不是随机噪声(随机噪声多半只让置信度下降、不改判),也不需要改变语义。文本模型同样有对抗样本,同义替换、插入不可见字符、改标点都能触发。
第 10 题:选 0.8
先算两个分量:精确率 P = TP/(TP+FP) = 50/60 ≈ 0.8333,召回率 R = TP/(TP+FN) = 50/65 ≈ 0.7692,F1 = 2PR/(P+R) = 2×0.8333×0.7692 ÷ (0.8333+0.7692) = 1.2821 ÷ 1.6026 ≈ 0.8。干扰项 0.833 是精确率、0.769 是召回率,两个都算对但没合成 F1 就会选错。F1 是精确率与召回率的调和平均,任一项塌了它都会跟着塌。
编程题:逐样本按公式模拟,坑在格式化
做法是每个样本独立处理:先一遍扫出 hᵢ = xᵢ + α·rᵢ,并把 i < l 的 hᵢ² 累加成 energy;分母固定取 d = max(l, 1) 以免 l = 0 时除零,RMS = √(energy/d + ε)。输出时 i ≥ l 的位置直接写 0(注意不能把 βᵢ 加进去),有效位写 γᵢhᵢ/RMS + βᵢ。
两个边界必须显式处理:l = 0 时无有效位,energy 与 RMS 都按 0 算、整行输出全 0;有效位 hᵢ 全为 0 且 ε = 0 时 RMS = 0,除法未定义,但此时每个有效 hᵢ 必为 0,归一化项按 0 处理、只保留 βᵢ。复杂度 O(m·n) 时间、O(n) 空间。
真正的失分点在小数格式化:题目要求满五远离零,而 printf(“%.2f”)、Python 的 format、Java 的 String.format 走的是银行家舍入,对能精确表示的 0.125 会印成 0.12 而不是 0.13。要么把数值放大 100 倍后用 llround(C++,满五远离零),要么对 double 的精确十进制做 setScale(2, HALF_UP) / quantize(Decimal(“0.01”), ROUND_HALF_UP)(Java / Python)。另外先判 |x| < 0.005 直接输出 0.00,可一并消掉 -0.00 这种输出。
用样例走一遍核对:第一组 l = 2、α = 0.5、x = [−1, 1, −1]、r = [2, −2, 1],得 h = [0, 0],energy = 0,RMS = √(0/2 + 0.01) = 0.10,有效位输出 0.00 与 1.00,第三位是 padding 写 0.00;第二组 energy = 3² + 4² = 25,RMS = √(25/3 + 0.01) ≈ 2.89,γ、β 分别代入后得到 1.04、1.69、0.00。