大厂真题 / 华为

华为 9.2 笔试真题 - 国内 AI 岗

本场考试概述

考试时间:2026 年 9 月 2 日

考试岗位:国内 AI 岗

证据边界:现有材料宣称本场包含 20 道选择题(15 道单选、5 道多选)和 2 道编程题,但正文实际只能恢复 12 道单选题、0 道多选题和 2 道编程题。本文只整理有正文依据的内容,不补写缺失的 8 道选择题,也不把概述中出现的考点反推成原题。


第 1 部分:可恢复单选题

以下答案均根据题干独立核验,而不是仅转录材料答案。

1. 可逆矩阵

矩阵逆运算的前提是?

  • A. 矩阵为长方形
  • B. 行列式为零
  • C. 矩阵为方阵且满秩
  • D. 列向量线性相关

独立核验答案:C。通常所说的双边逆要求矩阵为方阵;方阵可逆又等价于满秩、行列式非零和列向量线性无关。

2. 链式法则求梯度

对于单样本损失 $L=(wx+b-y)^2$,关于参数 $w$ 的梯度为?

  • A. $x^2$
  • B. $y-w$
  • C. $2(wx+b-y)$
  • D. $2(wx+b-y)x$

独立核验答案:D。由链式法则,

\[\frac{\partial L}{\partial w}=2(wx+b-y)\frac{\partial(wx+b-y)}{\partial w}=2(wx+b-y)x.\]

3. 过拟合判断

Transformer 文本分类训练时,训练精度持续上升至 97%、训练 loss 持续下降;验证精度达到峰值后回落、验证 loss 持续上升。下列判断与应对方案中不合理的是?

  • A. 模型出现欠拟合,需要增大模型容量
  • B. 可适当增大权重衰减(L2 正则)缓解过拟合
  • C. 模型出现过拟合,泛化能力下降
  • D. 可早停于验证性能最优处

独立核验答案:A。训练表现继续改善而验证表现恶化是典型过拟合现象;增大容量通常不能解决这一问题。B、C、D 均与该判断相符。

4. Residual Add 与 RMSNorm 融合

Transformer Block 中 Residual Add 后通常紧接 RMSNorm,推理优化中常把二者融合为一个 Kernel,主要原因是?

  • A. 硬件不支持加法
  • B. 残差连接无法计算
  • C. 避免残差结果写回 HBM,直接在片上完成归一化
  • D. 为了增加 FLOPs

独立核验答案:C。融合可以减少中间张量的一次写回与再次读取,并减少 Kernel 启动开销;目的不是增加计算量。

5. Top-P 采样

Top-P(Nucleus Sampling)中参数 $p$ 代表什么?

  • A. 抛弃概率低于 $p$ 的 Token
  • B. 按概率降序,截取累计概率达到或刚超过 $p$ 的最小 Token 集,重新归一化并采样
  • C. 从概率最高的前 $p$ 个 Token 采样
  • D. 以 $p$ 的概率选择最高概率 Token

独立核验答案:B。更严格地说,应取按概率降序排列后的最小前缀,使其累计概率不小于 $p$,再在该集合中重新归一化采样。

6. 漏检敏感指标

若任务对漏检正样本的代价特别敏感,应优先关注哪个指标?

  • A. Accuracy
  • B. Precision
  • C. Top-1 Accuracy
  • D. Recall

独立核验答案:D。漏检对应假负例 $FN$,而 $Recall=TP/(TP+FN)$,因此召回率直接反映正样本被找回的比例。

7. 通用近似定理

通用近似定理主要说明什么?

  • A. 增加深度一定比增加宽度好
  • B. 使用线性激活且至少有一个隐藏层的网络可任意逼近任何连续函数
  • C. 使用非线性激活(如 Sigmoid)且足够宽的单隐藏层网络可逼近任何连续函数
  • D. 神经网络总能找到全局最优解

独立核验答案:C(按本题考试意图)。严格地说,“只要非线性”过于宽泛:不同版本的定理会要求激活函数满足非多项式、sigmoidal 等条件,并通常讨论紧集上的连续函数。选项给出的 Sigmoid 示例符合经典版本;定理说明的是表示能力,不保证训练能找到全局最优解。

8. 持续新数据下的 HAC 工程方案

持续到来的新数据下,为兼顾 HAC 的层次分析能力和系统效率,通常采用什么工程方案?

  • A. 每来一个样本都对全量数据重做完整 HAC
  • B. 把 HAC 改成监督学习模型
  • C. 在线近似归组,离线用 HAC 重整或精修
  • D. 放弃历史簇,只聚类最新样本

独立核验答案:C。它是四个选项中最合理的工程折中。需要注意,这是一项依赖延迟、内存与数据分布的工程判断,不是唯一算法定理;增量层次聚类、微簇等方案在特定条件下也可能适用。

9. 单链接定义

层次聚类中 single-linkage 的簇间距离定义为?

  • A. 两簇最远样本点的距离
  • B. 两簇最近样本点的距离
  • C. 两簇中心点的距离
  • D. 所有跨簇点对距离的平均

独立核验答案:B。单链接取两个簇之间所有跨簇点对距离的最小值。

10. PCA 主成分数

PCA 降维时通常依据什么指标选择保留的主成分数量?

  • A. 特征值累计贡献率
  • B. 数据均值
  • C. 特征向量模长
  • D. 投影样本方差倒数

独立核验答案:A。协方差矩阵的特征值对应各主成分解释的方差,实践中常选择使累计解释方差达到目标阈值的最少主成分。

11. Prefill 与 Decode 的典型瓶颈

LLM 推理服务中 prefill 与 decode 的典型瓶颈分别更接近哪种特征?

  • A. 都只受网络带宽限制
  • B. prefill 访存受限、decode 算力受限
  • C. 都只受 CPU 线程限制
  • D. prefill 算力受限、decode 内存或访存受限

独立核验答案:D。Prefill 通常包含算术强度较高的大矩阵运算,decode 单步则常需要为少量 token 读取大量权重和 KV Cache。该结论是 Roofline 意义下的典型概括,实际瓶颈仍会随 batch、序列长度、硬件、量化和调度方式变化。

12. Megatron-LM 张量并行通信

Megatron-LM 风格的张量并行(TP)中,通信操作(如 All-Reduce)主要发生在?

  • A. 仅 Loss 计算阶段
  • B. 每个 Transformer 层内部的前向和反向传播过程中
  • C. 仅训练结束后的参数同步阶段
  • D. 仅数据加载阶段

独立核验答案:B。张量被切分后,每层前向与反向路径都可能需要集合通信来组合局部结果。具体使用 All-Reduce、Reduce-Scatter 还是 All-Gather,以及每层通信次数,会随行并行、列并行和序列并行实现而变化,不能把某个固定次数视为普遍规律。


第 2 部分:编程题

第 1 题:滑动窗口注意力机制

题面

标准缩放点积注意力为

\[\operatorname{Attention}(Q,K,V)=\operatorname{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V.\]

对于 batch 中每组长度为 $N=\text{seq_len}$、向量维度为 $d_k$ 的 $Q,K,V$,位置 $i$ 的 query 只关注满足 $\lvert i-j\rvert\le \omega$ 的 key 位置 $j$,其中 $\omega=\text{window_size}$;越过序列边界的部分自然截断。窗口内分数为

\[S_{ij}=\frac{Q_i\cdot K_j}{\sqrt{d_k}}.\]

Softmax 只在允许位置上归一化。为保证数值稳定,对每行先减去窗口内最大分数 $m_i$:

\[A_{ij}=\frac{\exp(S_{ij}-m_i)}{\sum_{t:\,\lvert i-t\rvert\le\omega}\exp(S_{it}-m_i)}, \qquad O_i=\sum_{j:\,\lvert i-j\rvert\le\omega}A_{ij}V_j.\]

窗口外权重为 0。这里的 window_size 按公式实际表示窗口半径,内部位置最多关注 $2\omega+1$ 个 token,并非窗口的总长度。

输入描述

第一行输入四个整数:

batch_size seq_len d_k window_size

随后输入 batch_size 组数据。每组依次包含:

  1. Q 的 seq_len 行,每行 d_k 个浮点数;
  2. K 的 seq_len 行,每行 d_k 个浮点数;
  3. V 的 seq_len 行,每行 d_k 个浮点数。

输出描述

每组输出 seq_len 行,每行 d_k 个浮点数并保留 2 位小数。相邻两组结果之间输出一个空行,最后一组之后不输出额外空行。

若首行参数违反约束,直接输出一行 0,不再读取矩阵。

约束

\[\text{batch\_size}\ge1,\quad \text{seq\_len}\ge1,\quad d_k\ge1, \quad 1\le\text{window\_size}\le\text{seq\_len}.\]

材料没有进一步定义浮点结果恰在两位小数中点时的舍入方式。本文约定输出采用 round half away from zero(恰好一半时向远离 0 的方向舍入),且把 -0.00 规范化为 0.00

样例 1

输入

1 4 4 1
0.1 0.2 0.3 0.4
0.2 0.3 0.4 0.5
0.3 0.4 0.5 0.6
0.4 0.5 0.6 0.7
0.1 0.0 0.1 0.0
0.0 0.1 0.0 0.1
0.1 0.1 0.0 0.0
0.0 0.0 0.1 0.1
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0

输出

0.50 0.50 0.00 0.00
0.33 0.34 0.33 0.00
0.00 0.33 0.33 0.34
0.00 0.00 0.50 0.50

样例 2

输入

1 2 2 0
0.3 0.4
0.4 0.5
0.5 0.6
0.6 0.7
0.1 0.0
0.0 0.1

输出

0

window_size=0 不满足题目给定范围,因此走非法参数分支。

算法

对每个 batch、每个 query 位置 $i$:

  1. 计算窗口端点 $l=\max(0,i-\omega)$、$r=\min(N,i+\omega+1)$;
  2. 只计算 $j\in[l,r)$ 对应的缩放点积分数,不构造 $N\times N$ 分数矩阵;
  3. 从所有分数中减去最大值,再求指数和,得到稳定的窗口内 Softmax;
  4. 用这些权重对对应的 $V_j$ 加权求和。

输出格式化只发生在全部实数计算完成之后,不能先把注意力权重截成两位小数再参与加权。

正确性证明

对任意 batch 和位置 $i$,算法计算的区间

\[[\max(0,i-\omega),\min(N,i+\omega+1))\]

恰好包含且仅包含所有满足 $0\le j<N$ 与 $\lvert i-j\rvert\le\omega$ 的位置,所以打分集合与题面要求完全相同。

算法对该集合中的每个 $j$ 计算题定分数 $S_{ij}$。所有分数同时减去 $m_i$ 不改变 Softmax,因为分子、分母都乘以相同常数 $e^{-m_i}$;因此算出的权重就是题定 $A_{ij}$,窗口外位置没有进入分子或分母,其权重等价于 0。最后逐维计算 $\sum_jA_{ij}V_j$,正好得到 $O_i$。上述过程覆盖每个 batch 的每个位置,故全部输出正确。

Python ACM 题解

import math
import sys
from decimal import Decimal, ROUND_HALF_UP


def format_two_digits(x):
    value = Decimal(str(x)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
    if value == 0:
        value = Decimal("0.00")
    return format(value, ".2f")


def solve():
    input = sys.stdin.buffer.readline
    first = input().split()
    if len(first) != 4:
        return
    batch_size, n, d, window = map(int, first)
    if batch_size < 1 or n < 1 or d < 1 or not (1 <= window <= n):
        print(0)
        return

    scale = math.sqrt(d)
    for batch_index in range(batch_size):
        q = [list(map(float, input().split())) for _ in range(n)]
        k = [list(map(float, input().split())) for _ in range(n)]
        v = [list(map(float, input().split())) for _ in range(n)]

        if batch_index:
            print()
        for i in range(n):
            left = max(0, i - window)
            right = min(n, i + window + 1)
            scores = []
            for j in range(left, right):
                dot = sum(q[i][t] * k[j][t] for t in range(d))
                scores.append(dot / scale)

            maximum = max(scores)
            exponentials = [math.exp(score - maximum) for score in scores]
            denominator = sum(exponentials)
            result = []
            for t in range(d):
                numerator = sum(
                    exponentials[j - left] * v[j][t]
                    for j in range(left, right)
                )
                result.append(numerator / denominator)
            print(" ".join(format_two_digits(x) for x in result))


if __name__ == "__main__":
    solve()

复杂度分析

令 $W_i$ 为位置 $i$ 的实际窗口长度,则 $W_i\le\min(N,2\omega+1)$。

时间复杂度:$O!\left(BN\min(N,2\omega+1)d_k\right)$,其中 $B$ 为 batch_size。当把 $\omega$ 视为局部小窗口时,也可写作 $O(BN\omega d_k)$。

空间复杂度:输入矩阵和当前组输出计算占 $O(Nd_k)$,单行分数与权重占 $O(\min(N,2\omega+1))$;不构造 $N^2$ 注意力矩阵。

注意事项

  1. window_size 是半径;序列内部最多有 $2\omega+1$ 个位置。
  2. Softmax 的最大值和分母都只能在当前窗口内计算。
  3. 必须先用完整精度权重完成加权,再格式化最终结果。
  4. 非法参数要在读取后续矩阵之前处理,样例 2 不提供可供正常计算的合法矩阵数据。
  5. window_size=seq_len 虽然合法,但与 seq_len-1 的覆盖效果相同。

第 2 题:全整型量化的矩阵乘法

题面

线性对称量化采用

\[q=\operatorname{round}(r/s),\qquad r\approx s q,\]

其中 8 bit 对称量化的整数范围是 $[-127,127]$,一列实数的缩放因子为

\[s=\frac{\max_t\lvert r_t\rvert}{127}.\]

缩放因子继续表示为

\[s\approx\frac{a}{2^b},\qquad 0\le a\le127,\quad 0\le b\le30.\]

对 B 的第 $j$ 列,按材料可恢复出的选择规则,取

\[b_j=\max\left\{b\in[0,30]: \operatorname{round}(s_j2^b)\le127\right\}, \qquad a_j=\operatorname{round}(s_j2^{b_j}).\]

矩阵 A 已按行量化。若 A 的第 $i$ 行表示为整数向量 $q^A_i$ 和缩放因子 $a^A_i/2^{b^A_i}$,B 的第 $j$ 列量化为 $q^B_j$ 和 $a^B_j/2^{b^B_j}$,则

\[C_{ij}\approx \left(\sum_t q^A_{it}q^B_{tj}\right) \frac{a^A_i a^B_j}{2^{b^A_i+b^B_j}}.\]

每个 $C_{ij}$ 输出三个整数:

\[q^C_{ij}=\sum_tq^A_{it}q^B_{tj},\qquad a^C_{ij}=a^A_i a^B_j,\qquad b^C_{ij}=b^A_i+b^B_j.\]

结果无需约简。

输入描述

第一行输入 m k n,表示 A 为 $m\times k$,B 为 $k\times n$。

接下来 $m$ 行描述已经量化的 A。每行包含 $k+2$ 个整数:前 $k$ 个是该行的量化值,最后两个是该行缩放因子的 $a,b$。

接下来 $n$ 行描述 B,每行包含 $k$ 个浮点数,表示 B 的一列。注意:B 是按列输入,而不是按行输入。

输出描述

输出 $m$ 行。每行包含 $n$ 组三元组,每组三个整数依次为该元素的 $q,a,b$,即每行共 3n 个整数。

约束

\[1\le m,k,n\le100.\]

A 和量化后 B 的量化值范围为 $[-127,127]$;输入缩放因子的参数满足 $0\le a\le127$、$0\le b\le30$。输出缩放因子无需约简,因此输出的 $a,b$ 可以超过单个输入缩放因子的范围。

现有材料没有定义或保证以下边界:

  • B 中浮点数的范围,以及是否可能出现 NaN 或无穷大;
  • 当 B 某列全为 0 时应输出哪个 $b$;
  • 当缩放因子过大、连 $b=0$ 都无法使 $a\le127$ 时应如何输出;
  • round 在负数恰好位于半整数时采用何种规则。

为使实现确定且不暗中猜测,本文明确采用以下约定

  1. 输入 B 必须是有限十进制数;代码用 Decimal 按输入文本精确读取。
  2. 所有 round 均采用 round half away from zero,即取最近整数,恰好一半时向远离 0 的方向舍入。例如 $63.5\to64$、$-63.5\to-64$。
  3. 对全零列,规定 $q$ 全为 0,并取 $(a,b)=(0,30)$。这是对未定义零列语义的本文约定,不是材料原题已经给出的规则。
  4. 对非零列,要求集合 ${b\in[0,30]:\operatorname{round}(s2^b)\le127}$ 非空。若不满足,题面没有合法输出;参考代码会显式报错,不擅自截断 $a$ 或改变缩放因子。

样例 1

输入

2 2 2
64 127 65 12
95 127 65 11
1.0 3.0
2.0 4.0

输出

18817 6305 24 20225 4225 23
20119 6305 23 22209 4225 22

样例 2

输入

2 2 1
64 127 65 12
95 127 65 11
1.0 3.0

输出

18817 6305 24
20119 6305 23

以样例 2 为例,B 的列为 $[1,3]$,故 $s=3/127$,量化值为 $[42,127]$;最大可行 $b=12$,且 $a=\operatorname{round}((3/127)\times4096)=97$。第一行整数点积为 $64\times42+127\times127=18817$,结果缩放因子为 $6305/2^{24}$。

算法

  1. 原样保存 A 每行的整数向量及参数 $(a^A_i,b^A_i)$。
  2. 对 B 的每一列求最大绝对值。非零列据此计算 $s$,用 half-away-from-zero 计算每个 $q^B$;再从 30 到 0 枚举 $b$,第一个使舍入后的 $a\le127$ 的值就是最大可行 $b$。全零列按本文约定直接返回全零量化向量和 $(0,30)$。
  3. 对每个 $(i,j)$ 计算 A 第 $i$ 行与量化后 B 第 $j$ 列的纯整数点积,并输出 $(q^C_{ij},a^A_i a^B_j,b^A_i+b^B_j)$。

正确性证明

先看 B 的单列量化。非零列的 $s=\max\lvert r\rvert/127>0$。算法对每个元素按本文明确的舍入规则计算 $q=\operatorname{round}(r/s)$,与量化公式一致;绝对值最大的元素对应幅值 127,其余元素的未舍入幅值不超过 127,因此量化值落在 $[-127,127]$。算法按 $b=30,29,\ldots,0$ 的顺序检查可行性,所以找到的第一个可行值正是题定最大可行 $b$,随后计算的 $a=\operatorname{round}(s2^b)$ 也与规则一致。对全零列,返回值严格遵循本文公开约定,并且 $sq=0$。

对任意输出位置 $(i,j)$,A 同一行共享缩放因子 $a^A_i/2^{b^A_i}$,B 同一列共享缩放因子 $a^B_j/2^{b^B_j}$。把二者从乘加和中提出,可得

\[C_{ij}\approx \left(\sum_t q^A_{it}q^B_{tj}\right) \frac{a^A_i a^B_j}{2^{b^A_i+b^B_j}}.\]

算法输出的三个整数分别就是该式中的整数点积、分子乘积和指数之和,因此每个三元组都正确;遍历全部行列后,整个结果矩阵正确。

Python ACM 题解

import sys
from decimal import Decimal
from fractions import Fraction

QMAX = 127
MAX_B = 30


def round_half_away(value):
    sign = -1 if value < 0 else 1
    numerator = abs(value.numerator)
    denominator = value.denominator
    quotient, remainder = divmod(numerator, denominator)
    if 2 * remainder >= denominator:
        quotient += 1
    return sign * quotient


def quantize_column(tokens):
    decimals = [Decimal(token.decode()) for token in tokens]
    if any(not value.is_finite() for value in decimals):
        raise ValueError("B 中只允许有限十进制数")
    column = [Fraction(value) for value in decimals]

    maximum = max(abs(value) for value in column)
    if maximum == 0:
        return [0] * len(column), 0, MAX_B

    scale = maximum / QMAX
    quantized = [round_half_away(value / scale) for value in column]

    chosen_b = None
    chosen_a = None
    for b in range(MAX_B, -1, -1):
        a = round_half_away(scale * (1 << b))
        if 0 <= a <= QMAX:
            chosen_b = b
            chosen_a = a
            break
    if chosen_b is None:
        raise ValueError("该列 scale 无法在题定 a、b 范围内表示")

    return quantized, chosen_a, chosen_b


def solve():
    input = sys.stdin.buffer.readline
    m, k, n = map(int, input().split())

    matrix_a = []
    for _ in range(m):
        row = list(map(int, input().split()))
        matrix_a.append((row[:k], row[k], row[k + 1]))

    matrix_b = []
    for _ in range(n):
        tokens = input().split()
        matrix_b.append(quantize_column(tokens))

    for qa, aa, ba in matrix_a:
        output = []
        for qb, ab, bb in matrix_b:
            qc = sum(x * y for x, y in zip(qa, qb))
            output.extend((qc, aa * ab, ba + bb))
        print(*output)


if __name__ == "__main__":
    solve()

复杂度分析

时间复杂度:量化 B 需要 $O(nk+31n)$,全部整数点积需要 $O(mnk)$,总时间复杂度为 $O(mnk)$。

空间复杂度:保存量化后的 A 与 B 需要 $O(mk+nk)$;逐行生成输出时,除输入存储外的输出暂存为 $O(n)$。

注意事项

  1. B 按列输入,每一行输入的是一整列。
  2. Python 内置 round 使用 ties-to-even,不能直接实现本文约定的 half-away-from-zero;floor(x+0.5) 对负半数也会出错。
  3. 全零列会使直接计算 value / scale 除以 0,必须先按公开约定单独处理。
  4. 不能在找不到合法 $b$ 时默默返回 0,也不能把超范围的 $a$ 强行截到 127;材料未定义这种输入的输出。
  5. 量化后的 B 整数受 $[-127,127]$ 限制,但整数点积以及输出 scale 的 $a,b$ 无需约简,可能超过单个量化参数的范围。