MLJ 是一个用纯 Julia 编写的开源机器学习工具箱。它提供了一个统一的接口来与目前分散在不同 Julia 包中的监督和无监督学习模型进行交互。
在早期的概念验证的基础上,开发工作于 2018 年 12 月在艾伦·图灵研究所正式开始。在短时间内,兴趣不断增长,该项目现已成为该研究所星标最多的软件库。
在概述了 MLJ 的当前功能之后,本文介绍了 MLJ 的学习网络,这是一种用于模型组合的超级管道功能。
快速链接
☞ 2019 年 3 月伦敦 Julia 用户组聚会上的视频(跳至21'39 处的演示)
☞ MLJ 的教程。
☞ 构建一个自调整随机森林
☞ MLJ 的docker 镜像(包括教程)
☞ 为一个新模型实现 MLJ 接口
☞ 如何贡献代码
☞ Julia Slack 频道:#mlj。
☞ 为MLJ加星标以表示支持,我们将不胜感激!
MLJ 已经拥有强大的功能
学习网络。超越传统管道的灵活模型组合(详情见下文)。
自动调整。自动调整超参数,包括复合模型。调整作为模型包装器实现,以便与其他元算法组合。
同构模型集成。
模型元数据注册表。无需加载模型代码即可获取元数据。是“任务”接口的基础,并有助于模型组合。
任务接口。自动将模型与指定的学习任务匹配,以简化基准测试和模型选择。
简洁的概率 API。改进对贝叶斯统计和概率图模型的支持。
数据容器不可知。以您喜欢的 Tables.jl 格式呈现和操作数据。
普遍采用分类数据类型。使模型实现能够正确地解释在训练中看到但在评估中未看到的类别。
未来计划的增强功能包括集成 Flux.jl 的深度学习模型,以及使用自动微分进行梯度下降调整连续超参数。
虽然目前只有少量机器学习模型实现了 MLJ 接口,但正在进行的工作旨在将流行的 Python 框架 scikit-learn 支持的模型作为临时解决方案进行包装。有关 MLJ 的设计与 Julia 包装ScikitLearn.jl的比较,请参见此常见问题解答。
MLJ 的模型组合接口足够灵活,可以实现例如数据科学竞赛中流行的模型堆栈。为了处理此类示例,接口设计必须考虑到预测和训练模式中的信息流不同。从以下简单双模型堆栈示意图(视为网络)可以看出这一点
在 MLJ 中,模型网络是使用您已经熟悉的声明式语法构建的,这与包的基本用法相同。例如,在对分类特征进行独热编码后,在 MLJ 中训练决策树的普通语法如下所示
using MLJ
@load DecisionTreeRegressor
# load some data:
task = load_reduced_ames();
X, y = task();
# one-hot encode the inputs, X:
hot_model = OneHotEncoder()
hot = machine(hot_model, X)
fit!(hot)
Xt = transform(hot, X)
# fit a decision tree to the transformed data:
tree_model = DecisionTreeRegressor()
tree = machine(tree_model, Xt, y)
fit!(tree, rows = 1:1300)
请注意,MLJ 中的模型只是一个包含超参数的结构体。将模型包装在数据中会生成一个机器结构体,该结构体还将记录训练结果。
如果没有管道,每次我们想要呈现新的数据进行预测时,都必须首先应用独热编码
Xnew = X[1301:1400,:];
Xnewt = transform(hot, Xnew);
yhat = predict(tree, Xnewt);
yhat[1:3]
3-element Array{Float64,1}:
223956.9999999999
320142.85714285733
161227.49999999994
要构建一个管道,只需将提供的源数据包装在源节点中并重复类似的声明,省略对fit!
的调用。现在不同之处在于每个“变量”(例如,Xt
、yhat
)都是我们管道的节点,而不是具体数据
Xs = source(X)
ys = source(y)
hot = machine(hot_model, Xs)
Xt = transform(hot, Xs);
tree = machine(tree_model, Xt, ys)
yhat = predict(tree, Xt)
如果我们愿意,可以将节点视为动态数据——“数据”因为它可以被调用(按行索引),但“动态”因为结果取决于训练事件的结果,而训练事件又取决于超参数值。例如,在拟合完成的管道后,我们可以像这样进行新的预测
fit!(yhat, rows=1:1300)
[ Info: Training NodalMachine @ 1…51.
[ Info: Spawned 1300 sub-features to one-hot encode feature :Neighborhood.
[ Info: Spawned 1300 sub-features to one-hot encode feature :MSSubClass.
[ Info: Training NodalMachine @ 1…17.
Node @ 1…79 = predict(1…17, transform(1…51, 1…07))
yhat(rows=1301:1302) # to predict on rows of source node
yhat(Xnew) # to predict on new data
156-element Array{Float64,1}:
223956.9999999999
320142.85714285733
...
一旦构建了这样的管道并在样本数据上进行了测试,就可以将其导出为一个独立的模型,准备在任何数据集上进行训练。有关详细信息,请参阅 MLJ 的文档。将来,Julia 宏将允许用几行代码构建常见的架构(例如,线性管道)。
最后,我们提到 MLJ 学习网络及其导出的对应物在某种意义上是“智能的”,因为更改超参数不会触发更改上游组件模型的重新训练
tree_model.max_depth = 4
fit!(yhat, rows=1:1300)
[ Info: Not retraining NodalMachine @ 1…51. It is up-to-date.
[ Info: Updating NodalMachine @ 1…17.
Node @ 1…79 = predict(1…17, transform(1…51, 1…07))
由于 Julia 的泛型编程特性,您可以对数据应用的任何类型的操作(算术运算、行选择、列连接等)都可以被重载以用于节点。这样,MLJ 的网络构建语法简洁、直观且易于阅读。在这方面,我们受到了关于机器学习和编程语言的启发。
我们现在邀请社区试用我们新注册的MLJ 包,并提供您在未来可能有的任何反馈或建议。我们也特别想知道您将如何使用我们的包,以及它可能缺少哪些功能。