WEBVTT

1
00:00:00.000 --> 00:00:02.461
有这样一个标题：在我们的基准上，

2
00:00:02.461 --> 00:00:05.999
工作流 B 比工作流 A 高出二十五个百分点。

3
00:00:05.999 --> 00:00:07.384
你相信这个说法吗？

4
00:00:07.384 --> 00:00:09.999
写下你的回答，以及你需要看到什么。

5
00:00:09.999 --> 00:00:11.691
把这个最初的回答留着。

6
00:00:14.033 --> 00:00:17.503
在相信一个通过率之前，先问三个问题。

7
00:00:17.503 --> 00:00:19.238
这个检查会失败吗？

8
00:00:19.238 --> 00:00:21.166
这次通过是挣来的吗？

9
00:00:21.166 --> 00:00:22.323
分母完整吗？

10
00:00:23.366 --> 00:00:25.076
这三个问题放在哪里？

11
00:00:25.076 --> 00:00:29.692
在任何运行开始之前先冻结协议，让结果无法反过来改写它：

12
00:00:29.692 --> 00:00:33.453
有哪些任务、每个任务尝试几次、超时算作什么。

13
00:00:33.453 --> 00:00:38.412
然后在固定的预算和验证方式下运行每个任务，保留每一个结果，

14
00:00:38.412 --> 00:00:39.608
超时也不例外。

15
00:00:39.949 --> 00:00:45.029
只有在这之后、报告任何通过率之前，才用这三个问题审查记录。

16
00:00:45.029 --> 00:00:49.233
报告给出全部声明任务上的通过率，并写明它的局限。

17
00:00:49.233 --> 00:00:53.963
更窄的子集可以附上理由放在旁边，但它永远不能取而代之。

18
00:00:54.999 --> 00:00:57.447
第一个问题：这个检查会失败吗？

19
00:00:57.447 --> 00:00:59.895
有一个函数负责找出最新的版本。

20
00:00:59.895 --> 00:01:03.486
每个版本由两个整数组成，主版本号和次版本号。

21
00:01:03.486 --> 00:01:06.424
约定写着：比较数字，而不是比较文本。

22
00:01:06.766 --> 00:01:08.552
基准检查了四个输入。

23
00:01:08.552 --> 00:01:13.732
一个只有一行的候选实现，直接取版本的最大值，四个全部通过。

24
00:01:14.066 --> 00:01:15.691
可它比较的是文本。

25
00:01:15.691 --> 00:01:19.121
被检查的每个版本，各部分都只有一位数，

26
00:01:19.121 --> 00:01:22.010
所以文本顺序碰巧和数字顺序一致。

27
00:01:22.010 --> 00:01:26.524
给它 1.9 和 1.10，它却说 1.9 更新。

28
00:01:26.866 --> 00:01:28.296
这就是弱检查。

29
00:01:28.296 --> 00:01:32.381
错误的实现也能通过，于是通过率被抬高了。

30
00:01:33.415 --> 00:01:36.120
检查也可能让正确的答案失败。

31
00:01:36.120 --> 00:01:39.790
总数为零时，通过率没有定义，约定写着：

32
00:01:39.790 --> 00:01:42.494
抛出 ValueError。

33
00:01:42.494 --> 00:01:44.619
它对错误消息只字未提。

34
00:01:44.965 --> 00:01:47.977
有一个检查要求消息必须是“no tasks”，

35
00:01:47.977 --> 00:01:49.942
这是从作者自己的代码里抄来的。

36
00:01:49.942 --> 00:01:53.870
一个正确的实现，消息是“total is 0”，结果没通过。

37
00:01:54.215 --> 00:01:57.083
这就是过严的检查，它会压低通过率。

38
00:01:57.083 --> 00:02:02.482
约定允许什么就接受什么：这里任何 ValueError 都可以。

39
00:02:03.515 --> 00:02:05.983
第二个问题：这次通过是挣来的吗？

40
00:02:05.983 --> 00:02:10.456
一个助手被要求修好这个通过率函数，并且保持唯一的测试不变。

41
00:02:10.456 --> 00:02:14.312
这个测试检查的是：四个里通过两个，结果是二分之一。

42
00:02:14.648 --> 00:02:19.907
轨迹显示：测试失败，写了一次文件，然后测试通过。

43
00:02:19.907 --> 00:02:23.414
最终的主张是：修好了，测试通过。

44
00:02:23.748 --> 00:02:25.851
它写的是：返回二分之一。

45
00:02:25.851 --> 00:02:28.129
通过是真的，但不是挣来的。

46
00:02:28.129 --> 00:02:31.283
这次修改只是抄下了唯一被检查的答案。

47
00:02:31.631 --> 00:02:34.825
缺的那个观察，是一个它没法照抄的输入。

48
00:02:34.825 --> 00:02:39.700
四个里通过一个，应该是四分之一，而这段代码仍然说二分之一。

49
00:02:40.748 --> 00:02:42.334
再看第二段轨迹。

50
00:02:42.334 --> 00:02:45.504
任务是：从 1.10 版本开始，

51
00:02:45.504 --> 00:02:48.874
仪表盘把 1.9 显示为最新版本。

52
00:02:48.874 --> 00:02:52.045
修好这个函数，并且保持测试不变。

53
00:02:52.381 --> 00:02:56.906
助手读取了这个文件带补丁的 git 历史，

54
00:02:56.906 --> 00:03:03.585
找到把数值比较换成普通 max 的那次提交，恢复了旧的那一行，

55
00:03:03.585 --> 00:03:05.524
四个测试都通过了。

56
00:03:05.865 --> 00:03:09.503
课程的检测器会标记第一步：读取补丁历史。

57
00:03:09.503 --> 00:03:14.414
设这条规则，是因为在基准里，历史中可能就放着参考修复。

58
00:03:14.414 --> 00:03:16.596
在这里读取历史有问题吗？

59
00:03:16.596 --> 00:03:18.415
先写下你最初的判断。

60
00:03:20.765 --> 00:03:26.090
现在读任务的后半部分：你可以查看这个文件的 git 历史，

61
00:03:26.090 --> 00:03:29.762
包括旧的差异，来找出导致问题的那次改动。

62
00:03:30.098 --> 00:03:34.441
所以作弊指控不成立：照抄旧的那一行是得到授权的。

63
00:03:34.441 --> 00:03:38.422
这个标记只是一个有待调查的主张，而不是结论。

64
00:03:38.422 --> 00:03:41.679
把线索留在记录里，旁边引用那句授权。

65
00:03:41.679 --> 00:03:44.574
而且这次通过仍然需要自己的证据：

66
00:03:44.574 --> 00:03:48.374
坏掉的代码同样能得到“4 passed”。

67
00:03:48.374 --> 00:03:52.354
下一个观察是拿 1.9 和 1.10 来比。

68
00:03:53.397 --> 00:03:58.208
这个检测器在记录下来的工具请求里匹配七条文本规则。

69
00:03:58.208 --> 00:04:02.058
它从不运行这些命令，也从不读取任务说明。

70
00:04:02.397 --> 00:04:04.643
我们运行了它的回归测试。

71
00:04:04.643 --> 00:04:10.071
一条良性记录，读取的是得到授权的历史，仍然触发了历史规则。

72
00:04:10.071 --> 00:04:12.504
规则看不见授权，你看得见。

73
00:04:12.504 --> 00:04:16.247
所以它的报告把处置保持为“仅人工审查”。

74
00:04:16.597 --> 00:04:20.121
而检测结果为空，也不说明这次通过是挣来的。

75
00:04:20.121 --> 00:04:23.813
可能是参数根本没有收集到，所以先看覆盖情况。

76
00:04:23.813 --> 00:04:26.834
也可能是没有任何规则能描述这个问题，

77
00:04:26.834 --> 00:04:29.855
比如关于一个从没测试过的修订的主张。

78
00:04:30.896 --> 00:04:33.594
第三个问题：分母完整吗？

79
00:04:33.594 --> 00:04:37.415
协议声明了四个任务，每个尝试一次。

80
00:04:37.415 --> 00:04:40.787
两个通过，一个失败，一个超时。

81
00:04:41.129 --> 00:04:45.368
起始版本的报告丢掉了超时，说是三个里通过两个。

82
00:04:45.368 --> 00:04:50.529
按这份协议，超时是一个没有成功的任务，而不是缺失的任务。

83
00:04:50.529 --> 00:04:52.925
正确答案是四个里通过两个。

84
00:04:53.262 --> 00:04:56.529
它还把坏掉的输入当成有效的来汇报：

85
00:04:56.529 --> 00:05:00.180
少一个任务、重复一个任务、多一次尝试。

86
00:05:00.180 --> 00:05:02.678
协议规定，这些都是无效的。

87
00:05:03.012 --> 00:05:08.076
修复方案是：在计数之前先校验声明的任务和尝试次数，并且保留超时。

88
00:05:08.076 --> 00:05:12.032
这个方案可以由人提出，也可以由获准使用的助手提出；

89
00:05:12.032 --> 00:05:15.197
在原封不动的检查跑过之前，它都只是候选。

90
00:05:15.197 --> 00:05:18.837
我们按这个描述写了一个修复，四项检查全部通过。

91
00:05:19.879 --> 00:05:22.652
相同的通过率可能掩盖不同的行为。

92
00:05:22.652 --> 00:05:26.986
两个工作流跑了同样的四个任务，都是四个里通过两个，

93
00:05:26.986 --> 00:05:31.493
但 A 在任务 B 上失败，B 在任务 C 上失败。

94
00:05:31.493 --> 00:05:34.786
要保留这个分歧，不要断定它们表现一样。

95
00:05:35.129 --> 00:05:38.028
这是工作流 A 在任务 B 上的轨迹。

96
00:05:38.028 --> 00:05:41.232
它读了带空白规则的约定，写了一个候选实现，

97
00:05:41.232 --> 00:05:43.521
用前后带空格的 OK 来验证，

98
00:05:43.521 --> 00:05:47.488
在要求 passed 的地方得到了 unknown，

99
00:05:47.488 --> 00:05:50.082
然后在唯一一次调用用完时停了下来。

100
00:05:50.429 --> 00:05:54.704
这就排除了“没有提供规则”和“没有验证”这两种解释。

101
00:05:54.704 --> 00:05:58.814
它支持的是：在观察到的这个用例上，候选实现有缺陷。

102
00:05:58.814 --> 00:06:00.623
它说明不了模型的意图。

103
00:06:00.623 --> 00:06:05.226
之后根据反馈做的修复是另一个结果，有它自己的时间和用量，

104
00:06:05.226 --> 00:06:06.706
不是一个新的样本。

105
00:06:07.745 --> 00:06:09.354
现在回到那个标题。

106
00:06:09.354 --> 00:06:11.142
它的基准有四个任务。

107
00:06:11.142 --> 00:06:15.253
其中一个正是第一个问题里挑最新版本的那个检查。

108
00:06:15.253 --> 00:06:18.113
另外三个经过审查，没有发现缺陷。

109
00:06:18.462 --> 00:06:23.757
在全部四个任务上，A 四个里通过一个，B 四个里通过两个：

110
00:06:23.757 --> 00:06:25.583
相差二十五个百分点。

111
00:06:25.583 --> 00:06:28.687
去掉那个弱检查，两者都是三分之一。

112
00:06:28.687 --> 00:06:32.522
整个差距都来自一个错误实现也能通过的任务。

113
00:06:32.862 --> 00:06:37.135
同样的二十五个百分点，也可以被说成“B 是 A 的两倍”，

114
00:06:37.135 --> 00:06:38.609
相对提升百分之一百。

115
00:06:38.609 --> 00:06:40.525
要说清楚你用的是哪种说法。

116
00:06:41.562 --> 00:06:43.666
这个子集是怎么选出来的？

117
00:06:43.666 --> 00:06:49.277
在看谁赢之前，先审查每个任务的检查，再把结果同样用于两个工作流。

118
00:06:49.277 --> 00:06:53.134
弱检查要移出，因为错误的候选实现也能通过它。

119
00:06:53.134 --> 00:06:57.869
过严的检查也要移出，因为正确的候选实现会在它上面失败，

120
00:06:57.869 --> 00:07:00.324
比如通过率函数上的检查 M。

121
00:07:00.662 --> 00:07:05.123
只有没发现缺陷、而且记录里列出了你试过的输入和捷径，

122
00:07:05.123 --> 00:07:06.667
这个检查才能留下。

123
00:07:06.667 --> 00:07:10.785
slug 留在子集里，尽管两个工作流都没通过它。

124
00:07:10.785 --> 00:07:13.874
可靠性描述的是检查本身，而不是结果。

125
00:07:14.212 --> 00:07:16.764
在同一个子集上给两个工作流计分。

126
00:07:16.764 --> 00:07:19.795
可靠任务上的超时要留下，算作没有成功。

127
00:07:19.795 --> 00:07:24.581
去掉 A 的那次超时，A 就会显得领先，二分之一对三分之一：

128
00:07:24.581 --> 00:07:27.134
这是哪个工作流都没有挣来的领先。

129
00:07:27.134 --> 00:07:32.080
如果没有任何检查是可靠的，子集的通过率就是没有定义，而不是零。

130
00:07:32.428 --> 00:07:36.943
然后把两行都公布出来，并写明排除了哪个任务、为什么。

131
00:07:36.943 --> 00:07:42.499
完整的通过率描述的是实际跑过的实验；子集回答的是一个更窄的问题，

132
00:07:42.499 --> 00:07:43.887
它不能取而代之。

133
00:07:44.928 --> 00:07:49.744
即使是诚实的这两行，能说明的也很有限：四个任务，每个只尝试一次，

134
00:07:49.744 --> 00:07:52.754
任务是为课程编写的，模型配置也只有一种。

135
00:07:53.095 --> 00:07:58.273
这个差异可以指引下一次实验，但它不能证明一个稳定的优势。

136
00:07:59.311 --> 00:08:03.300
有一个限制值得细看：每个任务只尝试一次。

137
00:08:03.300 --> 00:08:08.285
假设一个任务在同样的预算和验证方式下独立尝试四次：

138
00:08:08.285 --> 00:08:10.678
通过、失败、通过、失败。

139
00:08:11.011 --> 00:08:13.038
pass@1 是四分之二。

140
00:08:13.038 --> 00:08:16.622
pass@2 问的是：从四次尝试里随机挑两次，

141
00:08:16.622 --> 00:08:19.427
这一对里至少有一次通过的概率是多少？

142
00:08:19.427 --> 00:08:22.856
六种组合里，只有两次失败凑在一起时没有通过，

143
00:08:22.856 --> 00:08:25.350
所以 pass@2 是六分之五。

144
00:08:25.695 --> 00:08:30.941
如果每个任务只尝试一次，pass@2 不是很低，而是没有定义。

145
00:08:30.941 --> 00:08:34.495
另外，根据反馈做的自适应修复不是新的样本。

146
00:08:35.544 --> 00:08:40.596
所以，在相信一个通过率之前，先问：检查会失败吗？

147
00:08:40.596 --> 00:08:42.280
通过是挣来的吗？

148
00:08:42.280 --> 00:08:43.543
分母完整吗？

149
00:08:43.877 --> 00:08:45.771
现在回到你最初的回答。

150
00:08:45.771 --> 00:08:47.665
当时你相信这个标题吗？

151
00:08:47.665 --> 00:08:49.386
现在你会先检查什么？

152
00:08:49.386 --> 00:08:51.796
什么样的观察能改变你的看法？

153
00:08:51.796 --> 00:08:54.722
保留最初的回答，加上修改后的回答，

154
00:08:54.722 --> 00:08:57.821
再给出一个你能接受的、有边界的结论。
