训练管道

训练模式,gds.beta.pipeline.linkPrediction.train,负责数据分割、特征提取、模型选择、训练以及存储模型以供将来使用。运行此模式会导致一个类型为 LinkPrediction 的预测模型被存储在模型目录中,同时还包括训练期间收集的指标。该模型可以应用于一个可能不同的图,从而生成一种预测链接的关系类型,其中每个链接都将预测概率作为属性存储。

Visualization of Link Prediction pipeline data flow

更准确地说,该过程将按顺序执行以下操作:

  1. 使用 sourceNodeLabeltargetNodeLabel 应用节点过滤,并使用 targetRelationshipType 应用关系过滤。生成的图将用作分割的输入。

  2. 将图的关系分割成 testtrainfeature-input 图,如配置关系分割中所述。这些图在内部管理,并且仅在训练期间存在。

  3. 应用根据添加节点属性添加的节点属性步骤。每个步骤的图过滤器由 contextNodeLabels + targetNodeLabel + sourceNodeLabelcontextRelationships + feature-input relationships 组成。

  4. 将根据添加链接特征添加的特征步骤应用于 train 图,这会为每个 train 关系生成一个实例,即一个特征向量和一个二进制标签。

  5. 使用分层 k 折交叉验证分割训练实例。折叠数 k 可以使用 gds.beta.pipeline.linkPrediction.configureSplit 中的 validationFolds 进行配置。

  6. 根据参数空间对每个折叠的每个模型候选进行训练,并在相应的验证集上评估模型。评估使用指定的指标

  7. 声明在所有折叠中平均指标最高的模型为获胜模型。

  8. 在整个训练集上重新训练获胜模型,并在 traintest 集上进行评估。为了在 test 集上进行评估,特征管道首先会像对 train 集一样再次应用。

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

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

语法

在命名图上以训练模式运行链接预测
CALL gds.beta.pipeline.linkPrediction.train(
  graphName: String,
  configuration: Map
) YIELD
  trainMillis: Integer,
  modelInfo: Map,
  modelSelectionStats: Map,
  configuration: Map
表 1. 参数
名称 类型 默认值 可选 描述

graphName

字符串

不适用

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

configuration

映射

{}

算法特定配置和/或图过滤配置。

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

modelName

字符串

不适用

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

pipeline

字符串

不适用

要执行的管道名称。

targetRelationshipType

字符串

不适用

用于训练模型的关系统类型的名称。该关系类型必须是无向的。

sourceNodeLabel

字符串

'*'

训练集和测试集中关系应开始的节点标签名称[1]

targetNodeLabel

字符串

'*'

训练集和测试集中关系应结束的节点标签名称[1]

negativeClassWeight

浮点数

1.0

模型评估中负例的权重。正例的权重为 1。更多详细信息请参见此处

metrics

字符串列表

[AUCPR]

用于评估模型的指标

randomSeed

整数

不适用

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

concurrency

整数

4 [2]

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

jobId

字符串

内部生成

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

logProgress

布尔值

true

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

storeModelToDisk

布尔值

false

训练后自动将模型存储到磁盘。

1. 这有助于训练模型来预测具有特定标签组合的链接。

2. 在 GDS 会话中,默认值为可用处理器数量。

表 3. 结果
名称 类型 描述

trainMillis

整数

训练所用毫秒数。

modelInfo

映射

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

modelSelectionStats

映射

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

configuration

映射

训练过程使用的配置。

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

表 4. modelSelectionStats 字段
名称 类型 描述

bestParameters

映射

根据主要指标在验证折叠中平均表现最好的模型参数。

modelCandidates

列表

映射列表,其中每个映射包含一个模型候选的信息。此信息包括候选参数、训练统计信息和验证统计信息。

bestTrial

整数

产生最佳模型的试验。第一个试验编号为 1。

表 5. modelInfo 字段
名称 类型 描述

modelName

字符串

训练模型的名称。

modelType

字符串

训练模型的类型。

bestParameters

映射

根据主要指标在验证折叠中平均表现最好的模型参数。

metrics

映射

从指标描述到获胜模型在数据子集上的评估指标的映射,详见下文。

nodePropertySteps

映射列表

在管道内生成节点属性的算法。

linkFeatures

映射列表

结合端点节点属性为关系(链接)生成特征的特征步骤,作为管道模型的输入。

modelInfo 的结构是

{
    bestParameters: Map,              (1)
    nodePropertySteps: List of Map,
    linkFeatures: List of Map,
    metrics: {                        (2)
        AUCPR: {
            test: Float,              (3)
            outerTrain: Float,        (4)
            train: {                  (5)
                avg: Float,
                max: Float,
                min: Float,
            },
            validation: {             (6)
                avg: Float,
                max: Float,
                min: Float
            }
        }
    }
}
1 评分最高的模型候选配置。
2 metrics 映射包含每个指标描述(目前仅有 AUCPR)的条目以及该指标的相应结果。
3 最佳模型在测试集上评估的数值。
4 最佳模型在外部训练集上评估的数值。
5 train 条目汇总了 train 集上的指标结果。
6 validation 条目汇总了 validation 集上的指标结果。

在 (3)-(5) 中,如果指标是 OUT_OF_BAG_ERROR,则不报告这些统计信息。OUT_OF_BAG_ERROR 仅在 (6) 中作为验证指标报告,并且仅当模型为 RandomForest 时。

除了过程生成的数据外,还有大量关于训练的信息在过程进行时发送到 Neo4j 数据库的日志中。

例如,每个模型候选的表现如何,都会以 info 级别记录到数据库的 neo4j.log 文件中。

某些信息仅以 debug 日志级别记录,因此最终会出现在数据库的 debug.log 文件中。一个例子是模型候选训练期间(在模型选择阶段)特定于训练方法的元数据——例如逻辑回归的每 epoch 损失。请注意,此特定数据不会由过程调用产生。

示例

在此示例中,我们将创建一个小型图并使用我们迄今为止构建的训练管道。该图是一个小型的人与城市社交网络,包括人们居住地、出生地以及他们认识哪些其他人的信息。我们将尝试训练一个模型来预测哪些额外的人可能彼此认识。示例图如下所示:

Visualization of the example graph
以下 Cypher 语句将在 Neo4j 数据库中创建示例图:
CREATE
  (alice:Person {name: 'Alice', age: 38}),
  (michael:Person {name: 'Michael', age: 67}),
  (karin:Person {name: 'Karin', age: 30}),
  (chris:Person {name: 'Chris', age: 52}),
  (will:Person {name: 'Will', age: 6}),
  (mark:Person {name: 'Mark', age: 32}),
  (greg:Person {name: 'Greg', age: 29}),
  (veselin:Person {name: 'Veselin', age: 3}),

  (london:City {name: 'London'}),
  (malmo:City {name: 'Malmo'}),

  (alice)-[:KNOWS]->(michael),
  (michael)-[:KNOWS]->(karin),
  (michael)-[:KNOWS]->(chris),
  (michael)-[:KNOWS]->(greg),
  (will)-[:KNOWS]->(michael),
  (will)-[:KNOWS]->(chris),
  (mark)-[:KNOWS]->(michael),
  (mark)-[:KNOWS]->(will),
  (greg)-[:KNOWS]->(chris),
  (veselin)-[:KNOWS]->(chris),
  (karin)-[:KNOWS]->(veselin),
  (chris)-[:KNOWS]->(karin),

  (alice)-[:LIVES]->(london),
  (michael)-[:LIVES]->(london),
  (karin)-[:LIVES]->(london),
  (chris)-[:LIVES]->(malmo),
  (will)-[:LIVES]->(malmo),

  (alice)-[:BORN]->(london),
  (michael)-[:BORN]->(london),
  (karin)-[:BORN]->(malmo),
  (chris)-[:BORN]->(london),
  (will)-[:BORN]->(malmo),
  (greg)-[:BORN]->(london),
  (veselin)-[:BORN]->(malmo)

借助 Neo4j 中的图,我们现在可以将其投射到图目录中。我们通过使用 Cypher 投射,以 Person 节点和 KNOWS 关系为目标来完成此操作。我们还将投射 age 属性,以便在创建链接特征时可以使用它。对于关系,我们必须使用 UNDIRECTED 方向。这是因为链接预测管道仅针对无向图定义。我们忽略了额外的节点和关系类型,以使我们的投射是同构的。我们将在后续示例中说明如何使用更大的图。

以下语句将使用 Cypher 投射投射一个图,并将其以名称“myGraph”存储在图目录中。
MATCH (source:Person)-[r:KNOWS]->(target:Person)
RETURN gds.graph.project(
  'myGraph',
  source,
  target,
  {
    sourceNodeProperties: source { .age },
    targetNodeProperties: target { .age },
    relationshipType: 'KNOWS'
  },
  { undirectedRelationshipTypes: ['KNOWS'] }
)
链接预测模型要求图中的关系使用 UNDIRECTED 方向创建。

内存估算

首先,我们将使用 estimate 过程来估算训练管道的成本。估算有助于了解在您的图上训练管道将产生的内存影响。在实际训练管道时,系统将执行估算,如果估算显示执行内存不足的可能性非常高,则会阻止执行。要了解更多信息,请参阅自动估算和执行阻止

有关 estimate 的更多详细信息,请参阅内存估算

以下将估算训练管道的内存需求:
CALL gds.beta.pipeline.linkPrediction.train.estimate('myGraph', {
  pipeline: 'pipe',
  modelName: 'lp-pipeline-model',
  targetRelationshipType: 'KNOWS'
})
YIELD requiredMemory
表 6. 结果
requiredMemory

"[24 KiB ... 522 KiB]"

训练

现在我们准备好实际训练一个 LinkPrediction 模型。我们必须确保指定 targetRelationshipType 以指示模型仅使用该类型进行训练。对于图 myGraph,实际上没有其他关系类型被投射,但并非总是如此。

以下将使用管道训练一个模型:
CALL gds.beta.pipeline.linkPrediction.train('myGraph', {
  pipeline: 'pipe',
  modelName: 'lp-pipeline-model',
  metrics: ['AUCPR', 'OUT_OF_BAG_ERROR'],
  targetRelationshipType: 'KNOWS',
  randomSeed: 18
}) YIELD modelInfo, modelSelectionStats
RETURN
  modelInfo.bestParameters AS winningModel,
  modelInfo.metrics.AUCPR.train.avg AS avgTrainScore,
  modelInfo.metrics.AUCPR.outerTrain AS outerTrainScore,
  modelInfo.metrics.AUCPR.test AS testScore,
  [cand IN modelSelectionStats.modelCandidates | cand.metrics.AUCPR.validation.avg] AS validationScores
表 7. 结果
winningModel avgTrainScore outerTrainScore testScore validationScores

{batchSize=100, classWeights=[0.55, 0.45], focusWeight=0.070341817, hiddenLayerSizes=[4, 2], learningRate=0.001, maxEpochs=100, methodName="MultilayerPerceptron", minEpochs=1, patience=2, penalty=0.5, tolerance=0.001}

0.7579365079

0.7

0.6666666667

[0.4305555556, 0.5833333333, 0.4305555556, 0.75]

我们可以看到 MLP 模型配置获胜,在测试集上的得分为 0.67。该得分是根据AUCPR指标计算的,该指标的范围是 [0, 1]。一个对所有链接都比非链接给出更高分数的模型将获得 1.0 分,而一个随机分配分数的模型平均将获得 0.5 分。

使用上下文过滤器进行训练

在上述示例中,我们投射了一个 Person-KNOWS-Person 子图并将其用于训练和测试。原始图中的许多信息并未被使用。我们可能希望利用更多的节点和关系类型来生成节点属性(和链接特征),并调查它是否能改善链接预测。我们可以通过传入 contextNodeLabelscontextRelationshipTypes 来实现这一点。我们明确传入 sourceNodeLabeltargetNodeLabel 以指定用于训练和测试的更窄的节点集。

以下语句将使用 Cypher 投射投射完整的图,并将其以名称“fullGraph”存储在图目录中。

MATCH (source:Person)-[r:KNOWS|LIVES|BORN]->(target:Person|City)
RETURN gds.graph.project(
  'fullGraph',
  source,
  target,
  {
    sourceNodeLabels: labels(source),
    targetNodeLabels: labels(target),
    sourceNodeProperties: source { age: coalesce(source.age, 1) },
    targetNodeProperties: target { age: coalesce(target.age, 1) },
    relationshipType: type(r)
  },
  { undirectedRelationshipTypes: ['KNOWS'] }
)

完整的图包含 2 个节点标签和 3 种关系类型。我们仍然训练一个 Person-KNOWS-Person 模型,但使用上下文信息 Person-LIVES-City、Person-BORN-City 来生成模型在训练中使用的节点属性。请注意,我们不需要上下文关系类型的 UNDIRECTED 方向,因为这些类型被排除在 LinkPrediction 训练之外。

首先,我们将创建一个新的管道。

CALL gds.beta.pipeline.linkPrediction.create('pipe-with-context')

接下来,我们添加带有上下文配置的 nodePropertyStep。

CALL gds.beta.pipeline.linkPrediction.addNodeProperty('pipe-with-context', 'fastRP', {
  mutateProperty: 'embedding',
  embeddingDimension: 256,
  randomSeed: 42,
  contextNodeLabels: ['City'],
  contextRelationshipTypes: ['LIVES', 'BORN']
})

然后我们添加链接特征。

CALL gds.beta.pipeline.linkPrediction.addFeature('pipe-with-context', 'hadamard', {
  nodeProperties: ['embedding', 'age']
})

然后类似地配置数据分割。

CALL gds.beta.pipeline.linkPrediction.configureSplit('pipe-with-context', {
  testFraction: 0.25,
  trainFraction: 0.6,
  validationFolds: 3
})

然后我们添加一个 MLP 模型候选。

CALL gds.alpha.pipeline.linkPrediction.addMLP('pipe-with-context',
{hiddenLayerSizes: [4, 2], penalty: 1, patience: 2})
以下将使用在节点属性步骤中使用了附加上下文信息的管道训练另一个模型:
CALL gds.beta.pipeline.linkPrediction.train('fullGraph', {
  pipeline: 'pipe-with-context',
  modelName: 'lp-pipeline-model-filtered',
  metrics: ['AUCPR', 'OUT_OF_BAG_ERROR'],
  sourceNodeLabel: 'Person',
  targetNodeLabel: 'Person',
  targetRelationshipType: 'KNOWS',
  randomSeed: 12
}) YIELD modelInfo, modelSelectionStats
RETURN
  modelInfo.bestParameters AS winningModel,
  modelInfo.metrics.AUCPR.train.avg AS avgTrainScore,
  modelInfo.metrics.AUCPR.outerTrain AS outerTrainScore,
  modelInfo.metrics.AUCPR.test AS testScore,
  [cand IN modelSelectionStats.modelCandidates | cand.metrics.AUCPR.validation.avg] AS validationScores
表 8. 结果
winningModel avgTrainScore outerTrainScore testScore validationScores

{batchSize=100, classWeights=[], focusWeight=0.0, hiddenLayerSizes=[4, 2], learningRate=0.001, maxEpochs=100, methodName="MultilayerPerceptron", minEpochs=1, patience=2, penalty=1.0, tolerance=0.001}

0.832010582

0.6666666667

0.8611111111

[0.75]

如我们所见,结果实际上是相同的。尽管在这个玩具示例中训练和测试分数保持不变,但上下文信息对于大型数据集可能会产生更大的影响。

© . All rights reserved.