【复赛前排分享(一)】上分有路勤为径,大神教你剖析提分点
- 2020 年 12 月 16 日
- AI
2020腾讯广告算法大赛复赛已经落幕,决赛答辩终极一战即将在8月3日14:00深圳腾讯滨海大厦举行。了解决赛详情并预约直播观赛,请点击:
外部赛场战况激烈,腾讯公司也联合码客开启了面向员工的内部赛道。其中,chizhu团队强势上分,夺得内部榜第一名的好成绩。作为初赛便跻身前七名的实力队伍,本次的复赛排名也是实至名归。今天,chizhu受邀来分享他们针对本次赛题提分点优化的解题策略,为决赛前的你提供一些灵感。
本次比赛的主要思路还是按照我之前分享的——
以下是我们对本次赛题的一些理解和思路:
01 赛题解读
本届腾讯广告算法大赛的题目是用户画像,即根据用户点击广告的序列预测用户的年龄和性别。
02 赛题分析
这个题目对于我而言再熟悉不过了,因为之前的易观赛和华为赛也是预测年龄和性别。我们团队有幸在这两个比赛都取得第一名的好成绩。针对此类型的赛题,我们团队磨合出了一种思路,即先把id看成一个词,然后把id拼接起来连成一个句子,于是我们的任务就变成了一个脱敏场景下的文本分类问题。
03 词向量
回到正题,既然是文本分类,不可或缺的自然是文本表示——词向量。最常见的自然是word2vec,这里分享下个人的小经验:在数据量大的情况下采用skip-gram效果会好些,本次题目还有个重要参数window,实验发现从10提升到60可以提升将近3个千分点。我也尝试了fasttext词向量,不过同等参数下效果要差一个百分点。同时,词向量的维度也是一个提分点,我们尝试把维度从128提高到300维,也就是提升了将近4个千分点。我们之所以这么做,主要是因为本次赛题数据量大,参数大模型大效果会更好。
04 模型搭建
我采用的主体模型如下:

Why not bert here?虽然bert在NLP届的霸主地位不可动摇,但我们考虑到了本次赛题的特殊性,最强的creative_id的词表共有300w+个,从头预训练一个bert的成本是非常高的。而且经过我的尝试,效果也不尽如人意。
模型详情:将creative_id,ad_id,adv_id序列输入emb层,emb层的参数冻结不做更新,然后将这四个序列对应的emb拼接起来,这样做的好处是可以增加词的表征能力,同时接下来就只需要一个LSTM往下接,对比分散的四个emb,可以减少参数量。之后输入2层双向LSTM,分别做最大池化然后将两个最大池化拼接,这个是类似于残差的思想,利用了上一层的信息,巩固记忆。
05 联合训练
直接用end2end一个模型解决age和gender。
定义双loss:
“`python
def custom_loss(data1, targets1,data2, targets2):
”’ Define custom loss function ”’
loss1 = nn.CrossEntropyLoss()(data1, targets1)
loss2 = nn.CrossEntropyLoss()(data2, targets2)
return loss1*0.5+loss2*0.5
“`
此外,可以调节权重,看偏向哪个子任务。
06 提分点&结果
对于这次比赛,我觉得主要有三个提分点:
* w2v大参数:windoms要大60,emb_size也要大300。
* LSTM大参数:从128改大到256,提升4个千分点。
* 序列顺序无关性:在数据处理上对序列进行随机shuffle,训练的每个epoch我都进行了随机shuffle,这个可以提升3个千分点。同样对于测试集的序列可以用原始序列顺序和随机顺序序列做加权融合,这个可以提升1个千分点。
最终结果是我用了8个模型做系数加权融合,最后成绩为1.4801,也就是第11名。卡在前十名外,还是很遗憾的。
07 附:LSTM模型代码
最后附上LSTM模型代码:线上A榜1475。
“`python
########模型构造
class TXModel(nn.Module):
def__init__(self,embed_matrix1=embed_matrix1,embed_matrix2=embed_matrix2,
# embed_matrix3=embed_matrix3,
embed_matrix4=embed_matrix4,
embed_matrix5=embed_matrix5,
embed_matrix6=embed_matrix6,
lstm_hidden_size=256):
super(TXModel, self).__init__()
self.embedding1 = nn.Embedding(*embed_matrix1.shape)
self.embedding1.weight = nn.Parameter(torch.tensor(embed_matrix1, dtype=torch.float32))
self.embedding1.weight.requires_grad = False
self.embedding2 = nn.Embedding(*embed_matrix2.shape)
self.embedding2.weight = nn.Parameter(torch.tensor(embed_matrix2, dtype=torch.float32))
self.embedding2.weight.requires_grad = False
self.embedding4 = nn.Embedding(*embed_matrix4.shape)
self.embedding4.weight = nn.Parameter(torch.tensor(embed_matrix4, dtype=torch.float32))
self.embedding4.weight.requires_grad = False
self.embedding5 = nn.Embedding(*embed_matrix5.shape)
self.embedding5.weight = nn.Parameter(torch.tensor(embed_matrix5, dtype=torch.float32))
self.embedding5.weight.requires_grad = False
self.emb_dense2 = nn.Linear(300,128)
self.embedding_dropout = nn.Dropout2d(0.2)
self.lstm = nn.LSTM(300+128*2+300, lstm_hidden_size, bidirectional=True, batch_first=True)
self.lstm2 = nn.LSTM(lstm_hidden_size * 2, lstm_hidden_size, bidirectional=True, batch_first=True)
self.dropout = nn.Dropout(0.2)
self.relu = nn.ReLU()
self.linear = nn.Linear(lstm_hidden_size*2,64 )
self.classifier1 = nn.Linear(lstm_hidden_size*2*2,2 )
self.classifier2 = nn.Linear(lstm_hidden_size*2*2,10 )
def apply_spatial_dropout(self, h_embedding):
h_embedding = h_embedding.transpose(1, 2).unsqueeze(2)
h_embedding = self.embedding_dropout(h_embedding).squeeze(2).transpose(1, 2)
return h_embedding
def forward(self, x1,x2=None,x3=None,x4=None,x5=None,x6=None,attention_mask=None,
head_mask=None,):
h_embedding1 = self.embedding1(x1)
h_embedding1 = self.apply_spatial_dropout(h_embedding1)
h_embedding2 = self.embedding2(x2)
h_embedding2 = self.apply_spatial_dropout(h_embedding2)
h_embedding4 = self.embedding4(x4)
h_embedding4 = self.apply_spatial_dropout(h_embedding4)
h_embedding5 = self.embedding5(x5)
h_embedding5 = self.apply_spatial_dropout(h_embedding5)
h_embedding2 = self.emb_dense2(h_embedding2)
h_embedding5 = self.emb_dense2(h_embedding5)
h_embedding = torch.cat([h_embedding1,h_embedding4,h_embedding2,h_embedding5],-1)
h_lstm1, hidden= self.lstm(h_embedding)
h_lstm2, hidden= self.lstm2(h_lstm1)
max_pool1, _ = torch.max(h_lstm1, 1)
max_pool2, _ = torch.max(h_lstm2, 1)
out =torch.cat((max_pool1,max_pool2 ), 1)
out = self.dropout(out)
out1 = self.classifier1(out)
out2 = self.classifier2(out)
return out1,out2
“`
感谢chizhu团队的分享。每次比赛都能激发出选手们新的潜力,他们的宝贵经验也为大家的共同成长增添了新的养分。希望各位竞赛人能在每次竞技中都有所收获,不虚此行。
8月3日14:00腾讯广告算法大赛决赛即将启幕,算法王者巅峰对决,为你带来算法与技术激烈碰撞的盛筵。快点击【文末链接】,扫描报名页面底部二维码,预约线上直播观赛吧!
同时,欢迎选手们到“官网—个人信息”页面上传简历。加入腾讯,就趁现在!
扫码加入大赛官方QQ群
或搜索群号:1094257162
和小伙伴一起解锁更多内容
点击下方链接,预约直播观赛