
基于 NebulaGraph 图数据库的欺诈检测方法与代码示例
本文是一个基于 NebulaGraph 图算法、图数据库、机器学习、GNN 的 Fraud Detection 方法综述。除了基本方法思想的介绍之外,我还给大家弄了可以跑的 Playground。
值得一提的是,这是第一次给大家介绍 Nebula-DGL 这个项目。
>>>>基于图数据库的欺诈检测方法
1.1 建立图谱
首先,对现有的历史数据、标注信息面向关联关系进行属性图建模。这种原始数据是多个表结构中的银行、电子商务或者保险行业里的交易事件记录、用户数据和风控标注,而建模过程就是抽象出我们关心的实体、实体间的关联关系、和其中有意义的属性。
一般来说,自然人、公司实体、电话号码、地址、设备(比如终端设备、网络地址、终端设备所连接的 WiFi SSID 等)、订单都是实体本身,其他信息比如风险标注(是否高风险、风险描述等)、自然人和公司实体的信息(职业、收入、学历等)都作为实体的属性来建模。
下图是一个可以参考的贷款反欺诈的示例建模,它来自一份作者开源的图结构数据生成项目。
注,你可以访问 https://github.com/wey-gu/fraud-detection-datagen 获取这个开源的数据生成器代码和一份示例的数据。
1.2 图数据库查询识别风险
有了一张囊括了人、公司、历史贷款申请记录、电话、线上申请网络设备的图谱,我们可以挖掘一些有意思的信息。
事实上,很多被发现、并有效被阻止从而止损的骗保行为是具有群体聚集性的。比如欺诈团伙可能是一小批人(比如 3 到 5 人)有组织地收集更大规模的身份证信息(比如 30 张),同时发起多个金融机构大量贷款,然后在放款后选择丢弃这批留下了违约记录的身份证,再进一步选择下一批身份证信息如法炮制。
这种团伙作案的方式因为利用了大量新的身份信息,完全利用历史记录去黑名单规避风险的方式是无效的。不过,借助于关联关系的视角,这些模式是一定程度上可以被及时识别出来的。
这些可以被识别出的规律我把它分成两种:
一种是风控专家可以直接用某种模式来描述的,例如:和已经被标注为高风险的实体有直接或者间接的关联关系(新订单申请人使用了和过往高风险记录相同的网络设备),这种模式对应到图谱中,通过一个图查询就可以实时给出结果。
另一种是隐含在数据的关联关系背后,需要通过图算法挖掘得出的一些风险提示,例如:尽管给定的实体与有限的标注高风险实体没有匹配的关联,但是它在图中形成了聚集性可能提示我们这可能是一个尚未得手的进行中的团伙贷款诈骗的其中一次申请,这种情况可以通过定期在历史数据中批量执行社区发现算法得出,并在高聚集社区中利用中心性算法给出核心实体,一并提示给风险专家进行后续评估和风险标注。
1.2.1 基于图谱与专家图模式匹配的欺诈检测示例
在开始之前,我们利用 Nebula-UP 来一键部署一套 NebulaGraph 图数据库:
更多请参考 https://github.com/wey-gu/nebula-up/
首先,我们把前边建模的图谱加载到 NebulaGraph 里:
有了这样一个图谱,风控专家可以在可视化探索工具中按需探索实体之间的关系,绘制相应的风险模式:
在这个探索截图里,我们可以明显看到一个群控设备的风险模式,这个模式可以被交给图数据库开发者,抽象成可以被风控应用定期、实时查询的语句:
我们可以很容易在此模型之上,通过修改返回的关联设备计数,作为意向指标查询的判断 API:
如此,我们可以建立一个相对有效的风控系统,利用有限的标注数据和专家资源,去更高效控制团伙欺诈作案风险,然而,在现实情况下,我们的大多数标注数据的获取还是过于昂贵,那么有没有什么方法是更有效利用有限的风险标注和图结构,来预测出风险呢?
1.3 利用图扩充标注
答案是肯定的, Xiaojin Z. 和 Zoubin G. 在论文:Learning from Labeled and Unlabeled Data with Label Propagation http://mlg.eng.cam.ac.uk/zoubin/papers/CMU-CALD-02-107.pdf(CMU-CALD-02-107)中,利用标签传播(Label Propagation)算法来把有限的标注信息在图上通过关联关系传播到更多实体中。
这样,在我们建立的图谱中,我们可以很容易地借助有限的高风险标注,去“传播”产生更多的标注信息。这些扩展出来的标注信息一方面可以在实时的图查询中给出更多的结果,另一方面,它还能作为风控专家重要的输入信息,帮助推进反欺诈调查行动的开展。
一般来说,我们可以通过定期离线地全图扫描数据,通过图算法扩充、更新标注,再将有效的更新标注写回到图谱之中。
1.3.1 图算法扩充欺诈风险标注的示例
下面,我给出一个可以跑通的案例:
这个例子中,我用到了 Yelp 这个欺诈识别的经典数据,这份数据不只会用在这个例子中,后边 GNN 方法中的案例我也会用到它,所以大家可以耐心把数据导入 NebulaGraph。
生成导入的方法在这里,https://github.com/wey-gu/nebulagraph-yelp-frauddetection
结束之后,我们可以看一下图上的统计:
然后,我们可以看到:
目前,市面上的 LPA 标签传播算法都是用来做社区检测的,很少有实现是用来做标签拓展的(只有 SK-Learn 中有这个实现),这里,我们参考 Thibaud M https://datascience.stackexchange.com/users/77683/thibaud-m 给出来的实现。
原始的讨论参考:https://datascience.stackexchange.com/a/55720/138720
为了让这个算法跑的快一点,会从 NebulaGraph 里取一个点的子图,在这个小的子图上做标注的扩充:
首先,我们启动一个 Jupyter 的 Playground,
参考 https://github.com/wey-gu/nebula-dgl 中的 Playground 过程:
访问:http://localhost:8888/lab/tree/work?token=nebulagraph
安装依赖(这些依赖在后边的 GNN 例子中也会被用到)
然后,我们从图中读取一个子图,从 2048 这个点开始探索两步内的所有边。
然后,我们用上边提到的 Torch Label Spreading 实现,应用到我们的图上。
现在咱们看看染色的传播效果:
可以看到最后画出来的结果:
可以看到有一些蓝色标签被 Spread 开了,实际上我的这个例子的效果并不理想(因为这个例子里,绿色的才是重要的标签),不过我给的子图实在是太小了,也本不应该奢求有好的结果,只是为了个大家演示一下这个方法。
1.4 带有图特征的机器学习
在风控领域开始利用图的思想和能力之前,已经有很多利用机器学习的分类算法基于历史数据预测高风险行为的方法了,这些方法把记录中领域专家认为有关的信息(例如:年龄、学历、收入)作为特征,历史标注信息作为标签去训练风险预测模型。
那么读到的这里,我们是否会想到在这些方法的基础之上,如果把基于图结构的属性也考虑进来,作为特征去训练的模型可能更有效呢?答案也是肯定的,已经有很多论文和工程实践揭示这样的模型比未考虑图特征的算法更加有效。这些被尝试有效的图结构特征可能是实体的 PageRank 值、Degree 值或者是某一个社区发现算法得出的社区 id。
在生产上,我们可以定期从图谱中获得实时的全图信息,在图计算平台中分析运算获得所需特征,经过预定的数据管道,导入机器学习模型中周期获得新的风险提示,并将部分结果写回图谱方便其他系统和专家抽取、参考。
1.4.1 带有图特征的机器学习欺诈检测示例
这里,机器学习的方法我就不演示了,就是常见的分类方法,在此之上,我们可以在数据中通过图算法获得一些新的属性,这些属性再处理一下作为新的特征。我只演示一个社区发现的方法,我们可以对全图跑一个 Louvain,得出不同节点的社区归属,然后把社区的值当做一个分类处理成为数值的特征。
这个例子里我们还用 https://github.com/wey-gu/fraud-detection-datagen 这个数据,在此基础上,这个例子我用到了 Nebula-Algorithm 这个项目,它是一个 Spark 应用,可以在 NebulaGraph 图库上运行很多常用的图算法。
首先,我们部署 Spark 和 Nebula Algorithm,还是利用 Nebula-UP,一键部署:
集群起来之后,因为需要的配置文件我已经放在了 Nebula-UP 内部,我们只需要一行就可以运行算法啦!
而最终的结果就在 sparkmaster 容器内的 /output 里:
之后,我们可以对这个 Louvain 的图特征做一些处理,并开始传统的模型训练了。
1.5 图神经网络的方法
然而,这些图特征的方法的问题在于:
- 图特征并不能把关联关系,数据的局部性充分反映到我们的模型、方法里;
- 图的特征工程很昂贵且繁琐。
在最近几年的成果中,基于 GNN 的方法通过将图结构与属性信息进行嵌入表示,使得我们能在不进行图特征抽取、特征工程、专家与工程方法的数据标注的情况下,得到相比于基于传统图特征的机器学习更好的效果。有意思的是,现在正是这些方法快速被发现、演进的时期,基于图的深度学习是之前几年最热门的机器学习研究方向之一。
同时,图深度学习的一些方法可以做到 Inductive Learning——模型可以在新的点、边上进行推理,这样,配合图数据库上线上的子图查询能力,在线实时的风险预测也变得很简单可行了。
1.5.1 基于图表示的图神经网络欺诈检测系统示例
利用 GNN 的方法中,图数据库并不是必须的,数据的存储可以在其他几种常见的介质之中,但是图库能够最大化助益模型训练、模型更新、线上结果的更新。当我们把图数据库作为数据的单一数据来源(single source of truth)的时候,所有的基于线上、离线、图谱的方法可以很容易被集成起来,从而组合所有方法的优势与结果,做出更有效的欺诈检测复合系统。
在这个示例中我们一样分为:数据处理、模型训练、构建检测系统这几部分。
注,这里,我们使用的的工具为 Deep Graph library(DGL),NebulaGraph 图数据库和他们之间的桥梁,Nebula-DGL。
- DGL: https://www.dgl.ai/
- Nebula-DGL: https://github.com/wey-gu/nebula-dgl 我也是这个库的作者 😁
1.5.1.1 数据集
本例中,我们使用的数据集是 Yelp-Fraud,他直接来自于论文 Enhancing Graph Neural Network-based Fraud Detectors against Camouflaged Fraudsters。
这个图中有一种点,三种关系:
- 顶点:来自 Yelp 中的餐厅、酒店的评价,有两类属性:
- 每一个评价中有被标注了的是否是虚假、欺诈评价的标签
- 32 个已经被处理过的数字型属性
- 边:三类评价之间的关联关系
- R-U-R:两个评价由同一个用户发出 shares_user_with
- R-S-R:两个评价是同餐厅同评分(评分可以是 1 到 5) shares_restaurant_rating_with
- R-T-R:两个评价是同餐厅同提交月份 shares_restaurant_in_one_month_with
在开始之前,我们假设这个图已经在我们的 NebulaGraph 里边了。
注,我已经帮大家提前做好了将这张图导入 NebulaGraph 的工作,长话短说就是:
详情参考:https://github.com/wey-gu/nebulagraph-yelp-frauddetection
1.5.1.2 数据处理
这部分的任务是将图谱中和风险相关子图的拓扑结构表示和其中有关的特征(属性)进行工程处理,序列化成为 DGL 的图对象。
DGL 本身支持从点、边列表(edgelist)形式 CSV 文件,或者从 NetworkX 和 SciPy 的序列化稀疏的邻接矩阵(adjacency matrix)的数据来构造它的图对象,我们可以把原始的图数据或者图库中的数据全量导出为这些形式,不过在真实的例子中图库中的数据是实时变化的,能够直接在 NebulaGraph 中的子图上做 GNN 训练一般来说是更理想。得益于 Nebula-DGL 这个库,做这件事儿是很自然的。
注: DGL 外部数据员导入文档:https://docs.dgl.ai/guide/graph-external.html
现在我们开始这个数据的导入,在这之前,我先介绍一下 Nebula-DGL。
Nebula-DGL 可以根据给定的映射和转换规则(YAML 格式),将 NebulaGraph 中的顶点、边,和它们的属性按照规则处理成为点、边、和其中的标注(Label)与特征(Feature),从而构造为 DGL 的图对象。这其中,值得一提的是属性到特征的转换。我们知道,特征可能是某一个属性的值、一个或者多个属性的值做一定的数学变换、亦或是字符型的属性按照枚举规则输出为数字。相应的,Nebula-DGL 在规则中,我们都可以针对这几种情况利用 filter 进行表达:
- 特征直接选取属性的值:
这个例子里,NebulaGraph 图中 follow 这个边将被抽取,边上的属性 degree 的值将直接被作为名为 degree 的特征。
- 特征从属性中经过数学变换
这个例子中,我们把 serve 边之中的两个属性进行 (end_year - start_year) / 30 的处理,变为 service_time 这样的一个特征。
- 枚举属性值为数字特征
这个例子中,我们把 team 顶点中的 name 属性进行枚举,根据
可以看到这个转换规则非常简单直接,大家也可以参考 Nebula-DGL 的完整例子了解全部细节 https://github.com/wey-gu/nebula-dgl/tree/main/example。而有上边数据处理规则的了解之后,我们可以开始处理这个 Yelp 图数据了。
首先,定义如下规则,这里,我们把顶点 review 和三种边都对应过来了,同时,review 上的属性也按照原本的值对应了过来:
nebulagraph_yelp_dgl_mapper.yaml
然后,我们在安装好 Nebula-DGL 之后只需要这几行代码就可以将 NebulaGraph 中的这张图构造为 DGL 的 DGLHeteroGraph 图对象:
1.5.1.3 模型训练
这里,我用 GraphSAGE 算法的点分类(Node Classification)方法来举例,GraphSAGE 的原始版本是一个归纳学习(Inductive Learning)的算法,这里,归纳学习区别于它的反面:Transductive Learning ,可以把新的数据用在完全旧的图之上习得的模型,这样训练出来的模型可以进行线上增量数据的欺诈检测(而不是需要重新加载为全图训练才可以)。
模型训练系统(左边):
- 输入:带有欺诈标注的历史交易图谱
- 输出:一个 GraphSAGE 的 DGL 模型
线上推理系统(右边):
- 模型:基于带有欺诈标注的历史交易图谱基于 GraphSAGE 训练
- 输入:一笔新的交易
- 输出:这笔交易是否涉嫌欺诈
分割数据集
机器学习训练的过程需要在已经有的数据、信息中分割出用来训练、验证和测试的子集。他们可以是不相交的整体数据的真子集也可以彼此有重叠,在实际的情况中,有时候我们对数据的标注常常是不充分的,所以按照标注的比例去分割数据可能更有意义一些。下边的例子是我按照点上是否标注欺诈为标准去分割数据集。
这里边有两个地方值得注意:
train_test_split 中的 stratify=g.ndata['is_fraud']代表保持 is_fraud 的值的分布去分割,符合我们前边提到的思想。
我们分割的是 idx 索引,这样,可以最终获得三个集合的索引,供训练、验证和测试时候使用。同时我们还把对应集合 mask 放到图对象 g 里边去了。
异构图转换为同构图
GraphSAGE 是针对同构图,且边无 feature 的算法,而我们当下的 Yelp 图谱是异构的:一类点、三类边。那么,如何才能用 GraphSAGE 去建模 Yelp 图谱呢?
我们除了选择用针对异构图的 Inductive Learning 方法之外,还可想办法把同构图转换成异构图。为了在转换中不丢失重要的边类型信息,我们可以把边类型变成数值。
这里我给了一维的 edge feature,当然(3-1)二维也是可以的。
注:其实如果想用 0, 1, 2 这样的分布,转换到同构图之后的 hg.edata['_TYPE'] 也是可以直接拿来用的,详见 https://docs.dgl.ai/en/0.9.x/generated/dgl.to_homogeneous.html 中的例子。
代码如下:
然后将它转换为同构图,把 he 作为要保留的 edata:
默认的 GraphSAGE 实现是没考虑 edge feature 的,我们要修改消息传递的步骤,在后边会涉及到这部分的实操。
参考:
- https://discuss.dgl.ai/t/frequently-asked-questions-faq/1681 (问题 13)
- https://discuss.dgl.ai/t/using-node-and-edge-features-in-message-passing/762
模型训练代码
DGL 官方给出了例子在:https://github.com/dmlc/dgl/tree/master/examples/pytorch/graphsage,我在测试的时候还修复了一个小 bug。
因为我们处理过的同构图里是带有 edge feature 的,不能照搬官方的 GraphSAGE 例子代码,我们有两种方法来处理它:
a. 可以稍微改动一下 SAGEConv 消息传递的部分,以 mean 聚合的方式为例:
这个处理中,除了上边消息传递部分增加 edge feature 之外,还需要注意 feature 维度的处理。
b. 把边参数作为边权重,以 mean 聚合为例:
下边,我们以把边的类型作为权重的方式,mean 作为聚合的情况为例来实操:
我们来继承,并覆盖 SAGEConv:
我们其实只是修改了 Message Passing 的部分。
定义模型
定义训练、推理的函数
从 NebulaGraph 中加载图到 DGL,得到的是一个异构图(一类点、三类边)
分出训练、验证、测试集,然后转换成同构图。
训练、测试模型
有了模型之后,我们可以把它序列化成文件,在需要的时候,只需要把模型的形式和这个序列化文件再加载成一个 pyTorch 就可以用它进行推理了。
1.5.1.4 推理接口
前边提到过,GraphSAGE 是最简单的支持 Inductive Learning 的模型,而上边我们的训练推理过程实际上还不是这样的我们的测试和训练的图是同一张,虽然标注了训练的点的索引,但实际上是整张图作为输入的。为了做到 Inductive Learning 我们只需要把训练和测试分成两个无交集的子图来做训练和最终测试:
可以看到,我们上边的代码里,测试所用到的图和训练的图是完全不同的两组数据,这使得我们的线上系统可以是之前完全没有遇到的数据,我们只要把对新来的一个交易请求数据写进 NebulaGraph,然后再从这个点获取一个线上系统可以返回的小子图,就可以把它作为模型推理的输入,获得子图的标签了!
新的交易请求:
还记得我们前边画的线上推理系统的流程图么?
现在,我们假设这个新的交易请求已经发起了,这条交易记录已经被更新在图谱里了,咱们随便取一个点作为这样的请求吧
好,它是 2048 这个点。它的下一步是 1. Get New Record Subgraph 我们来获取它的子图:
可以看到返回的结果其实还是很多的,不过对于 NebulaGraph 来说,这个子图结果返回是在 10 ms 左右获取的,这里我就不贴出来了,如果我们在 NebulaGraph Studio 或者 Explorer 中可以把结果渲染出来(可视化展示的 Query 可以去掉 WITH PROP ,可以给浏览器省点内存),结果就更容易让人脑理解了:
现在我们就来实现这一步的代码吧,它的输入是点的 id:vertex_id。输出是一个 dgl_graph,用来传给推理接口。
这里我用到了 Nebula-Python 这个 NebulaGraph 的 Python SDK/Client,通过 execute_json 执行获得了这个交易的子图。下一步,咱们需要把它构造成一个 dgl_graph:
实际上我就是按照 DGL 文档:https://docs.dgl.ai/en/0.9.x/generated/dgl.heterograph.html,中的方式去构造 data_dict,然后用 heterograph() dgl_graph 了,其中 node_id_map Vertex_ID 到这个对象中 node_id 的字典。
最后,我们再把 node feature 也加载进去。
在开始推理之前,我们还需要把它转换成同构图,和前边完全一样:
最后,我们的推理接口就是:
我们可以调用一下试试推理我们这个新的点:
当然,我们也能在这个小子图上计算他的正确率:
输出结果:
这个示例项目的代码在:github.com/wey-gu/NebulaGraph-Fraud-Detection-GNN,如有问题欢迎留言、ISSUE。
>>>>总结
总结起来,欺诈检测的方法有:
- 在一个交易历史、风控的图谱上,通过图模式查询直接获得风险提示
- 定期利用图算法扩充风险标注,写回图库
- 定期计算图谱中的图特征,和其他特征一起用传统机器学习方法离线预测风险
- 将图谱中的属性处理成为点、边特征,用图神经网络方法离线预测风险,部分可以 Inductive Learning 的方法结合图库可以实现在线风险预测
文章转载自公众号:Nebula Graph Community
