机器学习与测试:为模型和项目编写测试

编写的代码非常耗时,但如果代码存在错误,则代码可能部分或完全不可靠。彻底测试代码对于确保可靠、可重现的研究至关重要。本文将介绍在机机器学习和深度学习项目中,如何进行测试,以及测试的细节。


▎测试的重要性

写代码非常容易出错。一个错误的字符可能会导致程序的输出完全错误。每个人都会犯错,导致宝贵的时间会浪费在调试代码上。

对于开发人员,时间是最稀缺的资源。你不应该因为时间不够而跳过写测试,你应该因为时间不够而写测试。编写测试是节约项目维护和调试的时间。

打印中间 不等于 测试

在编写代码时,我们通常在代码中打印变量并检查输出。但在上线后会注释这些输出的代码。

但测试应该是一套可以独立和自动运行的测试,可以验证程序正确行为并增加发现缺陷的过程。

测试 会 增加代码质量

测试可以增加代码质量,大量的测试用例可以验证程序功能是否正常,以及是否引入了额外的故障。

编写测试通常会迫使研究人员编写更清晰、更模块化的代码,因为这样的代码更容易编写测试,从而提高代码质量。


▎测试的最佳实践

测试 与 编码

测试可以分成不同的类型,并且每种都有具体的最佳实践。但编写测试是与编写代码同时进行的,或者在编写代码之前可以写好测试。

自动化测试

测试应该经常运行,并且可以自动化运行。一种常见的方式是在合并代码或者提交代码之前,通过工具来完成运行测试。

此外还需要考虑不同测试所需要消耗的时间,如如单元测试通常非常快,然而性能测试或系统测试可能需要很长时间才能运行。建议更具测试的耗时,来安排不同的测试频次。

测试环境

描述如何运行测试的文档非常重要,测试文档还应涵盖以下主题

  • 测试所需的测试数据集文件
  • 测试所需的任何配置/设置调整
  • 测试需要安装什么软件

测试框架

有一些工具可以让编写和运行测试变得更容易,这些工具被称为测试框架。常见的测试框架(以及它们适用的语言)包括:

  • C++
    • Catch
    • CppTest
    • Boost::Test
    • google-test
  • C
    • all C++ frameworks
    • Check
    • CUnit
  • Python
    • pytest (recommended)
    • unittest comes with standard Python library
  • R unit-tests
    • testthat
    • tinytest
    • svUnit (works with SciViews GUI)t
  • Fortran unit-tests:
    • funit
    • pfunit (works with MPI)
  • julia
    • Test.jl (stdlib)
    • ReTest.jl

代码覆盖率

代码覆盖率是衡量您的代码有多少被测试“覆盖”的指标。更准确地说,它衡量的是在进行测试时运行了多少代码。代码覆盖率不包括注释之类的文档,因此添加更多文档不会影响您的百分比。


▎测试类型

首先有正例测试和负例测试。正例测试检查某些东西是否有效,例如测试将一些数字相乘的函数是否输出正确答案。负例测试检查某些东西是否会在应有的时候产生错误。

除了这两种测试之外,还有不同级别的测试。一个全面的测试套件将包含所有这些级别的测试。

冒烟测试

冒烟测试是非常简短的初始检查,确保运行项目所需的基本要求。如果这些失败,则在修复之前没有必要继续进行其他级别的测试。

单元测试

单元测试是软件测试过程的一个级别,其中测试软件的各个单元。目的是验证软件的每个单元是否按设计执行。

集成测试

集成测试是一种软件测试级别,其中将各个单元组合在一起并作为一个组进行测试。此级别测试的目的是暴露集成单元之间交互中的错误。

系统测试

系统测试是测试完整的集成系统的软件测试过程的一个级别。该测试的目的是评估系统作为一个整体是否为给定的输入提供正确的输出。

验收测试

验收测试是测试系统可接受性的软件测试过程的一个级别。该测试的目的是评估系统是否符合项目要求,并评估是否可以接受。

回归测试

回归测试是一种可以在四个主要级别中的任何一个级别执行的测试,它比较代码更改前后的测试结果,如果不同则给出错误。


▎测试驱动开发(TDD)

测试驱动开发一种在代码之前编写单元测试的方法。测试描述了代码应遵守的“契约”。这确保代码在编写时是正确的(只要测试合同可以强制执行),并且它提供了一个有用的框架来思考代码应该如何设计、它应该提供什么接口以及它的算法如何可能工作。

编写测试后,将开发代码以使其通过所有相关测试。从一开始就测试代码可确保您的代码始终处于可发布状态。测试驱动开发迫使您将代码分解成小的离散单元,使它们更容易测试;代码必须是模块化的。单元测试部分讨论了这样做的好处。


▎测试中的随机性

有时代码包含随机性元素,测试这种代码可能非常困难,因为如果多次运行它会产生不同的答案,有两种主要方法来处理测试随机代码:

固定随机种子

这里有一个例子。这是一个打印三个随机数的小 Python 脚本:

import random

# Print three random numbers
print(random.random())
print(random.random())
print(random.random())

这个脚本没有错误,但如果你反复运行它,每次都会得到不同的答案。现在让我们设置一个随机数种子。

import random

# Set a random number seed
random.seed(1)

# Print three random numbers
print(random.random())
print(random.random())
print(random.random())

每次运行这个脚本你都会得到相同的输出,它会打印相同的三个随机数。如果更改随机数种子,将获得不同的三个随机数。

测量结果分布

如果测试结果存在随机性,则可以多次运行它并测试结果的分布。代码运行的次数越多,平均值和结果就越可靠。


▎测试机器学习模型

测试机器学习类似于测试传统软件, 但是也存在一些关键差异:

  • 数据可变性:机器学习模型是在数据集上训练的,这些数据的可变性会影响模型的性能。
  • 非确定性行为:某些机器学习模型(例如神经网络)在其训练过程中内置了一定程度的随机性。
  • 评估指标:与传统软件不同,机器学习模型通常使用准确度、精确度和召回率等指标进行评估,而不是传统的通过/失败标准。
  • 数据分布转移:机器学习模型对数据分布很敏感,这意味着它们可以很好地处理训练数据,但无法处理具有不同分布的看不见的测试数据。

结合上述已经介绍的测试方法,我们可以为机器学习模型编写测试,方法包括:

  • 单元测试:这些测试侧重于模型的各个组件,例如特定层或激活函数,以确保它们正常工作。
  • 集成测试:这些测试检查模型的不同组件协同工作的情况。
  • 功能测试:这些测试检查模型在给定特定输入时是否按预期运行,并产生预期的输出。
  • 性能测试:这些测试衡量模型在准确性、精度和召回率等指标方面的表现,并将其与预定义的基线或基准进行比较。
  • 端到端测试:这些测试检查从数据预处理、模型训练、评估到最终预测的完整管道。

▎测试深度学习模型

深度学习模型是机器学习子集,与传统的机器学习模型相比,它们通常具有更复杂的架构并且需要更多的数据来训练。

与测试传统机器学习模型相比,测试深度学习模型可能有一些额外的考虑因素:

  • 过拟合:深度学习模型更容易过度拟合,这意味着它们在训练数据上表现良好,但在看不见的测试数据上表现不佳。
  • 计算复杂性:深度学习模型是计算密集型的,这意味着测试可能需要更长的时间才能运行并且需要更多的计算资源。
  • 模型可解释性:深度学习模型比传统机器学习模型更难解释。

除了上述注意事项之外,测试机器学习模型的整个过程也适用于深度学习模型。


▎测试实施清单
  • 为所有代码单元编写单元测试
  • 编写集成测试以检查单元之间的集成
  • 写一些系统测试。
  • 进行良好语法检查
  • 记录测试文档
  • 验证运行测试所需的资源
  • 选择并使用测试框架
  • 定期运行测试
  • 自动化运行测试的过程
  • 不断改善代码覆盖率

本文转自:Coggle数据科学,转载此文目的在于传递更多信息,版权归原作者所有。如不支持转载,请联系小编demi@eetrend.com删除。

最新文章