Vision Transformer学习笔记1

最近Transformer结构在计算机视觉领域的应用非常火,时不时都有新的文章出来。作为一个已经使用了两三年Transformer结构的NLPer,一直很想了解一下它在视觉领域是怎么工作的,最近借着一个Kaggle比赛的数据集学习了一下,稍作总结分享给大家。 首先是学习了一下Vision Transformer,ViT的原理。看的论文是谷歌名作《An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale》,本文初稿发布于2020年10月,今年投了ICLR 2021,应该算是ViT的奠基论文之一。要用Transformer来处理图像,首先(也可能是唯一)要解决的是输入问题,原先的Transformer处理的是token序列,而图像是HWC的像素矩阵。这里做法也很暴力,第一步是将一张图拆成了N个PP个小块(patch),每个patch看做是一个token。一个patch里有PP个像素,每个像素C个通道,这里直接就给拍平了进一个全连接(线性变换)得到patch的D维Embedding表示。所以ViT里的Embedding层不再是一个lookup table了,而是一个可以学习的线性变换。 ViT结构图 {: .align-caption style=“text-align:center;font-size:smaller”} 通过这个方法,就把Transformer结构套在了图像上,虽然这不是唯一的方法,但这么做在参数量的角度和时间复杂度的角度都是比较合理的。首先是时间复杂度角度,Transformer的关于序列长度的时间复杂度是O(n^2),所以输入序列不宜过长。如文题所说,如果我们把图分成1616个patch,那transformer处理的序列长度将会是256,比BERT的默认长度521还短了一半。参数量上,尺寸正常的Transformer很大比例参数在embedding层上,例如BERT-base的30k个token768维的Embedding层有23M参数大约占了其110M总参数量的五分之一。ViT里Embedding层的参数量是正比于图像尺寸的,以224224图像为例,单patch像素点数为196,所以总参数量是196C*D,C是输入通道数,D是Embedding维数,以3和768记的话为0.45M,远小于BERT-base。从下表可以看到同样尺寸的ViT参数量都小于对应的BERT。 按论文的这种处理方式也有几个比较明显的问题,例如强行分割patch破坏了原有的邻域结构,也不再具有卷积的那种空间不变性。在中等规模数据集上用这种方法得到的结果还是比卷积要差,但是当把预训练数据变多用更大的数据集训练时,模型性能显著提升了(第二列比第三列),接近甚至超过了SOTA。 上面的结果都是针对有监督训练的,这篇文章还做了些无监督训练的初步实验,发现加入无监督预训练在下游任务比没有预训练强一2%,但是比有监督预训练差4%,总之一句话,没有实现BERT的效果。 实验的部分用Pytorch Lightning简单做了一下Kaggle的Pawpularity数据集。这是一个值域0-100的回归问题,评价指标是RMSE。模型部分没什么花头,直接backbone接了个回归头,代码如下 class Pawpularity(pl.LightningModule): def __init__(self, config): super().__init__() self.config = config self.backbone = timm.create_model(config.backbone_name, pretrained=not config.predict, num_classes=0) self.head = nn.Sequential( nn.Linear(self.backbone.num_features, 128), nn.GELU(), nn.Linear(128, 1) ) self.save_hyperparameters(config) 实验的运行环境是在我的HP Z4工作站上,它搭载了两个RTX 6000 GPU,因为显存是24GB版本,所以batchsize设的比较大。实验结果如下 模型 模型参数 lr batch size 单轮耗时 早停轮次 RMSE vit_base_patch16_224 85.9M 1e-3 128 36s 10 20.514 vit_base_patch16_224_in21k 85....

November 17, 2021 · 1 min · Yuanhao

试用Notion

上周看到Notion估值100亿美元的消息,有点受震撼。一来是因为它好像在国内都还没什么名气,身边除了青南老师还没见过第二个用户,怎么突然就炸了;二来是他们团队真的好小,据报道2019年才3个人,目前才180多人;最后,他们的增长是非常漂亮的指数曲线,在这个看似做不出什么花头的领域实数难能可贵。 2019年-2021年,公司披露的用户数分别为100万、400万和超2000万,今年的收入则大涨70%。 笔记真的是一个很重要的应用,之前我也曾经多方对比都没有找到特别满意的产品,于是先入为主用了好几年印象笔记。作为一个印象笔记的老付费用户,心中对它早已有诸多不满,功能乏善可陈不说,不知从什么时候开始给已付费用户疯狂发广告。 {: .align-center style=“width:80%”} 作死的印象笔记,不思进取,疯狂发续费广告 {: .align-caption style=“text-align:center;font-size:smaller”} 于是今天决定试用一下Notion,看下能不能替换掉印象笔记。 强大 我是在浏览器进行体验的,不得不说Notion的前端工程师有两把刷子,输入体验特别好(远好于Confluence),公式、图片、超链接都没啥问题,除了用自带的/进行功能呼出,还支持Markdown语法自动映射。除了浏览器版本,Notion还提供了各种系统的客户端,跨平台使用一点都没问题。 为了帮大家用好这个软件,开发者还提供了海量的模板,从个人用途的阅读清单、旅行规划,到团队用的看板、文档一应俱全。虽说都是几个核心组件的有机组合,但对于一个泛笔记类应用确实足够了。特别是对于一个小团队来说,完全可以用Notion达到Confluence+Jira的功能效果。 {: .align-center style=“width:80%”} Notion给Startups提供的模板,涵盖了日常工作的几乎所有环节 {: .align-caption style=“text-align:center;font-size:smaller”} 简洁 我是使用邮件注册的账号。和其他软件一样,当你输入邮箱并提交,Notion会给你发送一个激活码,填入激活码后需要设置用户名和密码,这里它没有按照常规做法让你输入两次密码来进行确认。虽然只输入一次密码会有可能会因为误操作填入不同于你设想的密码,但实际情况是: 这个比例应该很低 如果用户使用一个现代化浏览器例如Chrome,又有谁会真的自己去记忆密码呢,像我自己很多时候就是使用浏览器生成的随机密码。此时让用户输入两次就成了一个错误的设计 由于我对设置密码的期望是输入两次,他这个小心思一下就带来了眼前一亮的感觉。 Notion在浏览器端没有保存键,估计是随时都update到最新状态,这也更像是用笔写作状态,不知道为什么Office应用还要保留保存键。 精美 漂亮的东西无疑会增加用户使用的兴致,这方面Notion做的很棒,它内置了很多制作精良的模板,让你有兴趣继续探索它。就拿博客模板为例,里面不是简单地填充上文字和图片,还展现了丰富的样式如加粗、超链接甚至图文混排。这里选择的图片美观度也很高,颜色丰富且红、绿对比明显。 {: .align-center style=“width:80%”} 博客模板页面,样式丰富,图片精致 {: .align-caption style=“text-align:center;font-size:smaller”} 它还给每个类目都加上了一个小图标,对比一下印象笔记的界面,Notion显得活泼很多。 一些不成熟的想法 作为一个公司,想清楚怎么赚钱真的很重要。这里再次为印象笔记感到惋惜,作为笔记类应用的先行者没有快速进入到企业服务领域,一年两百的个人付费很难支撑起特别大的业务规模。从Notion的定价策略可以看出,它压根没想在个人用户身上赚多少钱,企业版单月价格是个人版的五倍。 {: .align-center style=“width:80%”} 从定价策略可以看出,企业用户能带来更多的利润 {: .align-caption style=“text-align:center;font-size:smaller”} 跟这个产品竞争最强的应该是Confluence,作为老牌企业知识平台产品,Confluence的售价贵的不是一星半点。Confluence的记录体验我认为远没有Notion强,跟外部的打通也更弱。其母公司Atlassian15年上市后股价涨了十多倍,目前市值一千多亿美元,从这个角度看,Notion还有很大的空间。 {: .align-center style=“width:80%”} 相比于Notion,Confluence昂贵得多 {: .align-caption style=“text-align:center;font-size:smaller”} 从生产力的角度看,Notion这样的应用确实补充了office系列的一些空白。Office主要针对长文档、幻灯片这种非常正式的文档类型。而笔记类应用则擅长帮助用户做一些即兴、随机、格式要求不严格的内容梳理。而Notion预置的模板也体现了近几年团队管理领域沉淀下的一些最佳实践,如果一个团队能用好这些工具,应该生产力不会太差。 {: .align-center style=“width:80%”} Office365,其实不贵 {: .align-caption style=“text-align:center;font-size:smaller”} 最后,想聊一下对国内工具或者企业服务类产品的看法。飞书看上去不错,功能全面,文档的体验跟Notion很像,但觉得它比较封闭,想在手机日历导入飞书日程都要费点劲,而且对个人用户不友好。钉钉之前用过,它更像一个管理工具而非生产力工具,已读状态也注定了它无法营造一个舒适的沟通环境,比较适合执行团队,例如销售来使用,而非创意团队。还有一个问题我一直没搞懂,为什么国内工具类应用都不收钱?zoom敢收2000块每人每月,腾讯会议到现在还免费,即使飞书这样号称”下一代工作方式“的产品都不敢收钱,企业应用不收钱给人的感觉就是不靠谱,更要命的是收了钱国内应用给人的感觉还是不靠谱,引人深思。 这篇文章就是在Notion上写的,写到这我感觉可以跟印象笔记说再见了。

November 7, 2021 · 1 min · Yuanhao

《增长黑客》阅读笔记

《增长黑客》阅读笔记 最近一年算是在做一个从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