大厂真题 / 华为
华为 2026-10-14 笔试真题 - AI岗
本场考试概述
考试时间:2026年10月14日
考试岗位:AI岗
难度评级:中等
收录范围:本页收录已披露的 5 道单选题和 2 道编程题。考试概述标注选择题共 20 道,但其余 15 道的题干、选项未披露,因此不补写。
考点分析:
- 选择题:RMSNorm 的几何意义、浮点相消误差、领域分词、模型后门与 F1 分数。
- 第一题:CART 分类树、基尼指数、精确分数比较与平局规则(中等)。
- 第二题:残差融合、掩码归一化、数值边界与格式化输出(简单)。
建议策略:
- CART 的切分是“等于某值 / 不等于某值”,不能套用连续特征的“小于等于阈值 / 大于阈值”。
- 平局规则和停止条件同样决定预测结果;用整数交叉相乘比较基尼指数,避免浮点误差。
- RMSNorm 先核对有效长度、偏置与 padding,再检查分母是否有定义,最后统一格式化。
选择题:已披露的 5 道
1. RMSNorm 对点积的影响
在 LLM 中,常在注意力计算前对特征向量使用 RMSNorm。对向量 $x$ 的操作为 $x/RMS(x)\cdot g$。忽略可学习参数,RMSNorm 对后续的 $q\cdot k$ 点积计算有何本质影响?
- A. 它强制对向量进行了近似的模长缩放
- B. 它使得点积在数学上严格等同于欧氏距离
- C. 它使得点积的结果恒定为 1
- D. 它改变了向量的夹角,导致原有的空间语义完全反转
答案:A。 忽略稳定项并取非零向量时,
\[RMS(x)=\sqrt{\frac{1}{d}\sum_{i=1}^{d}x_i^2}=\frac{\lVert x\rVert_2}{\sqrt d}.\]因此 $x/RMS(x)$ 的模长为 $\sqrt d$,方向不变。如果 $q,k$ 都按此方式直接归一化且维度相同,则 $q\cdot k=d\cos\theta$。点积随夹角变化,并非恒为 1,也不等于欧氏距离。实际 RMSNorm 一般带稳定项,模长只是近似固定;若归一化之后还经过不同线性投影,不能直接断言最终 Q、K 的模长仍为 $\sqrt d$。
2. 大数相减的误差控制
计算 $f(x)=\sqrt{x+1}-\sqrt x$ 时,若 $x$ 很大,最有效的误差控制方法是:
- A. 分子有理化
- B. 忽略极小项
- C. 增加计算位数
- D. 直接计算
答案:A。 两个接近的大数相减会损失有效数字。有理化后得到
\[f(x)=\frac{1}{\sqrt{x+1}+\sqrt x},\]避免了接近数的直接相减。增加精度能缓解问题,但没有从计算式上消除相消误差。
3. BPE 对领域术语的拆分
在企业级长文本 RAG 系统中,使用 BPE 分词器对中英文混合文档进行 token 化后,发现专业术语、稀有实体、代码变量名被大量拆分。以下哪种做法最直接针对这一问题?
- A. 改用字符级分词,提升对稀有词汇的表示能力
- B. 在 tokenizer 中加入领域词表,将专业术语、实体、代码标识符设为完整 token
- C. 直接增大文档切分长度,抵消 subword 碎片化影响
- D. 提高向量检索的 top-k,覆盖更多碎片化片段
答案:B。 领域词表能直接减少高频领域术语的子词拆分。字符级分词通常会增加序列长度,调整切块长度或 top-k 则没有改变分词方式。工程中增加 token 还需要同步扩展模型 embedding,并训练或适配新增表示;仅修改 tokenizer 文件并不能保证语义效果。
4. 后门攻击成功的表现
攻击者希望在模型中植入后门,使包含特定“触发器”的输入产生攻击者指定的输出。以下哪种情况最可能表示攻击成功?
- A. 模型在正常输入上表现良好,但在包含特定罕见字符组合的输入上强制输出特定有害内容
- B. 模型在所有输入上的准确率都下降了 50%
- C. 模型训练时间比正常情况增加了 3 倍
- D. 模型无法处理长度超过 512 token 的输入
答案:A。 后门的典型特征是正常输入下行为正常,出现触发器后才转向预设行为。整体性能下降、训练变慢或长度限制,都不能单独证明后门触发成功。
5. 混淆矩阵与 F1 分数
某分类器在测试集上的混淆矩阵为 TP=40、FP=10、FN=20、TN=30。F1 分数是多少?
- A. 0.667
- B. 0.5
- C. 0.8
- D. 0.727
答案:D。 精确率 $P=40/(40+10)=0.8$,召回率 $R=40/(40+20)\approx0.667$。
\[F_1=\frac{2PR}{P+R}=\frac{2TP}{2TP+FP+FN}=\frac{80}{110}\approx0.727.\]TN 不参与 F1 的计算,不能将准确率的分母带入该公式。
第 1 题:基于 CART 分类树预测客户购房选择
题目描述
给定客户训练数据,按指定规则构建 CART 二叉分类树,预测待测客户是否购房。每条训练记录包含 4 个整数枚举特征和 1 个二分类标签:
- 特征 1:年龄段,0 为 18—30 岁,1 为 31—40 岁,2 为 41—55 岁,3 为 56 岁及以上。
- 特征 2:婚姻状况,0 为单身,1 为恋爱,2 为已婚。
- 特征 3:是否有房,0 为无,1 为有。
- 特征 4:是否有工作,0 为无,1 为有。
- 标签:是否购房,0 为否,1 为是。
对特征 $A$ 和候选取值 $v$,左子集为 $D_1={s\in D:s_A=v}$,右子集为 $D_2={s\in D:s_A\ne v}$。候选值取当前节点出现的特征值。
对于包含 $K$ 个类别的数据集 $D$,第 $k$ 类占比为 $p_k$,基尼指数为
\[Gini(D)=1-\sum_{k=1}^{K}p_k^2.\]切分的加权基尼指数为
\[Gini(D,A,v)=\frac{\lvert D_1\rvert}{\lvert D\rvert}Gini(D_1)+\frac{\lvert D_2\rvert}{\lvert D\rvert}Gini(D_2).\]选择加权基尼指数最小的切分。多个候选同分时先选特征编号较小的;同一特征同分时选取值较小的。满足以下任一条件即停止,生成叶子:
- 所有样本标签相同。
- 样本数小于 2。
- 没有切分能够使基尼指数严格降低。
叶子预测多数类别;类别数相同时预测编号较小的 0。预测时特征值等于切分值走左支,否则走右支。
输入格式:第一行为 $N$,$4\le N\le20$;随后 $N$ 行各含 5 个整数,前 4 个为特征,最后一个为标签。再输入 $M$,$1\le M\le10$,随后 $M$ 行各含 4 个测试特征。
输出格式:输出一行 $M$ 个预测标签,用空格分隔。
样例 1
输入
8
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 0 1
2 2 1 1 1
2 0 0 0 0
3 2 1 0 0
3 2 0 1 1
3
2 0 0 0
1 1 1 0
3 2 1 0
输出
0 1 0
样例 2
输入
20
0 0 0 1 1
0 0 1 0 0
0 1 0 0 0
0 1 1 1 1
0 2 0 1 1
1 0 0 0 0
1 0 1 1 1
1 1 0 1 1
1 1 1 0 0
1 2 1 0 0
2 0 0 1 1
2 0 1 0 1
2 1 0 0 0
2 1 1 1 1
2 2 0 0 0
3 0 0 0 0
3 0 1 1 0
3 1 0 1 1
3 1 1 0 0
3 2 0 1 0
10
1 1 1 0
2 0 0 1
3 2 0 1
0 0 0 1
1 2 1 0
2 1 0 0
3 0 1 1
0 1 1 1
1 0 0 0
2 2 0 0
输出
0 1 0 1 0 0 0 1 0 0
思路分析
第一步:把训练过程视为确定性的递归规则。
本题不是寻找全局最优决策树,也不进行剪枝或随机选特征。对每个节点枚举规定的二元切分,选择当前最优,再递归处理左右子集即可。某个特征可以重复使用,因为先分出一种取值后,右侧仍可能包含该特征的其他取值。
第二步:用分数精确比较基尼指数。
设节点中标签 0、1 的数量分别为 $c_0,c_1$,样本数为 $s=c_0+c_1$。定义
\[mass(S)=\lvert S\rvert\cdot Gini(S)=\frac{s^2-c_0^2-c_1^2}{s}=\frac{2c_0c_1}{s},\]空集的 mass 约定为 0。对于同一个父节点,所有候选的加权基尼都有相同的分母 $\lvert D\rvert$,所以可以比较
\[mass(D_1)+mass(D_2).\]代码保存分数的分子和分母,不需要浮点运算。比较 $a/b<c/d$ 时判断 $ad<cb$;两分数相加使用 $(ad+cb)/(bd)$。这样不会把数学上的平局误判成微小差异。
第三步:用遍历顺序落实平局规则。
按特征 1 到 4、取值从小到大枚举,只在新分数严格更小时更新最优项。同分候选不覆盖旧候选,自然保留较小特征编号和较小取值。
最优切分仍必须严格优于父节点的 mass,否则直接返回多数类叶子。全体样本落到一侧的候选不会降低基尼,可以跳过。标签不纯也可能停止:例如异或型标签,两侧类别比例与父节点一致时,任何一步都不能降低基尼;不能为了以后可能变纯而强行继续切分。
第四步:核对样例与预测路径。
样例 1 的根节点标签数量为 3 个 0、5 个 1,基尼为 0.46875。以“特征 4 等于 0”切分,左侧标签为 0、1、0、0,右侧全为 1,加权基尼为 0.1875。左右互换的取值 1 得到同分,因此选取值 0。左侧再按“特征 1 等于 1”切分,两侧变纯。三个测试客户最终预测为 0、1、0。
训练时没有出现的测试取值,也按“不等于当前切分值”走右支,不需要单独建立未知类别分支。
题解代码
import sys
input = sys.stdin.readline
def mass(count_zero, count_one):
size = count_zero + count_one
return (2 * count_zero * count_one, size) if size else (0, 1)
def add_fraction(a, b):
return (a[0] * b[1] + b[0] * a[1], a[1] * b[1])
def less_fraction(a, b):
return a[0] * b[1] < b[0] * a[1]
def build_tree(rows):
count_one = sum(row[4] for row in rows)
count_zero = len(rows) - count_one
majority = int(count_one > count_zero)
if count_zero == 0 or count_one == 0 or len(rows) < 2:
return (majority,)
best_score = mass(count_zero, count_one)
best_feature = best_value = None
for feature in range(4):
for value in sorted({row[feature] for row in rows}):
left = [row for row in rows if row[feature] == value]
left_one = sum(row[4] for row in left)
left_zero = len(left) - left_one
score = add_fraction(
mass(left_zero, left_one),
mass(count_zero - left_zero, count_one - left_one),
)
if less_fraction(score, best_score):
best_score = score
best_feature, best_value = feature, value
if best_feature is None:
return (majority,)
left = [row for row in rows if row[best_feature] == best_value]
right = [row for row in rows if row[best_feature] != best_value]
return (best_feature, best_value, build_tree(left), build_tree(right))
def predict(tree, sample):
while len(tree) != 1:
feature, value, left, right = tree
tree = left if sample[feature] == value else right
return tree[0]
def solve():
n = int(input())
rows = [list(map(int, input().split())) for _ in range(n)]
tree = build_tree(rows)
m = int(input())
answers = [predict(tree, list(map(int, input().split()))) for _ in range(m)]
print(*answers)
if __name__ == "__main__":
solve()
复杂度分析
设树深为 $H$。每个特征的取值数不超过 4,节点中有 $s$ 条记录时,枚举并计算全部候选需要 $O(s)$ 时间。每层节点的样本集合互不重叠,建树需要 $O(NH)$,预测需要 $O(MH)$。
本题的取值域固定为 4、3、2、2。沿任一路径,每次有效切分都会使某个特征的剩余可能取值数至少减少 1,因此 $H\le(4-1)+(3-1)+(2-1)+(2-1)=7$。按本题固定域,时间复杂度为 $O(N+M)$,常数来自特征与候选枚举。如果只使用 $H\le N$ 而不利用固定域带来的更紧深度界,也可写成保守上界 $O(N^2+MN)$;这一估计仍以每个特征的候选数为常数为前提。
空间复杂度:递归会保留祖先的样本列表,上界为 $O(NH)$;本题 $H\le7$,因此为 $O(N)$。树节点、训练集和输出列表同样在此范围内。
第 2 题:轻量化推理引擎中的 Masked Fused RMSNorm
题目描述
实现融合残差连接、RMSNorm、逐元素缩放、偏置和 padding mask 的算子。共有 $m$ 个样本,向量最大长度为 $n$;所有样本共享缩放向量 $\gamma$、偏置向量 $\beta$ 和稳定项 $\varepsilon$。第 $k$ 个样本给出有效长度 $l_k$、残差系数 $\alpha_k$、输入向量 $x_k$ 和残差向量 $r_k$。
先融合残差:
\[h_{k,i}=x_{k,i}+\alpha_k\cdot r_{k,i}.\]只对前 $l_k$ 个有效位置统计能量与均方根:
\[energy_k=\sum_{i=1}^{l_k}h_{k,i}^2,\qquad d_k=\max(l_k,1),\qquad RMS_k=\sqrt{\frac{energy_k}{d_k}+\varepsilon}.\]有效位置缩放并加偏置;padding 位置固定为 0:
\[y_{k,i}=\begin{cases} \gamma_i\cdot h_{k,i}/RMS_k+\beta_i, & 1\le i\le l_k,\\ 0, & l_k<i\le n. \end{cases}\]输入格式与约束:
- 第一行为
m n epsilon,$1\le m\le200$,$1\le n\le256$,$0\le\varepsilon\le1$。 - 第二、三行各有 $n$ 个浮点数,分别为 $\gamma$ 和 $\beta$,每项范围为 $[-10^3,10^3]$。
- 接下来 $m$ 行,每行格式为
l alpha x_1 ... x_n r_1 ... r_n。 - $0\le l\le n$,$-10^3\le\alpha\le10^3$;$x_i,r_i$ 均在 $[-10^6,10^6]$ 内。
- 时间限制:C/C++ 1000ms,其他语言 2000ms;内存限制:C/C++ 512MB,其他语言 1024MB。
输出格式:每个样本输出一行 y_1 ... y_n | RMS | energy。各项之间单个空格,竖线两侧各一个空格。所有数保留两位小数,按标准四舍五入;绝对值小于 0.005 时统一输出 0.00,避免 -0.00。
题面边界缺口:约束允许 $\varepsilon=0$。若 $l>0$ 且全部有效 $h_i=0$,则 $RMS=0$,有效位置公式出现 $0/0$,题面没有规定结果。下方实现只对公式有定义的输入给出答案;遇到这类未定义输入会明确报错,不擅自把输出规定为 0 或偏置。$l=0$ 时不执行有效位置除法,因此即使 $\varepsilon=0$ 仍有定义。
样例 1
输入
2 3 0.01
1.0 0.5 -1.0
0.0 1.0 0.0
3 1.0 3.0 4.0 0.0 0.0 0.0 0.0
2 0.5 -1.0 1.0 -1.0 2.0 -2.0 10.0
输出
1.04 1.69 0.00 | 2.89 | 25.00
0.00 1.00 0.00 | 0.10 | 0.00
样例 2
输入
2 4 0.000001
1.0 1.0 1.0 1.0
0.0 0.0 0.0 0.0
4 0.0 1.0 2.0 3.0 4.0 0.0 0.0 0.0 0.0
0 1.0 0.0 0.0 0.0 0.0 1.0 2.0 3.0 4.0
输出
0.37 0.73 1.10 1.46 | 2.74 | 30.00
0.00 0.00 0.00 0.00 | 0.00 | 0.00
思路分析
第一步:确定掩码作用范围。
padding 不参与平方和,输出也不加偏置。可以只计算前 $l$ 个位置的融合值,并将完整输出向量初始化为 0。共享参数按位置索引,不能把缩放向量 $\gamma$ 与样本残差向量 $r$ 混淆。
第二步:按依赖顺序完成计算。
先得到有效位置的 $h$,然后累加 $energy$,再求 $RMS$,最后计算各个有效位置的 $y$。均方的分母是 $\max(l,1)$,不是向量最大长度 $n$;稳定项位于平方根内部。不能先把 RMS 舍入到两位再计算输出,只在最终展示时舍入。
当 $l=0$,平方和为 0,RMS 为 $\sqrt\varepsilon$,输出向量全零。样例 2 的第二个样本 RMS 实际为 0.001,只是打印后显示 0.00。
样例 1 的第一个样本得到 $h=[3,4,0]$、$energy=25$、$RMS=\sqrt{25/3+0.01}$。第二个样本完整融合值为 $[0,0,4]$,最后一个位置是 padding,因此平方和仍为 0;第二个有效位置的输出为偏置 1。
第三步:处理四舍五入和负零。
Python 的 f"{value:.2f}" 在精确中点采用 ties-to-even,并不总等价于题面所写的标准四舍五入。例如精确可表示的 0.125,前者输出 0.12,通常的四舍五入应为 0.13。这里用 Decimal.from_float 保留已经计算出的二进制浮点值,再用 ROUND_HALF_UP 定标到两位小数;计算过程仍使用双精度,最后一步才格式化。绝对值小于 0.005 的值先直接输出 0.00。
题面没有提供恰好半分值的判题样例或特殊容差,因而无法确认隐藏判题是否也严格采用 HALF_UP;本实现按文字要求处理,而不将 ties-to-even 当作同一种规则。二进制浮点值与理想十进制实数之间仍可能有微小差异,这不是增加打印位数能够完全消除的。
题解代码
import math
import sys
from decimal import Decimal, ROUND_HALF_UP
input = sys.stdin.readline
def format_value(value):
if abs(value) < 0.005:
return "0.00"
rounded = Decimal.from_float(value).quantize(
Decimal("0.01"), rounding=ROUND_HALF_UP
)
return format(rounded, ".2f")
def masked_rms_norm(length, alpha, x, residual, gamma, beta, epsilon):
fused = [x[i] + alpha * residual[i] for i in range(length)]
energy = sum(value * value for value in fused)
rms = math.sqrt(energy / max(length, 1) + epsilon)
if length > 0 and rms == 0.0:
raise ValueError("题面未定义:有效长度非零且 RMS 为零")
output = [0.0] * len(x)
for i in range(length):
output[i] = gamma[i] * (fused[i] / rms) + beta[i]
return output, rms, energy
def solve():
first = input().split()
m, n = int(first[0]), int(first[1])
epsilon = float(first[2])
gamma = list(map(float, input().split()))
beta = list(map(float, input().split()))
for _ in range(m):
tokens = input().split()
length, alpha = int(tokens[0]), float(tokens[1])
x = list(map(float, tokens[2:2 + n]))
residual = list(map(float, tokens[2 + n:2 + 2 * n]))
output, rms, energy = masked_rms_norm(
length, alpha, x, residual, gamma, beta, epsilon
)
print(" ".join(format_value(value) for value in output)
+ " | " + format_value(rms) + " | " + format_value(energy))
if __name__ == "__main__":
solve()
复杂度分析
时间复杂度:$O(mn)$。每个样本读取长度为 $n$ 的向量,计算有效位置,并输出 $n$ 个结果;题面数值范围有限,格式化每个数的开销可视为常数。
空间复杂度:$O(n)$。逐行处理样本,只保留共享向量和当前样本的输入、有效融合值、输出,不保存全部样本。
小结
- RMSNorm 的缩放与方向、F1 的分母、相消误差的计算式,都需要从定义出发判断。
- CART 是一套确定性规则:等值切分、严格降低基尼、两级平局优先级,缺少任何一条都会改变结果。
- 融合归一化要把有效位统计、padding 输出和最终舍入分开处理,避免提前舍入或给 padding 加偏置。
- 本页保留实际披露范围;RMS 为零的未定义边界与中点舍入判题口径仍需题面补充,不能据样例通过宣称所有允许输入均有确定答案。