训练管道
此功能处于 Alpha 级别。有关功能级别的更多信息,请参阅 API 级别。
训练模式 `gds.alpha.pipeline.nodeRegression.train` 负责数据拆分、特征提取、模型选择、训练和存储模型以供将来使用。运行此模式会生成一个 `NodeRegression` 类型的回归模型,然后将其存储在模型目录中。该回归模型可以应用到图上,以预测新节点的属性值。
更具体地说,训练过程如下
-
根据添加节点属性,在整个图上应用添加的节点属性步骤。每个步骤上的图过滤器由 `contextNodeLabels + targetNodeLabels` 和 `contextRelationships + relationshipTypes` 组成。
-
将 `targetNodeLabels` 过滤器应用到图上。
-
根据添加特征中指定,选择要用作特征的节点属性。
-
将输入图拆分为两部分:训练图和测试图。这在配置节点拆分中进行了描述。这些图由内部管理,仅在训练期间存在。
-
使用分层 k 折交叉验证拆分训练图中的节点。折叠数 `k` 可以根据配置节点拆分进行配置。
-
在参数空间中定义的每个模型候选者都在每个训练集上进行训练,并在每个折叠的相应验证集上进行评估。评估使用指定的主要指标。
-
根据主要指标的最高平均得分选择表现最佳的模型。
-
在整个训练图上重新训练获胜模型。
-
评估获胜模型在整个训练图和测试图上的性能。
-
在整个原始图上重新训练获胜模型。
-
在模型目录中注册获胜模型。
以上步骤描述了过程在逻辑上所做的事情。实际步骤及其在实现中的顺序可能有所不同。 |
一个步骤只能使用输入图中已存在的节点属性,或由之前添加的步骤生成的节点属性。 |
不支持在同一图上并行执行同一管道。 |
指标
Neo4j GDS 库中的节点回归模型支持以下评估指标
-
MEAN_SQUARED_ERROR
-
ROOT_MEAN_SQUARED_ERROR
-
MEAN_ABSOLUTE_ERROR
训练期间可以指定多个指标,但只有第一个指定的指标(即 `primary` 指标)用于评估,所有指标的结果都存在于训练结果中。
语法
CALL gds.alpha.pipeline.nodeRegression.train(
graphName: String,
configuration: Map
) YIELD
trainMillis: Integer,
modelInfo: Map,
modelSelectionStats: Map,
configuration: Map
名称 | 类型 | 默认值 | 可选 | 描述 |
---|---|---|---|---|
graphName |
字符串 |
|
否 |
存储在目录中的图的名称。 |
configuration |
映射 |
|
是 |
用于算法特定设置和/或图过滤的配置。 |
名称 | 类型 | 默认值 | 可选 | 描述 |
---|---|---|---|---|
pipeline |
字符串 |
|
否 |
要执行的管道的名称。 |
targetNodeLabels |
字符串列表 |
|
是 |
使用给定的节点标签过滤命名图,以获取用于训练和评估的节点。 |
字符串列表 |
|
是 |
使用给定的关系类型过滤命名图。 |
|
整数 |
|
是 |
用于运行算法的并发线程数。 |
|
字符串 |
|
是 |
可以提供一个 ID,以便更轻松地跟踪算法的进度。 |
|
布尔值 |
|
是 |
如果禁用,则不会记录进度百分比。 |
|
targetProperty |
字符串 |
|
否 |
节点的目标属性。必须是整数或浮点类型。 |
metrics |
字符串列表 |
|
否 |
用于评估模型的指标。 |
randomSeed |
整数 |
|
是 |
训练期间使用的随机数生成器的种子。 |
modelName |
字符串 |
|
否 |
要训练的模型名称,不得在模型目录中存在。 |
字符串 |
|
是 |
可以提供一个 ID,以便更轻松地跟踪训练进度。 |
|
1. 在 GDS Session 中,默认值是可用处理器数量 |
名称 | 类型 | 描述 |
---|---|---|
trainMillis |
整数 |
训练所用的毫秒数。 |
modelInfo |
映射 |
有关训练和获胜模型的信息。 |
modelSelectionStats |
映射 |
所有模型候选者的评估指标统计数据。 |
configuration |
映射 |
用于训练过程的配置。 |
`modelInfo` 也可以稍后通过使用模型列表过程来检索。`modelInfo` 返回字段具有以下算法特定的子字段
名称 | 类型 | 描述 |
---|---|---|
bestParameters |
映射 |
根据主要指标,在验证折叠上平均表现最佳的模型参数。 |
metrics |
映射 |
从指标描述到获胜模型在数据子集上的评估指标的映射,详见下文。 |
nodePropertySteps |
映射列表 |
在管道内生成节点属性的算法。 |
featureProperties |
字符串列表 |
选择作为管道模型输入特征的节点属性。 |
`modelInfo` 的结构是
{ bestParameters: Map, (1) nodePropertySteps: List of Map, featureProperties: List of String, metrics: { (2) <METRIC_NAME>: { (3) test: Float, (4) outerTrain: Float, (5) train: { (6) avg: Float, max: Float, min: Float, }, validation: { (7) avg: Float, max: Float, min: Float, params: Map } } } }
1 | 得分最高的模型候选配置。 |
2 | `metrics` 映射包含每个指标描述的条目,以及该指标的相应结果。 |
3 | 在过程配置中指定的指标名称,例如 `F1_MACRO` 或 `RECALL(class=4)`。 |
4 | 获胜模型在测试集上评估的数值。 |
5 | 获胜模型在外部训练集上评估的数值。 |
6 | `train` 条目总结了 `train` 集上的指标结果。 |
7 | `validation` 条目总结了 `validation` 集上的指标结果。 |
除了过程产生的数据之外,还有大量关于训练的信息会随着过程的进行发送到 Neo4j 数据库的日志中。 例如,每个模型候选者的表现如何会以 `info` 日志级别记录,并最终出现在数据库的 `neo4j.log` 文件中。 某些信息仅以 `debug` 日志级别记录,并因此最终出现在数据库的 `debug.log` 文件中。一个例子是在模型候选者训练期间(在模型选择阶段)与训练方法相关的元数据——例如逻辑回归的每个 epoch 损失。请注意,此特定数据不会由过程调用生成。 |
示例
以下所有示例都应在一个空数据库中运行。 这些示例通常使用Cypher 投影。原生投影将在未来版本中弃用。 |
在本节中,我们将展示在具体图上运行节点回归训练管道的示例。目的是说明结果是什么样子,并提供如何在实际设置中使用模型的指南。我们将在一个由少量代表房屋的节点组成的小图上进行此操作。在我们的示例中,我们希望预测房屋的 `price`。示例图如下所示
CREATE
(gold:House {color: 'Gold', sizePerStory: [15.5, 23.6, 33.1], price: 99.99}),
(red:House {color: 'Red', sizePerStory: [15.5, 23.6, 100.0], price: 149.99}),
(blue:House {color: 'Blue', sizePerStory: [11.3, 35.1, 22.0], price: 77.77}),
(green:House {color: 'Green', sizePerStory: [23.2, 55.1, 0.0], price: 80.80}),
(gray:House {color: 'Gray', sizePerStory: [34.3, 24.0, 0.0], price: 57.57}),
(black:House {color: 'Black', sizePerStory: [71.66, 55.0, 0.0], price: 140.14}),
(white:House {color: 'White', sizePerStory: [11.1, 111.0, 0.0], price: 122.22}),
(teal:House {color: 'Teal', sizePerStory: [80.8, 0.0, 0.0], price: 80.80}),
(beige:House {color: 'Beige', sizePerStory: [106.2, 0.0, 0.0], price: 110.11}),
(magenta:House {color: 'Magenta', sizePerStory: [99.9, 0.0, 0.0], price: 100.00}),
(purple:House {color: 'Purple', sizePerStory: [56.5, 0.0, 0.0], price: 60.00}),
(pink:UnknownHouse {color: 'Pink', sizePerStory: [23.2, 55.1, 56.1]}),
(tan:UnknownHouse {color: 'Tan', sizePerStory: [22.32, 102.0, 0.0]}),
(yellow:UnknownHouse {color: 'Yellow', sizePerStory: [39.0, 0.0, 0.0]}),
// richer context
(schiele:Painter {name: 'Schiele'}),
(picasso:Painter {name: 'Picasso'}),
(kahlo:Painter {name: 'Kahlo'}),
(schiele)-[:PAINTED]->(gold),
(schiele)-[:PAINTED]->(red),
(schiele)-[:PAINTED]->(blue),
(picasso)-[:PAINTED]->(green),
(picasso)-[:PAINTED]->(gray),
(picasso)-[:PAINTED]->(black),
(picasso)-[:PAINTED]->(white),
(kahlo)-[:PAINTED]->(teal),
(kahlo)-[:PAINTED]->(beige),
(kahlo)-[:PAINTED]->(magenta),
(kahlo)-[:PAINTED]->(purple),
(schiele)-[:PAINTED]->(pink),
(schiele)-[:PAINTED]->(tan),
(kahlo)-[:PAINTED]->(yellow);
将图放入 Neo4j 后,我们现在可以将其投影到图目录中,为管道执行做准备。我们使用针对 `House` 和 `UnknownHouse` 标签的 Cypher 投影来完成此操作。我们还将投影 `sizeOfStory` 属性作为模型特征,并投影 `price` 属性作为目标特征。
MATCH (house:House|UnknownHouse)
RETURN gds.graph.project(
'myGraph',
house,
null,
{
sourceNodeLabels: labels(house),
targetNodeLabels: [],
sourceNodeProperties: house { .sizePerStory, .price },
targetNodeProperties: {}
}
)
训练
在以下示例中,我们将演示在此图上运行节点回归训练管道。我们将训练一个模型,根据房屋的 `sizePerStory` 属性预测房屋的价格。管道的配置是运行上一页示例的结果
CALL gds.alpha.pipeline.nodeRegression.train('myGraph', {
pipeline: 'pipe',
targetNodeLabels: ['House'],
modelName: 'nr-pipeline-model',
targetProperty: 'price',
randomSeed: 25,
concurrency: 1,
metrics: ['MEAN_SQUARED_ERROR']
}) YIELD modelInfo
RETURN
modelInfo.bestParameters AS winningModel,
modelInfo.metrics.MEAN_SQUARED_ERROR.train.avg AS avgTrainScore,
modelInfo.metrics.MEAN_SQUARED_ERROR.outerTrain AS outerTrainScore,
modelInfo.metrics.MEAN_SQUARED_ERROR.test AS testScore
winningModel | avgTrainScore | outerTrainScore | testScore |
---|---|---|---|
{maxDepth=2147483647, methodName="RandomForest", minLeafSize=1, minSplitSize=2, numberOfDecisionTrees=5, numberOfSamplesRatio=1.0} |
658.1848249523812 |
1188.6296009999999 |
1583.5897253333333 |
在此我们可以观察到,具有 5 棵决策树的 `RandomForest` 候选者在训练阶段表现最佳。请注意,这只是一个在非常小的图上的玩具示例。为了获得更高的测试分数,我们可能需要使用更好的特征、更大的图或不同的模型配置。
为节点属性步骤提供更丰富的上下文
在上面的示例中,我们投影了一个没有关系的房屋子图,并将其用于训练和测试。原始图中的许多信息都没有被使用。我们可能希望利用更多的节点和关系类型来生成节点属性(和链接特征),并调查它是否能改善节点回归。我们可以通过在添加节点属性步骤时传入 contextNodeLabels 和 contextRelationshipTypes 来实现这一点。
以下语句将使用 Cypher 投影来投影包含房屋及其画家信息的图,并将其存储在图目录中,名称为 'paintingGraph'。
MATCH (house:House)
OPTIONAL MATCH (painter:Painter)-[r:PAINTED]->(house:House)
RETURN gds.graph.project(
'paintingGraph',
painter,
house,
{
sourceNodeLabels: ['Painter'],
targetNodeLabels: ['House'],
sourceNodeProperties: {},
targetNodeProperties: house { .sizePerStory, .price },
relationshipType: 'PAINTED'
},
{ undirectedRelationshipTypes: ['PAINTED'] }
)
我们仍然训练一个模型来预测每栋房屋的价格,但除了 `House` 之外,我们还使用 `Painter` 和 `PAINTED` 作为上下文来生成利用完整图结构的特征。然而,在特征生成之后,只有 `House` 节点被视为训练和评估实例,因此只有 `House` 节点需要具有目标属性 `price`。
首先,我们创建一个新的管道。
CALL gds.alpha.pipeline.nodeRegression.create('pipe-with-context')
其次,我们添加一个节点属性步骤(在本例中为节点嵌入),其中 `Painter` 作为 contextNodeLabels。
CALL gds.alpha.pipeline.nodeRegression.addNodeProperty('pipe-with-context', 'fastRP', {
embeddingDimension: 64,
iterationWeights: [0, 1],
mutateProperty:'embedding',
contextNodeLabels: ['Painter'],
randomSeed: 1337
})
我们将我们的嵌入作为模型的特征添加
CALL gds.alpha.pipeline.nodeRegression.selectFeatures('pipe-with-context', ['embedding'])
然后我们通过添加一个随机森林模型候选者来完成管道设置
CALL gds.alpha.pipeline.nodeRegression.addRandomForest('pipe-with-context', {numberOfDecisionTrees: 5})
我们现在准备好调用新创建管道的训练。
CALL gds.alpha.pipeline.nodeRegression.train('paintingGraph', {
pipeline: 'pipe-with-context',
targetNodeLabels: ['House'],
modelName: 'nr-pipeline-model-contextual',
targetProperty: 'price',
randomSeed: 25,
concurrency: 1,
metrics: ['MEAN_SQUARED_ERROR']
}) YIELD modelInfo
RETURN
modelInfo.bestParameters AS winningModel,
modelInfo.metrics.MEAN_SQUARED_ERROR.train.avg AS avgTrainScore,
modelInfo.metrics.MEAN_SQUARED_ERROR.outerTrain AS outerTrainScore,
modelInfo.metrics.MEAN_SQUARED_ERROR.test AS testScore
winningModel | avgTrainScore | outerTrainScore | testScore |
---|---|---|---|
{maxDepth=2147483647, methodName="RandomForest", minLeafSize=1, minSplitSize=2, numberOfDecisionTrees=5, numberOfSamplesRatio=1.0} |
758.087008266667 |
837.5558960000001 |
1192.523748 |
正如我们所见,结果表明随机森林模型的均方误差低于前面章节中的 `nr-pipeline-model`。这种变化是由于嵌入考虑了更多的上下文信息。虽然这只是一个玩具示例,但额外的上下文有时可以为管道步骤提供有价值的信息,从而带来更好的性能。