【问题标题】:Unit Testing Machine Learning Code单元测试机器学习代码
【发布时间】:2011-01-15 09:44:24
【问题描述】:

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

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

例如,我有一些代码用较低分辨率的曲线近似曲线,这样我就可以在较低分辨率的曲线上进行计算密集型工作。我不小心在这段代码中引入了一个错误,直到我的整个程序的结果稍微变差时才通过艰苦的搜索找到它。

但是,当我尝试为其编写单元测试时,我不清楚我应该做什么。如果我制作了一条具有明显正确的低分辨率版本的简单曲线,那么我并没有真正测试所有可能出错的东西。如果我制作一条简单的曲线,然后稍微扰动点,我的代码就会开始产生不同的答案,即使这段特定的代码现在看起来确实可以正常工作。

【问题讨论】:

    标签: unit-testing machine-learning


    【解决方案1】:

    您可能不理解其中的讽刺意味,但基本上您所拥有的是遗留代码:一块没有任何单元测试的软件。自然不知道从何说起。因此,您可能会发现阅读处理遗留代码很有帮助。

    对此最权威的想法是 Michael Feather 的书,Working Effectively with Legacy Code。 ObjectMentor 网站上曾经有一个有用的总结,但可惜该网站已经走上了公司的道路。然而,WELC 在评论和其他文章中留下了遗产。 Check them out (or just buy the book),虽然关键的教训是 S.Lott 和 tvanfosson 在他们的回复中提到的。


    2019 年更新:我已使用来自 Wayback Machine 网络存档的版本修复了指向 WELC 摘要的链接(感谢@milia)。

    此外 - 尽管知道主要包含指向其他网站的链接的答案是低质量的答案:) - 这里有一个指向 a new (2019 new) Google tutorial on Testing and Debugging ML code 的链接。我希望这对偶然发现此答案的未来寻求者有所启发。

    【讨论】:

    • 这实际上是最有用的建议。我所有成功的调试都是手工使用这种技术的结果。但是这个 PDF 为自动化过程提供了一些很好的建议。你的 PDF 链接对我不起作用,但一个简单的谷歌找到了它。
    • @forefinger - 我现在已经修复了链接。但我很高兴你找到了这篇文章,并且觉得它很有用。
    • 该 PDF 的作者现在有一本关于同一主题的优秀书籍:amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/…
    • @APC 链接好像又坏了。
    • @giac_man - 是的,看起来 ObjectMentor 网站已经死了。任何地方似乎都没有链接文章的另一个副本。也许 Wayback Machine 有它,但是当我刚刚尝试时它给出了 DNS 错误:-(
    【解决方案2】:

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

    正确。

    单元测试的工作不是去测试所有可能出错的东西。

    单元测试的工作是在给定特定输入和特定预期结果的情况下测试您所拥有的东西是否正确。这里的重要部分是特定测试用例满足特定可见的外部要求。并不是说所有可能出错的事情都以某种方式被阻止了。

    没有什么可以测试所有可能出错的东西。你可以写一个证明,但你会很难为所有东西写测试。

    明智地选择您的测试用例。

    此外,单元测试的工作是测试整个应用程序的每个小部分是否都在独立地做正确的事情。

    例如,您的“用较低分辨率曲线近似曲线的代码”可能有几个小部分可以作为单独的单元进行测试。隔离中。也可以对集成的整体进行测试以确保其正常工作。

    例如,您的“低分辨率曲线上的计算密集型工作”可能有几个小部分可以作为单独的单元进行测试。孤立无援。

    单元测试的重点是创建小的、正确的单元,然后再组装。

    【讨论】:

    • 这似乎是合理的建议,但它对我的具体问题的帮助不如其他一些回复。
    • “具体问题”?这不容易理解,因为您的问题似乎没有列出任何具体问题。如果您想了解更多信息,请随时更新您的问题。
    【解决方案3】:

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

    【讨论】:

    • 这个建议很有帮助。在示例案例中,我正在通过动态程序进行近似。这可以分解为几个确定性的组成部分: 1. 计算特定近似值的误差。对于某些特定的曲线,我可以手动执行此操作。 2. 确保整体目标函数正确。同样,我可以手动完成。 3. 确保动态程序正确。 (这就是错误所在。)
    • 如果我知道整体目标函数是正确的,我可以通过输入被扰动的简单可分解曲线来测试这一点。只要它给我的答案比我想要的答案高,动态程序可能工作正常。
    【解决方案4】:

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

    例如,如果您有一些返回浮点结果的函数,则几乎不可能编写一个在所有平台上都能正常工作的测试。您的检查需要执行近似值。

    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);
    

    当然,测试是非确定性的,因此您需要调整它们,以便您能够以高概率获得非易碎测试。 (例如,增加试验次数,或增加误差范围)。

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

    HTH。

    【讨论】:

    • 这是个好建议,但它并不能真正解决我的问题,因为我需要检查的许多东西都是离散的,因此无法为它们计算错误,也不能有意义地平均。
    【解决方案5】:

    通常,对于统计测量,您会在 epsilon 中构建您的答案。 IE。您的点的均方差将小于 0.01 或类似的值。另一种选择是运行多次,如果它“经常”失败,那么你就有问题了。

    【讨论】:

      【解决方案6】:
      1. 获取适当的测试数据集(可能是您通常使用的数据集的子集)
      2. 计算此数据集的一些指标(例如准确度)
      3. 记下获得的值(交叉验证)
      4. 这应该表明要设置阈值的对象

      当然,如果对代码进行更改时,数据集的性能会有所提高,但如果它大幅下降,则表明出现问题。

      【讨论】:

        猜你喜欢
        • 2012-09-02
        • 2019-08-24
        • 2012-04-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-01
        • 1970-01-01
        相关资源
        最近更新 更多