在金融反欺诈场景中,黑产已从“单打独斗”演变为“团伙作案”。他们共享设备、IP、甚至交替担保,形成了一张隐秘的关系网。传统基于树模型(如XGBoost)的特征工程仅关注个体属性,难以察觉这类结构化的团伙异常,存在严重的“特征盲区”。

图神经网络(GNN)天生为关系数据而生。本文将采用图注意力网络(GAT),通过注意力机制为不同的邻居节点分配不同权重,精准过滤噪声连接(如正常商户的偶尔转账),放大风险传导路径,在金融交易图上实现欺诈用户的精准识别。全程基于Windows原生环境,打通PyG(PyTorch Geometric)的工程落地痛点。


基础环境与依赖精准配置

环境基准:Windows 10/11 | Python 3.10 | PyTorch 2.1.0 | CUDA 12.1 | 显存 >= 8GB

在Windows下配置PyG是极具挑战性的坑点。由于缺乏原生C++编译环境,直接pip install torch_scatter等常常会报红。务必按照以下顺序,先安装PyTorch,再精准匹配CUDA版本的PyG预编译轮子。

# 1. 安装PyTorch
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
 
# 2. 安装PyG核心依赖 (务必携带-f参数指定PyG的官方轮子源)
pip install torch_scatter torch_sparse torch_cluster torch_spline_conv -f https://data.pyg.org/whl/torch-2.1.0+cu121.html
 
# 3. 安装PyG及数据处理库
pip install torch_geometric
pip install pandas numpy scikit-learn

1. 数据工程:从关系流水到图结构构建

金融风控的核心是“关系”。我们将用户的转账交易、共享设备、同IP登录等行为抽象为边,将用户抽象为节点。在真实业务中,这些是典型的异构图,为简化实战,我们将其同构化为统一的交易关系图。

1.1 特征与标签构造

假设我们有用户特征表user_features.csv(包含注册天数、交易频次等)和关系边表transaction_edges.csv(包含发起方、接收方)。

import pandas as pd
import numpy as np
import torch
from torch_geometric.data import Data
 
# 加载节点特征与标签 (0:正常, 1:欺诈)
user_df = pd.read_csv("user_features.csv")
# 确保特征经过标准化处理,GAT对输入特征的尺度敏感
features = torch.tensor(user_df.drop(columns=['user_id', 'is_fraud']).values, dtype=torch.float32)
labels = torch.tensor(user_df['is_fraud'].values, dtype=torch.long)
 
# 加载边数据 (构建无向图,风险具有双向传导性)
edges_df = pd.read_csv("transaction_edges.csv")
# PyG要求边索引为2xN的格式,且节点索引必须是从0开始的连续整数
src = torch.tensor(edges_df['src_idx'].values, dtype=torch.long)
dst = torch.tensor(edges_df['dst_idx'].values, dtype=torch.long)
# 构建无向边:在无向图中,信息可以双向传递,因此需要添加反向边
edge_index = torch.stack([torch.cat([src, dst]), torch.cat([dst, src])], dim=0)
 
# 构建PyG Data对象
graph_data = Data(x=features, edge_index=edge_index, y=labels)

1.2 极度不平衡的掩码划分

金融反欺诈的痛点在于正负样本极度不平衡(欺诈率往往不到1%)。在划分训练与测试集时,必须采用分层抽样,确保训练集中包含足够的欺诈样本。

from sklearn.model_selection import train_test_split
 
indices = range(graph_data.num_nodes)
# stratify确保训练集和测试集的欺诈比例一致
train_idx, test_idx = train_test_split(
    list(indices), test_size=0.2, stratify=graph_data.y, random_state=42
)
 
train_mask = torch.zeros(graph_data.num_nodes, dtype=torch.bool)
test_mask = torch.zeros(graph_data.num_nodes, dtype=torch.bool)
train_mask[train_idx] = True
test_mask[test_idx] = True
 
graph_data.train_mask = train_mask
graph_data.test_mask = test_mask

2. 模型构建:GAT网络设计与注意力机制

相比于GCN的均值聚合(所有邻居一视同仁),GAT的核心优势在于引入了自注意力机制。在反欺诈场景中,一个用户可能同时连接了正常用户和欺诈用户,GAT能够学习到“给予欺诈邻居更高的注意力权重”,从而避免正常邻居的特征稀释了关键的风险信号。

2.1 GAT模型定义

我们构建一个两层GAT模型。第一层使用多头注意力提取局部子图的风险拓扑特征,第二层单头输出用于最终的节点二分类。

import torch.nn as nn
import torch.nn.functional as F
from torch_geometric.nn import GATConv
 
class FraudGAT(torch.nn.Module):
    def __init__(self, in_channels, hidden_channels, out_channels, heads=8):
        super(FraudGAT, self).__init__()
        # 第一层GAT:多头注意力,抽取多维关系特征并拼接
        self.conv1 = GATConv(
            in_channels, 
            hidden_channels, 
            heads=heads, 
            dropout=0.3, # 随机丢弃注意力系数,防止过拟合
            concat=True  # 多头特征拼接: output_dim = heads * hidden_channels
        )
        # 第二层GAT:单头输出分类结果
        self.conv2 = GATConv(
            hidden_channels * heads, # 输入维度需匹配上一层的输出
            out_channels, 
            heads=1, 
            dropout=0.3,
            concat=False
        )
 
    def forward(self, data):
        x, edge_index = data.x, data.edge_index
        
        # 第一层:LeakyReLU激活 + Dropout正则化
        x = self.conv1(x, edge_index)
        x = F.elu(x)
        x = F.dropout(x, p=0.5, training=self.training)
        
        # 第二层:输出Logits (未经softmax的原始预测值)
        x = self.conv2(x, edge_index)
        
        return x

3. 模型训练:应对极度不平衡样本

在图上的欺诈检测中,绝不能使用常规的交叉熵损失。由于极度不平衡,模型会倾向于将所有节点预测为“正常”以获得99%以上的准确率。同时,图数据不能像表格数据那样简单做SMOTE过采样(会破坏图的拓扑连通性),因此必须在损失函数层面进行干预,加大对“欺诈样本”错判的惩罚。

from sklearn.utils.class_weight import compute_class_weight
 
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = FraudGAT(
    in_channels=graph_data.num_features, 
    hidden_channels=64, 
    out_channels=2, # 二分类
    heads=8
).to(device)
 
graph_data = graph_data.to(device)
 
# 基于训练集标签计算类别权重,欺诈样本权重将远大于正常样本
y_train = graph_data.y[graph_data.train_mask].cpu().numpy()
class_weights = compute_class_weight('balanced', classes=np.array([0, 1]), y=y_train)
weights_tensor = torch.tensor(class_weights, dtype=torch.float32).to(device)
 
# 使用加权的交叉熵损失
criterion = torch.nn.CrossEntropyLoss(weight=weights_tensor)
optimizer = torch.optim.Adam(model.parameters(), lr=0.005, weight_decay=5e-4)
 
def train():
    model.train()
    optimizer.zero_grad()
    out = model(graph_data)
    # 仅计算训练集节点的损失,避免数据泄露
    loss = criterion(out[graph_data.train_mask], graph_data.y[graph_data.train_mask])
    loss.backward()
    optimizer.step()
    return loss.item()
 
# Windows下若报Dataloader多进程错误,忽略即可,此处单图全量训练无此问题
for epoch in range(1, 201):
    loss = train()
    if epoch % 10 == 0:
        print(f'Epoch: {epoch:03d}, Loss: {loss:.4f}')

4. 模型评估:告别准确率,拥抱PR-AUC

对于极度不平衡的欺诈数据集,准确率毫无参考价值。我们重点关注Recall(召回率)(漏抓多少欺诈)和PR-AUC(精确率-召回率曲线下面积)。相比于ROC-AUC,PR-AUC对假阳性(FP)更加敏感,是业界评估风控模型排序能力的金标准。

from sklearn.metrics import classification_report, average_precision_score
 
def test():
    model.eval()
    with torch.no_grad():
        out = model(graph_data)
        # 提取欺诈类别的概率值
        probs = F.softmax(out, dim=1)[:, 1] 
        pred = out.argmax(dim=1)
        
        y_true = graph_data.y[graph_data.test_mask].cpu().numpy()
        y_pred = pred[graph_data.test_mask].cpu().numpy()
        y_prob = probs[graph_data.test_mask].cpu().numpy()
 
    print("====== Classification Report ======")
    # 重点看Fraud类的recall和f1-score
    print(classification_report(y_true, y_pred, target_names=['Normal', 'Fraud']))
    
    # 计算PR-AUC (关键指标)
    pr_auc = average_precision_score(y_true, y_prob)
    print(f"PR-AUC (Average Precision): {pr_auc:.4f}")
 
test()

5. 总结

本实战从金融反欺诈的核心痛点(团伙作案、极度不平衡)出发,在Windows原生环境下完成了一套基于GAT的图风控链路构建。

相较于传统树模型,GAT通过关系拓扑打破了特征孤岛;相较于GCN,其注意力机制实现了“关系降噪”,能有效识别出欺诈团伙中的核心节点与边缘节点。通过类别加权损失与PR-AUC评估指标的引入,模型真正具备了在极低欺诈率真实场景下的工程落地价值。在实际业务中,只需将离线计算的图特征或GNN节点表示(Embedding)作为增值特征送入风控评分卡,即可显著提升对黑产团伙的拦截率。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐