最后,我们需要将数据存储在某个地方。我们如何以及在哪里存储数据主要是由我们如何使用它来决定的,这实际上是一组关于训练和服务系统的问题。我们在第4章对这个问题有更多的探讨,而这里有两个主要的问题:存储的效率和元数据。
存储系统的效率是由访问模式决定的,而访问模式受到模型结构、团队结构和训练过程的影响。为了对我们的存储系统做出明智的决定,这里有一些我们需要回答的基本问题:
● 模型是对这些数据进行一次训练还是多次训练?
● 每个模型都将读取所有数据还是只读取部分数据?如果只读取部分数据,被读取的子集是由数据类型(哪些字段)选择的,还是由随机抽样的数据(所有记录的30%)选择的?
● 特别是,相关团队是否读取了数据中略有不同的字段子集?
● 我们是否需要以任何特定的顺序来读取数据?
关于数据的重复使用问题,事实证明,几乎所有的数据都会被多次读取,存储系统应该支持这种功能,即使模型所有者断言他们只会对数据进行一次模型训练。为什么呢?模型开发本质上是一个迭代的过程。一个机器学习工程师构建模型(读取必要的数据),测量模型在其设计的任务中表现如何,然后部署它。接着他们会有另一个想法:一个关于如何改进模型的想法。很快,他们又重新读取同样的数据来尝试他们的新想法。我们建立的每一个系统,从数据到训练一直到服务,都应该假定模型开发者为了改进模型都会半持续地重新训练相同的模型。事实上,当他们这样做的时候,可能每次都会读取不同的数据子集。
鉴于此,每个特征一列的面向列的存储方案(每个特征占一列)是一种常见的设计架构,特别适用于对结构化数据进行训练的模型
。大多数读者都熟悉面向行的存储模式,在这种存储中,每次从数据库中获取数据都会检索并匹配行中的所有字段。对于那些使用大部分或全部数据的应用程序集合,或者一些类似的程序集合来说,这是一个合适的架构。面向列的数据有利于只检索字段的一个子集。这对每个使用特定数据子集的应用程序(本例中的机器学习训练管道)的集合更有用。换句话说,面向列的数据存储允许不同模型有效地读取不同的特征子集,并且不用每次都读入整行数据。我们在一个地方收集的数据越多,就越可能拥有使用不同数据子集的模型。
然而,这种方法对于某些训练系统来说太复杂了。举个例子,如果在大量未经预处理的图像上进行训练,我们其实并不需要有一个列式存储系统,这意味着我们可以直接从一个目录或一个桶中读取图像文件。然而,假设我们正在读取一些更结构化的东西,比如交易数据日志,其中有时间戳、来源、推荐人、金额、项目、运输方式和支付机制等字段。那么,假设一些模型会使用其中的一些特征,而另一些会使用其他的特征,这将促使我们使用列式存储结构。
元数据帮助人类与存储的数据进行互动。当多人在同一数据上建立模型时(或者当同一个人长期从事这项工作时),存储特征的元数据会为他们提供巨大的帮助。它是理解之前的模型是如何构造出来,以及我们应当如何构造模型的路线图。存储系统的元数据是机器学习系统中常常被低估的部分之一。
本节会说明我们的数据管理系统主要是由两个因素促成的:
我们打算将数据用于何种商业目的
我们要解决的是什么问题?这个问题对我们整个组织或客户的价值是什么?
模型结构和策略
我们计划构建什么模型?它们是如何组合的?它们多久更新一次?它们有多少个?它们之间的相似度如何?
我们对数据管理系统的每一个决定都受到这两个因素的制约,同时也制约着这两个因素。如果数据管理是关于我们如何以及为什么写入数据,那么机器学习训练管道是关于我们如何以及为什么读取数据。