《增长黑客》阅读笔记

《增长黑客》阅读笔记 最近一年算是在做一个从0开始的项目,用户量看上去涨了不少,但也遇到了很多问题。有时候对问题的原因会有些模糊的猜测,也会想想怎么去解决,但大多不成体系也没有机会验证。 看这本书的时候感觉很亲切,因为写到了很多遇到过的问题;同时又学到了很多东西,因为它不仅很有体系,还引申到一些心理学、行为学的东西去解释现象背后的原因。它像一面镜子,没有镜子你也知道自己长什么样子,但多照镜子还是能发现自己的很多问题。这篇文章记录一些阅读之后的收获和思考。 数据驱动 这本书很强调ab实验和深挖数据,这两个概念在过去几年随处可见,甚至有种被奉为圭臬的感觉。之前看到一个说法,只要ab的速度足够快,就不需要产品经理了。但最近我看到不少关于数据驱动的反思,亲身经历后也更深刻地认识到要做好,特别是在产品的增长期(初期)做好数据驱动是很难的。不仅样本少、变量多,很多团队甚至连像样的ab工具都没有。 在做数据分析的时候我认为有两个大的gap,一个是主观预期和用户实际行为的gap,另一个是当前用户群和目标用户群的gap。 前一个像是一个症状明显的感冒,相对好解决。第二个却像一个难以发现的慢性病,很难搞。 因为第二个gap的存在,数据驱动像是在迎合用户,而产品驱动是在寻找“对味”用户。数据驱动可能带来短期的成功,但长期结果也许是一个没有灵魂的平庸产品。而有个性的产品一旦找到能发生共振的用户,应该能产生更紧密的链接。说到底这是一个选择问题,并不存在silver bullet。 我个人比较倾向于把数据作为工具,而不是驱动力。或者换一个角度,两种平庸的方案进行ab,并不会让你选到一个牛逼的方案。必须有一个不依赖结果的驱动力让产品不断提升,团队必须自己为送入ab的方案质量负责。 啊哈时刻 “啊哈时刻”就是产品使用户眼前一亮的时刻,是用户真正发现产品核心价值——产品为何存在、他们为何需要它以及他们能从中得到什么——的时刻 找到或定义产品的啊哈时刻,然后引导用户到达啊哈时刻应该是这本书里最重要的目标之一。我觉得这是一个很有效的思维模型,但好像在我们的产品里没有被很好地执行。 因为多线作战、语言不通、缺少用户研究团队,我们对产品在市场的反馈一直没有全面的了解。前几天问同事什么是我们的啊哈时刻,大家答案的方向差不多,但也没有完全达成共识。 而在引导用户到达啊哈时刻这方面我们也不够努力。例如用户的地点对我们至关重要,但目前的设计只会在ta第一次onboard的时候询问一次,后面就放任自流了。而且之前版本的第一次询问我觉得也不是很好。 这里有一个我一直没想明白的问题:不同渠道来的用户在提供地点的比例上有很大的差别。虽然之前产品同事给过一个解释,但我不是很能理解。同理心真的是对产品经理一个重要且难得的能力,根据产品猜测不同渠道、不同步骤的流失率可能是一个不错的考察办法。 储值 大体上讲,用户往产品放入的个人信息或财物被称为储值,储值的形式有很多,例如用户在印象笔记写的笔记,在微信的联系人,在亚马逊购买prime会员的年费等等。储值能很有效地增加用户的粘性。 比较可惜的是我们的产品几乎没有提供储值的途径(似乎只有收藏夹一个),就像前面说的,我们对用户信息的询问非常保守;用户没有办法花钱来获得增值体验;也没有在产品里设计任何回报和奖励。当用户过了蜜月期,基本上可以毫无负担地离开我们的产品。 要构建出储值体系对于我们现在的产品其实是比较困难的,但这个真的蛮重要,毕竟我们不具备什么不可替代性,需要多一些和用户建立物质和情感连接的渠道。 产品雕琢 这个话题散落在本书的很多地方,例如 找到语言语市场的匹配点,优化广告语 根据三个根本任务:传达相关性,展示产品价值和提供明确的行为召唤来设计landing page。 少并不总是多,便宜的价格不总是能带来更多的用户,因为面人们可能将价格视作质量的信号 根据“相对论”来设计烟幕弹套餐优化定价,例如《经济学人》网络版杂志全年订阅价是59美元,纸质版杂志全年是125美元(烟幕弹),而纸质版加网络版的合订价也是125美元。这一设置可以大大降低用户选59美元套餐的比例而增加用户选购第三种套餐的比例。 我是在微信读书上读的这本书,不得不说微信免费提供这些书籍真的很赞,后面准备再读一下书里提到的《怪诞行为学》和《设计心理学》,读完了再跟大家交流。 微信读书显示我3小时22分读完的这本书,感觉比我实际花的时间短一些。这种夸大用户单位时间收益的方式也许是他们的一个增长策略? 团队和工作流 书的第一部分叫“方法”,确实相对比较抽象。首先谈到的是如何构建增长团队, 大方向是要打破筒仓结构,构建职能齐备的复合型增长团队 增长团队里应当有对企业战略和目标有深刻了解的人,有能够进行数据分析的人,也要有能够对产品的设计、功能或营销方式进行改动并通过编程测试这些改动的工程师 对于这一点其实对于创业小团队问题不大,因为还没有像大公司那样的部门墙。

September 21, 2021 · 1 min · Yuanhao

Impvove Inference Efficiency with Batch Inference

As an algorithm engineer, it is inevitable that you will encounter the problem of bringing models online in your daily work. For some less demanding scenarios, you can handle this by utilizing a web framework: for each user request, call the model to infer and return the result. However, this straightforward implementation often fails to maximize the use of the GPU, and is slightly overwhelming for scenarios with high performance requirements....

June 20, 2021 · 7 min · Yuanhao

模型上线不用愁,批量推理来加油.

作为一个算法工程师,在日常工作中难免会碰到模型上线的问题。对于一些要求不高的场合,简单找一个web框架实现一下接口就能搞定:对于每个用户请求,调用模型得到结果再返回。但这种朴素的实现往往无法最大化利用GPU,对于性能要求比较高的场景应付起来就略显吃力。 优化的方法有很多,一个增益很大的措施就是把一个请求推理一次改成多个请求一起推理。去年大概也是这个时候我写了一个小工具来实现这个功能,还取了个蛮霸气的名字InferLight,但当时写得并不太好;最近参考香侬科技的Service-Streamer又重构了一版。这个功能看似简单,但是在实现的过程中可以了解很多Python异步编程的知识,感觉收获颇丰,于是写篇短文总结一下。 首先,要提高模型的线上推理吞吐量,应该把推理服务做成异步的。对于web服务来说,异步的意思是当模型在计算的时候它可以处理别的请求。对于Python来说,异步服务可以通过很多优秀的基于Asyncio的框架来实现,例如我常用的Sanic。而推理是计算密集的,也没有什么同步异步的说法,我们的目标就是能够汇聚多个推理请求,高效利用GPU的并行计算能力,并且能将批量推理的结果正确地返回给对应的请求者。 要实现上面的目标,需要以下几个模块 前端服务:用于接收请求、返回结果。可以是Http、PRC等各种协议。是一个独立进程。 推理Worker:负责模型的初始化、批量推理数据构建、推理计算。是一个独立进程。 任务队列:前端服务收到请求之后把计算任务送入任务队列;推理Worker监听该队列,每次取出一个小批量由模型推理 结果队列:推理服务推理完成后将结果送入结果队列;前端服务监听该队列,获得推理结果 结果分发:在将任务送入任务队列前需要生成任务的唯一标识,从结果队列取回结果后根据标识获取到任务对应的结果 其中两个任务队列的实现方式很多,可以通过一些成熟的中间件例如Kafka、Redis等,但为了避免外部依赖,这次我选择使用Python原生的多进程队列。结果队列监听和分发通过前端服务进程的一个子线程来完成。 实现细节 推理服务相对简单,由于各种模型的加载、数据处理步骤千奇百怪,所以我将推理Worker设计成了一个基类,使用时继承它并实现特定方法。 import logging import multiprocessing as mp import time from queue import Empty class BaseInferLightWorker: def __init__(self, data_queue:mp.Queue, result_queue:mp.Queue, model_args:dict, batch_size=16, max_delay=0.1, ready_event=None) -> None: self.data_queue = data_queue self.result_queue = result_queue self.batch_size = batch_size self.max_delay = max_delay self.logger = logging.getLogger('InferLight-Worker') self.logger.setLevel(logging.DEBUG) self.load_model(model_args) # 由于模型载入时间较长 # 加载完成后使用一个event来通知主进程 if ready_event: ready_event.set() def run(self): self.logger.info('Worker started!') while True: data, task_ids = [], [] since = time....

June 20, 2021 · 4 min · Yuanhao

Tricks of Semantic Segmentation

{: .align-center style=“width:80%”} HuBMAP - Hacking the Kidney {: .align-caption style=“text-align:center;font-size:smaller”} Last month, I spent some time doing the “HuBMAP - Hacking the Kidney” competition on Kaggle. The goal of this competition is the implementation of a successful and robust glomeruli FTU detector. It is a classical binary semantic segmentation problem. This is my second semantic segmentation competition, and our team ended up in 43rd place and won a silver medal....

May 30, 2021 · 4 min · Yuanhao

Training large model with your GPU

In the last post, I shared my story of the Kaggle Jigsaw Multilingual Toxic Comment Classification competition. At that time, I only had a 1080Ti with 11G VRAM, and this made it impossible for me to train the SOTA Roberta-XLM large model which requires larger VRAM than what I had. In this post, I want to share some tips about how to reduce the VRAM usage so that you can train larger deep neural networks with your GPU....

April 15, 2021 · 4 min · Yuanhao

面向电商场景的语言模型E-BERT

最近跟不少做电商NLP的朋友们聊天,有不少收获。我之前从来没想过【搜索】在电商里的地位是如此重要,可能GMV的50%以上都是从搜索来的。巨大的经济价值也极大地推动了技术的发展,他们的工作做得很细致,毕竟一个百分点的点击率后购买率提升也许对应的就是几百亿的成交额。 其实之前做的汽车领域NLP工作跟电商有很多相似的地方,场景先验都非常重要。直接使用开放域语料预训练的语言模型效果并不好。我们也尝试过一些方法,例如用本领域语料训练语言模型,结合一些词库词典等等。今天介绍最近看到的一篇针对电商场景调优BERT的论文《E-BERT: Adapting BERT to E-commerce with Adaptive Hybrid Masking and Neighbor Product Reconstruction》,其中的一些方法应该对细分领域NLP都有一些启发。 方法 论文的创新方法主要有两个:Adaptive Hybrid Masking(AHM,自适应混合掩码)和Neighbor Product Reconstruction(NPR,相似商品重构)。 E-BERT总览 {: .align-caption style=“text-align:center;font-size:smaller”} AHM 第一个方法AHM其实是对已有掩码方式的改进。原始版本的BERT采用的是随机mask,这个大家应该都比较清楚。这种mask方式针对的是token,而众所周知token是由单词通过wordpiece tokenizer分割而来。所以这种方式遮盖住的可能是单词的一个部分,学习这种类似看三个字母猜剩下四个字母的任务不是很符合大家的直觉。随后就诞生了更加符合人类认知的Whole Word Masking,这个方法就是说要遮就遮整个词。这里用一个网上的例子帮大家理解 Input Text: the man jumped up , put his basket on phil ##am ##mon ' s head Original Masked Input: [MASK] man [MASK] up , put his [MASK] on phil [MASK] ##mon ' s head Whole Word Masked Input: the man [MASK] up , put his basket on [MASK] [MASK] [MASK] ' s head philammon是一个词,他会被tokenizer分解成三个token,这时就体现了普通mask和WWM的区别。...

September 16, 2020 · 1 min · Yuanhao

受控文本生成2

昨天的文章介绍了在输出空间对文本生成进行控制的两篇论文,今天介绍一篇在隐空间控制的论文。 隐空间方法也分为两个流派,一种认为在隐空间里可以把内容和特性的向量表示分开(disentangled),然后通过修改特性向量来实现对特性的控制;另一种则无须这种假设。下面分别介绍一篇相关论文。 Style Transfer from Non-Parallel Text by Cross-Alignment disentangled representation的代表作之一,发表在2017年的NIPS上,如今引用已经接近300多。 Style Transformer: Unpaired Text Style Transfer without Disentangled Latent Representation 复旦大学NLP组发表于2019年的文章,已经被引用20次,文章标题中明确写了他们的方法without Disentangled Latent Representation。 在文章的introduction部分列举了一些Disentangled表示的问题,我觉得比较重要的两条是: 难以评价Disentangled表示的质量,纯粹的Disentangled表示也很难获得; 分离不是必要的,有文章已经论证了靠解码器就可以overwrite风格。 这篇文章总的来说是对抗生成网络的思路。模型分两大块,一块是典型的encoder-decoder结构的transformers,用来作为风格迁移器,另一块是判别器,用来解决由于没有平行语料带来的训练问题。 判别器训练 文中提出了两种判别器,从结果上看多分类判别器对BLEU指标更友好,而条件判别器对迁移后的风格更友好。 多分类判别器 这种方法比较好理解,即采用K+1类的多类分类器作为判别器,输入只有句子。后K类对应K种风格,第0类对应$f_\theta(\rm{x},\rm{\hat{s}})$,即假样本。在训练时判别器时,将原始语料和用原风格重建后的句子都标为对应的风格,假样本标为第0类。在训练风格转换器的时候,我们希望转换器能尽量提高$f_\theta(\rm{x},\rm{\hat{s}})$被判别为$\rm{\hat{s}}$类的概率,即能骗过判别器,使判别器不认为生成的是个假样本。 条件判别器 输入包括句子和风格,判别器需要判断句子是否含有风格(二分类)。训练判别器时将原始语料和重建句子$f_\theta(\rm{x},\rm{s})$标注为正样本,将变换后的句子$f_\theta(\rm{x},\rm{\hat{s}})$标注为负样本。 判别器训练算法 {: .align-caption style=“text-align:center;font-size:smaller”} 风格迁移器训练 风格迁移器有三个重要的任务,一个是自重建(Self Reconstruction),一个是循环重建(Cycle Reconstruction),以及风格控制(Style Controlling)。 自重建就是输入句子$\rm{x}$以及其原本风格的控制变量$\rm{s}$,让他生成自己。这个任务是可以使用监督学习来完成的,loss计算公式如下 $$ L_{\rm{self}}=-p_\theta(\rm y=\rm x|\rm x,\rm s) $$ 循环重建是先输入$\rm{x}$和一个其他的风格控制变量$\rm{\hat{s}}$,生成$\rm\hat y$,再用$\rm\hat y$和$\rm s$生成一个$\rm y$。此时$\rm y$应该和$\rm{x}$无论内容及风格都一致,并且可以使用监督学习来计算loss: $$ L_{\rm{cycle}}=-p_\theta(\rm y=\rm x|f_\theta(\rm x,\rm\hat s), \rm s) $$ 前面两个任务虽然解决了没有平行语料带来的训练问题,但思考一下就会发现这两个任务并不会起效果。模型可以完全只学习返回原句子就可以“蒙混过关”。解决的办法就是检验一下循环的中间结果$f_\theta(\rm x,\rm\hat s)$,这个中间结果应该尽可能含有$\rm\hat s$风格。因此引入了第三个风格控制任务,这个任务根据判别器的不同也分成两种情况:...

July 23, 2020 · 1 min · Yuanhao

受控文本生成1

关于文本生成的话题聊得比较少,印象中我们之前只有一期多轮问句改写涉及到了文本生成,受控文本生成就更少了。 受控文本生成是在保证内容的前提下对文本的特性,例如情绪、文风等,进行控制。典型的任务有文本风格迁移。图片和声音的风格迁移都已经商用落地了,例如之前很火的几个应用例如Prisma和FaceApp,相比起来文本风格迁移的发展要慢一些。 名噪一时的Prisma是图像风格迁移的代表性应用 {: .align-caption style=“text-align:center;font-size:smaller”} 文本风格迁移很像翻译任务(语言也可以认为是文本特性的一种),但相比于机器翻译,风格迁移任务几乎没有平行语料,所以要困难一些。如果你对这个方向有兴趣,强烈推荐北大付振新同学整理的这个Repo。 受控文本生成因为是文本生成的高级版,通过学习相关技术可以很好地加深对文本生成的理解。受控文本生成从技法上来讲主要有两类,第一类在隐空间做文章,第二类在生成器的输出空间上做文章。 相比于在隐空间施加控制,我感觉在输出空间施加控制在方法上更简单一些。今天先从这个流派开始。我认为在输出空间进行控制又可以细分出两种形式,一种是在概率空间,一种是在离散空间,下面分别用一篇文章来举例。 Delete, Retrieve, Generate: A Simple Approach to Sentiment and Style Transfer 来自斯坦福NLP组,发表在2018年的NAACL,目前引用150,可以说是这个方向的经典论文了。 这篇其实包含了四种方法,但我感觉最有代表性的是在token空间进行的方法(即后面的template based方法),可解释性强,效率也高。 DRG的四种迁移方法 {: .align-caption style=“text-align:center;font-size:smaller”} 这篇文章的思路很简单,因为它基于一个假设:通常文本特征迁移可以通过改变一些标志词或短语(attribute markers)来完成。 在做风格迁移时,首先要找到这些attribute markers。找的方法也很简单,就是考虑某个n-gram在不同风格语料中出现的概率。如果有显著(salience, s)差异,那它就很可能是个attribute marker,显著性的计算公式如下,$u$是某个term,$v$是某种风格,$\mathcal{D}_v$是某种风格的所有语料,$\lambda$是个平滑系数。公式简单,大家一看便懂,计算出数值后根据阈值最终确定所有的attribute marker。 $$ s(u,v)=\frac{\text{count}(u, \mathcal{D}v)+\lambda}{(\sum{v’\in \mathcal{V},v’\neq v}\text{count}(u, \mathcal{D}_{v’}))+\lambda} $$ 围绕这些attribute marker(后文简称AM),后续将进行如文字标题所写的三种核心操作:delete, retrieve和generate。 Delete Delete的目的是要删除句子中的AM,留下内容。用$a(x, v^{\text{src}})$表示源句子x中所有的AM,删除AM后的x表示为$c(x, v^{\text{src}})$,即不含AM的句子内容。 Retrieve 这一步是要在源句子中插入目标特性的AM。论文的策略是先使用$c(x, v^{\text{src}})$在目标特性句子集合中检索一个内容最接近的句子$x^{\text{tgt}}$。内容接近程度的评价可以使用任意的距离函数来完成。 Generate 这是最后一步,即获得最终的结果。文章里有四种策略 Retrieve Only 直接返回第二步的结果。这么做生成的句子在语言角度应该是正确的且带有目标特性,但可能在内容上和源句有出入。 Template Based 直接把$a(x, v^{\text{src}})$替换成$a(x^{\text{tgt}}, v^{\text{tgt}})$。这么做简单粗暴,可能产生不通顺的句子。 Delete Only 把$c(x, v^{\text{src}})$交给一个RNN进行编码,再拼上特性$v^{\text{tgt}}$的embedding,最后交由一个解码器解码。 Delete And Retrieve 和上一种相似,但不是拼上特性$v^{\text{tgt}}$的嵌入,而是用另一个RNN编码得到的$a(x^{\text{tgt}}, v^{\text{tgt}})$的表示向量。 前两种方法是不需要训练的,后两种则需要训练。对于Delete Only,使用重建句子任务(即训练一个自编码器)来训练。对于Delete And Retrieve则复杂一些,为了防止特征迁移的能力退化成句子拼接(c+a)的能力,作者在这里训练一个降噪自编码器,具体地说就是随机替换a里的AM。...

July 22, 2020 · 1 min · Yuanhao

Tweet Sentiment Extraction比赛总结

这是前段时间结束的Kaggle比赛,之前在文档问答的文章中我也有提到过,最终我们队获得了第七名,这篇文章分享一下我的参赛收获和感受。 首先感谢队友,特别是曹老师,如果没有曹老师我肯定中途就弃赛了。至于弃赛的原因,在感受部分会详细介绍。我的代码已经传到Github上了,感兴趣的朋友可以看一看,里面包含了我所有的commits,可以完整看到我方案的演进。 Repo: https://github.com/thuwyh/Tweet-Sentiment-Extraction 赛题回顾 比赛叫做Tweet Sentiment Extraction,对于给定的tweet和情感极性,需要选手从文本中找出支撑情感的部分。例如下面这条数据 "My ridiculous dog is amazing." [sentiment: positive] 模型应该返回amazing这个词。比赛的评价指标是word-level Jaccard score,它的含义看下面的实现就一目了然了。 def jaccard(str1, str2): a = set(str1.lower().split()) b = set(str2.lower().split()) c = a.intersection(b) return float(len(c)) / (len(a) + len(b) - len(c)) Baseline及一些改进 在比赛的初期讨论区和kernel分享区基本就定下了解题思路的基调,即用机器阅读理解(MRC)的方法来做span prediction。具体的说,就是把数据提供的情感词作为question,把tweet作为context,把预测对象作为answer。 模型也很简单,在RoBERTa后面接一个questionAnswering head预测start和end位置就可以了。这道题一个比较神奇的地方就是RoBERTa的效果比普通的BERT要好一些。 在这个框架下,大家也都做了一些改进,例如: 在语言模型输出后面加dropout; concat语言模型的多层输出结果; 引入FGM等对抗训练方法 以上都是一些比较常规的操作,也比较容易实现,类似FGM是比较稳定能提分的。还有一些稍微复杂一点的trick,例如: 在词级别进行数据增强,例如同义词替换,随机删词 在token级别的增强 label smoothing 蒸馏 因为是span prediction任务,数据增强如果做成随机动态的,需要考虑到改词后对label的影响,这是实现的一个小难点。英文的同义词替换可以使用wordnet来做,相比中文的一些同义词库来讲质量是比较高的。 label smoothing和蒸馏是很相关的两个技术,因为他们都需要用到KL散度作为损失函数。我也是趁这个比赛补了一补相关的知识,感觉还蛮有趣的,感兴趣的朋友可以参考这篇文章。做QA任务通常是对位置用CrossEntropyLoss,但是如果label不是一个确定的位置而是平滑过或者是teacher model预测得到的分布,就需要使用KLDivLoss。 这里在做标签平滑的时候遇到了一个小问题,蛮值得思考的。最开始是Google在Imagenet上用这个技巧,对于这个分类问题标签的种类是确定的K=1000类,所以在Inception论文里直接用一个系数来控制平滑的强度,即 $$ q’(k) = (1-\epsilon)\delta_{k,y}+\frac{\epsilon}{K} $$ 但是如果用同样方法在这些长短不一的句子上做平滑,其实是不合适的。每个位置的平滑概率反比于句子的长度,也就是K,所以我认为更好的确定平滑强度的方法是先确定一个单位平滑强度,再根据句子总长来确定原标签的权重。 针对数据特点的方法 这次的数据总体质量很差,噪声(其实是错误)很多,给参赛者带来了很多困扰。主要的噪声模式有两种,一种是把整个句子都标注成了支撑情感的selected_text,第二种是数据中有大量“断头词”出现在标签中。下图给出了一些例子。 对于第一种整句都是标签的情况,早期很多参赛者就发现了对于neutral类型的情感,绝大部分selected_text都和text一样;但对于其他情感,我们在人工审阅数据之后没有发现什么规律。我只好设计了一个辅助的分类任务让模型自己学习,实测下来有些微的提升,但并不明显。 对于“断头词”的情况,我们在比赛的末期终于发现了其规律。这种情况应该是由于标注环境不一致导致的。例如Twitter数据里有很多@用户的情况,这份比赛数据集会把相关的文本删除,但由于删除脚本的问题会导致文本中多出一个空格。我们猜测标注者看到的数据应该是没有多余空格的,类似于是使用' '.join(text.split())处理过的。这就会导致标出来的span相对于原text的位置产生了位移。且位移的大小就等于多余空格的数量。...

July 8, 2020 · 1 min · Yuanhao

跨语种语言模型

在著名的科幻电影《银河系漫游指南》里有一种叫巴别鱼的神奇生物。将它塞进耳朵里你就能听懂任何语言。多语种语言模型做得事情和巴别鱼很像,人们希望这个模型能用来处理所有的语言。举个例子,大家常用的中文bert有很强的中文处理能力以及一定的英文处理能力,但基本也就只能处理这两种语言;而目前的SOTA多语种模型XLM-RoBERTa能够处理104种语言。 巴别鱼,体型很小,黄色,外形像水蛭,很可能是宇宙中最奇异的事物。它靠接收脑电波的能量为生,并且不是从其携带者身上接收,而是从周围的人身上。它从这些脑电波能量中吸收所有未被人察觉的精神频率,转化成营养。然后它向携带者的思想中排泄一种由被察觉到的精神频率和大脑语言中枢提供的神经信号混合而成的心灵感应矩阵。所有这些过程的实际效果就是,如果你把一条巴别鱼塞进耳朵,你就能立刻理解以任何形式的语言对你说的任何事情。 数据集 训练跨语种语言模型会用到两种语料。一种是单语种(monolingual)语料,另一种是平行(parallel)语料。所谓平行语料就是源语言与译文“对齐”的语料。所谓对齐也有好几种级别,最常见的是句子级对齐,也有按词进行对齐的文本。可想而知,平行语料的获取相比于单语种语料要困难许多。如何充分借助单语种语料来提升模型能力是XLM研究的一个重点。 跨语种语言模型的评价一般有两个大方向,一个是其语义理解能力,另一个是文本生成能力。语义理解能力通常借助XNLI数据集,它提供了15种语言的平行文本,每种语言7500对的NLI语料。文本生成通常用翻译任务来评估,感兴趣的朋友可以自己查阅相关资料。 模型 下表列出了常见的单语种和多语种预训练语言模型。接下来我们将分析其中的mBERT、XLM和XLM-R三个模型。 Multilingual Bert(mBERT) 模型来自于这论文《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》,你没有看错,就是发表于2018年大名鼎鼎的BERT论文。 2018年11谷歌就放出了支持104种语言的多语种版本预训练模型,规格是BERT base。这个模型的较新版本是uncased版,即没有对输入文本进行规范化。使用WordPiece算法进行tokenization,词典大小是110k。其他的训练方法和普通的BERT一样,采用的是MLM和NSP两个loss,语料是Wikipedia。 XLM 模型来自于论文《Cross-lingual lan- guage model pretraining》,来自于FAIR,发表在NIPS2019。 XLM使用BPE算法进行tokenization,并且词典大小比mBERT更大,达到200k。论文指出Shared sub-word vocabulary对模型性能有很大的影响,在训练BPE算法的过程中他们使用了特殊的采样方式来避免低资源语种被进行字符集切分。 模型训练使用了三种不同的目标函数,在单语种语料上使用非监督的CLM和MLM。MLM就是masked language modeling,大家比较熟悉,在此就不再赘述了。CLM全称是Causal Language Modeling,简单的说就是用前面的词预测当前词,更详细的介绍大家可以参考我们之前UniLM和MASS的文章。在平行语料上使用的目标称为Translation Language Modeling (TLM)。其训练方式如下图所示,是将平行句子拼接后随机mask,希望让模型能借助另一种语言的信息来还原出被遮蔽的词。从图中可以看出模型用language embedding替换了BERT里的type embedding,并且在做TLM任务时position embedding在两个语言间是对应的。 我们来看一下XLM在XNLI上的表现。这张表很有意思,首先对这个数据集有3种处理方式:translate-train,translate-test和直接测试,即zeroshot。第一种是把英语的MNLI数据集机器翻译成XNLI内的15种语言用于训练,在XNLI测试集上测试;第二种是把XNLI测试集的15种语言翻译成英文。本文的对照组就是上面的mBERT。 可以看到效果最好的是翻译训练集,平均精度达到了76.7%,zero-shot次之,最差的是翻译测试集。在相同的实验设定下XLM稳定优于mBERT,甚至在zero-shot下的XLM也比finetune过的mBERT强。另外MLM+TLM也稳定优于只用MLM的方式。 XLM-RoBERTa 模型来自于论文《Unsupervised Cross-lingual Representation Learning at Scale》,和上文一样来自FAIR,已经被ACL 2020接收。 XLM-R使用了比XLM更大的词典,达到了250k。它也没有辜负RoBERTa的血统,使用了比Wikipedia大得多的cc100数据集。XLM-R只使用单语种语料,训练目标也只有MLM一个。 Tokenizer换成了sentence piece算法,在构建时也进行了采样,并且调整了系数使得各语言更加平衡。模型层面去掉了language embedding,变得更加简洁。我感觉用“重剑无锋”来形容XLM-R再合适不过了。 这篇论文总结了几个影响多语种模型的重要因素,可能会对大家有所启发: 当处理的语种变多的时候模型的能力会下降(嗯,符合常识)。增大模型可以一定程度对抗这种效应。 模型能力主要受词典大小、训练集大小、语种的采样频率影响 增大词典规模可以提高模型性能 sentence piece可以提高模型的通用性 下面这种图可以让大家对这些结论有更直观的印象 最后来看一下XLM-RoBERTa的实力。下表是在XNLI数据集上的结果对比,设定和XLM论文中差不多,其中Devlin et al.指的是mBERT,Lample and Conneau指的是XLM。可以看出XLM-R相比于XLM又前进了一大步。 顺便再提一嘴,论文作者还在GLUE数据集上对比了XLM-R和XLNET、RoBERTa等单语种语言模型,XLM-R超过了BERT-large,略低于XLNET和RoBERTa。也就是说XLM-R不仅获得了多语种能力,而且没有牺牲英文上的水平。 总结一下,从2018年的mBERT到2020年的XLM-R,跨语种预训练语言模型获得了长足的发展,地球语言范围内的巴别鱼指日可待。最近在Kaggle上正在进行一场跨语种文本分类的比赛,如果有想体验XLM最新进展的朋友可以去试试身手。 今天的文章就到这里,下期再见👋

May 11, 2020 · 1 min · Yuanhao