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