前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >芒果TV商品意图识别top3思路分享

芒果TV商品意图识别top3思路分享

作者头像
致Great
发布2022-06-15 19:10:22
1.1K0
发布2022-06-15 19:10:22
举报
文章被收录于专栏:程序生活程序生活

比赛简介

主办方提供了商品名称和用户query数据供选手进行模型训练,希望选手能够设计出一套高效、精准的商品意图识别模型,以帮助提升电商搜索的效果,改善顾客的购买体验。

其中提供了两份数据,一个是goods_data.csv是商品名称数据,一个是query_data.csv是用户query数据,共39470条

前期我们做的尝试比较多,后面差不多烂尾了,庆幸b榜还在第一页,下面介绍下我们队伍的比赛思路。

数据处理

由于本赛题数据分类一个质量比较高的goods数据,一个是用户场景下的query数据(相对有噪音),前期我们尝试单独训练goods或者query数据效果不是很好,goods数据容易过拟合,query数据比较难收敛,后续实验我们选择将两份数据进行合并训练,效果得到明显提升。

文本长度统计如下:商品名称数据中 文本字符长度最大为39,最小为6。我们在训练中选择了覆盖绝大部分数据长度的大小26,其余没有做过多尝试。

数据划分

由于本赛题的样本的标签分布不均衡,我们采用多折分层采样的方式进行划分训练集,然后输入到模型进行训练,直接采用sklearn的StratifiedKFold

from sklearn.model_selection import StratifiedKFold

模型设计

由于Bert等预训练模型变体效果要好于传统NLP建模方法,我们一开始实验是从预训练模型开始建模的,对比了几个模型变体之间的效果,其中本次比赛给出的baseline ernie模型效果比较好,尝试了开放的ernie3.0效果不如1.0;其次nezha 效果和chinese-roberta-wwm也不错。

  • ernie-1.0
  • nezha
  • chinese-roberta-wwm

训练优化

我们尝试了一些NLP训练优化方法,

  • 对抗训练:尝试了FGM/PGD,其中PGD没有效果,FGM在chinese-roberta-wwm模型有提升效果
class FGM():
    def __init__(self, model):
        self.model = model
        self.backup = {}
    def attack(self, epsilon=1., emb_name='word_embeddings'):
        # emb_name这个参数要换成你模型中embedding的参数名
        for name, param in self.model.named_parameters():
            if param.requires_grad and emb_name in name:
                self.backup[name] = param.data.clone()
                norm = torch.norm(param.grad)
                if norm != 0 and not torch.isnan(norm):
                    r_at = epsilon * param.grad / norm
                    param.data.add_(r_at)
    def restore(self, emb_name='emb.'):
        # emb_name这个参数要换成你模型中embedding的参数名
        for name, param in self.model.named_parameters():
            if param.requires_grad and emb_name in name: 
                assert name in self.backup
                param.data = self.backup[name]
        self.backup = {}
  • 模型泛化:加入了MultiDropout、Rdrop,其中Rdrop在nezha模型提升比较明显
import torch.nn.functional as F

# define your task model, which outputs the classifier logits
model = TaskModel()

def compute_kl_loss(self, p, q, pad_mask=None):
    
    p_loss = F.kl_div(F.log_softmax(p, dim=-1), F.softmax(q, dim=-1), reduction='none')
    q_loss = F.kl_div(F.log_softmax(q, dim=-1), F.softmax(p, dim=-1), reduction='none')
    
    # pad_mask is for seq-level tasks
    if pad_mask is not None:
        p_loss.masked_fill_(pad_mask, 0.)
        q_loss.masked_fill_(pad_mask, 0.)


    p_loss = p_loss.sum()
    q_loss = q_loss.sum()

    loss = (p_loss + q_loss) / 2
    return loss

# keep dropout and forward twice
logits = model(x)

logits2 = model(x)

# cross entropy loss for classifier
ce_loss = 0.5 * (cross_entropy_loss(logits, label) + cross_entropy_loss(logits2, label))

kl_loss = compute_kl_loss(logits, logits2)

# carefully choose hyper-parameters
loss = ce_loss + α * kl_loss
  • ema在nezha模型有提升效果
class EMA():
    def __init__(self, model, decay):
        self.model = model
        self.decay = decay
        self.shadow = {}
        self.backup = {}
 
    def register(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                self.shadow[name] = param.data.clone()
 
    def update(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                assert name in self.shadow
                new_average = (1.0 - self.decay) * param.data + self.decay * self.shadow[name]
                self.shadow[name] = new_average.clone()
 
    def apply_shadow(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                assert name in self.shadow
                self.backup[name] = param.data
                param.data = self.shadow[name]
 
    def restore(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                assert name in self.backup
                param.data = self.backup[name]
        self.backup = {}
 
# 初始化
ema = EMA(model, 0.999)
ema.register()
 
# 训练过程中,更新完参数后,同步update shadow weights
def train():
    optimizer.step()
    ema.update()
 
# eval前,apply shadow weights;eval之后,恢复原来模型的参数
def evaluate():
    ema.apply_shadow()
    # evaluate
    ema.restore()

模型融合

为了避免模型抖动,我们主要依赖线下cv分数以及a榜分数,对模型设置权重进行加权融合,具体融合方式如下:

其中preden1可以是模型融合的结果,然后基于它的分数再去分配其他两个单模的分数

比赛结论

本次比赛数据因为长度比较短以及粒度为实体名词级别的,ernie效果比较好,确实是意外之喜。由于时间问题有些想法还是没有去做尝试,主要有:

  • 数据增强
  • AWP对抗训练
  • 投票融合等

希望其他前排大佬可以多多交流

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-06-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 比赛简介
  • 数据处理
  • 数据划分
  • 模型设计
  • 训练优化
  • 模型融合
  • 比赛结论
相关产品与服务
NLP 服务
NLP 服务(Natural Language Process,NLP)深度整合了腾讯内部的 NLP 技术,提供多项智能文本处理和文本生成能力,包括词法分析、相似词召回、词相似度、句子相似度、文本润色、句子纠错、文本补全、句子生成等。满足各行业的文本智能需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档