01 / 本课学习路线
本课学习路线
汇总与分类 25 分钟 · 订正案例 25 分钟 · 修复与独立重写 70 分钟 · 收尾与自查 30 分钟
02 / 订正流程与完成条件
订正不是重做一遍:四个动作,每道错题各走一次
「再做一遍」不是修复。订正的定义是:说清第一次错在哪一类、用一个最小用例复现它、改掉它、证明改对了、再不看旧代码重写一次。前六个模块的错题订正已经走过六遍,本课把同一套流程用在本模块的注意力、缓存、量化题上。
| 动作 | 做什么 | 产出 | 对应正文 |
|---|---|---|---|
| ① 分类 | 按第一次出错的原因归到六类之一 | 登记表的「首次错误类型」一栏 | 第 03 节 |
| ② 定位并修复 | 找到导致错误的那几行代码或那条被漏读的规则,改掉 | 登记表的「错误原因」「修复动作」 | 第 03、04 节 |
| ③ 最小验证 | 构造一个只触发该错误的输入,修复前失败、修复后通过 | 登记表的「触发用例」「最小验证」 | 第 04、05 节 |
| ④ 独立重写 | 不看旧代码从空文件重写整题,用复测清单验证后提交 | 登记表的「独立重写」 | 第 06 节 |
本课没有新的在线必做题,记为完成需要如实勾选全部四条学习完成检查:阶段测验未通过的题已记录原因并独立重写通过;每条错题记录有反例;重写没有查看旧代码;订正通过后,RoPE 自测断言通过且能说明各自检查的情况。两道重做任务用于复习,按下方要求完成自查。仍有题未通过时,记录具体问题并安排再次重写,但不能勾选第 1 条,也不能把本课记为完成。原反例与复测清单用于检查原问题和相关边界,不能代替一般正确性的说明;检查后仍需独立重写并提交。
| 来源 | 题号 | 判题结果 | 先猜的错误类型 | 订正状态 |
|---|---|---|---|---|
| 阶段测验第 1 题 | P2580 | 答案错误(WA) / 运行错误(RE) / 未完成 / 通过(AC) | — | 未开始 |
| 阶段测验第 2 题 | P3285 | 同上 | — | 未开始 |
| 阶段测验第 3 题 | AI039 | 同上 | — | 未开始 |
| 第 1~5 课 未通过或看提示才通过的必做题 / 进阶题 | 逐题填 | 填判题结果 | — | 未开始 |
「先猜的错误类型」在第 03 节按判定信号确认后再改;AC 的题只登记曾经改过的具体问题,不进入订正流程。看提示才通过的题按「未通过」处理——提示告诉你的那一步,就是要独立重写验证的那一步。
03 / 六类错误的判定与定位
判定信号、定位步骤、修复动作、最小用例怎么构造(本模块版)
分类不靠感觉,靠信号:先看判题结果是哪一种,再用下面的问题逐个排除。本模块的题多了「规则的层次与方向」这一层——掩码 1 表示可见还是屏蔽、对称还是因果、并列先比谁、淘汰键是什么——它们几乎都落在读题与建模两类;.5 舍入与位宽落在语言一类。定位工具是各课正文里现成的逐格表:注意力四步、n=5 的可见表、AI007 的逐槽位表、AI043 的逐条状态表、量化的逐元素表。
| 类型 | 判定信号 | 定位步骤 | 修复动作 | 最小用例怎么构造 |
|---|---|---|---|---|
| 读题 | 样例能过、某些用例 WA;对「1 表示可见」「并列先比负载」「淘汰最早加入」「逢半远离零」的理解与题目页不一致 | 重新写题目要求清单:掩码含义、并列层次、淘汰键、舍入方式;逐条对照代码 | 按那一条改一处 | 构造恰好落在并列上的输入(案例 A:两个槽位前缀相同、负载不同) |
| 建模 | 所有用例都错或大面积错;说不清可见集合是什么、一轮做什么、缩放系数对应哪个下标 | 写出方法一句话,用课里的推演检验(第 1 课 的四步、第 2 课 的可见表、第 5 课 的样例 1) | 换可见集合 / 先全部打分再归一 / 改下标 | 取课里现成的推演(案例 B:题面示例第一行的输出) |
| 边界 | 只有特定输入错:全屏蔽行、w=0、q=0、单个文件超容量、p=0 | 列出四类边界输入逐个手算 | 补上判断(判空、截断、特判) | 就是那个边界输入本身 |
| 复杂度 | 超时(TLE),且不是读入问题 | 估算最坏次数:每行对全序列打分、线性扫描淘汰、每预算线性试、每窗口重新求和 | 只扫窗口 / 惰性堆 / 二分 / 右进左出 | 构造最大规模输入计时 |
| 语言 | 运行错误(RE)或结果对不上却找不到逻辑错 | 写 3 行小实验:round(0.5)、-0.0004:.2f、2**31、负下标 | 换成明确的写法(自己的取整函数、整数标度、64 位) | 触发该语言行为的最短输入(案例 C:0.5 恰好在中点) |
| 输出格式 | 答案错误(WA)或格式错误(PE),数字都对 | 把自己的输出与期望输出逐字节对比 | 改位数、-0.00、块间空行、字典序、NONE | 题面示例 |
登记时的一条硬要求:「错误原因」必须具体到能据此直接改代码——「粗心」「没注意」不符合要求,「比较元组第二项写成编号、第三项写成负载,前缀并列时按编号选了槽位 1」符合。写不出具体原因,说明还没定位到,回到定位步骤。
04 / 三个完整订正案例
失败用例 → 定位 → 修改前后对照 → 复测
三个案例都来自本模块必做题里真实会出现的错误,每个都走完整流程;你的错题按同样的格式处理。阶段测验三题的订正解析在交卷后的测验页,本页不重复。
案例 A · 读题类:AI007 并列时先比编号再比负载
判题结果: 答案错误(WA);没有前缀并列的用例都能过 失败用例: 3 2 / 3 3 1 2 3 / 1 3 1 2 4 / 0 1 9 / 3 1 2 5 / 2 9 8 期望 2 2 / 3 1 实际 1 2 / 3 1 定位: 重写题目要求清单 → 「公共前缀相同选负载更小,仍并列选编号更小」;代码的比较元组是 (−前缀, 编号, 负载),第二层比的是编号 修复: 元组改成 (−前缀, 负载, 编号)(见下方前后对照) 复测: 题面示例 → 2 2 / 3 1 ✓ 2 1 / 1 2 1 2 / 1 2 1 3 / 2 1 9 → 1 1 ✓(负载也并列时才看编号) 2 1 / 5 3 4 5 6 / 2 2 4 5 / 3 4 5 6 → 1 3 ✓
案例 A 修改前(片段)
Python# AI007:并列时先比编号再比负载——第二层写反了
key = (-k, i, loads[i])案例 A 修改后(片段)
Python# AI007:题面三层顺序是 前缀长 → 负载小 → 编号小
key = (-k, loads[i], i)只改了元组的项序;完整程序在第 3 课 第 09 节展开区。修改前后各跑一次三个复测用例,修改前第一个用例失败、修改后全部通过——这才是「修复生效」。
案例 B · 建模类:AI030 把对称窗口写成因果窗口
判题结果: 答案错误(WA);w=0 与单行块能过
失败用例: 题面示例 期望第一块 0.67 0.33 / 0.60 0.80 / 0.67 1.00 实际 1.00 0.00 / 0.33 0.67 / 0.67 1.00
定位: 用第 2 课 第 05 节的逐行表对照:i=0 应看 {0, 1},我的程序只看 {0},第一行输出等于输入——右端写成了 i
修复: 右端改成 min(n−1, i+w)(见下方前后对照)
复测: 题面示例 → 两块全对 ✓ 1 0 / 4 3 / … → 输出等于输入 ✓(w=0 不受影响) 1 60 / 4 2 / … → 等同全量注意力 ✓案例 B 修改前(片段)
Python# AI030:把对称窗口写成了因果窗口(右端只到 i)
lo, hi = max(0, i - w), i案例 B 修改后(片段)
Python# AI030:对称窗口 |i−j| <= w,右端到 min(n−1, i+w)
lo, hi = max(0, i - w), min(n - 1, i + w)建模类错误的定位工具是课里现成的可见表:n=5、w=1 两张表一对就知道自己写的是哪种窗口。完整程序在第 2 课 第 07 节展开区。
案例 C · 语言类:AI034 用内置舍入函数(round)做 .5 舍入
判题结果: 答案错误(WA);只有中点用例错 失败用例: 2 2 / 1.0000 0.5000 期望 1.000000 / 1 1 / 0.500000 实际 1.000000 / 1 0 / 0.500000 定位: 3 行小实验:round(0.5) 得 0、round(2.5) 得 2——Python 内置 round 是银行家舍入;题面要求逢半远离零 修复: 换成自己写的 round_half_away,并把 x、s′ 都换成整数标度再相除(见下方前后对照) 复测: 2 2 / 1.0000 0.5000 → 1 1 ✓ 题面示例 1 → 7 -4 2 -7 5 ✓(非中点不受影响) 2 8 / 0.0009 -0.0004 → 127 -57 ✓(截断仍生效)
案例 C 修改前(片段)
Python# AI034:用内置 round——.5 处走银行家舍入
q = round(x / scale)案例 C 修改后(片段)
Python# AI034:逢半远离零;x 的单位是 1e-4,scale 的单位是 1e-6
# x * 100 将 x 换成 1e-6 单位后,才能与 scale 相除
q = round_half_away(x * 100, scale)语言类错误的最小用例就是触发该语言行为的最短输入:一个恰好在中点的数。完整程序在第 4 课 第 08 节展开区,整数标度的必要性在第 4 课 第 07 节。
05 / 错题登记与最小验证
登记模板、填好的示例、最小用例的三个要求
登记表是订正的账本:每道错题一条,订正完把「独立重写」一栏改成「通过」。下面先给空模板,再给案例 C 填好的样子。
错题登记模板(每题一条)
Python# 错题登记(每题一条;订正完把「独立重写」改成「通过」)
# 题号:
# 来源: 阶段测验第_题 / 课_ 必做 / 课_ 进阶
# 判题结果: WA / RE / TLE / PE
# 首次错误类型: 读题 / 建模 / 边界 / 复杂度 / 语言 / 输出格式
# 触发用例: 输入=____ 期望=____ 实际=____
# 错误原因: (具体到能据此直接改代码)
# 修复动作:
# 最小验证: (至少三条:触发错误的、边界另一侧的、题面示例)
# 独立重写: 未做 / 通过 / 再错(类型=__)复制进你的错题本,每订正一项填一条;如果暂时无法准确描述错误原因,请结合失败用例和代码位置进一步检查,再回到六类错误原因重新分类。
填好的示例(案例 C)
Python# 题号: AI034
# 来源: 第 4 课 必做
# 判题结果: WA
# 首次错误类型: 语言
# 触发用例: 输入=2 2 / 1.0000 0.5000 期望=1.000000 / 1 1 / 0.500000 实际=1.000000 / 1 0 / 0.500000
# 错误原因: q = round(x / s') 用了 Python 内置 round,0.5 按银行家舍入到 0;题面要求逢半远离零到 1
# 修复动作: 换成自己写的 round_half_away(num, den),并把 x、s' 都换成整数标度再相除
# 最小验证: 2 2 / 1.0000 0.5000 → 1 1 ✓ 5 4 / 1.0000 -0.5000 0.2500 -1.0000 0.7500 → 7 -4 2 -7 5 ✓(非中点不受影响) 2 8 / 0.0009 -0.0004 → 127 -57 ✓(截断仍生效)
# 独立重写: 通过「触发用例」写明期望与实际;「错误原因」写到能直接改代码;「最小验证」至少三条:触发错误的、边界另一侧的、题面示例。
| 要求 | 含义 | 反例 |
|---|---|---|
| 只触发这一类错误 | 修复前失败、修复后通过,且不涉及其它规则 | 拿 500 个槽位验证「并列层次」 |
| 尽量短 | 手算能在 1 分钟内得到期望输出 | 用 n=50、d=16 的块验证「窗口种类」 |
| 带期望输出 | 登记时写清期望与实际 | 只写「输入 2 2 / 1.0000 0.5000」不写期望 |
每订正一项做一次最小验证:不要直接重交原题,先跑最小用例确认修复真的生效,再独立重写整题。本模块每课的错误做法表都是现成的最小用例来源。
06 / 独立重写与复测清单
不看旧代码从空文件重写,用清单验证后再提交
独立重写检验的是「离开旧代码还能不能写对」。重写前只允许看题目页和自己的方法一句话注释,不看旧代码、不看参考程序。
| 题目 | 题面示例 | 边界用例 | 错误专项用例 |
|---|---|---|---|
| AI007 前缀缓存调度器 | 3 2 / 3 3 1 2 3 / 1 3 1 2 4 / 0 1 9 / 3 1 2 5 / 2 9 8 → 2 2 / 3 1 | 3 1 / 7 1 1 / 3 1 2 / 3 1 3 / 2 9 9 → 2 0(零前缀) | 2 1 / 1 2 1 2 / 1 2 1 3 / 2 1 9 → 1 1(并列先比编号会一样,先比负载才对:换负载 2 … / 1 … 自测) |
| AI034 对称量化 | 5 4 / 1.0000 -0.5000 0.2500 -1.0000 0.7500 → 0.142857 / 7 -4 2 -7 5 / 0.071428 | 4 8 / 0.0000 0.0000 0.0000 0.0000 → 三行特殊值 | 2 2 / 1.0000 0.5000 → 第二行 1 1(内置 round 得 1 0) |
| P2580 文件缓存系统 | 题面无示例;题目页给出输出格式 a,c 与 NONE | 空操作序列 → NONE | 期望输出以交卷后的测验解析为准 |
| P3285 滑动窗口的最大值 | 题面无示例 | M = N;M = 1;全负数组 | 期望输出以交卷后的测验解析为准 |
| AI039 旋转位置编码 | 4 10000 3 / 1.00 0.50 -2.00 0.25 → -1.0606 -0.3539 -2.0066 0.1899;4 10000 0 / … → 与输入相同 | d = 2 单对 | 期望输出以交卷后的测验解析为准 |
清单里给出的输出都来自各课正文或题目页题面示例。重写后先跑清单再提交;提交通过后把登记表的「独立重写」改成「通过」。
重写仍未通过时,对比两次失败用例和代码位置。同一个用例仍失败,就重新检查原因与修复是否覆盖该情形;新的用例失败,则补记新的问题。可以记录问题后预习下一模块,但这只是调整学习顺序,不等于订正完成:保留未完成状态,安排第二次独立重写,通过后再如实勾选检查项。
07 / 迁移练习与完成自查
分类练习、找错练习、三套写法默写与 RoPE 自查
每题先自己做,再展开答案。
练习 1(分类):下面五个失败描述各属于六类中的哪一类?① AI031 某行掩码全 0 时程序抛出 ValueError: max() arg is an empty sequence;② AI043 在 2 3 / 100 7 / 50 7 / 30 7 上输出 100 7 / 30 7(期望 50 7 / 30 7);③ AI008 在 n=70000、q=1000 的用例上超时,代码对每个预算从 c=0 逐个试;④ AI036 在 k=140000 的用例上输出 2019127296.0000(期望 -2275840000.0000),语言是 C++;⑤ AI030 两块之间没有空行。
展开练习 1 答案
① 边界(全屏蔽行没判空);② 读题(并列淘汰最早加入者,不是标识小者);③ 复杂度(线性试 c,应二分);④ 语言(int 累加溢出,应 long long);⑤ 输出格式。判定依据:①运行错误且只在特定输入;②数字全对只在并列上错;③超时;④数值离谱且与位宽相关;⑤数字对、分隔不对。
练习 2(找错并写最小用例):一位同学的 AI035 把量化写成 q = round(x / s' + zp)(先加零点再取整)。写出它的错误类型、一个最小用例(含期望与实际表现)和修复动作。
展开练习 2 答案
类型:读题(题面公式是 zp + round(x/s′),括号位置就是运算顺序)。最小用例:2 2 / -0.0050 0.0250——s′ = 0.01、zp = 1,正确 0 3,先加后取整得 1 3(−0.5 远离零到 −1,而 0.5 远离零到 1)。修复:先取整再加零点。复测:题面示例 1 → 0 87 120 255 32 仍通过。
练习 3(三套写法默写):不看资料,各写一遍并用一个断言验证——① 可见集合 + 四步(visible / 打分 / 窗口内 softmax / 加权求和);② 并列元组(前缀长 → 负载 → 编号)与惰性堆(得分, 加入序号);③ 整数标度的逢半远离零 round_half_away(num, den)。
展开练习 3 答案
每套写法的参考实现都在对应课的展开区:① 第 2 课 第 07 节 local_visible 与完整程序;② 第 3 课 第 09 节 AI007 / AI043 完整程序;③ 第 4 课 第 08 节 round_half_away。默写后与之对照,差异处就是要再练的点。
练习 4(没有错题的同学):可选择印象最浅的一道必做题,从空文件重写并复测。随后完成学习检查第 4 条的 RoPE 自查:关闭第 3 课的参考内容,独立写出旋转位置编码函数,通过断言并说明每条断言检查什么。前面的额外重写由你选择,RoPE 自查则是现有完成检查的一部分,不是可跳过的额外练习。
08 / 复习入口与完成条件
订正完成之后做什么
订正只针对本模块;每类错误对应的课入口如下,订正完成后按顺序进入模块 8。
| 错误类型 | 回到哪里 | 重点看什么 |
|---|---|---|
| 读题(掩码含义、并列层次、淘汰键、舍入方式) | 注意力机制与 Q/K/V 计算、KV 缓存与束搜索、量化基础:对称与非对称量化 | 第 1 课 的掩码约定、第 3 课 第 05 与 07 节、第 4 课 第 04 节 |
| 建模(可见集合、四步顺序、缩放系数下标) | 局部注意力:对称窗口与因果窗口、整数矩阵乘法与反量化 | 第 2 课 第 04、05 节,第 5 课 第 04、05 节 |
| 边界(全屏蔽行、w=0、q=0、p=0) | 注意力机制与 Q/K/V 计算、局部注意力:对称窗口与因果窗口 | 各课错误做法表里的边界行 |
| 复杂度 / 语言(线性扫描、线性试预算、.5 舍入、位宽) | KV 缓存与束搜索、量化基础:对称与非对称量化、整数矩阵乘法与反量化 | 第 3 课 第 10 节复杂度表、第 4 课 第 07 节、第 5 课 第 04 节位宽表 |
| 输出格式(-0.00、块间空行、位数) | 局部注意力:对称窗口与因果窗口、量化基础:对称与非对称量化 | 第 2 课 第 06 节分块输出、第 4 课 的格式化函数 |
完成条件仍是全部四条学习完成检查:阶段测验错题已独立重写通过、错题记录含反例、重写不查旧代码,以及订正通过后的 RoPE 自查。仍有未通过题时,排好第二次重写并保留未完成状态;写明问题不等于通过。两道重做任务用于复习。完成这些检查后,再按计划进入模块 8。
09 / 练习
按顺序完成本课的任务
5 项自测任务,完成情况由你自己核对
填写错误原因记录表
必做任务 1自主练习练习重点:每道未通过的题:类别 + 一句话错误原因 + 反例输入 + 重做日期;预计用时:30 分钟
完成标准:每条记录都配上了能触发错误的反例输入
需要时查看提示
如暂时无法构造最小反例,可逐步缩小失败输入:把输入减半再测试,直到找到最小触发输入——这个方法模拟考试复盘日还会用。登记模板与填好的示例见第 05 节。
独立重写未通过的题
必做任务 2自主练习练习重点:先说明规则与算法,再从空文件整段重写并提交;预计用时:60 分钟
完成标准:重做的每道题都独立通过全部测试,且能说出这次和上次写法的差别在哪
需要时查看提示
重做前先把题目规则整理成注释放在文件顶部,写完对着注释逐条核对;两次都在同一处出错,可回到对应课程把相关段落再看一遍。复测清单见第 06 节。
AI007 前缀缓存调度器 · 独立重写
重做任务 1自主练习练习重点:三层并列元组、负载加未命中数、序列换新;预计用时:20 分钟
完成标准:从空文件写到通过全部测试,并记录本次用时供后续比较
需要时查看提示
独立重写时遇到困难超过 10 分钟:先暂停编码,把第 3 课 第 05 节两个请求的逐槽位表在纸上重新推演一遍再继续。用第 06 节清单里的并列用例验证;提交入口是模块 7 · 第 3 课 的 AI007 任务卡。
AI034 对称量化 · 同类强化
重做任务 2自主练习练习重点:整数标度、逢半远离零、s′ 定标顺序、截断;预计用时:20 分钟
完成标准:每个分支都能指出对应的题目规则
需要时查看提示
这是第 4 课 做过的题,本课重做它,重点不在通过,而在核对每条题目规则都有对应实现。用第 06 节清单里的中点用例验证;提交入口是模块 7 · 第 4 课 的 AI034 任务卡。
RoPE 独立自查(订正通过后)
进阶练习 1进阶练习自主练习练习重点:不看模块 7 · 第 3 课 的正文,从空文件写出 RoPE 旋转函数(rope)并通过 AI039 样例断言;预计用时:15 分钟
完成标准:在不查看旧代码的情况下正确完成并通过样例断言;能说明 θ 指数里的 i 为什么是「第几对」
需要时查看提示
如暂时无法独立实现,可回顾模块 7 · 第 3 课 第 08 节的三步公式,再关闭参考内容重新完成——独立重写的意义在于不查看参考。
自测代码(复制到你的代码文件中运行,检查输出是否一致)
import math
def rope(x, p, base=10000):
# 待完成:维度两两配对 (2i, 2i+1),theta_i = base**(-2i/d),alpha_i = p*theta_i,
# y[2i] = x[2i]cos(a) - x[2i+1]sin(a),y[2i+1] = x[2i]sin(a) + x[2i+1]cos(a)
...
# AI039 样例 1:d=4、p=3
y = rope([1.00, 0.50, -2.00, 0.25], 3)
assert [round(v, 4) for v in y] == [-1.0606, -0.3539, -2.0066, 0.1899]
# p=0:旋转角全 0,原样输出
assert [round(v, 4) for v in rope([1.00, 0.50, -2.00, 0.25], 0)] == [1.0, 0.5, -2.0, 0.25]自评状态
提交结果说明与处理方法
- WA
答案错误
若重做后仍为答案错误,先比较是否与原错误相同:相同则回到对应课程复习,不同则记录新的错误原因,并检查新的规则或边界问题(第 06 节末段)
- PE
格式错误
-0.00 / -0.0000 归一、空行分隔、小数位数、字典序与 NONE——本模块格式错误集中在这几处
- RE
运行错误
全屏蔽行判空、读入个数核对、空输入分支、对空字典取最小值
- TLE
超时
淘汰用惰性堆不用线性扫描;预算用二分不用线性试;窗口和右进左出不重新求和
- AC
通过
在登记表中将这条错题标记为已完成;所有错题完成修改、通过验证并更新状态后,本课的订正任务完成
10 / 学习完成检查
本课学习完成检查
完成本课需要:没有新的必做题,勾选全部学习完成检查即算完成。登录后,勾选记录会保存到账号,并更新课程总览的完成状态。