KGCN---pytorch代码(3)---model

代码:

import sys
import torch
import torch.nn.functional as F
import random
import numpy as np
import copy
from aggregator import Aggregator

class KGCN(torch.nn.Module):
    def __init__(self, num_user, num_ent, num_rel, kg, args, device):
        super(KGCN, self).__init__()
        self.num_user = num_user    #分别存储用户、实体和关系的数量
        self.num_ent = num_ent
        self.num_rel = num_rel
        self.n_iter = args.n_iter   #图卷积网络中的迭代次数或层数。每一次迭代代表从当前实体出发进一步探索其邻居的过程
        self.batch_size = args.batch_size   #批量大小
        self.dim = args.dim   #嵌入维度,这是用户、实体和关系向量的维度
        self.n_neighbor = args.neighbor_sample_size   #邻居采样大小
        self.kg = kg   #接收知识图谱数据
        self.device = device   #指定模型运行的设备(如CPU或GPU)
        self.aggregator = Aggregator(self.batch_size, self.dim, args.aggregator)  #聚合器初始化
        
        self._gen_adj()  #预处理知识图谱数据

        #嵌入层初始化    
        self.usr = torch.nn.Embedding(num_user, args.dim)  
        self.ent = torch.nn.Embedding(num_ent, args.dim)
        self.rel = torch.nn.Embedding(num_rel, args.dim)
        
    def _gen_adj(self):
        '''
        Generate adjacency matrix for entities and relations
        Only cares about fixed number of samples
        '''                  #为知识图谱中的实体生成邻接矩阵
        self.adj_ent = torch.empty(self.num_ent, self.n_neighbor, dtype=torch.long)
        self.adj_rel = torch.empty(self.num_ent, self.n_neighbor, dtype=torch.long)  
        #通过 torch.empty 方法创建两个空的PyTorch张量(self.adj_ent 和 self.adj_rel)
        #,分别用于存储实体的邻居和与这些邻居相关联的关系。这些张量的维度都是 [self.num_ent, self.n_neighbor],
        #其中 self.num_ent 是知识图谱中实体的总数,self.n_neighbor 是为每个实体考虑的邻居数量。
        
        for e in self.kg:
            if len(self.kg[e]) >= self.n_neighbor:
                neighbors = random.sample(self.kg[e], self.n_neighbor)   #通过 random.sample 从 self.kg[e] 中随机选择 self.n_neighbor 个邻居
            else:
                neighbors = random.choices(self.kg[e], k=self.n_neighbor)  #通过 random.choices 允许重复地选择邻居,直到达到 self.n_neighbor 个邻居为止
                
            self.adj_ent[e] = torch.LongTensor([ent for _, ent in neighbors])
            self.adj_rel[e] = torch.LongTensor([rel for rel, _ in neighbors])
            #对于选定的邻居,使用列表推导式提取邻居实体和关系,并将它们转换为 torch.LongTensor,分别填充到 self.adj_ent[e] 和 self.adj_rel[e]。
        
    def forward(self, u, v):
        '''
        input: u, v are batch sized indices for users and items
        u: [batch_size]
        v: [batch_size]
        '''
        batch_size = u.size(0)
        if batch_size != self.batch_size:
            self.batch_size = batch_size
        # change to [batch_size, 1]
        #将用户和物品索引的维度从 [batch_size] 重塑为 [batch_size, 1],这是为了使它们能够被嵌入层正确处理。
        u = u.view((-1, 1))
        v = v.view((-1, 1))
        
        # [batch_size, dim]
        user_embeddings = self.usr(u).squeeze(dim = 1)  #通过用户嵌入层 self.usr 获取用户的嵌入向量。self.usr(u) 返回的维度是 [batch_size, 1, dim],使用 .squeeze(dim = 1) 将其压缩为 [batch_size, dim],去除多余的中间维度。
        #这里做改进

        entities, relations = self._get_neighbors(v)   #获取每个物品的邻居实体和关系
        
        item_embeddings = self._aggregate(user_embeddings, entities, relations)  #将用户嵌入、物品的邻居实体和邻居关系进行聚合,以得到最终的物品嵌入表示
        #这里做改进

        scores = (user_embeddings * item_embeddings).sum(dim = 1)  #计算用户嵌入和物品嵌入之间的相似度。这通过对应元素相乘(element-wise multiplication)并在 dim = 1(即每个用户-物品对的嵌入维度上)求和来完成。结果是一个包含每个用户-物品对相似度得分的向量,维度为 [batch_size]。
            
        return torch.sigmoid(scores)  #将得分转换为一个介于0和1之间的预测值,代表用户对物品的偏好程度。
    
    def _get_neighbors(self, v):    #参数 v 是物品的索引,其形状为 [batch_size, 1],表示这个批次中有 batch_size 个物品。
        '''
        v is batch sized indices for items
        v: [batch_size, 1]
        '''
        entities = [v]  #entities 列表被初始化为包含输入物品索引 v 的列表。这意味着 entities 列表的第一个元素是初始的物品索引。
        relations = []
        '''循环执行 self.n_iter 次,其中 self.n_iter 表示图卷积网络中的迭代次数或层数。每一次迭代代表从当前实体出发进一步探索其邻居的过程。
在每次迭代中,通过访问邻接矩阵 self.adj_ent 和 self.adj_rel 来获取当前实体的邻居实体和关系。这里使用 entities[h] 来索引邻接矩阵,h 是当前迭代步骤。由于 entities 初始时包含了物品的索引 v,因此在第一次迭代时,它实际上是获取每个物品的直接邻居。
获取的邻居实体和关系索引通过 .view((self.batch_size, -1)) 调整形状,以确保它们与批量大小相兼容,并通过 .to(self.device) 移动到指定的计算设备上(如CPU或GPU)。
这些邻居实体和关系随后被添加到 entities 和 relations 列表中,为下一次迭代准备。'''
        for h in range(self.n_iter):
            neighbor_entities = torch.LongTensor(self.adj_ent[entities[h]]).view((self.batch_size, -1)).to(self.device)
            neighbor_relations = torch.LongTensor(self.adj_rel[entities[h]]).view((self.batch_size, -1)).to(self.device)
            entities.append(neighbor_entities)
            relations.append(neighbor_relations)
            
        return entities, relations
    
    def _aggregate(self, user_embeddings, entities, relations):
        '''
        Make item embeddings by aggregating neighbor vectors
        '''
        entity_vectors = [self.ent(entity) for entity in entities]    #对于输入的每个实体层(entities 列表中的每个元素),使用实体嵌入层(self.ent)获取对应的嵌入向量。这个列表的每一层代表不同跳数(hop)的邻居实体嵌入。
        relation_vectors = [self.rel(relation) for relation in relations]   #类似地,对于输入的每个关系层(relations 列表中的每个元素),使用关系嵌入层(self.rel)获取对应的嵌入向量。
        

        #聚合邻居向量,通过多次迭代完成,在每次迭代中,根据迭代的次数选择激活函数。最后一层使用 torch.tanh 作为激活函数,其他层使用 torch.sigmoid。
        for i in range(self.n_iter):
            if i == self.n_iter - 1:
                act = torch.tanh
            else:
                act = torch.sigmoid
            
            entity_vectors_next_iter = []  #存储该次迭代后的实体向量
            for hop in range(self.n_iter - i):   #内层循环遍历当前迭代步骤之后的每一跳(hop)的实体向量和关系向量,将它们与用户嵌入一起,通过聚合器 self.aggregator 进行聚合。
                vector = self.aggregator(   #self.aggregator 接收当前层的实体向量(self_vectors)、下一层的邻居实体向量(neighbor_vectors)、与这些邻居相关的关系向量(neighbor_relations)和用户嵌入(user_embeddings)作为输入,并通过指定的激活函数 act 生成聚合后的向量。
                    self_vectors=entity_vectors[hop],
                    neighbor_vectors=entity_vectors[hop + 1].view((self.batch_size, -1, self.n_neighbor, self.dim)),
                    neighbor_relations=relation_vectors[hop].view((self.batch_size, -1, self.n_neighbor, self.dim)),
                    user_embeddings=user_embeddings,
                    act=act)
                entity_vectors_next_iter.append(vector)    #聚合后的向量被添加到 entity_vectors_next_iter 列表中,为下一次迭代更新 entity_vectors
            entity_vectors = entity_vectors_next_iter
        
        #经过 self.n_iter 次迭代后,entity_vectors 列表中仅包含最终聚合后的实体向量(在最后一次迭代中生成)。函数最终将这个向量的形状调整为 (self.batch_size, self.dim) 并返回,作为物品的最终嵌入表示。
        return entity_vectors[0].view((self.batch_size, self.dim))

KGCN类:

__init__:

1.self.num_user,self.num_ent,self.num_rel:

分别存储用户、实体和关系的数量

2.self.n_iter

图卷积网络中的迭代次数或层数。每一次迭代代表从当前实体出发进一步探索其邻居的过程。

3.self.batch_size,self.dim

批量大小,嵌入维度(用户、实体和关系向量的维度)

4.self.n_neighbor

邻居采样大小

5.self.kg

接收的知识图谱数据

6.self.device

指定模型运行的设备(如CPU或GPU)

7.self.aggregator

聚合器初始化  KGCN---pytorch代码(2)---aggregator-CSDN博客

8.self._gen_adj()

预处理知识图谱数据

9.self.usr,self.ent,self.rel

嵌入层初始化

 _gen_adj:(预处理知识图谱数据)

  1. 为知识图谱中的实体生成邻接矩阵
  2. 邻接矩阵中,每个实体对应着self.n_neighbor个邻居以及对应的关系(不足self.n_neighbor个邻居的需要随机重复选择)
  3. self.adj_ent  邻居实体邻接矩阵
  4. self.adj_rel   邻居关系邻接矩阵

forward(self, u, v):

  1. u: [batch_size],v: [batch_size]

  2. 获取用户嵌入

  3. 获取项目邻居

  4. 聚合项目及邻居,得到项目编码

  5. 得到分数

  6. 对分数进行SIGMOD处理

_get_neighbors(self, v):

  1. 输入:v: [batch_size, 1]
  2. 输出:entities:[v,[xxxxxxx],[xxxxxxxx],...[xxxxxxxx]],relations:[[xxxxxxx],[xxxxxxxx],...[xxxxxxxx]]

_aggregate:

  1. 对于entities和relations中的每一组元素(即知识图谱中的每一层)进行嵌入表示。
  2. 迭代self.n_iter次,得到项目的编码(最后一次用tanh激活函数,其他用sigmoid激活函数)

  3. 获得项目编码[self.batch_size, self.dim]

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值