配置管道

此功能处于测试阶段。有关功能阶段的更多信息,请参阅 API 阶段

此页面说明了如何创建和配置链接预测管道。

创建管道

构建新管道的第一步是使用 gds.beta.pipeline.linkPrediction.create 创建一个。这会将一个可训练的管道对象存储在类型为 Link prediction training pipeline 的管道目录中。这表示一个可配置的管道,稍后可以调用它进行训练,这反过来会创建一个已训练的管道。后者也是一个模型,存储在类型为 LinkPrediction 的目录中。

语法

创建管道语法
CALL gds.beta.pipeline.linkPrediction.create(
  pipelineName: String
)
YIELD
  name: String,
  nodePropertySteps: List of Map,
  featureSteps: List of Map,
  splitConfig: Map,
  autoTuningConfig: Map,
  parameterSpace: List of Map
表 1. 参数
名称 类型 描述

pipelineName

字符串

创建的管道的名称。

表 2. 结果
名称 类型 描述

name

字符串

管道的名称。

nodePropertySteps

Map 列表

节点属性步骤的配置列表。

featureSteps

Map 列表

特征步骤的配置列表。

splitConfig

Map

定义模型训练前的拆分的配置。

autoTuningConfig

Map

定义自动调整行为的配置。

parameterSpace

Map 列表

模型的参数配置列表,训练模式使用这些配置进行模型选择。

示例

以下将创建一个管道
CALL gds.beta.pipeline.linkPrediction.create('pipe')
表 3. 结果
name nodePropertySteps featureSteps splitConfig autoTuningConfig parameterSpace

"pipe"

[]

[]

{negativeSamplingRatio=1.0, testFraction=0.1, trainFraction=0.1, validationFolds=3}

{maxTrials=10}

{LogisticRegression=[], MultilayerPerceptron=[], RandomForest=[]}

这表明新创建的管道尚不包含任何步骤,并且具有拆分和训练参数的默认值。

添加节点属性

链接预测管道可以在变异模式下执行一个或多个 GDS 算法,这些算法在投影图中创建节点属性。此类生成节点属性的步骤可以一个接一个地链接,并且创建的属性也可以用于 添加特征。此外,添加到管道的节点属性步骤将在 训练 管道和已训练模型 应用于预测 时执行。

要添加的过程的名称可以是完整限定的 GDS 过程名称,以 .mutate 结尾。可以省略结尾的 .mutate,也可以使用简写形式,例如 node2vec 而不是 gds.node2vec.mutate。但请注意,层级限定符必须仍然作为名称的一部分给出。

例如,可以将 预处理算法 用作节点属性步骤。

语法

添加节点属性语法
CALL gds.beta.pipeline.linkPrediction.addNodeProperty(
  pipelineName: String,
  procedureName: String,
  procedureConfiguration: Map
)
YIELD
  name: String,
  nodePropertySteps: List of Map,
  featureSteps: List of Map,
  splitConfig: Map,
  autoTuningConfig: Map,
  parameterSpace: List of Map
表 4. 参数
名称 类型 描述

pipelineName

字符串

管道的名称。

procedureName

字符串

要添加到管道的过程的名称。

procedureConfiguration

Map

用于生成过程配置的映射。它包含特定于过程的配置,除了 nodeLabelsrelationshipTypes 之外。它还可以选择性地包含下表中的参数。

表 5. 节点属性步骤上下文配置
名称 类型 默认值 描述

contextNodeLabels

字符串列表

[]

作为上下文添加的其他节点标签。

contextRelationshipTypes

字符串列表

[]

作为上下文添加的其他关系类型。

在训练期间,上下文配置与训练配置相结合,为每个节点属性步骤生成最终的节点标签和关系类型过滤器。

表 6. 结果
名称 类型 描述

name

字符串

管道的名称。

nodePropertySteps

Map 列表

节点属性步骤的配置列表。

featureSteps

Map 列表

特征步骤的配置列表。

splitConfig

Map

定义模型训练前的拆分的配置。

autoTuningConfig

Map

定义自动调整行为的配置。

parameterSpace

Map 列表

模型的参数配置列表,训练模式使用这些配置进行模型选择。

示例

以下步骤将向管道中添加节点属性步骤。
CALL gds.beta.pipeline.linkPrediction.addNodeProperty('pipe', 'fastRP', {
  mutateProperty: 'embedding',
  embeddingDimension: 256,
  randomSeed: 42
})
表 7. 结果
name nodePropertySteps featureSteps splitConfig autoTuningConfig parameterSpace

"pipe"

[{config={contextNodeLabels=[], contextRelationshipTypes=[], embeddingDimension=256, mutateProperty="embedding", randomSeed=42}, name="gds.fastRP.mutate"}]

[]

{negativeSamplingRatio=1.0, testFraction=0.1, trainFraction=0.1, validationFolds=3}

{maxTrials=10}

{LogisticRegression=[], MultilayerPerceptron=[], RandomForest=[]}

现在,管道将在模型训练前和训练后的模型应用于预测时,都以变异模式执行fastRP 算法。这确保了embedding属性可用作链接特征的输入。

添加链接特征

链接预测管道执行一系列步骤来计算机器学习模型使用的特征。特征步骤为给定的节点对计算特征向量。对于每个节点对,结果会被连接成单个的链接特征向量。链接特征向量中特征的顺序遵循特征步骤的顺序。与节点属性步骤类似,特征步骤在训练预测时也会执行。下面描述了获取特征的支持方法。

语法

向管道添加链接特征
CALL gds.beta.pipeline.linkPrediction.addFeature(
  pipelineName: String,
  featureType: String,
  configuration: Map
)
YIELD
  name: String,
  nodePropertySteps: List of Map,
  featureSteps: List of Map,
  splitConfig: Map,
  autoTuningConfig: Map,
  parameterSpace: List of Map
表 8. 参数
名称 类型 描述

pipelineName

字符串

管道的名称。

featureType

字符串

featureType 确定用于计算链接特征的方法。请参阅支持的类型

configuration

Map

添加链接特征的配置。

表 9. 配置
名称 类型 默认值 描述

nodeProperties

字符串列表

应作为输入使用的节点属性的名称。

表 10. 结果
名称 类型 描述

name

字符串

管道的名称。

nodePropertySteps

Map 列表

节点属性步骤的配置列表。

featureSteps

Map 列表

特征步骤的配置列表。

splitConfig

Map

定义模型训练前的拆分的配置。

autoTuningConfig

Map

定义自动调整行为的配置。

parameterSpace

Map 列表

模型的参数配置列表,训练模式使用这些配置进行模型选择。

支持的特征类型

特征步骤可以使用输入图中存在的或由管道添加的节点属性。对于每个潜在链接中的每个节点,nodeProperties的值都按配置的顺序连接成一个向量f。也就是说,对于每个潜在链接,源节点的特征向量,s equals s1 comma s2 comma dot dot dot s d,与目标节点的特征向量,s equals t1 comma t2 comma dot dot dot t d,组合成一个特征向量f

然后可以将支持的特征类型描述如下

表 11. 支持的特征类型
特征类型 公式/描述

L2

f equals vector of s1 minus t1 squared comma s2 minus t2 squared comma dot dot dot comma s d minus t d squared

HADAMARD

f equals vector of s1 dot t1 comma s2 dot t2 comma dot dot dot comma s d dot t d

COSINE

f equals sum of i from 1 to d of s i t i divided by square root of sum of i from 1 to d of s i squared times square root of sum of i from 1 to d of t i squared

SAME_CATEGORY

如果源和目标的类别值相同,则特征为1,否则为0。类似于相同社区

示例

以下步骤将向管道中添加特征步骤。
CALL gds.beta.pipeline.linkPrediction.addFeature('pipe', 'hadamard', {
  nodeProperties: ['embedding', 'age']
}) YIELD featureSteps
表 12. 结果
featureSteps

[{config={nodeProperties=["embedding", "age"]}, name="HADAMARD"}]

执行管道时,nodeProperties必须存在于输入图中,或者由之前的节点属性步骤创建。例如,embedding属性可以由前面的示例创建,并且我们期望age在用作输入的内存中图中(在训练和预测时)已经存在。

配置关系拆分

链接预测训练管道管理将关系拆分为多个集合,并向其中一些集合添加采样的负关系。配置拆分是可选的,如果省略,则将使用默认设置进行拆分。

可以使用gds.model.list检查管道的拆分配置,并且可能只产生splitConfig

关系的拆分在内部按以下步骤进行

  1. 根据指定的sourceNodeLabeltargetNodeLabeltargetRelationshipType过滤图,这些配置在训练时配置。

  2. 过滤后剩余的关系我们称为正关系,它们被拆分为testtrainfeature-input集合。

    • test集合包含testFraction分数的正关系。剩余的正关系称为testComplement集合。

    • train集合包含testComplement集合的trainFraction分数。

    • feature-input集合包含其余部分。

  3. 符合sourceNodeLabeltargetNodeLabel过滤器的随机负关系将添加到testtrain集合中。

    • 每个集合中负关系的数量是正关系数量乘以negativeSamplingRatio

    • 负关系与正关系不重合。

    • 如果指定了negativeRelationshipType,则不是进行采样,而是根据testtrain集合大小比率对图中此类型的全部关系进行分区,并将其添加为负关系。negativeRelationshipType的所有关系也必须符合sourceNodeLabeltargetNodeLabel过滤器。

正关系和负关系分别被赋予1.00.0的关系权重,以便能够区分它们。

traintest关系集合用于

  • 确定每个训练或测试示例的标签(正或负)

  • 识别要为其计算链接特征的节点对

但是,它们不被节点属性步骤中运行的算法使用。原因是,否则模型将使用预测目标(关系的存在)作为特征。

每个节点属性步骤都使用一个特征输入feature-input图具有具有sourceNodeLabeltargetNodeLabelcontextNodeLabels的节点,以及来自feature-input集合的关系以及contextRelationshipTypes的关系。此图用于计算节点属性和依赖于节点属性的特征。在feature-input图中生成的节点属性用于训练和测试。

语法

配置关系拆分语法
CALL gds.beta.pipeline.linkPrediction.configureSplit(
  pipelineName: String,
  configuration: Map
)
YIELD
  name: String,
  nodePropertySteps: List of Map,
  featureSteps: List of Map,
  splitConfig: Map,
  autoTuningConfig: Map,
  parameterSpace: List of Map
表 13. 参数
名称 类型 描述

pipelineName

字符串

管道的名称。

configuration

Map

拆分关系的配置。

表 14. 配置
名称 类型 默认值 描述

validationFolds

整数

3

模型选择期间使用的训练图的划分次数。

testFraction

双精度

0.1

为测试保留的图的分数。必须在范围(0,1)内。

trainFraction

双精度

0.1

为训练保留的测试补充集的分数。必须在范围(0,1)内。

negativeSamplingRatio

双精度

1.0

测试和训练集中负样本与正样本的期望比率。更多详细信息此处。它与negativeRelationshipType是互斥参数。

negativeRelationshipType

字符串

n/a

指定应使用哪些关系作为负关系,添加到testtrain集合中。它与negativeSamplingRatio是互斥参数。

表 15. 结果
名称 类型 描述

name

字符串

管道的名称。

nodePropertySteps

Map 列表

节点属性步骤的配置列表。

featureSteps

Map 列表

特征步骤的配置列表。

splitConfig

Map

定义模型训练前的拆分的配置。

autoTuningConfig

Map

定义自动调整行为的配置。

parameterSpace

Map 列表

模型的参数配置列表,训练模式使用这些配置进行模型选择。

示例

以下步骤将配置管道的拆分
CALL gds.beta.pipeline.linkPrediction.configureSplit('pipe', {
  testFraction: 0.25,
  trainFraction: 0.6,
  validationFolds: 3
})
YIELD splitConfig
表 16. 结果
splitConfig

{negativeSamplingRatio=1.0, testFraction=0.25, trainFraction=0.6, validationFolds=3}

我们现在重新配置了管道的拆分,这将在训练期间应用。

例如,考虑一个具有“Person”和“City”节点以及“KNOWS”、“BORN”和“LIVES”关系的图。请注意,这与训练管道中的示例相同。

Visualization of the example graph
图 1. 完整示例图

假设我们按sourceNodeLabeltargetNodeLabelPerson以及targetRelationshipTypeKNOWS进行过滤。过滤后的图如下所示

example graph for LP split
图 2. 过滤后的图

过滤后的图有 12 个关系。如果我们使用testFraction 0.25 和negativeSamplingRatio 1 配置拆分,它将随机选择12 * 0.25 = 3个正关系加上1 * 3 = 3个负关系作为test集合。

然后,如果trainFraction为 0.6 且negativeSamplingRatio为 1,它将随机选择9 * 0.6 = 5.4 ≈ 5个正关系加上1 * 5 = 5个负关系作为train集合。

黄色部分剩余的12 * (1 - 0.25) * (1 - 0.6) = 3.6 ≈ 4个关系是feature-input集合。

example graph for LP split
图 3. 根据拆分设置的每个集合的正关系和负关系。test集合为蓝色,train集合为红色,feature-input集合为黄色。虚线表示负关系。

例如,假设添加了一个节点属性步骤,其中contextNodeLabelCitycontextRelationshipTypeBORN。然后,该步骤的feature-input图将是

example graph for LP split
图 4. 特征输入图。feature-input集合为黄色。

添加模型候选

管道包含一个模型候选配置集合,该集合最初为空。此集合称为参数空间。每个模型候选配置包含训练参数的固定值或范围。当存在范围时,自动调整算法会自动确定范围内的值,请参阅自动调整。必须使用以下过程之一将一个或多个模型配置添加到训练管道的参数空间

  • gds.beta.pipeline.linkPrediction.addLogisticRegression

  • gds.beta.pipeline.linkPrediction.addRandomForest

  • gds.alpha.pipeline.linkPrediction.addMLP

有关 GDS 中可用训练方法(逻辑回归、随机森林和多层感知器)的信息,请参阅训练方法

训练管道中,我们将进一步解释如何训练、评估和比较配置的模型候选。

可以使用gds.model.list检查管道的参数空间,并可以选择仅产生parameterSpace

在训练管道之前,必须向管道中添加至少一个模型候选。

语法

配置训练参数语法
CALL gds.beta.pipeline.linkPrediction.addLogisticRegression(
  pipelineName: String,
  config: Map
)
YIELD
  name: String,
  nodePropertySteps: List of Map,
  featureSteps: List of Map,
  splitConfig: Map,
  autoTuningConfig: Map,
  parameterSpace: Map
表 17. 参数
名称 类型 描述

pipelineName

字符串

管道的名称。

config

Map

模型候选的逻辑回归配置。模型允许的参数在下一张表中定义。

表 18. 逻辑回归配置
名称 类型 默认值 可选 描述

batchSize

整数或映射 [1]

100

每个批次的节点数。

minEpochs

整数或映射 [1]

1

最小训练轮数。

maxEpochs

整数或映射 [1]

100

最大训练轮数。

learningRate [2]

浮点数或映射 [1]

0.001

学习率决定了在每个轮次中沿 Adam 优化器指示的方向移动以最小化损失时的步长。

patience

整数或映射 [1]

1

连续无生产性轮次的最多次数。

tolerance [2]

浮点数或映射 [1]

0.001

要视为有生产性的损失的最小改进。

penalty [2]

浮点数或映射 [1]

0.0

用于逻辑回归的惩罚。默认情况下,不应用任何惩罚。

focusWeight

浮点数或映射 [1]

0.0

焦点损失因子的指数,用于使模型在训练集中更多地关注困难的、错误分类的示例。默认值为0.0表示不应用焦点,并使用交叉熵。必须为正数。

classWeights

浮点数列表

[1.0, 1.0]

损失函数中每个类别的权重。列表长度必须为2。第一个权重用于负样本(缺失关系),第二个权重用于正样本(实际关系)。

1. 映射应采用{range: [minValue, maxValue]}的形式。它由自动调整使用。

2. 此参数的范围在对数尺度上自动调整。

表 19. 结果
名称 类型 描述

name

字符串

管道的名称。

nodePropertySteps

Map 列表

节点属性步骤的配置列表。

featureSteps

Map 列表

特征步骤的配置列表。

splitConfig

Map

定义模型训练前的拆分的配置。

autoTuningConfig

Map

定义自动调整行为的配置。

parameterSpace

Map 列表

模型的参数配置列表,训练模式使用这些配置进行模型选择。

配置训练参数语法
CALL gds.beta.pipeline.linkPrediction.addRandomForest(
  pipelineName: String,
  config: Map
)
YIELD
  name: String,
  nodePropertySteps: List of Map,
  featureSteps: List of Map,
  splitConfig: Map,
  autoTuningConfig: Map,
  parameterSpace: Map
表 20. 参数
名称 类型 描述

pipelineName

字符串

管道的名称。

config

Map

模型候选的随机森林配置。模型允许的参数在下一张表中定义。

表 21. 随机森林分类配置
名称 类型 默认值 可选 描述

maxFeaturesRatio

浮点数或映射 [3]

1 / sqrt(|features|)

寻找最佳分割时要考虑的特征比例

numberOfSamplesRatio

浮点数或映射 [3]

1.0

每个决策树要考虑的样本比例。我们使用有放回抽样。值为0表示使用每个训练样本(不进行抽样)。

numberOfDecisionTrees

整数或映射 [3]

100

决策树的数量。

maxDepth

整数或映射 [3]

无最大深度

决策树的最大深度。

minLeafSize

整数或映射 [3]

1

决策树中叶子节点的最小样本数。必须严格小于minSplitSize

minSplitSize

整数或映射 [3]

2

决策树中分割内部节点所需的最小样本数。必须严格大于minLeafSize

criterion

字符串

"GINI"

用于在决策树训练期间评估潜在节点分割的杂质标准。有效选项为"GINI""ENTROPY"(均不区分大小写)。

3. 映射应采用{range: [minValue, maxValue]}的形式。它由自动调整使用。

表 22. 结果
名称 类型 描述

name

字符串

管道的名称。

nodePropertySteps

Map 列表

节点属性步骤的配置列表。

featureSteps

Map 列表

特征步骤的配置列表。

splitConfig

Map

定义模型训练前的拆分的配置。

autoTuningConfig

Map

定义自动调整行为的配置。

parameterSpace

Map 列表

模型的参数配置列表,训练模式使用这些配置进行模型选择。

配置训练参数语法
CALL gds.alpha.pipeline.linkPrediction.addMLP(
  pipelineName: String,
  config: Map
)
YIELD
  name: String,
  nodePropertySteps: List of Map,
  featureSteps: List of Map,
  splitConfig: Map,
  autoTuningConfig: Map,
  parameterSpace: Map
表 23. 参数
名称 类型 描述

pipelineName

字符串

管道的名称。

config

Map

模型候选的多层感知器配置。模型允许的参数在下一张表中定义。

表 24. 多层感知器分类配置
名称 类型 默认值 可选 描述

batchSize

整数或映射 [4]

100

每个批次的节点数。

minEpochs

整数或映射 [4]

1

最小训练轮数。

maxEpochs

整数或映射 [4]

100

最大训练轮数。

learningRate [5]

浮点数或映射 [4]

0.001

学习率决定了在每个轮次中沿 Adam 优化器指示的方向移动以最小化损失时的步长。

patience

整数或映射 [4]

1

连续无生产性轮次的最多次数。

tolerance [5]

浮点数或映射 [4]

0.001

要视为有生产性的损失的最小改进。

penalty [5]

浮点数或映射 [4]

0.0

用于逻辑回归的惩罚。默认情况下,不应用任何惩罚。

hiddenLayerSizes

整数列表

[100]

表示每一层神经元数量的整数列表。默认值指定一个具有1个隐藏层(100个神经元)的MLP。

focusWeight

浮点数或映射 [4]

0.0

焦点损失因子的指数,用于使模型在训练集中更多地关注困难的、错误分类的示例。默认值为0.0表示不应用焦点,并使用交叉熵。必须为正数。

classWeights

浮点数列表

[1.0, 1.0]

交叉熵损失中每个类别的权重。列表长度必须为2。第一个权重用于负样本(缺失关系),第二个权重用于正样本(实际关系)。

4. 映射应采用{range: [minValue, maxValue]}的形式。它由自动调整使用。

5. 此参数的范围在对数尺度上自动调整。

表 25. 结果
名称 类型 描述

name

字符串

管道的名称。

nodePropertySteps

Map 列表

节点属性步骤的配置列表。

featureSteps

Map 列表

特征步骤的配置列表。

splitConfig

Map

定义模型训练前的拆分的配置。

autoTuningConfig

Map

定义自动调整行为的配置。

parameterSpace

Map 列表

模型的参数配置列表,训练模式使用这些配置进行模型选择。

示例

我们可以向管道中添加多个模型候选。

以下操作将添加一个具有默认配置的逻辑回归模型
CALL gds.beta.pipeline.linkPrediction.addLogisticRegression('pipe')
YIELD parameterSpace
以下操作将添加一个随机森林模型
CALL gds.beta.pipeline.linkPrediction.addRandomForest('pipe', {numberOfDecisionTrees: 10})
YIELD parameterSpace
以下操作将添加一个配置好的多层感知器模型,该模型使用类别加权焦点损失和范围参数
CALL gds.alpha.pipeline.linkPrediction.addMLP('pipe',
{hiddenLayerSizes: [4, 2], penalty: 0.5, patience: 2, classWeights: [0.55, 0.45], focusWeight: {range: [0.0, 0.1]}})
YIELD parameterSpace
以下操作将添加一个带有范围参数的逻辑回归模型
CALL gds.beta.pipeline.linkPrediction.addLogisticRegression('pipe', {maxEpochs: 500, penalty: {range: [1e-4, 1e2]}})
YIELD parameterSpace
RETURN parameterSpace.RandomForest AS randomForestSpace, parameterSpace.LogisticRegression AS logisticRegressionSpace, parameterSpace.MultilayerPerceptron AS MultilayerPerceptronSpace
表 26. 结果
randomForestSpace logisticRegressionSpace MultilayerPerceptronSpace

[{criterion="GINI", maxDepth=2147483647, methodName="RandomForest", minLeafSize=1, minSplitSize=2, numberOfDecisionTrees=10, numberOfSamplesRatio=1.0}]

[{batchSize=100, classWeights=[], focusWeight=0.0, learningRate=0.001, maxEpochs=100, methodName="LogisticRegression", minEpochs=1, patience=1, penalty=0.0, tolerance=0.001}, {batchSize=100, classWeights=[], focusWeight=0.0, learningRate=0.001, maxEpochs=500, methodName="LogisticRegression", minEpochs=1, patience=1, penalty={range=[0.0001, 100.0]}, tolerance=0.001}]

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

管道中的parameterSpace现在包含四个不同的模型候选,并扩展了默认值。每个指定的模型候选将在训练中的模型选择过程中进行尝试。

这些是关于如何添加和配置模型候选的一些简单的示例。有关如何调整每种方法的配置参数的更多信息,请参阅训练方法

配置自动调整

为了找到好的模型,管道支持自动调整训练算法的参数。可以选择使用下面描述的过程来配置自动调整行为。否则,将使用默认的自动调整配置。目前,只能配置要评估的超参数设置的最大尝试次数。

语法

配置自动调整语法
CALL gds.alpha.pipeline.linkPrediction.configureAutoTuning(
  pipelineName: String,
  configuration: Map
)
YIELD
  name: String,
  nodePropertySteps: List of Map,
  featureSteps: List of Map,
  splitConfig: Map,
  autoTuningConfig: Map,
  parameterSpace: List of Map
表 27. 参数
名称 类型 描述

pipelineName

字符串

创建的管道的名称。

configuration

Map

自动调整的配置。

表 28. 配置
名称 类型 默认值 描述

maxTrials

整数

10

maxTrials的值决定了在训练管道时应评估和比较的最大允许模型候选数。如果参数空间中不存在范围,则忽略maxTrials,并评估参数空间中的每个模型候选。

表 29. 结果
名称 类型 描述

name

字符串

管道的名称。

nodePropertySteps

Map 列表

节点属性步骤的配置列表。

featureSteps

Map 列表

特征步骤的配置列表。

splitConfig

Map

定义模型训练前的拆分的配置。

autoTuningConfig

Map

定义自动调整行为的配置。

parameterSpace

Map 列表

模型的参数配置列表,训练模式使用这些配置进行模型选择。

示例

以下操作将配置自动调整的最大尝试次数
CALL gds.alpha.pipeline.linkPrediction.configureAutoTuning('pipe', {
  maxTrials: 2
}) YIELD autoTuningConfig
表 30. 结果
autoTuningConfig

{maxTrials=2}

我们现在重新配置了自动调整,以便在训练期间最多尝试2个模型候选。