训练管道

此功能处于 Alpha 级别。有关功能级别的更多信息,请参阅 API 级别

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

更具体地说,训练过程如下

  1. 根据添加节点属性,在整个图上应用添加的节点属性步骤。每个步骤上的图过滤器由 `contextNodeLabels + targetNodeLabels` 和 `contextRelationships + 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

字符串

不适用

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

configuration

映射

{}

用于算法特定设置和/或图过滤的配置。

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

pipeline

字符串

不适用

要执行的管道的名称。

targetNodeLabels

字符串列表

['*']

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

relationshipTypes

字符串列表

['*']

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

concurrency

整数

4 [1]

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

jobId

字符串

内部生成

可以提供一个 ID,以便更轻松地跟踪算法的进度。

logProgress

布尔值

true

如果禁用,则不会记录进度百分比。

targetProperty

字符串

不适用

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

metrics

字符串列表

不适用

用于评估模型的指标

randomSeed

整数

不适用

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

modelName

字符串

不适用

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

jobId

字符串

内部生成

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

1. 在 GDS Session 中,默认值是可用处理器数量

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

示例

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

这些示例通常使用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'] }
)

我们仍然训练一个模型来预测每栋房屋的价格,但除了 `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
表 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`。这种变化是由于嵌入考虑了更多的上下文信息。虽然这只是一个玩具示例,但额外的上下文有时可以为管道步骤提供有价值的信息,从而带来更好的性能。

© . All rights reserved.