下面进行华为2026年7月1日AI岗机考题的复盘和关键知识点(重点)深度剖析,笔者昨天(7月5日)刷完选择题,今天刷完2道算法题。选择题考到线性代数、概率论与数理统计、机器学习基础理论和损失函数、向量检索、工程规范、学习率调度器(深度学习)等知识点。编程题还是传统的数据结构与算法的考点,一个是基础的排序和字典、匿名函数相关(推荐算法场景)的题目(评级中等),一个是通过Certainty Forcing修改版损失函数(深度学习场景)包装的整数线性规划问题(ILP,评级困难)。
说明:文章内选择题证明和论述部分的绿色字体是AI生成内容,红色字体是人工增添内容。
目录
第十题
损失函数的必备和建议性质(凸函数性,可导性,梯度稳定性,计算复杂性),正确答案A

交叉熵做分类损失函数因为对数在真数接近0时巨大的梯度数值,可以对抵sigmoid的梯度消失问题;但使用MSE做损失函数在极端情况下------比如真实标签1但预测0,真实标签0但预测1,将会导致梯度消失;且损失函数是非凸函数,海塞矩阵不是半正定矩阵,或者二阶导数符号并非恒正。具体证明过程如下(DeepSeek证明,配合人工修正):
这个问题问到了点子上,非常深刻。要理解这一点,我们不能只看直觉,必须看数学证明。
先说结论:MSE 加上 Sigmoid 之所以是非凸函数,是因为该复合函数关于模型参数
的二阶导数(Hessian 矩阵)不是半正定的。更直接地说,损失函数
关于中间变量
的二阶导数的符号会随着预测值的变化而改变。
- 数学推导(核心证据)
为了简化,我们看单个样本,真实标签为
,预测值为
,其中
。
MSE 损失函数为:

我们计算
关于
的二阶导数(这直接关系到损失函数曲面是向上凸起还是向下凹陷)。
首先,Sigmoid 函数有一个美妙的性质:
。
- 一阶导数:

- 二阶导数(这是关键):

为了看清楚符号,我们分两种情况讨论(因为逻辑回归中 y
只能是 0 或 1):
情况 1:当
时
代入上式并化简,得到:

情况 2:当
时
代入上式并化简,得到:

- 符号分析(判断凸性)
根据凸函数的定义(二阶导数恒
),我们看上面的结果:
- 当
,如果模型预测非常离谱,
(比如真实是 1,预测接近 0),那么
,导致
(函数是凹的)。 - 当预测稍微准确些,
,则
(函数是凸的)。 - 对于y=0同理,如果
,则二阶导数为负的凹函数,反之为正的凸函数。
结论:二阶导数的符号随着
的取值在正负之间摇摆,说明该损失函数既不是凸函数,也不是凹函数,而是凹凸不平的"波浪形"。
- 直观理解:为什么会这样?
你提到"Sigmoid 有界",这恰恰是问题的根源:
- 饱和区(梯度消失):当预测完全错误(y=1, 预测=0)时,z 是个很大的负数,Sigmoid 进入左饱和区,导数趋近于 0。此时损失曲面极其平坦(二阶导为负或接近 0),梯度下降几乎走不动。
- 非饱和区:当预测在中间地带(z 在 0 附近)时,Sigmoid 导数较大,曲面变得陡峭。
这就导致损失函数表面不是标准的"碗状"(凸函数),而是像起伏的山脉。有局部极小值、局部极大值和平坦的高原。
- 为什么交叉熵(Log Loss)就是凸的?
为了对比,我们看交叉熵损失
。
它的二阶导数是:

因为
的值域是 (0,1),所以
永远大于 0。这就是标准的凸函数,梯度下降可以放心地找到全局最小值。
第十一题
线性变换的基本性质,正确答案C

D的反例------V=1对应拉伸或者收缩变换不成立,这里的u和v我们简单假设成一维标量(线性变换不包括平移,即坐标空间原点经过线性变换后成为新空间的原点,可以包括剪切变换、旋转变换、拉伸或收缩变换)
第十二题
MLE极大似然估计的基本计算,正确答案D

题干错误,应该是
^2而不是μ^2。无论μ知不知道,MLE极大似然(计算联合概率分布PDF(iid直接累乘,不独立从CDF计算PDF),取对数,求导数,令为0,解方程)估计分母是n;矩法估计(样本矩等于总体矩,求解方程组)分母也是n;区间估计使用卡方分布,是(n-1)s^2/chi_squared(n-1)。
如果是UMVUE(Uniformly Minimum Variance Unbiased Estimation),则总体方差估计量分母应该是n-1,但是方差是分母为n情形的n/(n-1)^2倍。
第十三题
MLE与均匀分布,正确答案C
均匀分布的MLE估计,因为a不可能无限小,所以由抽样样本的极值决定边界a。
第十六题
贝叶斯定理与机器学习,正确答案ABD

贝叶斯定理结合MLE极大似然估计,将先验估计转换为含有先验概率分布知识的最大后验估计(MAP)。
A: 正则化项的推导来自高斯噪声的先验假设,使用贝叶斯定理和MAP估计得出损失函数。
B:贝叶斯优化是贝叶斯定理在超参数调优中的经典直接应用。
- 工作流程:贝叶斯优化会为目标函数(如验证集准确率)建立一个概率代理模型(通常是高斯过程 GP)。它利用贝叶斯定理,根据每次尝试的超参数及其结果(观测数据),不断更新这个代理模型的后验分布。
- 核心依赖:它通过后验分布构建采集函数(如 EI、UCB),来决定下一次该试哪组超参数。整个过程完全建立在"先验->似然->后验"的贝叶斯推理框架上。
- 可以类比成学习-试验-学习-试验的反馈环路。
D: 朴素贝叶斯分类器从"表型"出发,掌握"表型"概率和条件概率分布的先验知识条件下,通过全概率公式和贝叶斯定理,且基于条件独立或者完全(任意)独立的假设,将指数级别复杂度的概率函数拆分为线性复杂度相乘的概率函数,降低了计算复杂度,但"表型"和"基因型"交换了位置。

第十七题
向量检索算法(IVF,HNSW,PQ),正确答案:BCD

召回率和聚类数量负相关,但不能直接说成反比。这里需要明白召回率和准确率的区别,可以使用真阳假阳真阴假阴的2x2混淆矩阵辅助理解。
可以通过增加IVF算法里面nprobe探测聚类的数量提升召回率。
第十八题
模型训练存档与记录规范,正确答案AD

可复现模型训练工程不应该开启cuDNN的非确定性算法模式,因为cuDNN的优化实现可能通过改变浮点数累加顺序,从而造成保留精度之后出现偏差
第十九题
实对称矩阵的正交对角化分解(谱分解定理)与其指数矩阵的正定性(含具体证明),正确答案ABCD

注:证明过程用到【实对称矩阵的指数矩阵具有正定性的性质,证明用到正交对角化、矩阵的乘幂、麦克劳林展开、矩阵乘法与转置】知识点。
理论层面最严谨的证明,分为"对称性"和"正定性"两步走。
- 核心工具:谱分解定理(正交对角化)
因为
是实对称矩阵,根据谱定理,必定存在一个正交矩阵
(满足
)和一个实对角矩阵
,使得:

其中
,而
是
的实特征值。
- 矩阵指数的对角化
利用矩阵指数的定义(
),我们可以将
代入。因为
,所以
。
因此:

而
是一个对角矩阵,其对角元素为
:

- 证明正定性
要证明
正定,我们需要验证两点:它是对称的,且对于任意非零向量
,都有
。
第一步:对称性
由于
是对角矩阵,显然是对称的。

所以
是实对称矩阵。
第二步:正定性(关键)
取任意非零实向量
。因为
是正交矩阵(可逆),令
,则
也是一个非零向量(因为
可逆,零空间只有零向量)。
我们计算二次型:

将
代入,展开得:

关键结论:
无论
的特征值
是正是负还是零,指数函数
永远大于 0(恒为正)。因此,上式中每一项
,且由于
非零,至少存在一个
,导致总和严格大于 0。
即:

综上,
既是实对称的,又满足正定性定义,因此它一定是正定矩阵。
💡 额外深化:为什么你的直觉会成立?
你可能会想:"如果特征值是负的,比如
,e -100
虽然很小,但它还是正数啊!" 指数函数的值域是
,它把实数轴上的所有点(无论多么负)都映射到了正数轴上。这就好比给矩阵的特征值全部"加了一层绝对值的保护",使得无论如何
的特征值(即
)全为正数,从而保证了正定性。
⚠️ 重要提醒(易错点)
如果
不是对称矩阵(例如
),那么
是一个旋转矩阵,它甚至不是对称矩阵,连"正定"的定义都不满足。所以,"实对称"是这个结论成立的绝对前提。
第二十题
余弦退火(热重启)与余弦衰减,正确答案ABCD

余弦退火(Cosine Annealing)与余弦衰减(Cosine Decay)的核心区别,在于是否引入了"热重启"(Warm Restarts)机制。
简单来说,余弦衰减是让学习率平滑地降到最低;而余弦退火(SGDR)则是让学习率在周期性"重启"中不断探索。这两种策略与SGD优化器结合时,会展现出完全不同的学习特性。
⚙️ 核心差异:余弦衰减 vs. 余弦退火
| 特性 | 余弦衰减 (Cosine Decay) | 余弦退火 / SGDR (Cosine Annealing with Warm Restarts) |
|---|---|---|
| 核心机制 | 学习率按照余弦函数单调下降,从最大值平滑降至最小值。 | 学习率在一个周期内按余弦函数下降,周期结束后立即重置到最大值,开始下一个周期。 |
| 学习率曲线 | 平滑的、单调递减的"滑梯"曲线。 | 由多个"滑梯"首尾相连形成的"锯齿"或"波浪"曲线。 |
| 与SGD结合 | 稳定的、渐进的精细搜索。 | 动态的、周期性的"探索-利用"循环。 |
在这个
:
为了让你更直观地理解这种差异,可以参考余弦退火(带重启)的原始论文(SGDR),其公式如下:
η_t = η_min^i + 1/2 * (η_max^i - η_min^i) * (1 + cos(T_cur / T_i * π))
在这个公式中:
- 余弦衰减只运行一个周期(i=1),学习率从η_max单调降至η_min后便保持不变或极小。
- 余弦退火则会运行多个周期(i=1, 2, 3, ...)。在每个周期i结束时(T_cur = T_i或T_i-1),学习率降至η_min,但下一个周期会立即将学习率重置为η_max,开始新的下降。
- 如果周期不变可以使用先取余数后做除法的方式实现SGDR,η_t = η_min^i + 1/2 * (η_max^i - η_min^i) * (1 + cos((T_cur %(T_i))/ T_i * π))
📊 学习效果与场景分析
结合SGD优化器,两者的表现差异主要体现在以下方面:
- 余弦衰减:平滑收敛,稳定精调
- 学习过程:学习率平滑下降,为SGD提供了一个非常稳定的优化路径。这种平滑性有助于模型在训练后期进行精细的参数调整,找到局部最优解。
- 适用场景:适用于训练周期固定、目标明确的任务,如标准的图像分类(CIFAR-10/100)、时间序列预测等。在这些场景中,模型只需要一次充分的、从粗到细的搜索。
- 案例:在一项针对区域供热系统热负荷预测的研究中,CosineAnnealingLR调度器表现优异,因为它能平滑调整学习率,使模型有效捕捉数据中的周期性和非平稳性特征。
- 余弦退火(SGDR):逃离局部最优,追求更强泛化
- 学习过程:周期性重启使模型能多次跳出当前的局部最优解,探索损失平面上更广阔的区域。每次重启后的"热启动"都基于之前学到的权重,而非从零开始,因此能在更优的基础上进行探索。
- 适用场景:适用于损失平面复杂、容易陷入局部最优的任务,或需要模型具备更强泛化能力的场景。特别是在训练预算不固定或希望" anytime performance"(任意时刻的性能)都较好的情况下。
- 案例:SGDR的原始论文显示,在CIFAR-10和CIFAR-100数据集上,使用带重启的余弦退火策略,测试准确率分别提升了3.14%和16.21%,同时显著减少了训练所需的Epoch数量。
- 一些值得注意的研究发现
关于学习率调度,也有一些最新的研究成果值得关注:
- 线性衰减的竞争力:Meta和Google的研究者在2023年的一项研究中,通过大量实验(涵盖10个不同的深度学习问题)发现,线性衰减(Linear Decay)调度器的平均表现优于余弦衰减。
- 无限学习率调度:在持续预训练(Continual Pre-training)场景下,一种名为"无限学习率调度"(Infinite Learning Rate Schedule)的新方法,其效果被认为优于传统的重复余弦衰减。
💎 总结与选择建议
总的来说,两者没有绝对的优劣,关键在于匹配任务目标:
- 如果你的目标是在一个固定的训练周期内,获得一个稳定、可靠的模型,余弦衰减是更稳妥的选择。
- 如果你的目标是追求极致的模型性能,并且愿意接受更长的训练时间或更复杂的调参来换取更高的上限,那么余弦退火(SGDR) 更值得尝试。
对于大多数标准任务,可以先从带预热的余弦衰减(Warmup + Cosine Decay) 开始,这是一个被广泛验证有效且稳健的基线方案。如果希望进一步提升模型性能,再考虑引入余弦退火(SGDR)或尝试更前沿的调度策略。
代码题1
第2题-智能选品 - 基于特征加权的商品推荐 - problem_ide - CodeFun2000
加权平方距离(商品推荐),纯自己实现,关键在于二次排序和字典存储(使用字典方便结合lambda匿名函数进行排序),注意输出处理

python
def code1():
# 复习:sys的标准读取输入流操作
N, D, K = map(int, input().split())
W = list(map(int, input().split()))
T = list(map(int, input().split()))
goods = {}
prefers = {}
for i in range(N):
good = list(map(int, input().split()))
goods[good[0]] = good[1:]
dis = map(lambda x, y, w: w * (x - y) ** 2, T, good[1:], W)
prefers[good[0]] = sum(dis)
# 确保同样距离小序号在前
temp = list(sorted(prefers.keys()))
recommends = sorted(temp, key=lambda k: prefers[k], reverse=False)
for k in range(K):
print(recommends[k], end=" ")
代码题2
第3题-Certainty Forcing 训练损失计算 - problem_ide - CodeFun2000
核心是一维与二维整数线性规划(ILP,背包问题,借助DeepSeek场外编码),全部AC;辅助是math库对数函数和基本数学运算

python
def code2():
import math
N, V, B, lamb = map(float, input().split())
N, V, B = int(N), int(V), int(B)
ys = [-1 for i in range(N)]
cs = [-1 for i in range(N)]
ls = [-1 for i in range(N)]
Hs = [-1 for i in range(N)]
for i in range(N):
token_out = list(map(float, input().split()))
ys[i] = int(token_out[-2])
cs[i] = int(token_out[-1])
mi = max(t for t in token_out[:V])
token_out = [math.exp(token_out[t] - mi) for t in range(V)]
divisor = sum(token_out)
token_out = [t / divisor for t in token_out]
ls[i] = -math.log(token_out[ys[i]])
Hs[i] = sum([-p * math.log(p) for p in token_out])
bag_2d = [[0] * (B + 1) for i in range(N + 1)]
for i in range(1, N + 1):
for j in range(B, 0, -1):
if j < cs[i - 1]:
bag_2d[i][j] = bag_2d[i - 1][j]
else:
bag_2d[i][j] = max(bag_2d[i - 1][j], bag_2d[i - 1][j - cs[i - 1]] + ls[i - 1])
goods = []
j = B
for i in range(N, 0, -1):
if bag_2d[i][j] > bag_2d[i - 1][j]:
goods.append(i - 1)
j -= cs[i - 1]
final_l = lamb * sum([Hs[i] for i in goods]) + sum(ls)
print("{:.2f}".format(final_l))