使用图数据库 Amazon Neptune 构建你的第一个基于知识图谱的推荐模型
前言
关于本教程 | |
---|---|
时间 | 80-110分钟 |
费用 | 完成本教程预计花费2-3$ |
相关行业 | 电商行业、在线教育行业、资讯媒体等行业 |
相关产品 | CloudFormation、Amazon Neptune、Amazon Lambda、Amazon SageMaker |
受众 | 对大数据、AI、云等技术感兴趣的中高端开发者及泛互联网从业者 |
级别 | 初、中级 |
上次更新日期 | 2022年5月 |
-
实验环境搭建
模块一:环境搭建
步骤一:登录到 AWS console,选择 cloudshell
步骤二:创建 S3 存储桶,取个不常见的名字,需要记住创建的名字,后面都会用到
aws s3api create-bucket --bucket 自己取个复杂点的名字 --region us-east-1
步骤三:创建 cloudformation
aws cloudformation create-stack --stack-name get-started-neptune-ml --template-url https://s3.amazonaws.com/ee-assets-prod-us-east-1/modules/4f0f18a83e6148e895b10d87d4d89068/v1/gcr-buildon-selfpace/gcr-buildon-neptune-ml-nested-stack.json --capabilities CAPABILITY_IAM --region us-east-1 --disable-rollback
复制到 cloudshell 运行
复制到 cloudshell 运行
注:步骤三运行成功后后台会启动一系列的服务,需等待30分钟才能进行下一步。
上图的服务可以查看后台服务是否启动完成, 当根堆栈 get-started-neptune-ml 显示 CREATE_COMPLETE 表示服务创建完成
!!!部分服务是收费的,不管有没有做完实验,都需要进行删除环境的操作!!!
!!!部分服务是收费的,不管有没有做完实验,都需要进行删除环境的操作!!!
!!!部分服务是收费的,不管有没有做完实验,都需要进行删除环境的操作!!! -
模块二:打开 notebook 实验环境
搜索栏输入 neptune,点击进入,导航栏选择 notebook,点击 aws-neptune-get-test,点击 open notebook
注:倘若没有 notebook,需确定地区是否选择正确,默认为美国东部,其次确认后台服务是否都启动完成
-
动手实验一:图神经网络快速构建
打开 Neptune/04-Machine-Learning/CN - Neptune-ML-00-Getting-Started-with-Neptune-ML-Gremlin.ipynb
注:选择CN开头的中文实验文档打开
模块⼀:简介
该笔记本概括介绍了 Amazon Neptune ML 的功能,以及如何在属性图形中用它来推断缺失的数据。若要运行该教程,您只需要准备一个启用了 Neptune ML 功能的 Amazon Neptune Cluster,并在同一个区域中准备一个 S3 存储桶。
注意:除了 Neptune 集群的成本外,本教程会额外产生每小时约 2-3 美元的成本,大约需要 30 分钟可完成所有操作。
图形和图形数据的主要用途是使用数据中的值和连接提供新颖的见解。然而图形数据的一个常见问题在于,此类数据通常并不完整,这意味着其中包含缺失的属性值或连接。虽然不完整的数据并非图形独有的问题,但我们往往希望以互联的方式使用此类数据,这种本质需求使得这种问题会产生更大的影响,通常会导致无效的遍历和/或错误的结果。Neptune ML 通过将机器学习(ML)模型集成到实时图形遍历过程中,借此预测/推断缺失的图形元素(例如属性和连接),有效解决了这个问题。
Neptune ML 是 Amazon Neptune 的一项功能,它使用户能够在 Amazon Neptune 中自动创建、管理并使用图形神经网络(GNN)机器学习模型。Neptune ML 是使用 Amazon SageMaker 和 Deep Graph Library 构建而来的,它提供了一种简单易用的机制来构建/训练/维护这些模型,随后可在 Gremlin 查询中使用这些模型的预测能力来预测图形中的元素或属性值。这些模型涵盖了很多常见用例,例如:- 欺诈交易检测
- 预测社交或标识网络中的成员身份
- 预测产品推荐分类
- 预测用户流失
Neptune ML 通过使用 Gremlin 查询语言在 Neptune 中执行多种常见的机器学习任务来实现这一点。这些任务包括:- 节点分类 - 从一组有限的选项中预测属性值的能力。节点分类可用于确定交易是否有欺诈性,确定一个人最有可能购买哪种类型的产品,或预测一个人的年龄或职业等领域。
- 节点回归 - 预测数值属性值的能力,例如预测用户的信用评分或一个人对电影的评分等。
- 关联预测 - 预测两个顶点之间边缘的能力。借此可解决某些问题,例如在社交网络中找到朋友,向用户推荐产品,或判断某人是否为欺诈团伙成员。
- 边缘分类 - 从一组有限的选项中预测属性值的能力。边缘分类可用于确定交易是否有欺诈性,确定一个人最有可能购买哪种类型的产品,或预测一个人的年龄或职业等领域。
- 边缘回归 - 预测数值属性值的能力,例如预测用户的信用评分或一个人对电影的评分等。
为了在 Neptune ML 中实现上述目的,我们需要执行如下四个步骤的操作:
1.加载数据 - 使用任何常规方法(例如 Gremlin 驱动程序或 Neptune Bulk Loader)将数据加载到 Neptune 集群中。
2.导出数据 - 调用服务,指定机器学习模型类型和模型配置参数。随后将数据和模型配置参数从 Neptune 集群导出到 S3 存储桶。
3.训练模型 - 调用一系列服务对导出的数据进行预处理,训练机器学习模型,随后生成一个 Amazon SageMaker 端点暴露该模型。为此,Neptune ML 会自动执行常规的机器学习过程,将数据拆分为训练数据集、验证数据集和测试数据集。随后会使用训练数据集构建模型,用验证数据集验证模型并找出最佳模型,最后使用测试数据集评估模型的准确性。借助这些步骤,Neptune ML 可根据所提供的配置自动返回效果最佳的模型,进而简化整个模型构建过程。
4.运行查询 - 最后一步需要在 Gremlin 查询中使用这个推断端点,通过机器学习模型推断数据。完成上述过程可能需要相当长的时间(例如数小时)。为了让您能更快速地试用该功能,我们提供了一组可直接在该笔记本中使用的预训练模型。这些预训练模型使您无需执行大部分需要较长时间运行的步骤(导出、数据处理和模型训练),但您依然可以感受到 Gremlin 查询过程中推断数据所能带来的好处。
注意:若要自行完成这些步骤,请结合自己的实际用例,使用“(节点分类/节点回归/关联预测/边缘分类/边缘回归)简介)”这五个笔记本中的任意一个,这些笔记本位于 04-Machine-Learning 目录中。
这些预训练的模型使用了由 GroupLens Research 提供的 MovieLens 100k 数据集。该数据集包含电影、用户,以及用户对这些电影的评分信息。
-
模块二:确认已经准备好运行 Neptune ML
请运行下列代码,以检查您的集群是否已正确配置可以运行 Neptune ML。
import neptune_ml_utils as neptune_ml neptune_ml.check_ml_enabled()
-
模块三:加载数据
构建 Neptune ML 模型的第一步是将数据载入 Neptune 集群。为 Neptune ML 加载数据可使用与将数据摄入 Amazon Neptune 完全相同的标准流程,本例中我们将使用 Bulk Loader 加载数据。
我们编写了一个脚本,可以自动执行从 MovieLens 网站下载数据,调整数据格式,并将数据载入 Neptune 的全过程。您只需要提供一个与集群位于相同区域的 S3 存储桶的 URI 即可。注意:这是唯一一个需要用户提供输入的操作步骤,后续所有单元格均可自动填写需要的值。
s3_bucket_uri="s3://输入刚创建的 S3 bucket 名字"
# remove trailing slashes
s3_bucket_uri = s3_bucket_uri[:-1] if s3_bucket_uri.endswith('/') else s3_bucket_uri当您指定了 S3 存储桶后,运行下方单元格内容即可下载 MovieLens 数据,并将其调整为可被 Neptune 的 Bulk Loader 兼容的格式。
response = neptune_ml.prepare_movielens_data(s3_bucket_uri)
该过程只需几分钟即可完成,操作完成后,您就可以使用下方单元格中的 %load 命令加载数据了。
%load -s {response} -f csv -p OVERSUBSCRIBE --run
注:如果在运行:%load -s {response} -f csv -p OVERSUBSCRIBE --run 这个cell 遇到下面问题:
usg error: option -f not recognized ( allowed: "yns:r:" )
刷新页面后从这开始运行
-
模块四:配置端点
至此,我们已经确认了自己的集群配置可以运行 Neptune ML,接下来需要通过预训练的模型为每个模型类型创建端点。正如上文所述,我们针对 Neptune ML 提供的每一种模型类型都提供了一个预训练模型。在生成模型时需要注意下列几个重要问题:- 每个模型的训练方式使其只能执行一个任务,例如节点分类、节点回归、关联预测、边缘分类,或是边缘回归,每一类都有自己的模型。
- 对于节点分类、节点回归、边缘分类和边缘回归,要推断的属性是在构建模型时指定的,而这个属性也将是每个模型唯一客户推断的属性。
- 这些模型只能用于构建模型时图形中就已存在的元素,属于一种直推模型(Transductive model)。 在重新训练模型或针对新添加的数据对模型进行转换之前,将无法使用新添加的元素。
每个模型的训练和配置都可执行一种特定的任务。节点分类 - 该模型经过训练,可推断 movie 节点的 genre 属性。 节点回归 - 该模型经过训练,可推断 rating 节点的 score 属性。 关联预测 - 该模型经过训练,可推断 user 节点和 movie 节点之间的 rated 边缘。 边缘分类 - 该模型经过训练,可推断 rated 边缘的 scale 属性。 边缘回归 - 该模型经过训练,可推断 rated 边缘的 score 属性。
为了简化设置,我们在下方提供了一些 Python 代码,这些代码可以将 MovieLens 数据加载到 Neptune 集群并设置五个端点。对于这些代码,您可以对如下选项进行配置:- 每个任务类型均被配置为使用默认设置创建。如果不想设置其中的一个或多个任务类型,请将相映任务的变量设置为 False。例如,如果不希望设置节点分类端点,请设置 setup_node_classification=False。
- 所创建的每个端点都有相应的每小时费用,因此在使用完毕后请记得将其删除。为此可使用下方的 Cleaning Up 单元格,或通过 Amazon Web Services Console -> Amazon SageMaker -> Endpoints 删除。
在下方的单元格中,您需要提供用于保存模型工件的 S3 存储桶。配置完下方的单元格后,请运行该单元格,这样即可创建相关端点。该过程大约需要 5-10 分钟。
setup_node_classification=True
setup_node_regression=True
setup_link_prediction=True
setup_edge_classification=True
setup_edge_regression=Trueendpoints=neptune_ml.setup_pretrained_endpoints(s3_bucket_uri, setup_node_classification, setup_node_regression, setup_link_prediction, setup_edge_classification, setup_edge_regression)
node_classification_endpoint=endpoints['node_classification_endpoint_name']['EndpointName']
node_regression_endpoint=endpoints['node_regression_endpoint_name']['EndpointName']
link_prediction_endpoint=endpoints['prediction_endpoint_name']['EndpointName']
edge_classification_endpoint=endpoints['edge_classification_endpoint_name']['EndpointName']
edge_regression_endpoint=endpoints['edge_regression_endpoint_name']['EndpointName']
上述单元格运行完毕后,我们就可以看到新创建的推理端点的端点名称,随后配置每个 Gremlin 查询时会用到这些名称。
-
模块五:使用 Gremlin 进行查询
至此我们已经成功构建了推断端点,接下来一起看看如何使用这些端点借助 Gremlin 查询进行推断。首先是节点分类。
节点分类
节点分类是指从一组有限的选项中推断缺失属性数据的能力。在设置了推理端点后,我们将查询产品知识图谱,借此了解如何通过预测新电影的类型来预测分类属性值,首先我们从电影 Forrest Gump 开始。
在预测电影类型前,首先需要验证我们的图谱中,Forrest Gump 这个 movie 的 genre不包含任何 genre 值。
%%gremlin
g.V().has('title', 'Forrest Gump (1994)').properties("genre").value()
不出所料,上述命令没有返回任何值,接下来我们修改这个查询,来预测 Apollo 13 的类型。为此我们需要给上述查询添加两个步骤,借此让查询知道如何使用 Neptune ML 查找值。
首先,我们需要添加 with() 步骤来指定要在 Gremlin 查询中使用的推理端点,例如这样: g.with("Neptune#ml.endpoint","<INSERT ENDPOINT NAME>")。
注意:端点值可自动传递给下方的查询。
其次,当我们在查询中查询属性时,我们会使用 properties() 步骤以及一个额外的 with() 步骤(with("Neptune#ml.classification")),借此指定我们想要获取该属性的预测值。
将这些内容结合在一起就可以得到下方的查询,该查询可通过我们的产品知识图谱预测电影 Forrest Gump 的 genre。
%%gremling.with("Neptune#ml.endpoint","${node_classification_endpoint}"). V().has('title', 'Forrest Gump (1994)').properties("genre").with("Neptune#ml.classifica
查看结果可知,预测结果似乎是正确的,Forrest 似乎被正确预测为 Drama 类型。
很多情况下,我们可能需要预测一个节点的多个类别。例如在我们的产品知识图谱中,一部电影很可能被归类为多个类型,我们可能需要预测所有这些类型。默认情况下,Neptune ML 会返回排名第一的结果,但我们可以使用 .with("Neptune#ml.limit",3) 配置选项指定希望返回的结果数量。一起看看针对 Forrest Gump 返回的,排名前三的结果吧。
%%gremling.with("Neptune#ml.endpoint","${node_classification_endpoint}"). with("Neptune#ml.limit",3). V().has('title', 'Forrest Gump (1994)').properties("genre").with("Neptune#ml.classifica
Neptune ML 返回的每个值都有一个与之关联的置信度分数,而无论预测结果的置信度如何,上述查询都会返回排名前三的结果。虽然该分数在查询时不可用,但它可用于筛选掉置信度较低的预测。
假设我们想要返回 Forrest Gump 预测的排名前三的类型,但前提是这些结果必须满足特定的置信度要求。为此,可以使用 .with("Neptune#ml.threshold",0.2D) 选项为查询添加筛选器,如下所示。%%gremling.with("Neptune#ml.endpoint","${node_classification_endpoint}"). with("Neptune#ml.limit",3).with("Neptune#ml.threshold",0.2D). V().has('title', 'Forrest Gump (1994)').properties("genre").with("Neptune#ml.classifica
如上所示,目前我们只得到了 Drama 这个预测类型,因为这是唯一高于阈值的预测结果。
至此我们只针对一部电影进行了预测,但假设您希望预测所有不包含 genre 属性的电影类型,则可以使用下方的查询实现。
%%gremlin
g.with("Neptune#ml.endpoint","${node_classification_endpoint}").
V().hasLabel('movie').hasNot('genre').
project('title', 'predicted_genre').
by('title').
by( properties("genre").with("Neptune#ml.classification").value()).
order(local).by(keys, desc)
我们也可以为上述查询使用之前用过的筛选器,这样即可为所有“新”电影找出排名前三的预测类型,但前提是预测结果的置信度高于我们指定的阈值。
%%gremlin
g.with("Neptune#ml.endpoint","${node_classification_endpoint}").
with("Neptune#ml.limit", 3).
with("Neptune#ml.threshold", 0.2D).
V().hasLabel('movie').hasNot('genre').
project('title', 'predicted_genre').
by('title').
by(properties("genre").with("Neptune#ml.classification").value().fold()).
order(local).by(keys, desc)
至此我们已经介绍了有关节点分类的基础信息,接下来一起看看下一个类型的 Neptune ML 任务:节点回归。
节点回归
节点回归是推断缺失属性数据(该数据是一种数值)的能力。例如在产品知识图谱中预测评分值,通常我们可以使用这种方式预测客户可能给出最高评价的产品,进而推荐客户可能想要购买的产品。
对我们的预训练模型来说,这意味着我们可以推断出 rating 顶点的 score。为了演示这一点,我们将使用新创建的节点回归端点看看 user_1 会给自己评价过的每部电影给出怎样的评分。
在预测 user_1 的电影评分前,首先需要确认我们的图形中不包含 user_1 为电影给出的任何 score 值。
%%gremlin
g.V('user_1').out('wrote').
project('movie', 'score').
by(out('about').values('title')).
by(coalesce(properties("score").value(), constant(-999)))和我们的预期一样,上述查询没有返回任何 score 值,接下来我们修改这个查询来预测 user_1 会为每部电影给出的 score。为此我们需要给上述查询添加两个步骤,借此让查询知道如何使用 Neptune ML 来查找值。
首先,我们需要添加 with() 步骤来指定要在 Gremlin 查询中使用的推断端点,例如这样: g.with("Neptune#ml.endpoint","<INSERT ENDPOINT NAME>")。
其次,当我们在查询中查询属性时,我们会使用 properties() 步骤以及一个额外的 with() 步骤(with("Neptune#ml.regression"))来指定我们想要获取该属性的预测值。
将这些内容结合在一起就可以得到下方的查询,该查询可预测 user_1 会为每部电影给出的 score 评分。%%gremlin
g.with("Neptune#ml.endpoint","${node_regression_endpoint}").
V('user_1').out('wrote').
project('movie', 'score').
by(out('about').values('title')).
by(properties("score").with("Neptune#ml.regression").value())指定了上述配置后,现在已经可以看到为每个 rating 节点获得的 score 推断值。如果对上述查询进行一些排序和筛选,即可得到如下的查询内容,借此即可针对一些常见的查询获得答案,例如查看 user_1 推荐的排名前十的电影。
%%gremlin
g.with("Neptune#ml.endpoint","${node_regression_endpoint}").
V('user_1').out('wrote').
project('movie', 'score').
by(out('about').values('title')).
by(properties("score").with("Neptune#ml.regression").value()).
order().by('score', desc).limit(10)
在了解了节点回归后,接下来我们一起看看 Neptune ML 的下一个任务:关联预测。
关联预测
关联预测是推断图形中两个顶点之间边缘的能力。与节点分类和节点回归不同,关联预测可以推断出在模型创建时,图形中就已存在的边缘标签。在我们的模型中,这意味着我们可以推断出任意两个顶点之间存在 wrote、about、rated 或 included_in 边缘的概率。不过在本例中,我们将专注于推断 user 和 movie 顶点之间存在的 rated 边缘。
为了证明这一点,我们将通过查找 user_1 的 rated 边缘的预测,借此预测用户会对哪些电影进行评级。
%%gremlin
g.V('user_1').out('rated').hasLabel('movie').valueMap()
与我们的预期一样,user_1 并不存在任何 rated 边缘。也许 user_1 是系统中新注册的用户,但我们希望为该用户推荐某些产品。接下来将通过修改查询来预测 user_1 最有可能对哪些电影进行评价。
首先,我们需要添加 with() 步骤来指定要在 Gremlin 查询中使用的推断端点,例如这样:g.with("Neptune#ml.endpoint","<INSERT ENDPOINT NAME>")。
其次,在通过查询来查看关联时,需要使用 out() 步骤来预测目标节点,或使用 in() 步骤预测源节点。对于这些步骤,我们需要指定为 with() 步骤(with("Neptune#ml.prediction"))使用的模型类型。
将这些内容结合在一起就可以的到下方的查询,该查询可返回 user_1 最有可能评价的电影。
%%gremling.with("Neptune#ml.endpoint","${link_prediction_endpoint}"). V('user_1').out('rated').with("Neptune#ml.prediction").hasLabel('movie').valueMap('title')
太好了,到这里可以看到,通过预测的边缘我们已经可以知道 user_1 最有可能评价的电影。在上述例子中,我们预测了目标节点,但其实我们也可以使用相同的机制来预测源节点。
接下来将上述场景反转过来:假设我们有一个产品,那么该如何知道哪些人最有可能对该产品做出评价?
%%gremlin
g.with("Neptune#ml.endpoint","${link_prediction_endpoint}").
with("Neptune#ml.limit",10).
V().has('title', 'Forrest Gump (1994)').
in('rated').with("Neptune#ml.prediction").hasLabel('user').id()
至此,我们已经成功地介绍了如何使用关联预测来预测从传入或传出节点开始的边缘。
%%gremlin
g.with("Neptune#ml.endpoint", "${link_prediction_endpoint}").
V('user_1').
out('rated').with("Neptune#ml.prediction").
hasLabel('movie').
out('included_in').
path().by(id()).by(values('title')).by(id())
正如在上面看到的,返回的值包含从 user_1 到电影 Good Morning (1971) ,再到名为 unknown 的电影类型之间的路径。至此我们已经了解了关联预测的工作方式,接下来一起看看 Neptune ML 的下一个任务:边缘分类。
边缘分类
边缘分类是指从一组有限的选项中推断缺失属性的能力。现在我们已经设置了推理端点,接下来将查询我们的产品知识图谱来,借此介绍如何通过预测用户对某部电影的喜爱程度来预测边缘上的分类属性值。
对于产品知识图谱,您可能需要进行的一个最常见的操作就是为用户提供产品推荐。在我们的产品知识图谱中,我们可以使用 Neptune ML 查找 user_2 的所有 scale 值,进而为 user_2 进行预测。
%%gremlin
g.with("Neptune#ml.endpoint", '${edge_classification_endpoint}').
V('user_2').
outE('rated').
project('title', 'predicted_scale').
by(inV().values('title')).
by(properties('scale').with("Neptune#ml.classification").value())然而很多情况下,您可能希望通过预测,只推荐用户真正会喜爱的产品。在我们的产品知识图谱中,我们可以将预测结果限制为 Love 这个值的范围内来做到这一点。
%%gremlin
g.with("Neptune#ml.endpoint", '${edge_classification_endpoint}').
V('user_2').
outE('rated').as('r').
properties('scale').with("Neptune#ml.classification").
value().
is('Love').
select('r').
inV().
values('title')从结果中可以看到,我们预测到 user_2 会 Love 6 部电影。
在上述查询中,我们查询到的是全部范围内的预测结果,但并不清楚这些预测结果的确定性如何。假设我们需要返回 user_2 会 Love 的电影,但前提是结果的置信度高于某个阈值。为此我们可以使用 .with("Neptune#ml.threshold",0.35D) 选项为上述查询添加一个筛选器,如下所示。%%gremlin
g.with("Neptune#ml.endpoint", '${edge_classification_endpoint}').
with("Neptune#ml.threshold", 0.35D).
V('user_2').
outE('rated').as('r').
properties('scale').with("Neptune#ml.classification").
value().
is('Love').
select('r').
inV().
values('title')至此我们已经了解了如何在 Neptune ML 中使用边缘分类来预测最适合推荐给用户的电影,接下来一起看看 Neptune ML 的最后一个任务:边缘回归。
边缘回归
边缘回归是推断缺失属性数据(该数据是一种数值)的能力。例如在产品知识图谱中预测评分值,通常我们可以使用这种方式预测客户可能给出最高评价的产品,进而推荐客户可能想要购买的产品。
对我们的预训练模型来说,这意味着我们可以推断出 rating 顶点的 score。为了演示这一点,我们将使用新创建的边缘回归端点看看 user_1 会给自己 rated 过的每部电影给出怎样的评分。
在预测 user_1 的电影评分前,首先需要确认我们的图形中不包含 user_1 为电影给出的任何 score 值。%%gremlin
g.with("Neptune#ml.endpoint", '${edge_regression_endpoint}').
V('user_2').
outE('rated').
project('title', 'predicted_score').
by(inV().values('title')).
by(properties('score').with("Neptune#ml.regression").value())然而很多情况下,我们可能只希望通过预测提供用户最有可能给出高评价的产品。在我们的产品知识图谱中,我们可以限制预测结果只推荐排名前十的电影来做到这一点。
%%gremlin
g.with("Neptune#ml.endpoint", '${edge_regression_endpoint}').
V('user_2').
outE('rated').
project('title', 'predicted_score').
by(inV().values('title')).
by(properties('score').with("Neptune#ml.regression").value()).
order().by('predicted_score', desc).limit(10)通过结果可以看到为 user_2 预测的排名前十的电影以及预测出的评分。
-
模块六:清理
至此我们已经完成了本次的全部练习,我们之前创建的 SageMaker 端点依然在运行并会按照标准费率产生费用。如果已完成 Neptune ML 的试用工作,希望避免产生这种重复性的成本,请运行下列单元格删除所创建的推断端点。
neptune_ml.delete_pretrained_endpoints(endpoints)
除了推断端点的成本外,您之前使用的 CloudFormation 脚本也创建了多个额外资源。如果您的全部操作均已完成,我们建议您删除 CloudFormation 栈,以避免产生重复的费用。相关说明请参阅在亚马逊云科技 CloudFormation 控制台中删除栈。请记得要删除根栈(您早前创建的栈)。删除根栈会自动删除其中嵌套的其他所有栈。
-
动手实验二:图神经网络关联预测
打开 Neptune/04-Machine-Learning/CN - Neptune-ML-03-Introduction-to-Link-Prediction-Gremlin.ipynb
注:选择 CN 开头的中文实验文档打开
模块⼀:简介
在这个笔记本中,我们将介绍如何使用 Amazon Neptune ML 功能针对属性图形进行关联预测。
注意:该笔记本的操作大约需要花费 1 小时。Neptune ML 是 Amazon Neptune 的一项功能,它使用户能够在 Amazon Neptune 中自动创建、管理并使用图形神经网络(GNN)机器学习模型。Neptune ML 实是使用 Amazon SageMaker 和 Deep Graph Library 构建而来的,它提供了一种简单易用的机制来构建/训练/维护这些模型,随后可在 Gremlin 查询中使用这些模型的预测能力来预测图形中的元素或属性值。
在该笔记本中,我们将展示如何执行名为 关联预测的一种常见机器学习任务。关联预测是一种无监督的机器学习任务,可通过图形中的节点和边缘构建模型,进而预测两个特定节点之间是否存在边缘。关联预测并非基于 GNN 的模型所独有的(其他可支持的模型还包括 DeepWalk 或 node2vec),但 Neptune ML 中基于GNN 的模型通过将节点局部邻居的连接性和特征结合在一起为预测提供额外的上下文,可产生预测性更强的模型。
关联预测常用于解决很多业务问题,例如:- 预测社交或标识网络中的成员身份
- 标识图谱中的实体解析
- 知识图谱完成
- 产品推荐
Neptune ML 可通过下列四步操作自动完成生产就绪的 GNN 模型的创建过程:- 加载数据 - 使用任何常规方法(例如 Gremlin 驱动程序或 Neptune Bulk Loader)将数据加载到 Neptune 集群中。
- 导出数据 - 调用服务,指定机器学习模型类型和模型配置参数。随后将数据和模型配置参数从 Neptune 集群导出到 S3 存储桶。
- 训练模型 - 调用一系列服务对导出的数据进行预处理,训练机器学习模型,随后生成一个 Amazon SageMaker 端点暴露该模型。
- 运行查询 - 最后一步需要在 Gremlin 查询中使用这个推断端点,通过机器学习模型推断数据。
该笔记本将使用由 GroupLens Research 提供的 MovieLens 100k 数据集。该数据集包含电影、用户,以及用户对这些电影的评分信息。
在该笔记本中,我们将介绍如何使用 Neptune ML 在产品知识图谱中预测推荐产品。为了演示这一点,我们将预测用户最有可能进行评价的电影,并会预测哪些用户最有可能对某一部特定电影做出评价。我们还将介绍如何加载和导出数据,以及如何配置并训练模型。最后,我们还将介绍如通过该模型使用 Gremlin 遍历推断电影的类型。 -
模块二:确认已经准备好运行 Neptune ML
请运行下列代码,以检查您的集群是否已正确配置可以运行 Neptune ML。
import neptune_ml_utils as neptune_ml
neptune_ml.check_ml_enabled()如果上述检查没有说该集群已经准备好运行 Neptune ML 作业,请确认集群是否满足这里列出的所有前提要求。
-
模块三:加载数据
构建 Neptune ML 模型的第一步是将数据载入 Neptune 集群。为 Neptune ML 加载数据可使用与将数据摄入 Amazon Neptune 完全相同的标准流程,本例中我们将使用 Bulk Loader 加载数据。
我们编写了一个脚本,可以自动执行从 MovieLens 网站下载数据,调整数据格式,并将数据载入 Neptune 的全过程。您只需要提供一个与集群位于相同区域的 S3 存储桶的 URI 即可。
注意:这是唯一一个需要用户提供输入的操作步骤,后续所有单元格均可自动填写需要的值。s3_bucket_uri="s3://输入刚创建的 S3 bucket 名字"
# remove trailing slashes
s3_bucket_uri = s3_bucket_uri[:-1] if s3_bucket_uri.endswith('/') else s3_bucket_uri当您指定了 S3 存储桶后,运行下方单元格内容即可下载 MovieLens 数据,并将其调整为可被 Neptune 的 Bulk Loader 兼容的格式。
response = neptune_ml.prepare_movielens_data(s3_bucket_uri)
该过程只需几分钟即可完成,操作完成后,您就可以使用下方单元格中的 %load 命令加载数据了。
%load -s {response} -f csv -p OVERSUBSCRIBE --run
注:如果在运行:%load -s {response} -f csv -p OVERSUBSCRIBE --run 这个cell 遇到下面问题:
usg error: option -f not recognized ( allowed: "yns:r:" )
刷新页面后从这开始运行
确认数据已成功加载
上述单元格运行完毕后,数据就已成功载入集群。若要验证数据是否已成功加载,可下列遍历命令来查看不同标签的节点数量:注意:下方显示的数据会假设集群中没有加载其他任何数据。
%%gremlin
g.V().groupCount().by(label).unfold()如果节点数据正确加载,那么应该能看到类似下面的输出结果:
- 19 genres
- 1682 movies
- 100000 rating
- 943 users
要确认边缘也已正确加载,可查看边缘数量:
%%gremlin
g.E().groupCount().by(label).unfold()如果边缘正确加载,那么应该能看到类似下面的输出结果:
- 100000 about
- 2893 included_in
- 100000 rated
- 100000 wrote
-
模块四:导出数据
准备导出
完成数据验证操作后,我们首先需要移除一些 rated 顶点,以便构建可以预测这些缺失连接的模型。正常情况下,我们想要预测的数据很可能在载入的数据中是缺失的,因此在构建机器学习模型之前移除这些数据就能模拟这样的情况。
具体来说,我们要移除 user_1 的 rated 边缘,这样就可以为我们的关联预测任务提供几个候选的顶点。接下来,首先看看目前存在哪些 rated 边缘。
%%gremlin
g.V('user_1').outE('rated')接下来移除这些边缘以模拟数据中缺失的边缘。%%gremlin
g.V('user_1').outE('rated').drop()再次检查数据,可以看到这些边缘已被移除。%%gremlin
g.V('user_1').outE('rated')导出数据和模型配置
注意: 在导出数据之前,请务必按照这里介绍的方法配置 Neptune Export:Neptune Export Service。
载入产品知识图谱后,我们已经可以导出数据和配置,并将其用于训练我们的 ML 模型。
导出过程可通过调用 Neptune Export 服务端点来触发。该调用包含一个配置对象,其中指定了要构建的机器学习模型(本例中我们要构建节点分类模型)以及与各种功能有关的必要配置。注意:该笔记本中用到的配置只指定了最少量的配置选项,这意味着我们模型的预测可能不像预期的那么准确。该配置中包含的参数只是最终用户可用于调优模型并优化预测结果准确性的众多参数中的一小部分。
提供给导出服务的配置选项主要可分为两部分:选择目标,以及配置特征。
选择目标
在第一部分“选择目标”中,我们需要指定要运行的机器学习任务类型。要运行关联预测模型,请不要在 additionalParams 值中指定任何 targets。与节点分类或节点回归不同,关联预测可用于预测图形中任意两个顶点之间所存在的边缘类型,因此无需为值定义目标。配置特征
在第二部分“配置特征”中,我们需要指定图形中所存储数据类型的详细信息,以及机器学习模型该用何种方式解读这些数据。在机器学习领域,每个属性都可以看作一个特征,模型可使用这些特征做出预测。
从 Neptune 导出的数据会包含所有顶点的所有属性。每个属性均会被视作 ML 模型一个单独的特征。Neptune ML 会尽可能推断一个属性的某个特征的正确类型,大部分情况下,只需要指定与特征所用属性有关的信息,即可提高模型的准确性。默认情况下,Neptune ML 会将特征归于下列两个类别之一:- 如果特征代表了数值属性(浮点、双精度、整数),那么会被视作 numerical 特征类型。在此类特征中,数据会表示为一组连续的数字。在我们的示例中,user 的 age 就非常适合表示为这种 Numerical 特征,因为用户的年龄最适合用一系列连续的值来代表。
- 所有其他属性类型会被表示为 category 特征。在这种类型的特征中,数据的每一个唯一值都会表现为模型所使用的一系列分类中的一个唯一值。在我们的 MovieLens 示例中,user 的 occupation 就是 category 特征的一个例子,因为我们希望将用户按照工作进行分组。
如果所有属性都能归于上述两种特征类型,那么在导出时就不需要更改任何配置。然而很多情况下,这些默认值并非总是最佳选择。此时可以指定额外的配置选项,以便更好地定义如何将属性表示为特征。
数值数据是一种最常见的,需要额外进行配置的特征,尤其是用于代表一块或一组项,而非连续数据流的数值数据。
假设我们不希望将 age 表示为一组连续值,而是希望将其表示为一组离散的桶值(例如 18-25、24-26、35-44 等)。此时我们需要为该特征指定一些额外的属性,以便将这些属性归纳到已知的桶集中。为此可将该特征指定为 numerical_bucket。该特征类型可接受某一范围内的预期值以及多个桶,并能在训练过程中将数据分组到不同的桶中。
另一个需要额外属性的常见特征是文本特征,例如名称、标题或说明。虽然 Neptune ML 默认会将其视作分类特征,但实际上这些特征对于每个节点来说可能都是唯一的。例如,由于某个 movie 节点的 title 属性并不能归于某一个分类中,因此将此类特征表示为 text_word2vec 特征可以更好地为我们的模型提供服务。text_word2vec 特征可以使用自然语言处理技术来创建代表文本字符串的数据向量。
在下列导出示例中,我们指定了 movie 的 title 属性应该以 text_word2vec 特征的形式导出并进行训练,而 age 字段的范围应介于 0-100 之间,并且这些数据应分组到 10 个桶中。重要:下列示例只展示了模型配置参数中最少数量的特征,因此所产生的模型准确度可能并非最高。此处介绍了可用于优化该配置,以获得最高质量模型所需的额外选项: Neptune Export Process Parameters
运行下列单元格即可设置导出配置并执行导出操作。通过设置 cloneCluster=True,Neptune 导出功能将会自动创建集群的克隆,整个过程大约需要 20 分钟,运行克隆的集群会产生额外的成本。从现有集群导出只需要大约 5 分钟,但这要求将 Parameter group 中的 neptune_query_timeout 参数设置为一个足够大的值(>72000),以防止出现超时错误。
export_params={
"command": "export-pg",
"params": { "endpoint": neptune_ml.get_host(),
"profile": "neptune_ml",
"cloneCluster": False
},
"outputS3Path": f'{s3_bucket_uri}/neptune-export',
"additionalParams": {
"neptune_ml": {
"version": "v2.0",
"features": [
{
"node": "movie",
"property": "title",
"type": "word2vec"
},
{
"node": "user",
"property": "age",
"type": "bucket_numerical",
"range" : [1, 100],
"num_buckets": 10
}
]
}
},
"jobSize": "small"}%%neptune_ml export start --export-url {neptune_ml.get_export_service_host()} --export-iam --wait --store-to export_results${export_params}
-
模块五:ML 的数据处理、模型训练
导出操作完成后,即可开始训练自己的机器学习模型并创建推断端点。Neptune ML 模型的训练需要三个步骤。
注意:下方单元格仅配置了运行模型训练所需的最少数量的参数。数据处理
第一步(数据处理)需要通过标准的特征处理技术来处理导出的图形数据集,借此为 DGL 准备所需的数据。该步骤会执行一些函数,例如数值数据的特征标准化,并会使用 word2vec 对文本特征进行编码。此步骤完成后,数据集将被调整为模型训练所需的正确格式。
该步骤是通过 SageMaker Processing Job 实现的,作业完成后,相关数据工件会存储在预先指定的 S3 位置。
您可通过下列链接了解数据处理作业可用的其他选项和配置参数:运行下列单元格即可创建数据处理配置并开始处理作业。
# The training_job_name can be set to a unique value below, otherwise one will be auto generated
training_job_name=neptune_ml.get_training_job_name('link-prediction')curl_shell = f"""curl -X POST https://{neptune_ml.get_host()}:8182/ml/dataprocessing \\
-H 'Content-Type: application/json' \\
-d '{{
"inputDataS3Location" : "{export_results['outputS3Uri']}",
"id" : "{training_job_name}",
"configFileName": "training-data-configuration.json",
"processedDataS3Location": "{str(s3_bucket_uri)}/preloading",
"processingInstanceType": "ml.m5.2xlarge"}}'"""
!$curl_shellprocessing_params = f"""--job-id {training_job_name}"""
%neptune_ml dataprocessing status --wait --store-to processing_results {processing_params}模型训练
第二步(模型训练)将训练用于进行预测的 ML 模型。模型训练工作分为两个阶段。第一个阶段需要使用 SageMaker 处理作业生成模型训练策略。模型训练策略是一种配置集,其中指定了要在模型训练工作中使用哪些类型的模型和模型超参数范围。第一阶段完成后,SageMaker 处理作业会启动一个 SageMaker 超参数调优作业。SageMaker 超参数调优作业会针对已处理的数据运行预先指定数量的模型训练作业 Trail,并将模型训练过程中生成的模型工件保存在 S3 输出位置。所有训练作业完成后,超参数调优作业还会记录产生了最佳性能模型的训练作业。
您可以通过下列链接了解模型训练作业可用的其他选项和配置参数:信息:关联预测是一种在计算方面比分类或回归更复杂的模型,因此该模型的训练大约需要花费 2-3 小时。
training_params=f"""
--job-id {training_job_name}
--data-processing-id {training_job_name}
--instance-type ml.c5.4xlarge
--s3-output-uri {str(s3_bucket_uri)}/training
--max-hpo-number 2
--max-hpo-parallel 2 """%neptune_ml training start --wait --store-to training_results {training_params}
-
模块六:端点创建
最后一步需要创建推断端点,这是一种 Amazon SageMaker 端点实例,可使用最佳训练作业所生成的模型工件启动。我们的图形查询将使用该端点为请求中输入的内容返回模型预测结果。端点一经创建就会始终保持活动状态,直到将其手工删除。每个模型只能绑定到一个端点。
您可以通过下列链接了解端点创建可用的其他选项和配置参数:信息:端点的创建过程大约需要 5-10 分钟。endpoint_params=f"""
--id {training_job_name}
--model-training-job-id {training_job_name}"""%neptune_ml endpoint create --wait --store-to endpoint_results {endpoint_params}
上述操作完成后,我们即可获得新创建推断端点的名称。下列单元格将设置用于下方 Gremlin 查询的端点名称。
endpoint=endpoint_results['endpoint']['name'] -
模块七:使用 Gremlin 进行查询
至此我们已经设置好了推断端点,随后一起来查询产品知识图谱,看看如何预测用户会对某部电影给出怎样的评价吧。预测产品知识图谱中不同连接的可能性,这种方法主要被用于向客户推荐最有可能感兴趣并想要购买的产品。
与节点分类和节点回归不同,关联预测可推断在创建模型时就已存在于图形中的任意边缘的标签。在我们的模型中,这意味着我们可以推断任意两个顶点之间存在 wrote、about、rated 或 included_in 边缘的概率。不过在本例中我们将只专注于推断 user 和 movie 顶点之间的 rated 边缘。
预测用户可能对哪部电影发表评价
在预测 user_1 最有可能对哪部电影发表评价之前,首先需要确认我们的图形并不包含 user_1 的任何 rated 边缘。
%%gremlin
g.V('user_1').out('rated').hasLabel('movie').valueMap()正如预期的那样,user_1 并不存在任何 rated 边缘。也许 user_1 是系统中新注册的用户,而我们想要给该用户推荐一些产品。让我们来修改查询以预测 user_1 最有可能评价哪些电影。
首先,我们添加了 with() 步骤以指定要在 Gremlin 查询中使用的推断端点,例如这样:g.with("Neptune#ml.endpoint","<INSERT ENDPOINT NAME>")。注意:后续查询中可以自动传递端点值。其次,在通过查询来查看关联时,需要使用 out() 步骤来预测目标节点,或使用 in() 步骤预测源节点。对于这些步骤,我们需要指定为 with() 步骤(with("Neptune#ml.prediction"))使用的模型类型。
将这些内容结合在一起就可以的到下方的查询,该查询可返回 user_1 最有可能评价的电影。%%gremlin
g.with("Neptune#ml.endpoint","${endpoint}").
V('user_1').out('rated').with("Neptune#ml.prediction").hasLabel('movie').valueMap('title')太好了,到这里可以看到,通过预测的边缘我们已经可以知道 user_1 最有可能评价的电影是 Sleepers。在上述例子中,我们预测了目标节点,但其实我们也可以使用相同的机制来预测源节点。
接下来将上述场景反转过来:假设我们有一个产品,那么该如何知道哪些人最有可能对该产品做出评价?
预测最有可能评价某部电影的前十位用户
为了实现这一点,我们需要从 movie 顶点开始,预测指向 user 的相关边缘。由于我们只需要返回排在前十位的推荐用户,因此需要使用 .with("Neptune#ml.limit",10) 配置选项。将这些内容结合在一起即可获得下列查询,通过该查询即可知道最有可能对电影 Apollo 13 发表评价的前十位用户。%%gremlin
g.with("Neptune#ml.endpoint","${endpoint}").
with("Neptune#ml.limit",10).
V().has('title', 'Apollo 13 (1995)').
in('rated').with("Neptune#ml.prediction").hasLabel('user').id()至此,我们已经成功地掌握了如何使用关联预测来预测始于任何一端的边缘。
通过这些示例可以了解到该如何推断图形中未知的连接,进而借助 Amazon Neptune 实现很多有趣且独特的用例。 -
模块八:清理
至此我们已经完成了本次的全部练习,我们之前创建的 SageMaker 端点依然在运行并会按照标准费率产生费用。如果已完成 Neptune ML 的试用工作,希望避免产生这种重复性的成本,请运行下列单元格删除所创建的推断端点。
neptune_ml.delete_endpoint(training_job_name)<自己取个复杂点的名字>除了推断端点,您之前使用的 CloudFormation 脚本也创建了多个额外资源。如果您的全部操作均已完成,我们建议您删除 CloudFormation 栈,以避免产生重复的费用。相关说明请参阅在亚马逊云科技 CloudFormation 控制台中删除栈。请记得要删除根栈(您早前创建的栈)。删除根栈会自动删除其中嵌套的其他所有栈。
-
删除环境
为了防止之后的额外扣费,必须进行下面的删除环境操作
模块一:删除 cloudformation
为了防止之后的额外扣费,必须进行下面的删除环境操作 -
模块二:删除 S3 存储桶
选择 cloudshell,删除 S3 存储桶,名字是创建环境是创建的 S3 名字
aws s3 rb s3://自己取的 bucket 名字 --force复制到 cloudshell 运行
-
模块三:确认并删除 sagemaker 终端节点
Build On是什么?
亚马逊云科技开发者 Build On 是由亚马逊团队策划、开发者社区联合打造的动手实操系列活动。它是以现实技术应用和需求场景为核心,结合时下重点技术领域与亚马逊云科技的前沿技术方案打造的,面向开发人员、IT 技术人员、或技术领域决策者的必备云课程。
亚马逊云科技 Build On 讲什么?
2022年亚马逊云科技 Build On 系列活动将围绕数据、软件、架构、运维和前沿技术领域的核心技术领域展开,旨在通过提供专业技术方向的动手实验、助教指导、专家答疑等服务,帮助开发者了解相关领域内的以经典技术框架及经典案例最佳实践,并最终通过精心设计实验流程环境,由技术专家手把手带领开发者亲自设计、部署和操作。话题将涵盖云计算入门基础和应用专业级服务应用,如机器学习、IoT技术、Serverless、基础设施等,覆盖从初创项目到成熟企业的全场景全生命周期的商业实战案例,无论您是刚接触到云的开发者,还是开发经验丰富的专家,您都将从 Build On 活动中获得实质性收获。