训练管道
训练模式 gds.beta.pipeline.linkPrediction.train
负责分割数据、特征提取、模型选择、训练和存储模型以供将来使用。运行此模式会导致类型为 LinkPrediction
的预测模型存储在 模型目录 中,以及训练期间收集的指标。该模型可以 应用 于可能不同的图,从而产生一种预测链接的关系类型,每种链接都具有存储为属性的预测概率。
更准确地说,该过程将按顺序执行以下步骤
-
使用
sourceNodeLabel
和targetNodeLabel
应用节点过滤,使用targetRelationshipType
应用关系过滤。生成的图用作分割的输入。 -
根据 配置关系分割 中所述,创建图的关系分割为
test
、train
和feature-input
图。这些图是内部管理的,仅在训练期间存在。 -
应用节点属性步骤,根据 添加节点属性 添加。每个步骤的图过滤器包括
contextNodeLabels + targetNodeLabel + sourceNodeLabel
和contextRelationships + feature-input relationships
。 -
根据 添加链接特征 添加的特征步骤应用于
train
图,这会为每个train
关系生成一个实例,即特征向量和二进制标签。 -
使用分层 k 折交叉验证分割训练实例。可以使用
gds.beta.pipeline.linkPrediction.configureSplit
中的validationFolds
配置折叠次数k
。 -
将跨折叠具有最高平均指标的模型声明为获胜者。
-
在整个训练集上重新训练获胜模型,并在
train
和test
集上对其进行评估。为了在test
集上进行评估,首先将特征管道应用于train
集。 -
在 模型目录 中注册获胜模型。
以上步骤描述了该过程的逻辑操作。实现中的实际步骤及其顺序可能有所不同。 |
一个步骤只能使用输入图中已存在的节点属性或由该步骤之前添加的步骤生成的节点属性。 |
不支持在同一图上并行执行相同的管道。 |
语法
CALL gds.beta.pipeline.linkPrediction.train(
graphName: String,
configuration: Map
) YIELD
trainMillis: Integer,
modelInfo: Map,
modelSelectionStats: Map,
configuration: Map
名称 | 类型 | 默认值 | 可选 | 描述 |
---|---|---|---|---|
graphName |
字符串 |
|
否 |
存储在目录中的图的名称。 |
配置 |
映射 |
|
是 |
针对特定算法和/或图过滤的配置。 |
名称 | 类型 | 默认值 | 可选 | 描述 |
---|---|---|---|---|
modelName |
字符串 |
|
否 |
要训练的模型的名称,在模型目录中必须不存在。 |
pipeline |
字符串 |
|
否 |
要执行的管道的名称。 |
targetRelationshipType |
字符串 |
|
否 |
用于训练模型的关系类型的名称。关系类型必须是无向的。 |
sourceNodeLabel |
字符串 |
|
是 |
节点标签的名称,训练和测试集中的关系应从 [1] 开始。 |
targetNodeLabel |
字符串 |
|
是 |
节点标签的名称,训练和测试集中的关系应以 [1] 结束。 |
negativeClassWeight |
浮点数 |
|
是 |
模型评估中负样本的权重。正样本的权重为 1。更多详情请 点击这里。 |
metrics |
字符串列表 |
|
否 |
指标 用于评估模型。 |
randomSeed |
整数 |
|
是 |
训练过程中使用的随机数生成器的种子。 |
整数 |
|
是 |
用于运行算法的并发线程数。 |
|
字符串 |
|
是 |
一个 ID,可以提供用于更轻松地跟踪训练的进度。 |
|
storeModelToDisk |
布尔值 |
|
是 |
训练后自动将模型存储到磁盘。 |
1. 这有助于训练模型预测具有特定标签组合的链接。 |
名称 | 类型 | 描述 |
---|---|---|
trainMillis |
整数 |
用于训练的毫秒数。 |
modelInfo |
映射 |
关于训练和最佳模型的信息。 |
modelSelectionStats |
映射 |
关于所有模型候选者的评估指标的统计信息。 |
配置 |
映射 |
用于训练过程的配置。 |
modelInfo
也可以稍后使用 模型列表过程 检索。modelInfo
返回字段具有以下特定于算法的子字段
名称 | 类型 | 描述 |
---|---|---|
bestParameters |
映射 |
在验证折上根据主要指标平均表现最佳的模型参数。 |
modelCandidates |
列表 |
映射列表,其中每个映射包含有关一个模型候选者的信息。此信息包括候选者的参数、训练统计信息和验证统计信息。 |
bestTrial |
整数 |
产生最佳模型的试验。第一个试验的编号为 1。 |
名称 | 类型 | 描述 |
---|---|---|
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) 中,如果指标是 |
除了过程产生的数据外,还有大量关于训练的信息在过程进行时被发送到 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 中的图,我们现在可以将其投影到图目录中。我们使用针对 Person
节点和 KNOWS
关系的 Cypher 投影来完成此操作。我们还将投影 age
属性,以便在创建链接特征时可以使用它。对于关系,我们必须使用 UNDIRECTED
方向。这是因为链接预测管道仅针对无向图定义。我们忽略了其他节点和关系类型,以便我们的投影是同构的。我们将说明如何在 后续示例 中使用更大的图。
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
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
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 子图并将其用于训练和测试。原始图中的许多信息都没有被使用。我们可能希望利用更多节点和关系类型来生成节点属性(和链接特征),并研究它是否会改进链接预测。我们可以通过传入 contextNodeLabels
和 contextRelationshipTypes
来做到这一点。我们明确地传入 sourceNodeLabel
和 targetNodeLabel
来指定更窄的节点集,用于训练和测试。
以下语句将使用 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 方向,因为这些类型将被排除在链接预测训练之外。
首先,我们将创建一个新的管道。
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
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] |
正如我们所见,结果实际上是相同的。虽然训练和测试分数在该玩具示例中保持不变,但对于更大的数据集,上下文信息可能会产生更大的影响。