Key Phrase Extraction

做了一段时间的新闻NLP,越来越感受到抓重点对长文本理解的重要性。类别、话题、关键词句这种离散标签对下游的推荐、搜索业务以及产品的形态都有很重大的影响。最近读了两篇关键短语抽取(Key Phrase Extraction,KPE)相关的论文,感觉挺有意思,跟大家分享一下。 问题定义和数据集 首先,对于一篇文章来说什么是其中的关键短语就没有一个统一的标准,标注的时候也比较主观,而且标注难度很大。常见的类别体系可能包含几百个类别,话题体系包含成千上万个话题,而对于关键短语来说,连个确定的候选集都没有。 目前主流的KPE任务benchmark数据集有好几个,这里列两个比较有名的 KP20k:2017年论文Deep Keyphrase Generation贡献的数据集,由科学论文组成。文本包括标题和摘要。发过论文的都知道,作者需要给文章提供几个关键词,确实是很好的数据来源。 KPTimes:2019年论文****KPTimes: A Large-Scale Dataset for Keyphrase Generation on News Documents****贡献的数据集,文章都是新闻,下面是一个例子。 KPTimes数据样例 这两个数据集规模应该都挺大了,KPTimes的论文里有一张主流数据集规格对照表,一目了然,大家可以参考。从统计上看KP20k和KPTimes篇均5个KP的确实比较实用,但它们的问题是测试集里很大比例的标签并没有在文本中出现,对于模型来说难度可能太大了 主流数据集对比 监督方法 KP20k数据集其实是那篇论文的副产品,那篇论文的主要贡献其实是一个叫CopyRNN的方法,看名字大概就知道是个seq2seq+copy机制的生成式方法。这里引入copy机制也是有比较明确的动机的,因为在RNN时代生成式方法会受限于字典,decoder输出层没有的词是无法被预测出来的。 RNN+copy机制可以在KP20k上获得0.255的F1@10 到了2020年,BERT等Transformers模型已经成了NLP领域的标配,那自然也会想到用来做KPE。Joint Keyphrase Chunking and Salience Ranking with BERT 就是里面简单且有效的一个方法。题目里的Salience是个显著的意思,这篇文章的方法也非常直接,就是把最可能是KP的文本段落(n-gram)用排序的方法找出来。那怎么得到一个n-gram的表示呢,这篇文章的办法就是在Transformer上面再套一个一维CNN,n和卷积核的大小相对应。 论文里用了两个任务来训练这个网络,一个任务是二分类,即n-gram是否是KP;另一个是排序任务,这个任务是对于文档中的每个unique n-gram,获得最大的预测值(文中称为max pooling),然后用hinge loss来使得KP的概率值大于非KP。 JointKPE的成绩大大提高 感兴趣的朋友们可以参考他们的代码实现。 非监督方法 一开始我是想找一些靠谱的非监督方法的,毕竟像KP20k这样优质的的训练数据集一般只有英语。然后就在paperswithcode上看到了目前的榜一,UCPhrase。这个方法比较有意思,它的流程如下面这张图所示 分为几个核心步骤: 找到所谓的Core Phrase。这其实是通过一些规则找到文本中反复出现的片段,并且把它们当做KP,以及后续网络训练的Silver Labels。 用Transformers语言模型生成特征。这里的特征不是大家常用的embedding,而是attention map。 训练一个图像分类器,对于一个attention map进行是否KP的二分类。 一个attention map样例,从中可以发现:1. attention map把句子分成了比较明显的几块 2.attention map可以可以作为图像输入来进行KP分类 这个论文的结果如下,在KP20k上的F1@10是19.7,和2017年的RNN+copy差了6个百分点,但和同样使用Transformers的监督方法相比差了16个百分点。 非监督方法比起监督方法来确实逊色不少 这个工作的代码也开源了:https://github.com/xgeric/UCPhrase-exp。 写在最后 提到KPE,可能大家第一个想到的方法是SpanBert那样的span prediction方法,亦或是序列标注里常用的BIO分类法,但JointBert论文里对比下来还是这种接一个CNN的方法更好。相比于单纯序列标注或片段预测,这个方法确实可以更直接地利用附近的邻域信息,在Kaggle中其实也常有在序列标注前先加一层CNN或RNN来强化邻域信息的做法。 UCPhrase的方法让人眼前一亮,有一种学术美,但与JointBert 16个百分点的性能差异又实际上让它的实用价值大打折扣。所以在业务明确的前提下,搞漂亮方法确实不如扎扎实实搞点标注数据啊。

March 26, 2022 · 1 min · Yuanhao

围观特斯拉总监把玩MNIST

最近大名鼎鼎的特斯拉AI总监Andrej Karpathy发了篇博客(看来写博客是个好习惯),叫Deep Neural Nets: 33 years ago and 33 years from now。饭后花了点时间围观了一下,写得确实挺有意思。 他先尝试复现了一下深度学习开山模型LeNet,然后尝试利用这33年人类的新知识去改进模型的效果。他干了这么几个事情: Baseline. eval: split train. loss 4.073383e-03. error 0.62%. misses: 45 eval: split test . loss 2.838382e-02. error 4.09%. misses: 82 把原文的MSE loss换成如今多分类的标配Cross Entropy Loss eval: split train. loss 9.536698e-06. error 0.00%. misses: 0 eval: split test . loss 9.536698e-06. error 4.38%. misses: 87 首战失败,怀疑SGD优化器不给力,换成了AdamW,并使用“大家都知道”的最优学习率3e-4,还加了点weight decay eval: split train. loss 0.000000e+00. error 0.00%. misses: 0 eval: split test ....

March 9, 2022 · 1 min · Yuanhao

心流

断断续续读完了《心流》这本书,感觉不错,特别是序言和前几章,大家都可以读读看,应该会有些启发(序二的作者说自己在推荐这本书时也总加上一句“读前三章就行了”)。我也把我的一些收获分享给大家。 管理好你的注意力 体验过心流的人都知道,那份深沉的快乐是严格的自律、集中注意力换来的。 书里有一个很有意思的观点,关于享乐和乐趣的区别,其中有一个差别就是乐趣是需要投入注意力的,而享受是无需耗费精神能量的。投入注意力也是体验心流的重要条件,因此不花力气的享乐只能体会到低级的“刺激”。 现代人的注意力其实是个稀缺的资源,无数的人和公司在为之竞争。而这种相对“自我”来说外部的激烈竞争甚至是侵入式的,它们把“自我”对注意力的控制权也削弱了——好多人把自己的注意力交给抖音、b站、小红书去打理。这其实是比较遗憾的。 心流较强的那组人能关闭其他资讯的管道,只把注意力集中在接收闪光的刺激上。 我我感觉注意力是可以管理和训练的,有一些简单的方法例如不带手机进卧室,把搜索作为主要的信息获取起点,多读书,多看长视频少看短视频等等。 学会自得其乐 这一点听上去有点阿Q,但我感觉确实很重要,我也挺庆幸自己对这一点掌握的还可以。之前跟总哥探讨过这个问题,我们是本科同学,他比我多金且光鲜,但他觉得我一直比他快乐。后来我们总结了几点原因,记得其中一个是我的好奇心比较强,对啥都感兴趣,所以兴趣爱好比较多,例如打游戏、弹吉他,从而可以获取乐趣的渠道比较多。 对弹吉他这点近来体验尤其强烈。之前弹吉他是下载个谱子照着弹,最近更多是就着一个backing自己即兴乱弹。虽然知道弹得很烂,但确实能体验心流。书里也提到孔子说的“立于礼,成于乐”,古人诚不欺我。 现在都说内卷,为什么卷?因为大家的差异小了,或者说是大家都不差了。如果此时再强调竞争,边际收益是很低的。特别是对个人而言,结果可能是多赚了几块钱,但身心俱疲。既然已经不差了,而且从竞争获胜获得的乐趣已经变淡,为什么不转而直接去获取快乐呢? 克服现代生活的焦虑与沮丧,必须先从社会环境中独立出来,不再孜孜以求,只以社会赋予的赏罚为念 塑造乐趣 书里有一段话描述乐趣出现的八项元素 首先,这种体验出现在我们面临一份可完成的工作时。其次,我们必须能够全神贯注于这件事情。第三和第四,这项任务有明确的目标和即时的反馈。第五,我们能深入而毫不牵强地投入到行动之中,日常生活的忧虑和沮丧都因此一扫而空。第六,充满乐趣的体验使人觉得能自由控制自己的行动。第七,进入“忘我”状态,但心流体验告一段落后,自我感觉又会变得强烈。第八,时间感会改变——几小时犹如几分钟,几分钟也可能变得像几小时那么漫长 前四项可谓是塑造乐趣的方法,比较实用。回到刚才弹吉他的例子,我感觉即兴弹比练谱有乐趣的原因就是难度比较容易匹配我的水平,也就是在做“可完成的工作”,但相比练谱也缺少“明确的目标”。 书中还有一个塑造乐趣的方法是竞争。当然这里是指良性的竞争,例如体育活动里的对抗,而不是内卷里的低效竞争。这点我也很认同,就像是我之前做Kaggle比赛的时候,竞争让我进步非常快。 英文的“竞争”(compete)一词,源自拉丁文的“con petire”,意为“共同追寻”。每个人追求的都是实现自己的潜能,在别人逼迫我们全力以赴时,这份差使就变得容易些。 以上就是所有内容,如果觉得自己最近日子过得没啥意思,不妨读读这本书。

March 9, 2022 · 1 min · Yuanhao

分级利器:序数回归

之前面试的时候遇到过好几个候选人在做”评级“相关的项目,例如针对图片、视频的色情程度,评论的粗鲁程度分级等等。绝大部分的人在面对这种问题时通常想到的都是用回归或分类来解决。这两种方法都是有效的,但都有一些问题: 常规的分类无法很好地建模类别间的关系。例如你要对评论的不文明程度分5档,但对于分类常用的交叉熵损失函数来说,把一个最高档的评论分成了最低档还是中间档对它来说损失是一样的。但对于实际的业务,前者显然比后者是更难接受的。 回归算法需要比较多的超参调试。在之前的文章里聊过,回归对标签的尺度是敏感的,把细粒度,例如100档(标签为1-100)的评级问题直接交给MSE Loss往往得不到好的结果。回归对标签中的最大值和最小值也天然会有一些抗拒。 在Pawpularity比赛结束后CPMP说他使用了一种叫Ordinal Regression(中文名没找到,姑且称它为序数回归)的方法,我在一些评级问题上尝试之后发现这个方法确实行之有效,而且非常简单优美。 数学解释 说是序数“回归”,但我它认为本质上是一个考虑了类别间关系的分类算法。 大家一定都很熟悉sigmoid函数$σ$,它的定义域是(-∞,+∞),而值域是(0,1),且是单调增函数,连续可导。我们可以把$σ(x)$看做是随机变量小于x的概率,即某个(-∞,+∞)上随机变量的累积分布函数(CDF)。 假设我要处理一个5档的分类问题,而上面说的随机变量就是模型的输出,那么问题可以转化为找到四个切分点$\theta_1, \theta_2, \theta_3, \theta_4$,并用$P(x<\theta_1)$, $P(\theta_1< x<\theta_2)$, $P(\theta_2< x<\theta_3)$, $P(\theta_3< x<\theta_4)$, $P(\theta_4< x<+\infty)$这五个概率来表示$x$分别属于五个等级的概率。进一步结合前面的sigmoid函数做CDF的方法,可以把五个概率转化为$σ(\theta_1-x)$, $σ(\theta_2-x)-σ(\theta_1-x)$, $σ(\theta_3-x)-σ(\theta_2-x)$, $σ(\theta_4-x)-σ(\theta_3-x)$, $1-σ(\theta_4-x)$。 这样我们就把一个模型输出的实数logit转化成了属于五个等级的概率,进而可以使用负对数似然损失函数来优化这个分类问题。在这样的设定下既可以使用一组固定的切分点来优化模型,又可以把切分点也作为可学习的权重和模型一起优化。 代码 一开始我在网上找到了一个pytorch的Ordinal Regression实现spacecutter,但经过一番实验之后我发现它写的并不完美,于是自己又修改了一下,在这里分享给大家 class OrdinalRegressionLoss(nn.Module): def __init__(self, num_class, train_cutpoints=False, scale=20.0): super().__init__() self.num_classes = num_class num_cutpoints = self.num_classes - 1 self.cutpoints = torch.arange(num_cutpoints).float()*scale/(num_class-2) - scale / 2 self.cutpoints = nn.Parameter(self.cutpoints) if not train_cutpoints: self.cutpoints.requires_grad_(False) def forward(self, pred, label): sigmoids = torch.sigmoid(self.cutpoints - pred) link_mat = sigmoids[:, 1:] - sigmoids[:, :-1] link_mat = torch....

March 2, 2022 · 1 min · Yuanhao

2021面试总结

今年由于各种原因参加了很多面试,面过的候选人可能快一百个了。其中有经验丰富的高P,也有初出茅庐的应届生。面的多了之后不仅能发现候选人的问题,也能发现自己作为面试官的问题。就像古人说的,千里马常有而伯乐不常有,为了以后能更好地评估候选人(主要是工程师)的水平,我做了一些总结,也分享出来跟大家讨论。 明确要招什么样的人 正所谓看人下菜碟,在面试之前要对候选人有个大致的定位,当然这个不是静态的,可以在面试的过程中调整。总体来说我目前接触过的大概分成三类 工具人。对应的大概是三年以内工作经验的人,可以完成安排的任务,不需要考虑为什么做这个。 能独立解决问题的人。三年以上经验的候选人我会期待他能够在工具人的基础上具有方案设计能力,如果能有一些业务洞察就更好了。 能带团队做业务的人。带队大佬还聊得不多,这篇就先不谈。 考察什么 目前我认为有以下三个方面需要考察: 业务能力 专业技能 数理逻辑能力 知识面 三观 软技能 沟通能力 领导力 首先业务能力达标是候选人需要满足的基本要求;然后是三观,跟一个价值取向正确、积极向上、有趣的人一起工作一点会让自己和公司收益;最后是软技能,基本是作为加分项。 怎么考察 聊项目 这部分对面试官的要求最高,因为候选人做的东西可能超出了自己的知识范围,但我觉得这部分又特别重要。以技术面为例,候选人在项目上花的时间远比花在面试时的代码测试长,所以这部分更能综合地看出候选人的上限。 聊项目我认为有几个层次: 第一个层次是聊出候选人在其中的工作量和项目的完成度。一个合格的工具人应该能做到高完成度并讲清楚自己做的事情。 第二个层次是聊价值和动机。为什么做这些事情,技术指标和业务指标怎么对应,为什么按照简历里写的方案做。一个能独立解决问题的人应该能回答出这些问题。 聊项目的时候我觉得应该避免太泛也难量化评估的问题,例如:之前项目里遇到的最大困难是什么,怎么解决的。如果是候选人是大神应该觉得都没啥困难,真的困难大概率也还没有被解决。 方案设计 这是我目前认为比较好的一种考察方式,刚才聊项目是顺着候选人来,方案设计则是由面试官来主导。这里可以选一个工作里实际遇到且比较开放的问题和候选人进行讨论,几乎可以考察到业务能力里面的各个维度。可以提前准备一些比较细致、刁钻的follow up,不仅能考察候选人,说不定还能对自己的工作产生启发。 代码测试 代码测试也很重要,但我认为这是用来控制下限的。考LeetCode上的数据结构和算法感觉也不是一个特别好的选择,试问大家工作中用过几次动态规划呢。所以我比较倾向于考一些即使没有见过也能用基本编程思想解决的问题。 数学题、基础知识 我之前面试的时候也被问过数学题和基础知识,这是考察之前项目不是特别对口的候选人或者应届生的一个好手段。对于比较有经验的候选人可以让总结一下近些年技术的发展脉络,这个对逻辑思维和知识面是个不错的考察。 聊天 聊天主要是对三观和软技能的考察,最直接的可以聊一下换工作的动机,对年轻候选人可以聊聊人生规划,对老人可以聊聊对领域和行业的看法,有个前辈经常问候选人平常有什么兴趣爱好等等。 让候选人问问题 从我面试的结果看,不同人问的问题不太一样。不少人会问公司规模、工作节奏相关的问题,有的会问自己面试的岗位定位业务发展相关的问题。有两个候选人的问题我印象比较深刻。一个是说他看了应用商店里的评论后发现不少用户在抱怨一个问题,问为什么会出现这个问题,从这个问题可以看出候选人主动做了功课,还对后面的技术问题有好奇心。另一个问我当时为什么决定加入这家公司,这个问题不仅可以拉近和面试官的距离,也可以给候选人带去很多信息,如果一个新人问这个问题,那ta大概率是比较有探索精神的一类人。 建立打分表 不管公司的打分表是怎么样的,最好都给自己的考察方案设计一套最合适的打分表,提前确定好各个维度的权重和打分细则,这样不仅能更加公平地做候选人之间的比较,也能让面试更加有针对性。这里也给出我针对3-5年经验工程师的打分表,算是对上面内容的总结。 维度 分值 细则 备注 项目:工作量和完成度 6 工作量正常、完成良好4分,能回答各种问题2分 项目:价值和动机 5 抓住对业务的价值重点2.5分,技术方案综合考虑效果、成本、可行性2.5分 方案设计 5 方案能满足功能3分,方案体现优秀的技术深度、广度2分 代码测试 6 正确、完整实现功能4分,速度快、代码风格好2分 三观 2 正常人1分,特别正2分 不正常人直接淘汰 软技能 1 沟通、表达特别好1分 总和 25

December 20, 2021 · 1 min · Yuanhao

多模态对比学习预训练模型CLIP

我经常在面试的时候问候选人如何构建一个文本配图系统,有不少人都会想到OpenAI的 CLIP (Contrastive Language–Image Pre-training) 模型。确实,CLIP的思路应该是解决这个问题的一个好框架,正好之前的几篇文章又都是关于其中的关键技术,于是这篇文章重温一下CLIP。 方法 自然语言信号 At the core of our approach is the idea of learning perception from supervision contained in natural language. 正如作者所说,这是CLIP的核心,但并不是一个新的方法。很多过去的研究都使用自然语言信号来训练图片编码器,但大家使用的方法各不一样。 用自然语言信号有几个好处,一个是数据收集容易了,有相关性的图文在互联网上很多,不需要标注,第二个是与之前那种类别空间相比,自然语言信号更容易迁移,后面还会具体讲到。 更大的数据集 CLIP构建了一个400 million 图片-文本对组成的数据集。比之前类似工作所使用的数据集大了二十几倍。而且这些数据集都是互联网上现成的,只是做了一些过滤来保证质量。 it is trained on a wide variety of images with a wide variety of natural language supervision that’s abundantly available on the internet 更大的模型 文本编码器使用的是12层8个头512个隐层神经元的Transformers模型,但没有使用预训练模型。我猜测这是因为要跟图像编码器交互,所以预训练可能帮助不大,如果使用预训练模型还需要特殊的策略来让图像和文本编码器的embedding空间匹配起来。 图像编码器尝试了resnet家族和ViT家族。最佳结果是来自于ViT,并且ViT相比于Resnet有更高的训练效率。图像编码器同样也没有使用Imagenet上的预训练权重来初始化。ViT我们在之前有两篇文章介绍,感兴趣的同学可以参考。 更高效的训练目标 过去的SOTA CV模型,如Noisy Student EfficientNet-L2,只训练Imagenet就需要耗费大量的训练时长(33个TPU年),如何能够在超大规模、自然语言信号的数据集上训练出一个好模型是个挑战。这部分也是CLIP最核心的地方。 This data is used to create the following proxy training task for CLIP: given an image, predict which out of a set of 32,768 randomly sampled text snippets, was actually paired with it in our dataset....

December 13, 2021 · 2 min · Yuanhao

对比学习学习笔记

对比学习已经火了一阵了,之前看过一下SimCLR和SimCSE的论文,但走马观花也没有实践。这两天仔细学习了一下,大概明白了是怎么回事。 首先对比学习通常是在自监督的设定下进行表征学习,也就是不依赖标注数据获得一个编码器(Encoder),大致的环节如下 通过一些方式构造人工正样本对 在一个Batch内构造负样本对 设计一个loss,拉近正样本对表征(Embedding)间的距离,扩大负样本对表征间的距离 构造正样本对 对比学习一开始是在计算机视觉领域兴起的,CV论文里最初是通过对一张图片进行两次不同的数据增强来构造正样本对的。 SimCLR里用到的图像增强方法,可以看出来强度是比较高的,模型要学会图像间的关系不是那么容易 后来这把火烧到了NLP领域,最开始也是模仿CV的做法,通过例如删字词、换同义词等数据增强来构造。直到大名鼎鼎的SimCSE横空出世,提出了用两次不同的dropout来构造正样本对的方法,而且效果还特别好。这个方法的前提是在transformers里面每层都有dropout,但常见的卷积神经网络里面dropout往往都只在最后才有,所以并不能迁移到CV界;但最近ViT大火,应该也有人会试着使用这种方法。 SimCSE除了有自监督的版本,还有通过数据集特点构造的有监督版本 损失函数构造 SimCLR里面用的是NT-Xent Loss,它是the normalized temperature-scaled cross entropy loss的缩写,我来翻译的话会叫他“归一化的带温度交叉熵”。其公式如下 $$l(i,j)=-\text{log}\frac{e^{\text{sim}(z_i,z_j)/\tau}}{\sum_{k=1}^{2N}1_{k\ne i}e^{\text{sim}(z_i, z_k)/\tau}}$$ $$L=\frac{1}{2N}\sum_{k=1}^N[l(2k-1,2k)+l(2k,2k-1)]$$ SimCLR中一个batch是由N张图片通过两组不同的增强变成2N张并且穿插排列,即2k-1 和 2k 是由同一张图构造的一对人造正样本。从第二个式子可以发现,一个Batch的Loss是其中N对loss的均值。跟cross entropy相比,首先是指数项从模型预测的概率变成了样本对间的相似度。分子与正样本对的相似度相关,分母则与第i张图与其余图的相似度有关。注意分母中只有2N-1项,因为自己与自己天然组成正样本,不去除的话这个分式的极限值(完美模型的loss值)将变成0.5,总loss也就不是0了。 SimCSE里使用的loss是上面的变种,或者说是个简化版本。$z_i$是原始第i个样本的表征,$z’_i$是对应的人造正样本的表征。与上面不同的是原始样本表征之间的相似度、变换样本表征之间的相似度都没有参与loss计算。 $$l(i)=-\text{log}\frac{e^{\text{sim}(z_i, z’i)}}{\sum^N{j=1}e^{\text{sim}(z_i, z’_j)}}$$ 代码实现 下面是我实现的SimCSE版本的对比学习loss,供大家参考 class NTXentLoss(nn.Module): def __init__(self): super().__init__() def forward(self, rep1, rep2, temperature=0.5): normalized_rep1 = F.normalize(rep1) normalized_rep2 = F.normalize(rep2) dis_matrix = torch.mm(normalized_rep1, normalized_rep2.T)/temperature pos = torch.diag(dis_matrix) dedominator = torch.sum(torch.exp(dis_matrix), dim=1) loss = (torch.log(dedominator)-pos).mean() return loss 实验心得 我还是在之前提到的Pawpularity数据集上进行的实验,并且和论文里的表征学习不同,我是将对比学习作为一个辅助任务来帮助主任务的训练。经过一天的实验,有以下一些发现 在参数合理的情况下,加入对比学习作为辅助任务确实可以提升主任务的表现。 加入对比学习作为辅助任务看上去可以让模型收敛更加稳健,从而可以使用更大的学习率、更高强度的数据增强。 Loss中的温度是很重要的参数,在SimCLR论文中最好的温度是0.1,在SimCSE论文中最好的温度是0.05,但在我的实验里最好的值跟这俩差的很多。熟悉蒸馏的朋友应该知道,温度越高会让样本间的差异越小,loss趋近常数;温度越低则反之。SimCSE论文的消融实验尝试了不同数量级的温度,大家在用的时候也可以大胆地多尝试一下。 将对比学习作为辅助任务额外增加的时间代价不明显。 今天先到这里,上班去辽。

December 6, 2021 · 1 min · Yuanhao

Swin Transformer (v2)学习笔记

上篇总结了一下最初的ViT模型,它有几个明显的问题: 建模能力方面,强行分割patch破坏了原有的邻域结构,也不再具有卷积的那种空间不变性 复杂度方面,之前的ViT是在每层都做全局(global)自注意力。如果保持每个Patch的大小不变,随着图片尺寸的变大,Patch的个数会增加,而Patch的个数等于进入Transformer的Token个数,且Transformer的时间复杂度是O(n^2)。 易用性方面,由于Embedding(结构是全连接)和图片大小是绑定的,所以预训练、精调和推理使用的图片必须是完全同等的尺寸。 Swin Transformer提出了一种称为shifted window的方法来解决(缓解)以上问题。 Swin Transformer的结构如下图所示 {: .align-caption style=“text-align:center;font-size:smaller”} Embedding Stage(stage1)。将图片划分为若干4*4的patch,使用线性变换来将patch变为Embedding向量,这一步和ViT是一样的。但是注意,这里的patch比ViT的14*14小了很多。 若干个使用Swin Transformer 的Stage(stage2-4)。这里模仿了经典卷积网络backbone的结构,在每个Stage都将feature map(对应到Vit就是Patch或Token的个数)变成原来的四分之一。这是通过简单地将2*2patch合并成一个来完成的。同时,用Swin Transformer替代了原来的标准Transformer,主要变化如下 用M*M大小的窗口自注意力代替全局自注意力。因为自注意力机制时间复杂度是O(n^2),通过减少参加自注意力的元素,将原来关于patch数平方复杂度的计算变为关于patch数线性复杂度 用对角线方向的shift来使Swin Transformer里的每一层窗口都是不同的,这样一个patch有机会和不同的patch交互。这里还使用了一个mask trick来使得这种shift的自注意力计算更高效。 添加了相对位置偏置(relative position bias),对比发现这比添加绝对位置embedding效果好很多 shifted window示意图,l+1层的窗口是从l层往右下角平移2个patch得到的 {: .align-caption style=“text-align:center;font-size:smaller”} 从结果来看,SwinT相比于ViT有了很大的提升 Swin Transformer实验结果,可以看出来比ViT已经有了很大的提升 {: .align-caption style=“text-align:center;font-size:smaller”} 综合消融实验的结果可以对比三种不同的attention方式: fixed window、sliding window和shifted window的性能。他们的imagenet top1 acc分别是80.2, 81.4和81.3。从中可以看出类似于卷积的sliding window性能是最好的,无奈太慢了。fixed window丢失了很多有用的窗口间交互,性能最差。shifted window性能相比sliding window下降微弱,但速度提升了好几倍。同样可视为fixed window的ViT只能得到0.78的top1 acc,我想这是小patch带来的差别,因为现在的线性变换embedding实在太弱了,patch越大带来的信息丢失就越多。 前不久原班人马又发布了V2版的Swin Transformer,主要是解决模型上规模的问题,有几个主要的改动: 把每个Block里的LN从前面换到了后面,来解决深度增加之后训练不稳定的问题 把原来的scaled dot attention换成了scaled cosine attention,也是为了解决训练不稳定的问题(否则可能被某些像素对的相似度主导)。 改进相对位置偏置。V1版里这个模块是用一个规模跟窗口大小M相关可学习参数矩阵来处理的,如果预训练和finetune时M大小改变,就用插值来生成原来不存在的值。V2版首先是引入了一个小网络来取代参数矩阵,其次是将相对位置从线性空间换到了对数空间,通过取对数压缩空间差距来让M变化时的过渡更加顺滑 通过取对数,让finetune时增大窗口和图片的性能损失大为减小。但其实这里还是跟卷积神经网络有差距。通常卷积神经网络在finetune时使用更大的图片可以提升性能。 {: .align-caption style=“text-align:center;font-size:smaller”} 从结果来看,更大的网络确实带来了更好的性能,30亿参数版的SwinV2-G比8800万参数版的SwinV2-B性能提升了不少。同样参数量的V2版也比V1版提升了一些。 不同模型Imagenet结果 {: .align-caption style=“text-align:center;font-size:smaller”} 消融实验也比较清晰地反映出了V2版加入的新技术带来的技术提升...

November 28, 2021 · 1 min · Yuanhao

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