通过率 100% · 提交 2 · 通过 2
这道 OJ 的配套动画
缩放点积注意力 · 对应本题的思路、过程和代码
给定同一序列的 Q、K、V 三个矩阵,请计算单头因果自注意力输出。第 i 个 token 只能关注编号不大于 i 的 token。注意力分数为 dot(Q[i], K[j]) / sqrt(d),权重为这些分数的 Softmax,输出为对应 V 的加权和。
这类题属于算法机考高频题型中「华为 AI 岗 / Attention」方向的高频题型,通常考察对「华为 AI 岗 / Attention」的建模能力与边界条件处理。掌握本题的解题思路后,可举一反三应对同类真题方向,稳步提升机考通过率。
第一行输入 n d。接下来 n 行输入 Q 矩阵,再接下来 n 行输入 K 矩阵,最后 n 行输入 V 矩阵。每行 d 个实数。
输出 n 行,每行 d 个实数,表示注意力输出。每个数保留四位小数,绝对值小于 0.00005 时输出 0.0000。
1 <= n <= 80;1 <= d <= 16;矩阵元素绝对值不超过 1000。测试数据保证输出不落在四位小数的舍入中点。
示例 1
输入示例
2 1 0 0 0 0 2 4
输出示例
2.0000 3.0000
一维两 token 的平均效果
示例 2
输入示例
3 1 1 1 1 0 0 10 1 2 100
输出示例
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。
训练营动画视频讲解
登录后可查看你在本题的历史提交,以及每次的各用例通过情况。
1.0000 1.5000 99.9911
后面的 token 不得影响前面输出
时间限制 3000 ms · 内存限制 256 MB
© 2026 广州慕课网络科技有限公司 · 吴师兄学算法官网 版权所有
这些是真正决定能不能 AC、但通用题解里常被略过的点。
对第 i 个查询,只枚举 0≤j≤i 的键,计算缩放点积分数 Q[i]·K[j]/sqrt(d)。在这些可见分数中减去最大值,再计算 Softmax 权重;最后用权重对对应的 V 行逐维加权求和。直接限制 j 的范围即可实现因果掩码。
枚举范围恰好包含当前位置及其之前的所有位置,排除了未来信息。减去同一个最大值不会改变 Softmax 比例,只提高数值稳定性。权重归一化后对 V 求加权和,正是题面定义的因果自注意力输出。
第 i 行处理 i+1 个键,每个点积和加权都需要 O(d),总时间复杂度为 O(n²d)。输入与输出占 O(nd),单行分数和权重占 O(n)。
缩放因子是 sqrt(d),掩码方向为 j≤i,最大值也只能在可见位置中选取。输出前按四位小数规则处理负零。
# 因果注意力:第 i 行只对 j<=i 打分 dot(Q[i],K[j])/√d,行内减 max 再 softmax,加权和 V;
# 掩码用收窄循环范围实现,max 也只在掩码内取;输出四位小数注意负零钳制。
import math
import sys
def solve() -> None:
data = list(map(float, sys.stdin.buffer.read().split()))
if not data:
return
at = 0
n = int(data[at]); at += 1
d = int(data[at]); at += 1
def read_matrix():
nonlocal at
matrix = []
for _ in range(n):
matrix.append(data[at:at + d])
at += d
return matrix
q = read_matrix()
k = read_matrix()
v = read_matrix()
scale = math.sqrt(d)
ans = []
for i in range(n):
scores = []
for j in range(i + 1):
scores.append(sum(q[i][p] * k[j][p] for p in range(d)) / scale)
mx = max(scores)
weights = [math.exp(score - mx) for score in scores]
total = sum(weights)
row = [0.0] * d
for j, weight in enumerate(weights):
weight /= total
for p in range(d):
row[p] += weight * v[j][p]
ans.append(" ".join(f"{0.0 if abs(value) < 0.00005 else value:.4f}" for value in row))
print("\n".join(ans))
if __name__ == "__main__":
solve()