
2.4 数据可靠性
因为我们的数据处理系统需要运转,所以数据在经过系统时必须有几个特征。阐明这些特征可能是有争议的。对一些人来说,它们似乎显而易见,而对另一些人来说,它们似乎无法被真正保证。这两种观点都没有说到重点。
阐明一组关于我们的数据应该总是正确的不变量的目的是,当它们不正确时,或者当系统不能保证它们是正确的情况下,它允许我们注意到。这使我们能够采取行动,在未来做得更好。请注意,可靠性的主题,甚至是数据管理系统的可靠性,是非常广泛的,在这里无法完全涵盖,更多细节请参见由Betsy Beyer等人编辑的Site Reliability Engineering: How Google Runs Production Systems(https://oreil.ly/ ZzIkN;O'Reilly,2016)。
本节只涵盖确保数据不丢失(持久性)、所有数据副本都一样(一致性)以及随时间推移仔细跟踪数据变化(版本控制)的基本内容。我们还会覆盖如何考虑数据的读取速度(性能)以及数据不能被读取到的频率(可用性)。对这些概念的快速概述可以帮助我们专注于正确的领域。
2.4.1 持久性
在阐述对存储系统的要求时,持久性最常被忽视,因为它是假设的。持久性是指存储系统存储你的数据,并且没有将其丢失、删除、覆盖或破坏的属性。我们肯定希望这个属性的值越高越好。
持久性通常表示为每年并未不可挽回地丢失的字节或区域的数据所占的百分比。好的存储系统的常见值是11个或12个9,也可以表示为“99.999999999%或更多的存储字节不会丢失”。虽然这可能是原始底层存储系统提供的,但我们的保证可能要保守得多,因为我们正在编写与存储系统互动的软件。
值得注意的是,有些系统有非常持久的数据,即没有任何东西丢失,但确实有一些故障,会使一些数据在极长的时间内无法访问。这可能包括需要从另一个较慢的存储系统(例如,磁带驱动器)恢复数据或通过缓慢的网络连接从异地复制数据的情况。如果这是原始数据,并且对模型很重要,你可能不得不恢复它。但是,对于那些以某种方式从现有原始数据中衍生出来的数据,可靠性工程师会考虑重新创建数据更容易一些,而不是恢复它。
对于一个有许多数据转换的机器学习存储系统,我们需要谨慎对待这些转换数据的写入和监控方式。我们应该对数据转换进行记录,如果有能力的话,可以存储转换前后的数据副本。最难跟踪的阶段是数据提取阶段,当数据从非管理状态转换为管理状态的时候。由于我们建议使用API来提取,这就提供了一个明确的位置来确保数据被存储、记录转换并确认数据的接收。如果数据没有被干净、持久地接收,发送系统应当可以在数据仍然可用时重试发送操作。
在数据转换的所有阶段,如果能负担得起,我们应该存储数据转换前和转换后的副本。我们应该监控转换的吞吐量以及预期的数据大小变化。例如,如果我们对数据进行30%的采样,那么除非发生错误,否则转化后的数据量显然应该是转化前的30%。另一方面,如果我们通过分桶将一个浮点数转化为一个整数,根据数据的表示方法,我们期望得到的数据大小基本不变。如果它大得多或小得多,那么它一定有问题。
2.4.2 一致性
我们也许想保证当我们从多台计算机访问数据时,每次读取的数据都是一样的;这就是一致性的特性。任何规模的机器学习系统通常都是分布式的。我们正在做的大部分处理从根本上说是可并行的,假设我们从一开始就使用机器集群,那么这种方式是有价值的。这意味着存储系统将通过网络协议从其他计算机上获得,并对可靠性提出了挑战。重要的是,它引入了这样一个事实:同一数据的不同版本可能同时可用。很难保证数据在任何地方都是复制的、可用的和一致的。
模型的训练系统是否关心一致性,实际上是模型和数据的一个属性。并非所有的训练系统都对数据的不一致敏感。就这一点而言,不是所有的数据都对不一致敏感。思考这个问题的一个方法是考虑数据的密度或稀疏程度。当每块数据所代表的信息都很稀少时,数据就是稀疏的。当每块数据所代表的信息都很常见时,数据就是密集的。而当数据集有很多零值的时候,数据也是稀疏的。因此,如果yarnit.ai有10种流行的纱线,几乎代表了我们销售的所有产品类别,那么任何给定的购买这些纱线的数据都是密集的——它不可能让我们学到很多新的东西。如果一个流行纱线的购买在我们存储系统的一个副本中是可读的,而在另一个副本中则不可读,那么这个模型将基本上不受影响。另一方面,如果我们采购的90%是不同的纱线,那么每一次采购都很重要。如果我们训练系统的一部分看到了某一特定纱线的购买,而另一部分没有看到,那么我们可能会针对该特定纱线或与该纱线相似的纱线产生一个不连贯的模型。在某些情况下,一致性是很难保证的,但通常,如果我们能在一定程度上等待数据的到达和同步,我们就能很容易地保证这一属性。
我们可以通过两种直接的方法来排除数据层中的关于一致性的问题。首先是建立对不一致的数据有容忍度的模型。就像其他数据处理系统一样,机器学习系统提供了折中方案。如果我们可以容忍不一致的数据,特别是当数据是最近写的,那么训练模型的速度会大大加快,并且使用存储系统的成本会更加低廉。在这种情况下,其代价是灵活性和对数据的保证。如果使用这种方法,我们不会让自己没有任何限制地操作使用存储系统,而且我们只能训练满足这一特性的模型。这是其中一个选择。
第二种方法是使用一个能够提供一致性保证的训练系统。对于一个复制存储系统来说,最常见的方法是由系统本身提供关于哪些数据被完全且一致地复制了的信息。读取数据的系统可以使用这个字段并选择只在完全复制的数据上进行训练。这对存储系统来说通常比较复杂,因为我们需要提供一个复制状态的API。它明显会更昂贵或更慢。如果想在提取和转换后快速使用数据,我们可能需要为网络(复制数据)和存储I/O容量(写入副本)提供大量资源。
考虑一致性需求是一个战略性决策。它对平衡成本和能力具有长期影响,应该与机器学习工程师和组织决策者共同参与。
2.4.3 版本控制
机器学习数据集的版本管理在很多方面类似于传统的数据或源代码的版本管理,用于标记数据的状态,以便我们可以在未来的实验中应用数据集的特定版本。当有新的数据可供重新训练时,或当我们计划实施不同的数据准备或特征工程技术时,版本管理变得非常重要。在真实的生产环境中,机器学习专家要处理大量的数据集、文件和指标来进行日常操作。因为实验是在多次迭代中进行的,因此需要对不同版本进行跟踪和管理。版本控制是管理众多数据集、机器学习模型和文件的一个非常好的方法,此外,还可以保存多个迭代的记录,即何时改变、为何改变以及改变了什么[9]。
2.4.4 性能
存储系统需要写入吞吐足够快,以快速提取数据,而不是缓慢地进行转换。系统的读取带宽要足够快,以使我们能够使用符合模型行为方式的访问模式快速训练模型。值得注意的是,缓慢的读取性能的代价可能相当大,原因很简单,机器学习训练经常使用相对昂贵的计算资源(GPU或高端CPU)。当这些处理器因此停滞而等待数据进行训练时,它们只是在空转浪费时间,没有完成任何有用的工作。许多组织认为他们负担不起投资存储系统,而实际上他们不能不投资。
2.4.5 可用性
当读取数据时,我们之前写入的数据应该已经存在。从某种方面来说,可用性是持久性、一致性和性能的产物。如果数据在我们的存储系统中,并被持续复制,而且我们能够以合理的性能读取它,那么该数据将被视为可用的。