使用DGL做自建异质图上的链接预测

本文是自定义的图。
首先自定义图的结构:

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

n_users = 1000  # 定义 user 个数
n_items = 500   # 定义 item 个数
n_follows = 3000    # 定义 follow个数
n_clicks = 5000     # 定义 click 个数
n_dislikes = 500    # 定义 dislikes 个数
n_hetero_features = 10  # 定义 hetero_features 嵌入维数
n_user_classes = 5  # 用户也有 5 种类别
n_max_clicks = 10   # 定义 click 类别数
"""
异质关系如下:
('user', 'follow', 'user')
('user', 'click', 'item')
('user', 'dislike', 'item')
"""
follow_src = np.random.randint(0, n_users, n_follows)   # 边 follow 的源节点
follow_dst = np.random.randint(0, n_users, n_follows)   # 边 follow 的目标节点
click_src = np.random.randint(0, n_users, n_clicks)     # 边 click 的源节点
click_dst = np.random.randint(0, n_items, n_clicks)     # 边 click 的目标节点
dislike_src = np.random.randint(0, n_users, n_dislikes) # 边 dislike 的源节点
dislike_dst = np.random.randint(0, n_items, n_dislikes) # 边 dislike 的目标节点

# 将构造的节点和边都转移到 gpu 上
# 将 NumPy 数组转换为 Torch 张量并移至适当设备
follow_src = torch.tensor(follow_src, device=device)
follow_dst = torch.tensor(follow_dst, device=device)
click_src = torch.tensor(click_src, device=device)
click_dst = torch.tensor(click_dst, device=device)
dislike_src = torch.tensor(dislike_src, device=device)
dislike_dst = torch.tensor(dislike_dst, device=device)

# 构建图 构建人工异质图数据集,包含两种类型节点 和 六种类型边
hetero_graph = dgl.heterograph({
    ('user', 'follow', 'user'): (follow_src, follow_dst),   # follow_src 和 follow_dst 之间有关系 follow
    ('user', 'followed-by', 'user'): (follow_dst, follow_src),
    ('user', 'click', 'item'): (click_src, click_dst),
    ('item', 'clicked-by', 'user'): (click_dst, click_src),
    ('user', 'dislike', 'item'): (dislike_src, dislike_dst),
    ('item', 'disliked-by', 'user'): (dislike_dst, dislike_src)})
    
hetero_graph = hetero_graph.to(device)

为节点初始化特征,将节点user分为5类,将 边 click 分为 10类


# 使用random方式随机为 节点 初始化特征
hetero_graph.nodes['user'].data['feature'] = torch.randn(n_users, n_hetero_features).to(device)
hetero_graph.nodes['item'].data['feature'] = torch.randn(n_items, n_hetero_features).to(device)

# 标签细分,将节点user分为5种,将 边 click分为10种
hetero_graph.nodes['user'].data['label'] = torch.randint(0, n_user_classes, (n_users,)).to(device)  # 为每个user打一个标签(0-4)。返回一个 [0-n_user_classed)内的int的 形状为(n_users,)的一维张量
hetero_graph.edges['click'].data['label'] = torch.randint(1, n_max_clicks, (n_clicks,)).float().to(device) # 为每个click打一个标签

# 随机在 user节点 和 click边 生成训练mask
hetero_graph.nodes['user'].data['train_mask'] = torch.zeros(n_users, dtype=torch.bool).bernoulli(0.6).to(device)    # 使用伯努利分布选60%的为train
hetero_graph.edges['click'].data['train_mask'] = torch.zeros(n_clicks, dtype=torch.bool).bernoulli(0.6).to(device)  # 使用伯努利分布选60%的为train

损失函数计算损失:

def compute_loss(pos_score, neg_score):
    n_edges = pos_score.shape[0]
    return (1 - pos_score.unsqueeze(1) + neg_score.view(n_edges, -1)).clamp(min=0).mean()

对边进行负采样:


# 负采样
# 对要进行链接预测的边类型构造一个负采样图
def construct_negative_graph(graph, k, etype):
    """

    :param graph:
    :param k: 对于每个正样本,生成k个负样本
    :param etype:  边的类型。生成的图中要包含这种 异质边 的类型
    :return:
    """
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    utype, _, vtype = etype  # 提取异质图的源节点类型和目标节点类型
    src, dst = graph.edges(etype=etype)  # 提取特定类型的所有边的源节点和目标节点索引
    neg_src = src.repeat_interleave(k).to(device)  # 为每个正样本重复 k 次源节点的索引(负采样生成的链接的源节点和正样本链接的源节点一样)
    neg_dst = torch.randint(0, graph.num_nodes(vtype), (len(src) * k,)).to(device)  # 负样本链接的目标节点是随机的。
    return dgl.heterograph(
        {etype: (neg_src, neg_dst)},  # 指定异质边的类型(utype, reltype, vtype). 这里的utype, vtype是负采样得到的节点。边是给定的特定的etype。
        num_nodes_dict={ntype: graph.num_nodes(ntype) for ntype in graph.ntypes})  # 为每种节点类型指定节点数量(保证和原图数量一致)

主函数:


def main():
    # 构建好的图是 hetero_graph 图

    hetero_graph = construct_hete_graph()
    graph_feature_init(hetero_graph)

    model = Model(10, 20, 5, hetero_graph.etypes)   # 输入10, hid20, 输出5,边特征为hetero_graph.etypes
    model = model.to(device)

    # 将节点的特征全部取出
    # 用户特征
    user_feats = hetero_graph.nodes['user'].data['feature']
    # 商品特征
    item_feats = hetero_graph.nodes['item'].data['feature']
    # 将所有节点特征存储到一个字典中
    node_features = {'user': user_feats, 'item': item_feats}

    optimizer = torch.optim.Adam(model.parameters())
    epoches = 10
    k = 5

    for epoch in range(epoches):
        # 生成负图
        negative_graph = construct_negative_graph(hetero_graph, k, ('user', 'click', 'item'))   # 为(user click item) 类型的边 生成负图
        negative_graph.to(device)
        pos_score, neg_score = model(hetero_graph, negative_graph, node_features, ('user', 'click', 'item'))
        loss = compute_loss(pos_score, neg_score)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        print(loss.item())

if __name__ == '__main__':
    main()
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用DGL创建自己的数据集来用于分类,可以按照以下步骤操作: 1.准备数据:将形数据存储为形文件或使用Python脚本生成形数据。确保每个节点都有唯一的ID,并且形数据以节点和边列表的形式存储。 2.使用DGL创建Graph对象:使用DGL创建一个空形对象,并使用节点和边列表填充它。 3.添加标签:为每个节点添加标签,这将成为我们的目标变量。标签可以是任何类型的标记,例如整数或字符串。 4.划分数据集:将数据集划分为训练集、验证集和测试集。 5.使用DGLDataset创建自定义数据集:使用DGL提供的DGLDataset类创建自定义数据集。在这个类中,你需要实现__init__、__getitem__和__len__方法。__init__方法用于加载数据,__getitem__方法用于返回单个数据样本,__len__方法用于返回数据集的大小。 6.创建数据加载器:使用DGL提供的Dataloader类创建数据加载器。 7.训练和测试:使用创建的数据加载器进行训练和测试。 以下是一个简单的示例,演示如何使用DGL创建自己的数据集: ```python import dgl from dgl.data import DGLDataset from dgl.dataloading import GraphDataLoader class MyDataset(DGLDataset): def __init__(self): super().__init__(name='mydataset') # Load data and labels # data is a list of tuples (src, dst) # labels is a list of integers self.data, self.labels = load_data_and_labels() # Create a DGL graph object self.graph = dgl.graph((self.data[:, 0], self.data[:, 1])) # Add labels to nodes self.graph.ndata['label'] = self.labels # Split dataset into train, validation, and test sets self.train_idx, self.valid_idx, self.test_idx = split_dataset() def __getitem__(self, idx): return self.graph, self.graph.ndata['label'][idx] def __len__(self): return len(self.graph) # Create a data loader dataset = MyDataset() train_loader = GraphDataLoader(dataset, batch_size=32, shuffle=True) # Train and test the model for epoch in range(num_epochs): for batched_graph, labels in train_loader: # Train the model pass # Test the model for batched_graph, labels in test_loader: # Evaluate the model pass ``` 在这个示例中,我们首先使用load_data_and_labels函数加载数据和标签,然后使用dgl.graph函数创建一个DGL对象。我们将标签作为节点数据添加到形中,并使用split_dataset函数将数据集划分为训练、验证和测试集。 接下来,我们使用MyDataset类创建自定义数据集,并使用GraphDataLoader类创建数据加载器。在训练和测试循环中,我们使用数据加载器加载数据,并用它们训练和测试模型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值