训练管道

此功能处于 alpha 层级。有关功能层级的更多信息,请参见 API 层级.

训练模式,gds.alpha.pipeline.nodeRegression.train,负责数据拆分、特征提取、模型选择、训练和存储模型以供将来使用。运行此模式将生成类型为 NodeRegression 的回归模型,该模型随后将存储在 模型目录 中。该回归模型可以 应用 到图上,以预测新节点的属性值。

更准确地说,训练过程如下

  1. 将根据 添加节点属性 添加的节点属性步骤应用于整个图。每个步骤上的图过滤器包括 contextNodeLabels + targetNodeLabelscontextRelationships + relationshipTypes.

  2. targetNodeLabels 过滤器应用于图。

  3. 选择要用作特征的节点属性,如 添加特征 中所述。

  4. 将输入图拆分为两部分:训练图和测试图。这在 配置节点拆分 中进行了描述。这些图是在内部管理的,仅在训练期间存在。

  5. 使用分层 k 折交叉验证拆分训练图中的节点。折数 k 可以根据 配置节点拆分 中的描述进行配置。

  6. 参数空间 中定义的每个模型候选者都在每个训练集上进行训练,并在每个折的相应验证集上进行评估。评估使用指定的首要指标。

  7. 根据首要指标的最高平均得分选择性能最佳的模型。

  8. 在整个训练图上重新训练获胜模型。

  9. 评估获胜模型在整个训练图和测试图上的性能。

  10. 在整个原始图上重新训练获胜模型。

  11. 模型目录 中注册获胜模型。

上述步骤描述了该过程在逻辑上的作用。实际步骤及其在实现中的顺序可能有所不同。
一个步骤只能使用已存在于输入图中的节点属性,或由在该步骤之前添加的步骤生成的节点属性。
不支持在同一图上并行执行同一个管道。

指标

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
表 1. 参数
名称 类型 默认值 可选 描述

graphName

字符串

n/a

存储在目录中的图的名称。

configuration

映射

{}

针对算法特定情况和/或图过滤的配置。

表 2. 配置
名称 类型 默认值 可选 描述

pipeline

字符串

n/a

要执行的管道的名称。

targetNodeLabels

字符串列表

['*']

使用给定的节点标签过滤命名图,以获取接受训练和评估的节点。

relationshipTypes

字符串列表

['*']

使用给定的关系类型过滤命名图。

concurrency

整数

4

用于运行算法的并发线程数。

targetProperty

字符串

n/a

节点的目标属性。必须为整数或浮点数类型。

metrics

字符串列表

n/a

指标 用于评估模型。

randomSeed

整数

n/a

训练期间使用的随机数生成器的种子。

modelName

字符串

n/a

要训练的模型的名称,模型目录中不存在。

jobId

字符串

内部生成

可以提供的 ID,以便更轻松地跟踪训练进度。

表 3. 结果
名称 类型 描述

trainMillis

整数

用于训练的毫秒数。

modelInfo

映射

有关训练和获胜模型的信息。

modelSelectionStats

映射

所有模型候选者的评估指标的统计信息。

configuration

映射

用于训练过程的配置。

可以使用 模型列表过程 在稍后检索 `modelInfo`。`modelInfo` 返回字段具有以下特定于算法的子字段

表 4. 模型信息字段
名称 类型 描述

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` 文件中。这方面的一个示例是训练方法特定的元数据(例如,逻辑回归的每个纪元损失)在模型候选训练(在模型选择阶段)期间。请注意,此特定数据不会由过程调用产生。

示例

以下所有示例都应在空数据库中运行。

这些示例使用 Cypher 投影 作为规范。原生投影将在未来的版本中弃用。

在本节中,我们将展示在具体图上运行节点回归训练管道的示例。其目的是说明结果的样子,并提供在实际环境中如何使用模型的指南。我们将在一个包含几个节点的示例图上进行演示,这些节点代表房屋。在我们的示例中,我们想要预测房屋的 `price`。示例图如下所示

node property pipeline graph
以下 Cypher 语句将在 Neo4j 数据库中创建示例图
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` 属性以用作目标特征。

以下语句将使用 Cypher 投影投影一个图,并将它存储在图目录中,名为 `myGraph`。
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
表 5. 结果
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'] }
)

我们仍然训练一个模型来预测每个房屋的价格,但是使用 `Painter` 和 `PAINTED` 作为上下文,除了 `House` 之外,还可以生成利用完整图结构的特征。然而,在特征生成之后,只有 `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
表 6. 结果
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` 相比,随机森林模型的均方误差更低。这种变化是由于嵌入考虑了更多上下文信息。虽然这只是一个玩具示例,但额外的上下文有时可以为管道步骤提供有价值的信息,从而提高性能。