去年在做 Cambricon-Q:量化训练架构 的工作时,我发现许多同学不会做误差估计,也没有意识到随机实验中需要进行误差估计。体系结构领域似乎并不重视这一点,同行做实验时常常在真实系统上测试跑一个几十毫秒的程序,然后直接用time命令截取用时,再汇报模拟实验结果的加速比。这样的测量是有误差的,结果常常在一个范围内波动;如果加速比达到上百倍,一点误差可能会导致最终报告出完全不同的数值。
小初高通识教育中,实验课会教我们“多次测量取平均值”,但“多次”应该是多少次?5次够吗?10次呢?100次呢?还是直到工作截稿之前,一直重复做下去呢?我们需要了解科学的实验方法:重复随机实验中的误差估计。我发现并非所有本科概率论课程都教授这些,但要从事科学研究工作,这却是一项必备技能。
我不是统计学家,本科时我也是全校挂科王,肯定算不上概率论专家。但我曾经作为业余爱好钻研过蒙特卡洛模拟,我来展示我自己是如何完成这个过程的。如果有误,还请概率论专家们不吝纠正。
高斯估计
我们有一组实验测量值
虽然分布参数中有
虽然以上推演过程首先假设了高斯分布,但是根据列维-林德伯格中心极限定理(Levy-Lindeberg CLT),任意无限个随机变量叠加后,其和都趋近于服从高斯分布,只要这些随机变量满足以下两个条件:
- 方差是有限的;
- 独立。
这样,无论实验测量值实际服从的分布是什么,我们都可以直接从CLT导出最终
高斯分布告诉我们,我们有99.7%的把握说,
我们用到的常数3和99.7%是查表得出的高斯分布累积分布函数(CDF)上的一个点,类似常用值还有1.96和95%。从确定的置信区间推算置信度,我们使用CDF:
编程实现时,高斯分布的CDF可以比较直接地用数学库函数erf实现。它的逆函数erfinv并不常见,在C语言和C++的标准库里就不存在,不过因为CDF都是连续、单调、可导的,其导函数即概率密度函数(PDF),因此用牛顿法、割线法、二分法等数值方法都可以比较高效地求逆。
然而,以上估计完全依赖于CLT,CLT毕竟只描述了一个极限情况。实际实验时我们取5次、10次实验结果,离无限次实验差得远,难道也强行应用CLT吗?这显然不科学。
“学生” t-分布估计
描述有限多次随机实验叠加值,有一个更专用的概率分布,即“学生” t-分布。除了以上高斯估计推算的过程,t-分布还额外考虑了
t-分布与自由度直接相关,在重复随机实验里自由度可以理解为
当试验次数不多时,我们直接用t-分布代替高斯分布来描述
实现
在Python中,直接调包:高斯估计使用scipy.stats.norm.cdf和scipy.stats.norm.ppf;“学生” t-分布估计使用scipy.stats.t.cdf和scipy.stats.t.ppf。
C++里比较难做,STL库功能不全,而且引入外部库不方便。下面的代码给出了两种误差估计的C++实现。两条注释条之间的内容可以抽出组成一个头文件供直接使用,更下面的部分则展示了一个样例程序:从