python实现排队论模型_python实现TransE模型
⼀般来说,要想训练⼀个模型,⼤致分为四个步骤:数据处理、模型构建、训练模型、测试模型,接下来的内容也会从这四个步骤开始介
绍。
数据处理
FB15K数据是从Freebase(www.freebase)抽取到的⼀系列三元组(同义词集,关系类型,三元组)。该数据集可以看作是3模
张量,描述了同义集之间的三元关系。
总共包含了3种⽂件:
< 36M
< 3.7K
< 4.4M
⾸先我定义了⼀个config.py⽂件⽤来存放⼀些与数据集相关的路径。
class Config(object):    def __init__(self):        super()        ain_fb15k = "./datasets/"    # 训练集路径        st_fb15k = "./datasets/fb15k/test.然后定义了⼀个data_process.py⽂件来对数据集进⾏处理,该⽂件包含⼀个Datasets类⽤来处理数据。
import osfrom config import Configclass Datasets(object):    def __init__(self, config):        super()        fig = config        ity2id = {}       
然后可以在该脚本上看看数据的处理过程。
原数据可以通过load_data⽅法读取,并将其输出
config = Config()datasets = Datasets(config)lines = datasets.load_ain_fb15k)print(lines[:1])
最后在控制台会得到这样的结果
上图中的内容实际上是⼀个三元组,其格式为(头实体,关系,尾实体),只不过实体和关系之间⽤/t隔开,因此,标准的格式应该是
(/m/027rn,/location/country/form_of_government,/m/06cx9),这是知识图谱的RDF表⽰形式。知道了读取的数据格式,就可
以对其进⾏处理,⾸先,计算机是很难处理字符型数据的,此外字符类型数据作为存储的话会占⽤⽐较⼤的内存空间,因此需要将这种字符
类型的数据转换为one-hot编码,这⾥采⽤索引的⽅式,通过调⽤build_data2id⽅法来完成。
datasets.build_data2id()print("entity to index:")print(ity2id.items())[:1])print("relation to index:")print(lation2id.items())[:1])
上⾯是输出了构建好的实体到索引映射的第⼀条和关系到索引映射的第⼀条,然后在控制台就可以看到输出的结果:
前⾯说的,计算机不好直接处理字符类型,所以我们需要把输⼊模型的数据也转换为这种索引类型的,以下⾯这条三元组为例:
转换后的结果就变为,表⽰索引为0的实体与索引为1的实体存在着索引0的关系。这种原始数据到索引表⽰的数据的处理是通过build_data
⽅法来实现的。
entity_set, relation_set, triple_list = datasets.build_data()
这样⼦就构建好了模型需要的数据格式。
模型构建
这部分主要介绍TransE是怎么实现的,在[1]中,论⽂给出了TransE模型的算法伪代码。
分析上⾯的伪代码,可以看到TransE的算法分为两个步骤:初始化initialize和loop下的训练部分。根据上述伪代码可以通过定义⼀个TransE.py,该⽂件中实现了TransE模型。
from utils import distanceL1, distanceL2import numpy as npimport randomimport timeimport copyimport codecsclass TranSE(object):    def __init__(self, e
在初始化阶段,对应TranSE类中的embedding_init⽅法,该⽅法将每个关系实体都初始化了⼀个embedding维度的向量,最后
其中表⽰的是正确实体(正例)和破坏后错误实体(负例)的⼀个集合。在看论⽂的时候,怎么破坏⼀个正例是⽐较核⼼的内容,论⽂中说:
因此,每⼀个实体只破坏头实体或者尾实体,对应TranSE类中的corrupt_triple⽅法。
def corrupt_triple(self, triple):        '''        The set of corrupted triplets is composed of training triplets        with either the head or tail replaced by a rando
这⾥我使⽤⼀个随机数种⼦对输⼊的三元组随机破坏头实体或者尾实体。
python怎么读取py文件update embeddings
TransE模型的核⼼是训练得到实体和关系所对应的embedding向量,最后就是根据破坏掉的实体,结合损失函数对embedding进⾏训练
更新,论⽂采⽤的损失函数⽅程如下所⽰:
上式中的表⽰的是正值,其实就是hinge loss,因此我在TransE类中定义了update_embeddings⽅法和hinge_loss⽅法,embedding更新需要对上式进⾏求导,然后根据梯度不断更新,需要注意的是,上⾯这个式⼦的梯度更新需要将与分开更新。
def update_embeddings(self, Tbatch):        copy_entities = copy.ities)        copy_relations = copy.lations)        for triple
⽂章中对向量相似度的刻画采⽤的是L1-norm或者L2-norm,我在utils.py中定义了这两个函数,专门⽤来计算embedding之间的相似
度,在代码中我才⽤L1-norm来作为相似度衡量,也可以换成L2-norm,只需要在模型初始化的时候将norm参数设置成L2-norm即可。Training
在上⾯的基础上,进⾏模型的训练,我编写了train.py⽂件,调⽤上⾯说的⼏个⽂件进⾏训练。
from config import Configfrom data_process import Datasetsfrom TranSE import TranSEif __name__=="__main__":    config = Config()    datasets = Datas
这个训练好的只是实体和关系的embedding向量,还需要对其性能进⾏测试,在这⾥我采⽤链接预测任务,衡量指标是hits10和mean rank,性能测试代码对应test.py中。
from config import Configfrom data_process import Datasetsimport numpy as npimport timeimport operatorimport codecsdef load_data2id(config):    # ent 得到下⾯训练400代的效果:
hits:  5720 rank sum:  3262746
hits:  11407 rank sum:  6664410
hits:  17174 rank sum:  10058771
hits:  22906 rank sum:  13428817
hits:  28650 rank sum:  16678083
hits:  34355 rank sum:  19921455
hits:  40085 rank sum:  23137841
hits:  45819 rank sum:  26537245
hits:  51561 rank sum:  29760948
hits:  57313 rank sum:  32927922
hits:  63045 rank sum:  36246251
hits10:  0.5731746542296559 mean rank:  658.1611619915018
cost time: 19170 second
这个效果距离论⽂中的还是存在⾮常⼤的差距的,可能跟训练的epochs不够久有⼀定关系,还有就是,训练的⾮常久,下⼀步会采⽤pytorch进⾏重写。
参考⽂献
[1] Antoine Bordes, Nicolas Usunier, Alberto Garcia-Duran, Jason Weston, Oksana Yakhnenko. Translating Embeddings for Modeling Multi-relational Data. Neural Information Processing Systems (NIPS), Dec 2013, South Lake Tahoe, United States. pp.1-9. ⟨hal-00920777⟩

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。