一文教你深挖6万篇论文、50万学者信息,瓜分10万元奖金丨Baseline详解


推荐算法支配着半个互联网世界的运转,加快了信息和价值的流通速度。

然而,面对同样海量且更讳莫如深的学术信息,算法能否判断,一篇冷门角落里的论文,比一篇在自媒体上刷屏的论文更适合你读。


今年的“未来杯 AI 挑战赛” 赛题——预测一篇论文对哪些学者具有吸引力,便与这个挑战息息相关。


日前,由 “未来杯 AI 挑战赛” 发起,智谱・AI 与 AI TIME 联合承办的 “未来杯 - 智谱人工智能科技探索赛” 正式启动(大赛官网:https://ai.futurelab.tv/contest_detail/21)

该挑战赛总奖金池 100000 元,使用 AMiner 数据提供的数据集,其中包括 6 万篇学术文献信息(含标题、摘要、关键词等),以及 50 万名 “公开专家” 数据集,含 50 万的学者画像信息(包括姓名、研究兴趣、学术指标信息、论文等)。


为此,比赛主办人员、智谱・AI 算法工程师杨珍针对本次大赛baseline进行详细剖析,点击文末 “阅读原文” 即可收看回放。


本文整理出如下 4 个部分baseline干货和具体代码,帮助广大选手进一步理解和参与比赛。

1、赛题解析

2、OAG-BERT介绍

3、数据处理

4、基于OAG-BERT的专家推荐

一、赛题解析及简介

首先是赛题解析。

比赛采用的是AMiner提供的数据集,主要包含了三个部分,第一个部分是论文和专家的数据集,选手需要利用此数据集进行offline的模型训练。

此外,本次比赛还提供了论文的属性数据和专家的属性数据,其中包括了6万篇的学术文献信息,包含了标题、摘要、关键词等信息,以及50万名的公开专家数据,即学者画像信息,包括姓名、研究兴趣、学术指标信息和论文等等。

选手需要做的是,根据这些数据库中的信息,去搭建模型来预测对文章感兴趣的学者。也就是说,通过模型可以预测该论文会吸引到哪些学者的阅读的兴趣。


其实,本次比赛的任务是一个预测问题,只要能够分别学习到论文和专家的embedding,也就是嵌入表示之后,计算论文和专家的相似度,就可以进行专家推荐了。

二、OAG-BERT介绍

简单介绍一下OAG-BERT。这是清华大学唐杰老师课题组做的一项工作, OAG-BERT的训练语料库为Open Academic Graph,考虑title、abstract、venue等异构实体信息。

关于OAG-BERT的详细内容可以阅读我们arXiv上的paper:https://arxiv.org/abs/2103.02410。

同时,我们也给出OAG-BERT的GitHub的代码链接:https://github.com/THUDM/cogdl/tree/master/cogdl/oag。

三、数据处理

在数据处理部分,使用的是AMiner数据开放计划的公开论文和公开专家数据。

首先是论文专家数据集,有论文的id,以及这篇论文评审专家的id集合,如上图所示, id代表的是论文, experts代表的是不同的专家。

第二部分是论文和专家的属性信息。

在此说明一下论文的属性信息,论文的属性信息有包括title、abstract、中文 key words、year等等。如下表所示,对于每一个字段都有一个详细的描述。

有了这些id、title、abstract中文之后,用这些属性信息作为feature的话,肯定是要进行一定的选择,下文会介绍如何处理。


第三个部分是专家的属性信息,包括专家的id、中文name、interest、target、学术指标以及他所发表的一些论文等。

我们采用的这些数据中,最重要的就是论文专家数据,因为这个数据集是训练的主要数据。

至于论文的属性信息,包括专家的属性信息,可以作为feature去用。

接下来来看数据集的划分,也就是对于paper-expert pairs的划分原则是什么呢?

我们需要构建的是paper和experts的pairs,希望借助这样的一个样本对来分别学习到paper embedding和expert embedding,然后根据竞赛的要求,进行top-K召回,为每一篇paper召回500个相关的ex。

因此,划分的原则是,对每一篇paper,与该paper交互的所有的experts,随机选择一个作为test,再选择一个作为valid,其余的experts作为train。这里,当该paper交互的experts少于3人时,我们将该paper和其交互的experts全部作为train data。

这是我们对于训练集的一个构造处理的方式,还有一种方式是可以随机采样80%作训练集,20%作为测试集,其中把这个80%训练集再划分出来,10%作为它的验证集都可以。


但是在做baseline的时候,采取的是一篇作test,再选择一篇作validation,其余都作train。

介绍完划分原则之后,来对paper-expert pairs进行预处理。

对于paper而言,给定的数据集中,每一篇paper会包含多种属性,包括id、 title、 abstract、 key words等等中英文版本都会有,我们选择title 、abstract和key words英文版这三个属性来作为paper的feature,进行预处理。

对这些feature进行处理,肯定需要NLP领域的一些知识。

这里我们选择的是OAG-BERT来将paper的这些属性作为feature输入。

值得注意的是,输入到OAG-BERT的是一段sequence,而这里的keywords是list,我们需要将其处理成sequence,具体的做法是将keywords逐次相连成一个sequence,每个keyword之间用空格隔开。

title和abstract不用多做处理。它们可以直接输入到OAG-BERT。

继续看一下关于expert,即关于专家信息的处理。

在给定的数据集中,每个专家也会有多种的属性来,包括id、 interest等等,需要注意的一点是,对于experts而言的话,它有它本身的属性,但也有从侧面来反映expert feature信息的东西,比如发表论文的信息。

为了简单起见,我们选择了两个部分,第一个部分把 interest作为它的feature来用。interest作为每个expert研究兴趣的话,能代表专家的一部分学者画像。若是interests为空,选择tags为研究兴趣,或者tags也为空,则interests为空。


除此之外,pub_info也是表从侧面反映了学者画像。

pub_info中包含了该expert发表的论文,这里我们同样选择title、abstract及keywords作为feature。

基本的数据处理之后,下面来了解基于OAG-BERT的专家推荐。

四、基于OAG-BERT的专家推荐

我们选择OAG-BERT作为学习embedding的模型。

OAG-BERT以每篇paper的title、keywords、abstract作为输入,来得到每一篇paper的embedding表示。这里,需要先得到每篇paper的title、keywords、abstract等的token表示,而非简单的seq句子。具体会在在batch数据的得到中详细讲述。


对于batch数据,需要得到batch数据,进行OAG-BERT的finetune训练。

值得注意的是,给定的数据集中只包含有paper-expert正的交互项,没有负样本,这里我们对每一个正paper-expert选择negs_num个负样本,也就是负采样。

负采样具体的操作是,将该paper没有交互过的所有experts作为负样本的候选集合,然后随机采样negs_num个。这样可以得到batch的数据,包括正、负样本。注意,这里得到的训练样本集合,以单个为例的话就是[一篇paper, 一个正expert,negs_num个负experts]。这样就构成了一个训练样本。

得到了batch数据之后,OAG-BERT和BERT是类似的,输入的并不是sequence本身,而是token化的一个东西,接下来就要对batch数据进行token化处理。

借助OAG-BERT的build_inputs()函数得到OAG-BERT的inputs——token化的inputs。

这里的input tokens包括input_ids、input_masks、token_type_ids、masked_lm_labels、position_ids、position_ids_second、masked_positions、num_spans。详细操作可以看github上OAG-BERT详细使用说明。

之后,就可以把它输到OAG-BERT中。


第一步,获得paper embedding。

我们的OAG-BERT的输入需要input_ids、input_masks、token_type_ids、position_ids、position_ids_second作为输入,输出paper的embedding表示。


然后,获得expert embedding。

当得到expert的tokens后,可以将其输入到OAG-BERT,得到expert的embedding。

值得注意的是,这里expert的embedding由两部分组成:expert的interests的embedding,expert的pub_info的embedding。

结合interests embedding和pub_info embedding,这里,简单使用torch.mean()来进行merge这两种embedding来得到最终的expert embedding。参赛选手可以对此处进行改进。可以去想一想,怎么样得到更好的expert embedding。

之后,还要获得最终的paper embedding & expert embedding,此时要加入MLP去非线性变换了OAG-BERT得到的embedding,以便更好地finetune。


获得完 paper和expert的embedding之后,进入训练环节。此时需要定义loss,在这里我们采用的是 infoNCE 这么一个loss,具体的loss形式如下所示:


最后一个部分是Test/Valid,在valid/test上进行验证/测试。

valid可以用来调整模型的超参,test来测试模型的泛化能力。这些都是offline的测试。最终,保存效果最好的模型参数,再进行online的valid和test。

这里用mrr来作为评价指标,当然,各位选手可以选择给定的评价指标。

注意,由于test时,为每篇paper做全局召回,耗时太大,我们采用的是随机sample 100个负样本,与test/valid中的正例进行rank。

为了进一步节省test的时间,采用了两种test方式:每个batch共享100个negs;整个test共享100个negs。

接下来,先简单介绍一baseline文件(“数据实战派”后台回复“OAG-BERT”获取下载链接)。

如上图所示,其中,cogdl——这是唐杰老师团队开发的一个工具包,包含了OAG-BERT模型。

主要的代码则分别是:finetune.py--finetune的代码,包括训练和test/valid;finetune_config.py--配置代码,包括batch_size等;modeling.py-- loss及MLP;load_data.py--data处理以及token化。

首先是finetune.py代码,分为两个部分先进行load model & data,再进行define loss。

if __name__ == "__main__":
    # create model
    tokenizer, model = oagbert("./saved/oagbert-v2")
    model = model.cuda()
    projection = MLP(config["output_dim"]).cuda()




    # load data
    data_loader = data_loader(model)
    # paper-experts
    train_data, valid_data, test_data = data_loader.train_data, data_loader.valid_data, data_loader.test_data
    print("train_data_length", len(train_data))
    print("valid_data_length", len(valid_data))
    print("test_data_length", len(test_data))
    paper_infos = data_loader.paper_infos
    experts_infos = data_loader.experts_infos
    print("experts_infos.length", len(experts_infos.keys()))


    train_batches = data_loader.get_batch(train_data, batch_size)
    valid_batches = data_loader.get_batch(valid_data, 10*batch_size)
    test_batches = data_loader.get_batch(test_data, 10*batch_size)
    print("train_batches", len(train_batches))
    print("valid_batches", len(valid_batches))
    print("test_batches", len(test_batches))


    # infoNCE loss
    criterion = infoNCE().cuda()
    optimizer = torch.optim.Adam([{'params':model.parameters()},{'params': projection.parameters()}], lr=config["learning_rate"])


    model.train()
    projection.train()
    best_mrr = -1
    patience = 0

接下来是详细的训练代码:

# finetuning
    for epoch in range(epochs):
        random.shuffle(train_batches)
        batch_loss = []
        batch_num = 0
        for batch in train_batches:
            batch_num += 1
            # get anchor pos neg
            anchor, pos, neg = data_loader.generate_batch_data(paper_infos, experts_infos, batch, config["neg_num"]) 


            anchor_tokens = data_loader.get_batch_tokens(anchor, "anchor") 
            pos_tokens = data_loader.get_batch_tokens(pos, "pos")
            neg_tokens = data_loader.get_batch_tokens(neg, "neg")


            anchor_emb = get_batch_embed(anchor_tokens, "anchor")
            pos_emb = get_batch_embed(pos_tokens, "pos")
            neg_emb = get_batch_embed(neg_tokens, "neg")


            # add MLP 
            # infoNCE loss 
            loss = criterion(projection(anchor_emb), projection(pos_emb), projection(neg_emb))
            print("loss...", loss.item())


            # compute gradient and do Adam step
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()


            if batch_num > 1 and batch_num % valid_step == 0:
                print("evalute.......")
                t_valid = time()
                mrr = evaluate(model, valid_batches, data_loader, paper_infos, experts_infos)
                print("time for valid....", time() - t_valid)
                print("Epoch:{} batch:{} loss:{} mrr:{}".format(epoch, batch_num, loss.item(), mrr))
                if mrr > best_mrr:
                    best_mrr = mrr
                    # save model
                    torch.save(model.state_dict(), output_dir + "oagbert")
                    print("Best Epoch:{} batch:{} loss:{} mrr:{}".format(epoch, batch_num, loss.item(), mrr))
                else:
                    patience += 1
                    if patience > config["patience"]:
                        print("Best Epoch:{} batch:{} loss:{} mrr:{}".format(epoch, batch_num, loss.item(), mrr))


                model.train()
                projection.train()

以上便是整个finetune的大体代码。

接下来,get embeddings的代码如下:

def get_batch_embed(batch_tokens, flag):
    # get embed
    batch_embed = []
    for tokens in batch_tokens:
        for p_id, token in tokens.items():
            if flag == "anchor":
                input_ids, input_masks, token_type_ids, masked_lm_labels, position_ids, position_ids_second, maksed_positions, num_spans = token
                _, pooled_output = model.bert.forward(
                    input_ids=torch.LongTensor(input_ids).unsqueeze(0).cuda(),
                    token_type_ids=torch.LongTensor(token_type_ids).unsqueeze(0).cuda(),
                    attention_mask=torch.LongTensor(input_masks).unsqueeze(0).cuda(),
                    output_all_encoded_layers=False,
                    checkpoint_activations=False,
                    position_ids=torch.LongTensor(position_ids).unsqueeze(0).cuda(),
                    position_ids_second=torch.LongTensor(position_ids_second).unsqueeze(0).cuda())
                batch_embed.append(pooled_output)
            else:
                # experts embedding
                # interests process
                interests = token["interests"]
                #print("interests", interests)
                input_ids, input_masks, token_type_ids, masked_lm_labels, position_ids, position_ids_second, maksed_positions, num_spans = interests
                if input_ids != []:
                    _, pooled_output_expert_interests = model.bert.forward(
                        input_ids=torch.LongTensor(input_ids).unsqueeze(0).cuda(),
                        token_type_ids=torch.LongTensor(token_type_ids).unsqueeze(0).cuda(),
                        attention_mask=torch.LongTensor(input_masks).unsqueeze(0).cuda(),
                        output_all_encoded_layers=False,
                        checkpoint_activations=False,
                        position_ids=torch.LongTensor(position_ids).unsqueeze(0).cuda(),
                        position_ids_second=torch.LongTensor(position_ids_second).unsqueeze(0).cuda())
                else:
                    pooled_output_expert_interests = None
                # pub_info of experts process
                pub_info = token["pub_info"]
                pub_info_embed = []
                for pid, p_token in pub_info.items():
                    input_ids, input_masks, token_type_ids, masked_lm_labels, position_ids, position_ids_second, maksed_positions, num_spans = p_token
                    if input_ids != []:
                        _, pooled_output_expert_pub = model.bert.forward(
                            input_ids=torch.LongTensor(input_ids).unsqueeze(0).cuda(),
                            token_type_ids=torch.LongTensor(token_type_ids).unsqueeze(0).cuda(),
                            attention_mask=torch.LongTensor(input_masks).unsqueeze(0).cuda(),
                            output_all_encoded_layers=False,
                            checkpoint_activations=False,
                            position_ids=torch.LongTensor(position_ids).unsqueeze(0).cuda(),
                            position_ids_second=torch.LongTensor(position_ids_second).unsqueeze(0).cuda())
                        pub_info_embed.append(pooled_output_expert_pub)


                # merge interests_embed and pub_info_embed
                # here, we use torch.mean() for merge
                # check...
                if pooled_output_expert_interests == None:
                    if len(pub_info_embed) != 0:
                        pooled_output_expert_cat = torch.cat(pub_info_embed)
                    else:
                        pooled_output_expert_cat = None
                else:
                    if len(pub_info_embed) != 0:
                        pooled_output_expert_cat = torch.cat((pooled_output_expert_interests, torch.cat(pub_info_embed)), 0)
                    else:
                        pooled_output_expert_cat = pooled_output_expert_interests
                pooled_output_expert_final = torch.mean(pooled_output_expert_cat, 0).view(1, config['output_dim'])
                batch_embed.append(pooled_output_expert_final)
    return torch.cat(batch_embed, 0)  

test/valid的部分如下:

def evaluate(model, valid_batches, data_loader, paper_infos, experts_infos):
    model.eval()
    mrr = 0.0
    total_count = 0
    with torch.no_grad():
        """
        整个test公用一个negs
        """
        negs = data_loader.generate_negs_data(paper_infos, experts_infos, config["Negs"])
        neg_tokens = data_loader.get_batch_tokens(negs, "neg")
        neg_emb_candidates = get_batch_embed(neg_tokens, "neg")
        """
        share batch negs
        """
        for batch in valid_batches:
            anchor, pos, _ = data_loader.generate_batch_data_test(paper_infos, experts_infos, batch, config["Negs"])


            # use too much time
            anchor_tokens = data_loader.get_batch_tokens(anchor, "anchor") 
            pos_tokens = data_loader.get_batch_tokens(pos, "pos")


            # use too much time
            anchor_emb = get_batch_embed(anchor_tokens, "anchor")
            pos_emb = get_batch_embed(pos_tokens, "pos")
            neg_emb = neg_emb_candidates.repeat(len(batch), 1)
        # batch share negs
        #for batch in valid_batches:
        #    anchor, pos, negs = data_loader.generate_batch_data_test(paper_infos, experts_infos, batch, config["Negs"])


        #    # use too much time
        #    tt = time()
        #    anchor_tokens = data_loader.get_batch_tokens(anchor, "anchor") 
        #    print("time...", time() - tt)
        #    tt = time()
        #    pos_tokens = data_loader.get_batch_tokens(pos, "pos")
        #    print("time...", time() - tt)
        #    tt = time()
        #    neg_tokens = data_loader.get_batch_tokens(negs, "neg")
        #    print("time...", time() - tt)


        #    # use too much time
        #    tt = time()
        #    anchor_emb = get_batch_embed(anchor_tokens, "anchor")
        #    print("time...", time() - tt)
        #    tt = time()
        #    pos_emb = get_batch_embed(pos_tokens, "pos")
        #    print("time...", time() - tt)
        #    tt = time()
        #    neg_emb_candidates = get_batch_embed(neg_tokens, "neg")
        #    print("time...", time() - tt)
        #    neg_emb = neg_emb_candidates.repeat(len(batch), 1)


            # anchor & pos_embed
            anchor_emb = F.normalize(anchor_emb.view(-1, 1, dim), p=2, dim=2)
            pos_emb = F.normalize(pos_emb.view(-1, 1, dim), p=2, dim=2)
            neg_emb = F.normalize(neg_emb.view(-1, config["Negs"], dim), p=2, dim=2)


            pos_score = torch.bmm(anchor_emb, pos_emb.transpose(1, 2)) # B*1*1
            neg_score = torch.bmm(anchor_emb, neg_emb.transpose(1, 2))  # B*1*Negs


            # logits:B*(1+Negs)
            logits = torch.cat([pos_score, neg_score], dim=2).squeeze()
            logits = logits.cpu().numpy()


            for i in range(batch_size):
                total_count += 1
                logits_single = logits[i]
                rank = np.argsort(-logits_single)
                true_index = np.where(rank==0)[0][0]
                mrr += np.divide(1.0, true_index+1)


        mrr /= total_count


    return mrr

介绍完finetune.py的代码,来看finetune_config.py,即配置代码,包括batch_size下图显示的部分等。

config = {
    "train_ratio": 0.8,
    "valid_ratio": 0.1,
    "batch_size": 2,
    "epochs": 10,
    "output_dim": 768,
    "neg_num": 2, 
    "learning_rate": 2e-5,
    "valid_step": 5000,
    "Negs": 100,
    "patience": 5,
    }

然后是modeling.py,包括 loss及MLP,如下图所示:

# infoNCE loss
class infoNCE(nn.Module):
    def __init__(self):
        super(infoNCE, self).__init__()
        self.T = 0.07
        self.cross_entropy = nn.CrossEntropyLoss().cuda()


    def forward(self, query, pos, neg):
        query = F.normalize(query.view(batch_size, 1, dim), p=2, dim=2)
        pos = F.normalize(pos.view(batch_size, 1, dim), p=2, dim=2)
        neg = F.normalize(neg.view(batch_size, K, dim), p=2, dim=2)


        pos_score = torch.bmm(query, pos.transpose(1, 2)) # B*1*1
        neg_score = torch.bmm(query, neg.transpose(1, 2))  # B*1*K


        # logits:B*(K+1)
        logits = torch.cat([pos_score, neg_score], dim=2).squeeze()
        logits /= self.T


        labels = torch.zeros(logits.shape[0], dtype=torch.long).cuda()


        info_loss = self.cross_entropy(logits, labels)


        return info_loss
class MLP(nn.Module):
    def __init__(self, in_dim):
        super(MLP, self).__init__()
        self.projection = nn.Sequential(
            nn.Linear(in_dim, in_dim),
            nn.ReLU(),
            nn.Linear(in_dim, in_dim)
        )


    def forward(self, x):
        x = self.projection(x)
        return x

第四个部分是load_data.py,包括get paper-expert pairs、划分数据集等。

get train, valid, test data form training_set
        """
        with open(self.data_dir+'training_set/results.json', 'r') as f:
            self.raw_data_dict = json.load(f)
        # train_data, valid_data, test_data
        self.train_data_dict, self.valid_data_dict, self.test_data_dict = self.get_examples(self.raw_data_dict) 
        print("Train:{} Valid:{} Test:{}".format(len(self.train_data_dict.keys()), len(self.valid_data_dict.keys()), len(self.test_data_dict.keys())))
        self.train_data = self.get_data_pairs(self.train_data_dict) 
        self.valid_data = self.get_data_pairs(self.valid_data_dict) 
        self.test_data = self.get_data_pairs(self.test_data_dict)     

在get pairs之后,如下是get paper infos、get expert infos的代码部分:

def load_data(self):
        """
        get paper info
        """
        with open(self.data_dir+'training_set/publications.json', 'r') as f:
            self.raw_paper_infos = json.load(f)
        print("self.raw_paper_infos", len(self.raw_paper_infos))
        self.paper_infos = self.get_papers(self.raw_paper_infos)
        print("self.paper_infos", len(self.paper_infos.keys()))


        """
        get experts info
        """
        with open(self.data_dir+'experts/experts0.json', 'r') as f:
            self.raw_experts_0 = json.load(f)
        print("self.raw_experts_0", len(self.raw_experts_0))    
        self.experts_infos_0 = self.get_experts(self.raw_experts_0) 
        print("self.experts_infos_0", len(list(self.experts_infos_0.keys())))


        with open(self.data_dir+'experts/experts1.json', 'r') as f:
            self.raw_experts_1 = json.load(f)
        print("self.raw_experts_1", len(self.raw_experts_1))    
        self.experts_infos_1 = self.get_experts(self.raw_experts_1) 
        print("self.experts_infos_1", len(list(self.experts_infos_1.keys())))


        with open(self.data_dir+'experts/experts2.json', 'r') as f:
            self.raw_experts_2 = json.load(f)
        print("self.raw_experts_2", len(self.raw_experts_2))    
        self.experts_infos_2 = self.get_experts(self.raw_experts_2) 
        print("self.experts_infos_2", len(list(self.experts_infos_2.keys())))


        with open(self.data_dir+'experts/experts3.json', 'r') as f:
            self.raw_experts_3 = json.load(f)
        print("self.raw_experts_3", len(self.raw_experts_3))    
        self.experts_infos_3 = self.get_experts(self.raw_experts_3) 
        print("self.experts_infos_3", len(list(self.experts_infos_3.keys())))




        with open(self.data_dir+'experts/experts4.json', 'r') as f:
            self.raw_experts_4 = json.load(f)
        print("self.raw_experts_4", len(self.raw_experts_4))    
        self.experts_infos_4 = self.get_experts(self.raw_experts_4) 
        print("self.experts_infos_4", len(list(self.experts_infos_4.keys())))


        self.experts_infos = {**self.experts_infos_0, **self.experts_infos_1, **self.experts_infos_2, **self.experts_infos_3, **self.experts_infos_4}
        print("self.experts_infos", len(list(self.experts_infos.keys())))

load_data.py还包括get batch data 。

def generate_batch_data_test(self, paper_infos, experts_infos, batch, neg_num):
        batch_infos_anchor = []
        batch_infos_pos = []
        batch_infos_neg = []
        # generate anchor, pos, neg 
        batch_experts = []
        for pid, eid in batch:
            p_infos = paper_infos[pid]


            e_infos = experts_infos[eid]


            # build anchor, pos, neg
            # anchor
            anchor_infos = {}
            if pid in anchor_infos:
                print("repeat pid....")
            else:
                anchor_infos[pid] = p_infos
            batch_infos_anchor.append(anchor_infos)


            # pos
            pos_infos = {}
            if pid in pos_infos:
                print("repeat pid in pos_infos...")
            else:
                pos_infos[pid] = e_infos
            batch_infos_pos.append(pos_infos)
            batch_experts.extend(self.train_data_dict[pid])


        # batch share negs
        # random.sample K negs 
        #print("batch_experts", batch_experts)
        negs_id = random.sample(list(set(experts_infos.keys()) - set(batch_experts)), neg_num)
        #print("negs_id", negs_id)
        negs_infos = {}
        for neg in negs_id:
            if neg in negs_infos:
                print("repeat negs in negs_info....")
            else:
                negs_infos[neg] = experts_infos[neg]
                if experts_infos[neg]["interests"] == "" and experts_infos[neg]["pub_info"] == {}:
                    print("experts_empty", experts_infos[neg])
        batch_infos_neg.append(negs_infos)


        return batch_infos_anchor, batch_infos_pos, batch_infos_neg

得到sequence后,下一步是token化:

def get_batch_tokens(self, infos, flag):
        batch_tokens = []
        for info in infos:
            tokens_dict = {}
            for p_id, p_info in info.items():
                # get tokens
                tokens = self.build_bert_inputs(p_info, flag)
                #print("tokens...", tokens)
                if p_id in tokens_dict:
                    print("repeat p_id.....")
                else:
                    tokens_dict[p_id] = tokens
            batch_tokens.append(tokens_dict)
        return batch_tokens




    def build_bert_inputs(self, p_info, flag):
        if flag == "anchor":
            # title & abstract & keywords
            if p_info.get("abstract", None) != None:
                abstract = p_info["abstract"]
            else:
                abstract = ""
            if p_info.get("title", None) != None:
                title = p_info["title"]
            else:
                title = ""
            if p_info.get("keywords", None) != None:
                keywords = p_info["keywords"]
            else:
                keywords = ""
            return self.oagbert.build_inputs(title=title, abstract=abstract, concepts=keywords)
        elif flag == "pos" or flag == "neg":
            # experts
            if p_info.get("interests", None) != None:
                interests = p_info["interests"]
            else:
                interests = ""
            e_tokens = self.oagbert.build_inputs(title=interests, abstract="")
            # prcoess experts'pub infos
            expert_pub_infos = p_info["pub_info"]
            pub_tokens = {}
            for pid, expert_pub_info in expert_pub_infos.items():
                title = expert_pub_info['title']
                abstract = expert_pub_info['abstract']
                keywords_list = expert_pub_info['keywords']
                keywords = ""
                if len(keywords_list) != 0:
                    for word in keywords_list:
                        if word == keywords_list[0]:
                            keywords = word
                        else:
                            keywords = keywords + ' ' + word
                p_tokens = self.oagbert.build_inputs(title=title, abstract=abstract, concepts=keywords)
                if pid in pub_tokens:
                    print("repeat pid....")
                else:
                    pub_tokens[pid] = p_tokens
            tokens = {"interests": e_tokens, "pub_info": pub_tokens}
            return tokens 
        else:
            raise Exception("undefine flag")
            return 

以上便是完整的代码解读。目前比赛仍在招募选手中,添加大赛小助手 —— 微信号:futurelab001,发送数字 “1” 加入【2021 未来杯 - 智谱人工智能科技探索大赛报名交流群】,群内可以进行参赛问题解答、组队邀约、选手交流等。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值