返回列表

11th Place Solution

416. Riiid Answer Correctness Prediction | riiid-test-answer-prediction

开始: 2020-10-05 结束: 2021-01-07 学习效果预测 数据算法赛
第11名方案

第11名方案

作者: Darragh (Grandmaster)
比赛排名: 第11名

感谢我的队友 Akihiko 与我并肩作战,对于我们要说,从社区中学到了很多。也要感谢主办方带来了如此精彩的挑战。祝贺所有参赛者。

该方案深受 Bestfitting 的 TalkingData 方案 启发,我们注意到本次比赛中有很多参与者都曾参加过那个比赛 :)

我们使用了大约 35 个特征(包含原始特征),构建了一个双层 LSTM 模型。每层都是单向的,训练时的序列长度为 256,推理时为 512。
训练的 Batch size 为 2048。隐藏层大小为 512。
示例如下。

第一层

  • embcatq 中使用了以下特征,没有使用连续特征。
  • 第一层中没有标签,类似于 SAINT 论文中的做法。
  • 将部分 Embedding 的差值添加到了最终的 Embedding 中。这为模型提供了信息,表明每个历史问题与样本中当前问题的相似程度。

第二层

  • 输入包含第一层的输出以及连续特征。
  • 添加了问题和所选答案交互的 Embedding。
  • 连续特征是利用 @its7171 的精彩笔记生成的——这也是我希望能多次点赞的原因。
  • 一个重要的特征是答案比率,即选择与当前答案相同选项的学生百分比。

技术细节

如何在内存中处理历史数据是一个问题,但 GPU 上有足够的空间,所以我们先将其加载到 numpy 中,然后转为 GPU 上的 torch 张量(历史特征约占 6GB);然后再将其他对象加载到内存(RAM)中。

Attention 机制对我们没有生效——尽管在验证集上看起来很有希望——也许我们应该坚持下去。我们只是取了 LSTM 的最后一个隐藏单元作为输出。

下面的代码在 Public LB 上获得了约 0.811 的分数,通过对架构进行一些修改并融合四个模型,分数提升到了 Public 0.813,Private 0.816。

class LearnNet(nn.Module):
    def __init__(self, modcols, contcols, padvals, extracols, 
                 dropout = 0.2, hidden = args.hidden):
        super(LearnNet, self).__init__()
        
        self.dropout = nn.Dropout(dropout)
        
        self.modcols = modcols + extracols
        self.contcols = contcols
        
        self.emb_content_id = nn.Embedding(13526, 32)
        self.emb_content_id_prior = nn.Embedding(13526*3, 32)
        self.emb_bundle_id = nn.Embedding(13526, 32)
        self.emb_part = nn.Embedding(9, 4)
        self.emb_tag= nn.Embedding(190, 8)
        self.emb_lpart = nn.Embedding(9, 4)
        self.emb_prior = nn.Embedding(3, 2)
        self.emb_ltag= nn.Embedding(190, 16)
        self.emb_lag_time = nn.Embedding(301, 16)
        self.emb_elapsed_time = nn.Embedding(301, 16)
        self.emb_cont_user_answer = nn.Embedding(13526 * 4, 5)
            
        self.tag_idx = torch.tensor(['tag' in i for i in self.modcols])
        self.cont_wts = nn.Parameter( torch.ones(len(self.contcols)) )
        self.cont_wts.requires_grad = True
        self.cont_idx = [self.modcols.index(c) for c in self.contcols]
        
        self.embedding_dropout = SpatialDropout(dropout)
        
        self.diffsize = self.emb_content_id.embedding_dim + self.emb_part.embedding_dim + \
                        self.emb_bundle_id.embedding_dim + self.emb_tag.embedding_dim * 7 
        IN_UNITSQ = self.diffsize * 2 + \
                    self.emb_lpart.embedding_dim + self.emb_ltag.embedding_dim + \
                        self.emb_prior.embedding_dim + self.emb_content_id_prior.embedding_dim + \
                        len(self.cont_idxcts)
        IN_UNITSQA = ( self.emb_lag_time.embedding_dim + self.emb_elapsed_time.embedding_dim + \
                self.emb_cont_user_answer.embedding_dim) + len(self.contcols)
        LSTM_UNITS = hidden 
        self.diffsize = self.emb_content_id.embedding_dim + self.emb_part.embedding_dim + \
                        self.emb_bundle_id.embedding_dim +