ConvKB代码:A Novel Embedding Model for Knowledge Base Completion Based on Convolutional Neural Network

1 介绍

本篇论文以卷积的方式对知识图谱进行补全,其方法采用CNN的形式进行知识图谱补全,将三元组统一处理,进行评估,评估出得分最高的一组,该方法在论文ConvE的基础上进行改进,其在逻辑实现的过程中十分简单,通过相应的模型图即可知道其原理。

2 模型

2.1 模型图

在这里插入图片描述

2.2 模型解释

  • 将三元组进行embedding,将 ( h , r , t ) (h, r, t) (h,r,t)三元组转化为 ( v h , v r , v t ) \left(\boldsymbol{v}_{h}, \boldsymbol{v}_{r}, \boldsymbol{v}_{t}\right) (vh,vr,vt)三元组的向量形式, 向量的维度为K维。
  • 对三元组进行拼接,形成一个matrix, A = [ v h , v r , v t ] ∈ R k × 3 \boldsymbol{A}=\left[\boldsymbol{v}_{h}, \boldsymbol{v}_{r}, \boldsymbol{v}_{t}\right] \in \mathbb{R}^{k \times 3} A=[vh,vr,vt]Rk×3
  • 对matrix进行卷积, ω ∈ R 1 × 3 \omega \in \mathbb{R}^{1\times3} ωR1×3作为卷积核
  • 对卷积产生的向量进行concat,对拼接的向量进行全链接,判断正确与否
  • 其公式如下[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XM8RAGK4-1646914998519)(C:\Users\Home-PC\AppData\Roaming\Typora\typora-user-images\image-20220310200922633.png)]

2.3 损失函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eiAUXQJe-1646914998524)(C:\Users\Home-PC\AppData\Roaming\Typora\typora-user-images\image-20220310201016779.png)]
softplus函数: S o f t p l u s ( x ) = l o g ( 1 + e x ) Softplus(x)=log(1+e^x) Softplus(x)=log(1+ex),图像参考:机器学习中的数学——激活函数(十):Softplus函数, 如图:
在这里插入图片描述
对于损失函数的解释,在训练时,对数据正负例进行取反操作,使正例损失函数值趋近于0,负例的损失函数不断减少。

3 核心代码

完整代码

class ConvKB(nn.Module):
    def __init__(self, config):
        super(ConvKB,self).__init__()
        self.config = config
        self.device = device
        #进行实体和关系embedding
        self.ent_embeddings = nn.Embedding(config.ent_num, config.dim)
        self.rel_embeddings = nn.Embedding(config.rel_num, config.dim)
        self.bn_1 = nn.BatchNorm2d(1)
        self.conv = nn.Conv2d(1, config.out_channels, (1, 3))#采用1x3的卷积核
        self.bn_2 = nn.BatchNorm2d(self.config.out_channels)
        self.dropout1 = nn.Dropout(0.5)
        self.non_linearity = nn.ReLU()
        #全连接层,将dim*out_channel数据进行线性变换
        self.fc_layer1 = nn.Linear((config.dim)*config.out_channels,1)
        #定义损失函数
        self.criterion = nn.Softplus()
        
        #加载embedding的参数,如果没有则采用nn.init.xavier_uniform_方式进行初始化
    def init(self, ent2vec, rel2vec):
        self.ent_embeddings.weight.data.copy_(torch.from_numpy(ent2vec))
        self.rel_embeddings.weight.data.copy_(torch.from_numpy(rel2vec))
        nn.init.xavier_uniform_(self.fc_layer1.weight.data)
        #nn.init.xavier_uniform_(self.fc_layer2.weight.data)
        nn.init.xavier_uniform_(self.conv.weight.data)

    
    def _calc(self, h, r, t):
        h = h.unsqueeze(1)#batch*1*dim
        r = r.unsqueeze(1)
        t = t.unsqueeze(1)
        
        conv_input = torch.cat([h, r, t], dim = 1)# batch*3*dim
        #print(conv_input.shape)
        conv_input = conv_input.transpose(1, 2)#batch*dim*3
        conv_input = conv_input.unsqueeze(1)#batch*1*dim*3,增加维度1是因为CNN需要通道为1
        out_conv = self.bn_1(conv_input)
        out_conv = self.conv(out_conv)
        out_conv = self.bn_2(out_conv)
        out_conv = self.non_linearity(out_conv)
        out_conv = out_conv.view(-1,(self.config.dim)*self.config.out_channels)
        input_fc = self.dropout1(out_conv)
        score = self.fc_layer1(input_fc)
        score = score.squeeze(1)#注意这里,在调试时没有注意,导致训练出错,难以检测出来
        return score
    
    def loss(self, score, regul, labels):
        #损失函数,取反,使正列趋近于0,负例不断优化,逐渐变小
        return torch.mean(self.criterion(-1*score*labels))+self.config.lambd*regul
        
    
    def forward(self, h, r, t, labels):
        h_embed = self.ent_embeddings(h)
        r_embed = self.rel_embeddings(r)
        t_embed = self.ent_embeddings(t)
        
        score = self._calc(h_embed, r_embed, t_embed)
        
        #正则化
        l2_reg = torch.mean(h_embed**2) + torch.mean(r_embed**2) + torch.mean(t_embed**2)
        
        for W in self.conv.parameters():
            l2_reg += W.norm(2)
        for W in self.fc_layer1.parameters():
            l2_reg += W.norm(2)
        
        return self.loss(score,l2_reg, labels)  
    #预测函数,与_calc函数类似
    def predict(self, h, r, t):
        h_embed = self.ent_embeddings(h)
        r_embed = self.rel_embeddings(r)
        t_embed = self.ent_embeddings(t)
        
        
        score = self._calc(h_embed, r_embed, t_embed)
        return score.cpu().data.numpy()
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值