515. Google AI4Code – Understand Code in Python Notebooks | AI4Code
该模型基于将问题视为回归任务,其中已知的代码单元相对位置被分配一个介于0到1之间的值,而预测的Markdown单元位置可以取-0.2到1.2之间的值。通过这种方式,我对代码单元施加了归纳偏置,并允许Markdown单元放置在代码单元之前或之后的任何位置。
模型架构如下:
首先,分词后的(CodeBERT分词器)代码和Markdown单元分别输入到CodeBERT中。仅选取CodeBERT输出的第一个潜在代码和Markdown向量:
x_code = self.code_bert(code_tokens.flatten(0,1),
attention_mask=code_mask.flatten(0,1).to(device))\
.last_hidden_state.view(*code_tokens.shape[:3],-1)[:,:,0,:]
然后,将位置编码添加到潜在代码向量中,作为编码器的输入。编码器的输出随后与潜在Markdown向量一起(作为上下文)输入到解码器中,解码器可以关注所有单元(代码和Markdown)之间的交互。解码器的输出最终输入到回归器中,输出Markdown单元的位置预测。
模型仅使用比赛提供的数据集进行训练。与其他解决方案相比,训练中唯一显著的区别在于,我没有使用MSE或MAE作为损失函数,而是尝试使用受Spearman Rho启发的损失函数来近似Kendall Tau,该函数内部使用软排名,使其具有可微性。
def spearman_p_loss(pred, target_ranks, **kw):
d2 = 0.
n = 0.
for p,t in zip(pred.flatten(1),target_ranks.flatten(1)):
mask = t != -1
rp = soft_rank(p[mask].unsqueeze(0), **kw) - 1.
rt = t[mask].unsqueeze(0)
d2 += (rt-rp).square().sum()
n += mask.sum()
return 4. * d2/ ((n*(n-1)))
参考链接:维基百科:斯皮尔曼等级相关系数
我注意到计算Kendall Tau的代码有点慢,即使是基于二分查找的版本也是如此。因此,作为一个有趣的实验,我加快了它的速度,并在没有任何循环(且批量化)的情况下实现了它:
def update(self,preds,index_gt):
masks = index_gt != -1
_preds=preds.clone()
_index_gt = index_gt.clone()
m = masks.flatten(1)
_index_gt[~masks] = MAX_CELLS*2
_preds[~masks] = np.inf
pred_ranks = _preds.flatten(1).argsort(dim=1)
ranks=torch.gather(_index_gt.flatten(1),1,pred_ranks)
self.inversions += torch.triu((ranks.unsqueeze(1).permute(0,2,1)>ranks.unsqueeze(1))).sum()
len_gt = masks.sum(dim=(1,2))
self.total_2max +=((len_gt-1)*len_gt).sum()
def compute(self):
return 1. - 4. * self.inversions / self.total_2max
由于在截止日期前一个月才参加比赛,我的算力和时间都不足,因此我的模型最终训练不足。
我非常享受这次比赛,咱们下一场见!