点击上方关注,All in AI中国
在过去的十年中,深度学习模型已经证明在视觉、语音和语言方面执行各种各样的机器学习任务非常有效。在Uber,将这些模型用于各种任务,包括客户支持、对象检测、改进地图、简化聊天通信、预测和防止欺诈。
许多开源库,包括TensorFlow,PyTorch,CNTK,MXNET和Chainer等,已经实现了构建此类模型所需的构建块,从而可以实现更快,更不易出错的开发。反过来,这促使机器学习研究界和行业从业者采用这些模型,从而在架构设计和工业解决方案方面取得了快速进展。
在Uber AI,我们决定避免重新发明轮子并开发基于开源库提供的强大基础之上的软件包。为此,2017年我们发布了Pyro,一种基于PyTorch的深度概率编程语言,并在开源社区的帮助下继续改进它。Uber创建的另一个主要开源人工智能工具是Horovod,这是一个由LF深度学习基金会主办的框架,允许在多个GPU和多台机器上进行深度学习模型的分布式训练。
我们正在发布Ludwig,这是一个基于TensorFlow构建的开源深度学习工具箱,它允许用户在不编写代码的情况下训练和测试深度学习模型。
Ludwig的独特之处在于它能够帮助非专家更轻松地理解深度学习,并为经验丰富的机器学习开发人员和研究人员提供更快的模型改进迭代周期。通过使用Ludwig,专家和研究人员可以简化原型设计过程并简化数据处理,以便他们可以专注于开发深度学习架构而不是纠结于数据。
Ludwig
过去两年,我们一直在Uber内部开发Ludwig,以简化应用项目中深度学习模型的使用,因为它们通常需要在不同架构和快速迭代之间进行比较。我们目睹了其对优步自己的几个项目的价值,包括COTA,驾驶执照的信息提取,驾驶员 - 合作伙伴和车手之间对话中的兴趣点识别,食品配送时间预测等等。出于这个原因,我们决定将其作为开源发布,因为我们认为目前没有其他解决方案具有相同的易用性和灵活性。
我们最初将Ludwig设计为一种通用工具,用于在处理新的应用机器学习问题时简化模型开发和比较过程。为了做到这一点,我们从其他机器学习软件中汲取灵感:来自Weka和MLlib,直接处理原始数据并提供一定数量的预制模型的想法;来自Caffe,定义文件的声明性质;从scikit-learn,它简单的编程API。这种混合的影响使它成为一个完全不同的工具,与通常的深度学习库提供张量代数原语和很少的其他实用程序来编码模型,同时使它比其他专业库如PyText,StanfordNLP,AllenNLP和OpenCV更加通用。
Ludwig提供了一组模型架构,这些体系结构可以组合在一起,为给定的用例创建端到端模型。作为类比,如果深度学习库为您提供构建模块,Ludwig提供了构建您城市的积木,您可以选择可用的建筑物或将您自己的建筑物添加到可用的建筑集合中。
我们在工具箱中融入的核心设计原则是:
- 无需编码:无需编码技能即可训练模型并将其用于获取预测。
- 通用性:一种新的基于数据类型的深度学习模型设计方法,使该工具可跨许多不同的用例使用。
- 灵活性:经验丰富的用户可以对模型构建和训练进行广泛的控制,而新手则会发现它易于使用。
- 可扩展性:易于添加新模型体系结构和新功能数据类型。
- 可理解性:深度学习模型内部通常被认为是黑盒子,但我们提供标准的可视化来理解它们的性能并比较它们的预测。
Ludwig允许其用户通过仅提供包含数据的表格文件(如csv)和YAML配置文件来训练深度学习模型,该文件指定表格文件的哪些列是输入要素,哪些是输出目标变量。配置文件的简单性可以加快原型设计速度,从而可以将编码时间减少到几分钟。如果指定了多个输出目标变量,Ludwig将执行多任务学习,学习同时预测所有输出,这通常需要自定义代码。
模型定义可以包含附加信息,特别是数据集中每个特征的预处理信息,用于每个特征的编码器或解码器,每个编码器和解码器的架构参数以及训练参数。预处理、训练和各种模型架构参数的默认值是根据我们的经验选择的,或者是根据学术文献改编的,允许新手轻松训练复杂的模型。同时,在模型配置文件中单独设置每个设置的能力为专家提供了充分的灵活性。使用Ludwig训练的每个模型都会被保存,并且可以在以后加载以获得对新数据的预测。作为示例,可以在服务环境中加载模型以在软件应用程序中提供预测。
图1:可以在Ludwig的模型描述文件中指定几个输入和输出功能,它们的组合涵盖了许多机器学习任务
Ludwig引入的主要新思想是数据类型特定的编码器和解码器的概念,这导致高度模块化和可扩展的架构:支持的每种类型的数据(文本,图像,类别等)都具有特定的预处理功能。简而言之,编码器将原始数据映射到张量,解码器将张量映射到原始数据。
通过这种设计,用户可以访问组合来自所有输入编码器的张量的组合器(架构的胶水组件),处理它们,并返回用于输出解码器的张量。例如,Ludwig的默认concat组合器连接不同编码器的输出,将它们传递到完全连接的层,并提供最终激活作为输出解码器的输入。其他组合器可用于其他用例,通过实现简单的函数接口可以轻松添加更多组合器。
通过编写这些特定于数据类型的组件,用户可以在各种任务上制作Ludwig训练模型。例如,通过组合文本编码器和类别解码器,用户可以获得文本分类器,而组合图像编码器和文本解码器将使用户能够获得图像字幕模型。
每种数据类型可以具有多于一个编码器和解码器。例如,文本可以用卷积神经网络(CNN),递归神经网络(RNN)或其他编码器编码。然后,用户可以直接在模型定义文件中指定要使用的参数和超参数,而无需编写任何代码。
这种多功能且灵活的编码器 - 解码器架构使经验较少的深度学习从业者能够轻松地训练各种机器学习任务的模型,例如文本分类,对象分类,图像字幕,序列标记,回归,语言建模,机器翻译,时间序列预测和问答。这开启了各种用例,这些用例通常对于没有经验的从业者来说是遥不可及的,并且允许在一个域中有经验的用户接近新域。
目前,Ludwig包含二进制值,浮点数,类别,离散序列,集合,包,图像,文本和时间序列的编码器和解码器,以及加载一些预先训练的模型(例如字嵌入)的功能,但我们计划在将来的版本中扩展支持的数据类型。
除了可访问性和灵活的架构外,Ludwig还为非程序员提供额外的好处。 Ludwig包含一组用于训练,测试模型和获取预测的命令行实用程序。该工具箱进一步提高了易用性,提供了一个程序化API,允许用户只需几行代码即可训练和使用模型。
此外,它还包括一套其他工具,用于评估模型,通过可视化比较它们的性能和预测,并从中提取模型权重和激活。
最后,通过使用开源分布式训练框架Horovod,在本地和以分布式方式在多个GPU上训练模型的能力使得可以迭代模型并快速获得结果。
使用Ludwig
为了更好地理解如何将Ludwig用于实际应用程序,让我们使用工具箱构建一个简单的模型。 在这个例子中,我们创建了一个模型,根据书的标题,作者,描述和封面来预测书的类型和价格。
训练模型
我们的图书数据集如下所示:
为了学习使用标题,作者,描述和覆盖列的内容作为输入来预测类型和价格列中的值的模型,模型定义YAML将是:
input_features:
–
name: title
type: text
–
name: author
type: category
–
name: description
type: text
–
name: cover
type: image
output_features:
–
name: genre
type: category
–
name: price
type: numerical
training:
epochs: 10
我们通过在控制键入以下命令来启动训练:
ludwig train –data_csv path/to/file.csv –model_definition_file model_definition.yaml
使用此命令,Ludwig对训练、验证和测试集中的数据进行随机分割,对其进行预处理,并为四个输入构建四个不同的编码器,为两个输出目标构建一个组合器和两个解码器。然后,在训练集上对模型进行训练,直到验证集的准确性停止改善或达到最大十次迭代次数。
训练进度将显示在控制台中,但也可以使用TensorBoard。
文本功能默认使用CNN编码器进行编码,但我们可以使用RNN编码器,该编码器使用状态大小为200的双向LSTM来代替编码标题。我们只需要将标题编码器定义更改为:
name: title
type: text
encoder: rnn
cell_type: lstm
bidirectional: true
如果我们想要更改训练参数,如epochs数、学习率和批量大小,我们将更改模型定义,如下所示:
input_features:
- ......
- output_features:
- ......
- 训练:
- epochs:100
- learning_rate:0.001
- batch_size:64
有关如何执行拆分和数据预处理的所有参数,每个编码器组合器和解码器的参数都具有默认值,但它们是可配置的。请参阅用户指南以了解各种可用的模型定义和训练参数,并查看我们的示例,了解Ludwig如何用于多个不同的任务。
可视化训练结果
在训练之后,Ludwig创建一个结果目录,其中包含训练模型及其超参数和训练过程的摘要统计。我们可以使用可视化工具提供的几个可视化选项之一来可视化它们,例如:
ludwig visualize -visualization learning_curves -training_stats results / training_stats.json
这将显示如下所示的图表,显示损失和准确性作为训练纪元号的功能:
图2:这些学习曲线显示了训练时期的损失和准确性
有几种可视化。用户指南中的可视化部分提供了更多详细信息。
使用训练有素的模型预测结果
拥有新数据且希望其先前训练过的模型预测目标输出值的用户可以键入以下命令:
ludwig predict –data_csv path/to/data.csv –model_path /path/to/model
如果数据集包含与预测进行比较的地面实况信息,则运行此命令将返回模型预测以及一些测试性能统计信息。这些可通过visualize命令(上图)显示,也可用于比较不同模型的性能和结果预测。例如:
ludwig visualize -visualization compare_performance -test_stats path / to / test_stats_model_1.json path / to / test_stats_model_2.json
将返回一个条形图,比较不同措施的模型:
图3:此图比较了两个模型的性能
还有一个handi实验命令,可以执行第一次训练然后进行预测,而无需使用两个单独的命令。
使用Ludwig的编程API
Ludwig还提供了一个简单的Python编程API,允许用户训练或加载模型并使用它来获取对新数据的预测:
from ludwig import LudwigModel
# train a model
model_definition = {…}
model = LudwigModel(model_definition)
train_stats = model.train(training_dataframe)
# or load a model
model = LudwigModel.load(model_path)
# obtain predictions
predictions = model.predict(test_dataframe)
model.close()
此API允许在现有代码中使用Ludwig训练的模型在其上构建应用程序。有关在Ludwig中使用编程API的更多详细信息,请参阅用户指南(about:blank)和API文档(https://uber.github.io/ludwig/api/)。
结论
我们决定开源Ludwig,因为我们相信它可以成为非专业机器学习从业者和经验丰富的深度学习开发人员和研究人员的有用工具。非专家可以快速训练和测试深度学习模型,而无需编写代码。专家可以获得强大的基线来比较他们的模型,并具有实验设置,通过执行标准数据预处理和可视化,可以轻松测试新想法和分析模型。
在未来的版本中,我们希望为每种数据类型添加几个新的编码器,例如用于文本的Transformer,ELMo和BERT,以及用于图像的DenseNet和FractalNet。我们还希望添加其他数据类型,如音频、点云和图形,同时集成更多可扩展的解决方案来管理大数据集,如Petastorm。
Ludwig在构建时考虑了可扩展性原则,为了促进社区的贡献,我们提供了一个开发人员指南,展示了为现有的数据类型添加其他数据类型以及其他编码器和解码器的简单程度。
,