2010-02-10 128 views
24

我正在为计算机视觉的论文写一个相当复杂的机器学习程序。它工作得很好,但我需要不断尝试新事物并添加新功能。这是有问题的,因为我在扩展代码或试图简化算法时有时会引入错误。单元测试机学习代码

显然,正确的做法是添加单元测试,但不清楚如何执行此操作。我的程序的许多组件产生了一个有点主观的答案,我不能自动执行完整性检查。

例如,我有一些代码使用较低分辨率的曲线来近似曲线,这样我就可以在较低分辨率曲线上进行计算密集型工作。我意外地在这段代码中引入了一个bug,并且只有在我的整个程序的结果稍微恶化的时候才发现它是一个艰苦的搜索。

但是,当我试图为它编写一个单元测试时,我不清楚该怎么做。如果我制作了一个简单的曲线,它有一个明确正确的低分辨率版本,那么我并没有真正测试出所有可能出错的东西。如果我制作一个简单的曲线,然后稍微扰动这些点,我的代码就开始产生不同的答案,即使这段代码现在看起来确实很好。

回答

8

你可能不会感激这个讽刺,但基本上你有什么是遗留代码:一大块没有任何单元测试的软件。当然你不知道从哪里开始。因此,您可能会发现阅读处理遗留代码很有帮助。

关于此问题的权威性思想是Michael Feather的书,与遗产代码有效地工作。过去在ObjectMentor网站上有一个有用的总结,但可惜的是,该网站已经走过了公司的道路。但是WELC在评论和其他文章中留下了遗产。 Check them out (or just buy the book),虽然关键的经验教训是S.Lott和tvanfosson在他们的回复中提到的。

+0

这实际上是最有用的建议。我所有成功的调试都是通过使用这样的技术手工完成的。但是这个PDF为自动化过程提供了一些很好的建议。 您的PDF链接不适用于我,但一个简单的谷歌找到它。 – forefinger 2010-02-10 21:28:27

+0

@forefinger - 我现在已经修复了这个链接。但我很高兴你找到了这篇文章,并发现它很有用。 – APC 2010-02-10 21:38:55

+2

该PDF的作者有一本关于同一主题的出色书籍:http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052 – TrueWill 2010-02-10 21:42:51

11

没有看到您的代码,很难说,但我怀疑您正在尝试编写太高级别的测试。您可能想考虑将您的方法分解为确定性较小的组件并对其进行测试。然后通过提供从基础方法(可能位于不同对象上)返回可预测值的模拟实现来测试使用这些方法的方法。然后,您可以撰写涵盖各种方法领域的测试,确保您覆盖全部可能的结果。对于通过提供代表输入域的值的小型方法。对于依赖于这些方法的方法,通过提供模拟实现来返回依赖关系的结果范围。

+0

这条建议很有帮助。在这个例子中,我正在通过一个动态程序来进行逼近。这可以被分解为确定性的几个分量: 1.计算特定部分近似的误差。我可以通过一些特定的曲线手工完成。 2.确保总体目标函数是正确的。再次,我可以手工完成。 3.确保动态程序是正确的。 (这是错误发生的地方。) – forefinger 2010-02-10 21:23:30

+1

如果我知道总体目标函数是正确的,我可以通过提供简单的可分解曲线进行测试。只要答案给了我比我想要的答案更好的分数,动态程序可能正常工作。 – forefinger 2010-02-10 21:24:01

11

“那么我并没有真正测试出所有可能出错的东西。”

正确。

的单元测试工作是测试一切可能出错。

单元测试的工作是测试你有什么权利事情,给出具体的输入和具体的预期结果。这里的重要部分是具体的可见的,外部要求通过特定的测试用例来满足。不是说每一件可能出错的事情都会被阻止。

没什么可以测试一切都可能出错。你可以写一个证明,但你很难写的一切的测试。

明智地选择你的测试用例。另外,单元测试的工作就是测试整个应用程序的每个小部分都是正确的 - 孤立地进行测试。

例如,您的“用较低分辨率曲线近似曲线的代码”可能有几个小部件可以作为单独的单位进行测试。处于隔离状态。整体整体也可以进行测试,以确保它的工作。

例如,“在较低分辨率曲线上的计算密集型工作”可能有几个小部件可以作为单独的单位进行测试。处于隔离状态。

单元测试的要点是创建稍后组装的小的,正确的单元。

+0

这似乎是合理的建议,但它不像其他一些回应那样帮助解决我的具体问题。 – forefinger 2010-02-10 22:31:23

+0

“具体问题”?这并不容易理解,因为你的问题似乎没有列出任何具体问题。如果您需要更多信息,请随时更新您的问题。 – 2010-02-10 22:38:57

1

一般来说,对于统计测量,你可以在你的答案中建立一个epsilon。 I.E.你的积分的均方差将是< 0.01或其他。另一种选择是运行多次,如果“太频繁”失败,那么你有问题。

6

您的单元测试需要使用某种模糊因子,要么通过接受近似值,要么使用某种概率检查。

例如,如果您有一些函数返回浮点结果,那么编写可在所有平台上正确运行的测试几乎是不可能的。您的支票需要执行近似值。

TEST_ALMOST_EQ(result, 4.0); 

以上TEST_ALMOST_EQ可能验证result是3.9和4.1(例如)之间。或者,如果您的机器学习算法是概率性的,那么您的测试需要通过取多次运行的平均值并期望它在某个范围内来适应它。

x = 0; 
for (100 times) { 
    x += result_probabilistic_test(); 
} 

avg = x/100; 
TEST_RANGE(avg, 10.0, 15.0); 

Ofcourse,测试是不确定的,所以你需要对其进行调整,这样你可以得到一个高概率的非片状的测试。 (例如,增加试验次数或增加误差范围)。

您也可以使用模拟(例如,用于您的概率算法的模拟随机数生成器),它们通常有助于确定性地测试特定的代码路径,但它们需要很多努力来维护。理想情况下,您可以使用模糊测试和mocks的组合。

HTH。

+0

这是一个很好的建议,但它并不能真正解决我的问题,因为我需要检查的许多事情都是离散的,所以不能为他们计算错误,而且他们不能被有意义地平均。 – forefinger 2010-02-10 21:25:44

0
  1. 找一个合适的测试数据集
  2. 计算这个数据集的一些指标(也许您通常使用的是什么的一个子集)(例如,精度)
  3. 记下获得的(交叉验证)的值
  4. 这应该是在修改代码时给出如何设置为

当然门槛的迹象,如果可以的数据集的性能会增加一点,但是如果它减少了很多,这可能表明出现了问题。