论文笔记-无监督机器翻译

Extract and Edit: An Alternative to Back-Translation for Unsupervised Neural Machine Translation

王威廉老师组的一篇文章,大致看了下跟最近自己做的研究相关性挺大的。文中也简单的介绍了无监督机器翻译的一些方法,所以借这个机会把无监督机器翻译也好好了解下。记得在三星研究院实习时,有个中科院自动化所的师姐(据说是宗成庆老师的学生)说过一句话,2018年是无监督机器翻译元年。但当时我在搞QA,就没怎么深入研究。感觉很多NLP其他方向的做法都是源于 NMT,所以还是很有必要看一下的。

Motivation

Back-translation 得到的伪平行语料,是基于 pure target sentence 得到 pesudo source sentence,然后把 prue target sentence 作为 label 进行监督学习(保证target 端是pure sentence,source端的sentence可以稍微 noisy)。这实质上就是一个 reconstruction loss. 其缺点在于 pesudo source sentence 质量无法保证,会导致误差累积(pesudo source sentence 并没有得到更新,所以并没有纠正存在的错误)。

基于此,作者提出了一种新的范式,extract-edit.

单语语料的选择

neural-based methods aim to select potential parallel sentences from monolingual corpora in the same domain. However, these neural models need to be trained on a large parallel dataset first, which is not applicable to language pairs with limited supervision. 

通过平行语料训练翻译模型,进而从单语中选择 domain related sentences. 这并不是完全的无监督,还是需要有限的平行语料得到 NMT 模型之后,去选择合适的单语。

  • Parallel sentence extraction from comparable corpora with neural network features, LERC 2016

  • Bilingual word embeddings with bucketed cnn for parallel sentence extraction, ACL 2017

  • Extracting parallel sentences with bidirectional recurrent neural networks to improve machine translation, COLING 2018

完全的无监督机器翻译

The main technical protocol of these approaches can be summarized as three steps: 

  • Initialization

  • Language Modeling

  • Back-Translation

Initialization

Given the ill-posed nature of the unsupervised NMT task, a suitable initialization method can help model the natural priors over the mapping of two language spaces we expect to reach.

初始化的目的基于自然语言的一些先验知识来对两种语言的映射关系进行建模。

there two main initiazation methods:

  • bilingual dictionary inference 基于双语词典的推理

    • Word translation without parallel data. Conneau, et al. ICLR 2018

    • Unsupervised neural machine translation, ICLR 2018

    • Unsupervised machine translation using monolingual corpora only, ICLR 2018a

  • BPE

    • Phrase-based & neural unsupervised machine translation. emnlp Lample et al. 2018b

本文作者采用的是 Conneau, et al. 中的方式,并且类似于 Lample 2018b 中的方式两种语言共享 bpe(需要在看下相关论文). 这里实际上就是训练得到两种语言的 word embedding,并不是 word2vec 那种对单种语言的无监督,而是训练得到两种语言的 share embedding.

language modeling

Train language models on both source and target languages. These models express a data-driven prior about the composition of sentences in each language.

在初始化之后,在 share embedding 的基础上分别对 source 和 target 的语言进行建模。

In NMT, language modeling is accomplished via denosing autoencoding, by minimizing:

本文作者采用的 Lample 2018a 的方式。共享 encoder 和 decoder 的参数???

Back-Translation

  • Dual learning for machine translation, NIPS 2016

  • Improving neural machine translation models with monolingual data. ACL 2016

Extract-Edit

  • Extract: 先根据前两步得到的 sentence 表示,从 target language space 中选择与 source sentence 最接近的 sentence(依据相似度?).

  • Edit: 然后对选择的 sentence 进行 edit.

作者还提出了一个 comparative translation loss。

Extract

因为在 language model 阶段作者已经共享了 encoder 和 decoder,所以在这个场景下对于 two language 的表示,都可以用 encoder 得到。

在 target language space 中选择出与 source sentence 最接近的 top-k extracted sentences. 为什么是 top-k 而不是 top-1 呢,确保召回率,并获得更多更相关的 samples.

Edit

简单点就是 max-pooling + decode

employ a maxpooling layer to reserve the more significant features between the source sentence embedding $e_s$ and the extracted sentence embedding $e_t$ ($t\in M$), and then decode it into a new sentence $t’$.

具体是怎么操作的呢,这似乎需要看代码。

$e_s$: [es_length, encoder_size]

$e_t$: [et_length, encoder_size]

这怎么 max-pooling 呢(句子长度都可能不一样),然后 decode 得到新的 sentence 吧。。

Evaluate

虽然 M’ 中可能存在潜在的 parallel sentence 对应 source sentence s. 但是依然不能用 (s, t’) 作为 ground-truth stence pairs 来训练 NMT 模型。因为 NMT 模型对噪声非常敏感。

作者提出了一个 evaluation network R, 实际上就是多层感知机,也许是个两层神经网络吧,具体没说。two labguage 共享 R.

$$r_s=f(W_2f(W_1e_s+b_1)+b_2)$$

$$r_t=f(W_2f(W_1e_t’+b_1)+b_2)$$

假设是这样,也就是将 t’ 转换成 t* 了。

理解错了

其目的是将 s 和 t’ 映射到同一向量空间,然后计算两者的相似度:

接下来将 $\alpha$ 转换成概率分布。 也就是计算 top-k 个 extracted-edited 得到的 target sentences t* 与 source sentence s 相似的概率,并且这些概率相加为 1.

其中 $\lambda$ 可以看作是 inverse temperature, $\lambda$ 越小,表示所有 t* 平等看待,越大,表示更看重 $\alpha$ 最大的那一句。显然前面的 $\alpha$ 是通过 cosine 计算的,也就是更看重 k 个 t* 中与 s 距离最近的那个 sentence.

learning

Comparative Translation

cosine 相似度越大越接近,所以 -logP 越小越好。这里面涉及到的参数 $\theta_{enc}, \theta_R$

Basically, the translation model is trying to minimize the relative distance of the translated sentence t* to the source sentence s compared to the top-k extracted-and-edited sentences in the target language space. Intuitively, we view the top-k extracted-and-edited sentences as the anchor points to locate a probable region in the target language space, and iteratively improve the source-to-target mapping via the comparative learning scheme.

Adversarial Objective

we can view our translation system as a “generator” that learns to generate a good translation with a higher similarity score than the extracted-and-edited sentences, and the evaluation network R as a “discriminator” that learns to rank the extracted- and-edited sentences (real sentences in the target language space) higher than the translated sentences.

借助于对抗学习的思想,可以把 translation system 看作是 生成器 generator, 用来学习得到 translated target sentence,使得其优于 extracted-and-edited sentences.

把 evalution newtork R 看作是判别器,其目的就是判别 extracted-and-edited sentences 优于 translated target sentences.

因此对于 evaluation network R,有

final adversarial objective

Model selection

无监督学习因为没有平行语料,所以需要一个指标来表示模型的好坏,也就是翻译质量。

Basically, we choose the hyper-parameters with the maximum expectation of the ranking scores of all translated sentences.

Implementation details

Initialization

cross-lingual BPE embedding, set BPE number 60000.

然后用 Fasttext 训练得到 embedding, 512 dimension. 其中 Fasettext 设置 window size 5 and 10 negative samples

Model structure

all encoder parameters are shared across two languages. Similarly, we share all decoder parameters across two languages.

The λ for calculating ranking scores is 0.5. As for the evaluation network R, we use a multilayer perceptron with two hidden layers of size 512.

论文笔记-对话系统

paper

A Survey on Dialogue Systems: Recent Advances and New Frontiers, Chen et al. 2018

motivation

这是一篇关于对话系统的综述。

对话系统主要分为两大类:

  • 任务导向型(task-oriented) 对话系统

  • 非任务导向型(non-task-oriented)对话系统

    • 序列到序列模型 sequence-to-sequence models

    • 检索式模型 retrieval-based methods

task-oriented dialogue system

面向任务的系统旨在帮助用户完成实际具体的任务,例如帮助用户找寻商品,预订酒店餐厅等。

有两种方式:

  • pipeline methods

  • end-to-end methods

pipeline methods

其流程是4个步骤:

  • language understanding

  • dialogue state tracking

  • policy learning

  • natural language generation

language understanding

第一步是 utterance 理解。将给定的 utterance 映射成对应的语义槽 (semantic slots).

Given an utterance, natural language understanding maps it into semantic slots. The slots are pre-defined according to different scenarios.

slots 都是根据特定的场景定义好的。

看表格能发现,包含三个任务:

  • intent dection: 这个是 utterance-level classification,也就是一个分类任务

  • domain classification: 也是分类任务

  • slot filling: 这是 word-level 的任务,可以定义成序列标注问题,输入是一个 utterance,输出是对应每个 word 的 semantic label.

关于 slot filling 的 paper:

  • CRF baseline

  • DBNs:

    • Deep belief network based semantic taggers for spoken language understanding

    • Use of kernel deep convex networks and end-to-end learning for spoken language understanding

  • RNN:

    • Investigation of recurrent-neural-network architectures and learning methods for spoken language understanding, 2013

    • Deep belief nets for natural language call-routing. 2011

    • Recurrent neural networks for language understanding, 2013

    • Spoken language understanding using long short-term memory neural networks. 2014

Dialogue State Tracking

对话的状态跟踪,预测每一轮对话 user 的 goal. 对话状态跟踪是确保对话系统健壮性的核心组件。它在对话的每一轮次对用户的目标进行预估,管理每个回合的输入和对话历史,输出当前对话状态。这种典型的状态结构通常称为槽填充或语义框架。

所以对应的 state 是根据场景预定义好了的嘛?比如 online shopping,对应的 state 可能就有 推荐,比较,下单等等?

基于传统方法的有很多,基于 deep learning 的有:

  • [26] Deep neural network approach for the dialog state tracking challenge. 2013

  • [58] Multi-domain dialog state tracking using recurrent neural networks. 2015

  • [59] Neural belief tracker: Data-driven dialogue state tracking, 2017

Policy learning

根据上一步得到的 state,来制定下一步的 action. 很符合强化学习的理念啊,不过需要解决 热启动 (warm-start) 的问题。

  • 基于规则的监督学习(state 的状态需要规则来定义):

    • [111] Building task-oriented dialogue systems for online shopping,
  • deep reinforcement learning:

    • [14] Strategic dialogue management via deep reinforcement learning, 2015

基于强化学习的方法已经超过监督学习了。

natural language generation

一个好的生成器通常依赖于几个因素:适当性、流畅性、可读性和变化性。传统的NLG方法通常是执行句子计划。它将输入语义符号映射到代表话语的中介形式,如树状或模板结构,然后通过表面实现将中间结构转换为最终响应。深度学习比较成熟的方法是基于LSTM的encoder-decoder形式,将问题信息、语义槽值和对话行为类型结合起来生成正确的答案。同时利用了注意力机制来处理对解码器当前解码状态的关键信息,根据不同的行为类型生成不同的回复。

  • [123] Context-aware nat- ural language generation for spoken dialogue systems. Zhou et al, 2016 COLING

adopted an encoder-decoder LSTM-based structure to incorporate the question information, semantic slot values, and dialogue act type to generate correct answers. It used the attention mechanism to attend to the key information conditioned on the current decoding state of the decoder. Encoding the di- alogue act type embedding, the neural network-based model is able to generate variant answers in response to different act types.

end-to-end model

传统的 pipeline 的方法的缺点:

  • user 的反馈很难传递到每一个 module

  • 每一个 module 都是相互依赖的 (process interde- pendence)

也就是在不同的 domain 或者 scenarios 时,pipeline 设计的对话系统可能就不使用的,因为 slots 和 features 都是 task-specificed,都会相应的改变。而这些过程都需要大量的人工工程。

因此我们需要 end-to-end model。与传统的 pipeline 模型不同,端到端模型使用一个模块,并与结构化的外部数据库交互。

  • network-based end-to-end 模型需要大量的标注数据

    • Learning end-to-end goal-oriented dialog, Bordes et al, 2017 ICLR

    • A network-based end-to-end trainable task-oriented di- alogue system, 2017 ACL

  • end-to-end reinforcement learning 在对话管理中,联合训练 state tracking 和 policy learning, 从而使得模型鲁棒性更强。

    • Towards end-to-end learn- ing for dialog state tracking and management us- ing deep reinforcement learning,2016 ACL
  • task-completion neural dialogue system, 其目标就是完成一个任务。

    • End-to-end task- completion neural dialogue systems,2017

以任务为导向的对话系统通常还需要查询外部知识库。传统的采用的方法就是通过 semantic parsing 形成一个 query,然后去匹配外部知识库,通过检索得到想要的 entries. 其缺点是:

  • 检索的结果不包含有关语义分析中的不确定性信息

  • 检索的过程是不可微的 (non-differentiabl), 因此 semantic parsing 和 dialogue policy 只能分别训练,导致 online end-to-end 的模型很难部署。

解决这个问题的 paper:

Non-task-oriented dialogue system

非任务导向型对话系统也就是聊天机器人, 是通过生成模型或基于检索的方法实现的。 生成模型能够生成更合适的回复(也就是跟上下文语义更接近),而这些回复可能从来没有出现在语料库中,而基于检索的模型则能得到具有信息充裕 (informative) 和 fluent 的回复。

Neural Generative models

深度学习在机器翻译中的成功应用,即神经机器翻译,激发了人们对神经生成对话研究的热情。

最开始也有一篇 paper,将对话当最机器翻译来做的 paper. 把对话看作是将 post 翻译成 response。但是区别在于 response 的范围很广,而且 post 和 response 并不像翻译的两个句子之间存在对齐关系。

目前神经生成模型的热门研究课题,主要是讨论:

  • response diversity

  • modeling topics and personalities

  • leveraging outside knowledge base

  • the interactive learning

  • evaluation

Sequence-to-Sequence Models

这个就是基本的 seq2seq 模型。好奇的是,如何解决多轮对话,如何结合 history 信息,如何控制对话的状态,这些都需要深入看 paper 吧。

Dialogue Context

考虑历史对话的历史信息的能力是建立可保持对话活跃的对话系统的关键。

Response Diversity

A challenging problem in current sequence-to-sequence dialogue systems is that they tend to generate trivial or non-committal, universally relevant responses with little meaning, which are often involving high frequency phrases along the lines of I dont know or Im OK.

在当前的序列对话系统中,一个具有挑战性的问题是,它们倾向于产生意义不大的普通或不重要的、普适的回答,而这些回答往往涉及到“我不知道”或者“我很好”这样的高频率短语。

  1. MMI and IDF

模型的这种行为可以归咎于模型赋予了 “safe” response 更高的概率。A diversity-promoting objective function for neural con- versation models. ACL 2016 使用了 Maximum Mutual Information 作为优化目标,这是最初在语音识别领域引入的。 它测量了输入和输出之间的相互依赖关系,并考虑了消息回复的逆向依赖性。 An attentional neural conversation model with improved speci- ficit, 2016 结合逆文档频率(IDF)到训练过程来评价回复的多样性。(在不同的 document 中出现的回复次数越多,其相应的权重越低)。

  1. beam-search

一些研究表明,解码的过程也是回复冗余的另一个缘由。[86][72][42] 发现 beam-search 在生成候选答案时中缺乏多样性。[86] 提出了一种衡量不同回复之间的相似度的方法,类似于正则惩罚项吧,来增强 beam-search 的目标函数。[72] 提出了一种随机 beam-search 的方法,[42] 则使用了一个惩罚项来惩罚来自同一父节点中的子节点的展开。

  1. re-ranking

[38][77][72] 结合全局特征,重新执行 re-ranking 的步骤,从而避免生成 dull or generic 的回复。

  1. PMI

[57] 猜测问题不仅仅在于解码和 respones 的频率,而且消息本身也缺乏足够的信息。 它提出使用逐点互信息(PMI)来预测名词作为关键词,反映答复的主要依据,然后生成一个包含给定关键字的答复.

  1. latent variable

另一系列工作着重于通过引入随机隐变量来产生更多不同的输出。 他们表明,自然对话不是确定性的 —— 对同一信息的答复可能会因人而异。 但是,当前回复是从确定性 encoder-decoder 模型中采样的。 通过整合隐变量,这些模型的优点是,在生成时,他们可以通过首先对隐变量的分配进行采样,然后确定性地进行解码,从分布中采样回复。

Topic and Personality

明确对话的内在属性是提高对话多样性和保证一致性的另一种方法。在不同的属性中,主题和个性被广泛地进行研究探讨。

  1. Topic aware neural response generation, AAAI 2017 注意到人们经常把他们的对话与主题相关的概念联系起来,并根据这些概念做出他们的回复。他们使用Twitter LDA模型来获取输入的主题,将主题信息和输入表示输入到一个联合注意模块中,并生成与主题相关的响应。
  1. Multiresolution recurrent neural networks: An application to dialogue response generation. AAAI 2017 对粗粒度的 tokens sequence 和 dialogue generation 进行联合建模,粗粒度的 tokens 主要是用来探索 high-level 的语义信息,通常是 name entity 或 nouns.
  1. Emotional chatting machine: Emotional conversation generation with internal and external memory 将情感 embedding 融入到了对话生成中。Affective neural response generation, 2017 通过三种方式增强回复的情感:
  • incorporating cognitive engineered affective word embeddings

  • augmenting the loss objective with an affect-constrained objective function

  • injecting affective dissimilarity in diverse beam-search inference procedure

  1. Assigning personality/identity to a chatting machine for coherent conversation generation 让对话个性化,并且保持一致性。Neural per- sonalized response generation as domain adaptation 提出了一种两阶段的训练方法,使用大规模数据对模型进行初始化,然后对模型进行微调,生成个性化响应。
  1. Personalizing a dialogue system with transfer reinforcement learning 使用强化学习来消除对话的前后不一致性。

Outside Knowledge Base

人类对话与对话系统之间的一个重要区别是它是否与现实相结合。结合外部知识库(KB)是一种很有前途的方法,可以弥补背景知识之间的差距,即对话系统和人之间的差距。记忆网络(Memory Network)是一种以知识库处理问题的经典方法。因此,它非常直接的别用于在对话生成中。实际研究表明,所提出的模型能够通过参考知识库中的事实来生成对问题的自然和正确答案。

Interactive Dialogue learning

通过交互来学习是对话系统的最终目标之一。Deep reinforcement learning for dialogue generation, ACL 2016 利用两个虚拟智能体模拟对话。它们定义了对描述一个较好的对话的汇报的一个简单的启发式的估计:好的对话是有前瞻性[1]或者交互式的(当前轮为下一轮对话铺垫),是信息丰富的和连贯的。一个RNN的编码器-解码器所有参数定义了一个在无穷大的动作空间上从所有可能的话语中进行选择的策略。智能体是通过策略梯度方法 Simple statistical gradient-following al- gorithms for connectionist reinforcement learning, 1992 来优化由开发者定义的长期奖励,而不是通过标准seq2seq的MLE目标函数来学习策略。[32]进一步试图提高机器人从交互中学习的能力。通过对文本和数字反馈使用策略学习和前向预测,该模型可以通过(半)在线方式与人进行交互来提高自身性能。

由于大多数人类在对答案并不自信时通常会要求提供一些澄清或者提示,所有机器人拥有这种能力也是相当自然的。Learning through dialogue interactions by asking questions. 2017 定义了机器人在回答问题时遇到困难时的三种情况。与不采用提问的实验结果相比,这种方法在一些情况下有了很大的改进。Deal or no deal? end-to-end learning of negotiation dialogues, ACL 2017 在谈判任务中进行了探索。由于传统的序列到序列模型模拟人类的对话没有优化具体的目标,这项工作采取了面向目标的训练和解码方法,并展示了一个有价值的视角。

Evaluation

评价生成回复的质量是对话系统的一个重要方面。任务导向型的对话系统可以基于人工生成的监督信号进行评估,例如任务完成测试或用户满意度评分等,然而,由于高回复的多样性,自动评估非任务导向的对话系统所产生的响应的质量仍然是一个悬而未决的问题。目前的方法有以下几种:

  • BLEU, METEOR, and ROUGE 值,也就是直接计算 word overlap、ground truth和你生成的回复。由于一句话可能存在多种回复,因此从某些方面来看,BLEU 可能不太适用于对话评测。

  • 计算 embedding的距离,这类方法分三种情况:直接相加求平均、先取绝对值再求平均和贪婪匹配。

  • 进行图灵测试,用 retrieval 的 discriminator 来评价回复生成。

Retrieval-based Methods

基于检索的方法从候选回复中选择回复。检索方法的关键是消息-回复匹配,匹配算法必须克服消息和回复之间的语义鸿沟。

single-turn response match

$$match(x,y)=x^TAy$$

Convolutional neu- ral network architectures for matching natural lan- guage sentences, 2014 利用深度卷积神经网络体系结构改进模型,学习消息和响应的表示,或直接学习两个句子的相互作用表示,然后用多层感知器来计算匹配的分数。

multi-turn response

Hybrid Methods

将生成和检索方法结合起来能对系统性能起到显著的提升作用。基于检索的系统通常给出精确但是较为生硬的答案,而基于生成的系统则倾向于给出流畅但却是毫无意义的回答。在集成模型中,被抽取的候选对象和原始消息一起被输入到基于RNN的回复生成器中。这种方法结合了检索和生成模型的优点,这在性能上具备很大的优势。

展望

端到端的框架不仅在非面向任务的聊天对话系统中流行,而且在面向任务的对话系统中逐步流行起来。深度学习能够利用大量的数据,从而模糊了任务导向型对话系统和非任务导向型对话系统之间的界限。值得注意的是,目前的端到端模型仍然远非完美。尽管取得了上述成就,但这些问题仍然具有挑战性。接下来,我们将讨论一些可能的研究方向。

  • Swift Warm-Up,在一些新的领域,特定领域对话数据的收集和对话系统的构建是比较困难的。未来的趋势是对话模型有能力从与人的交互中主动去学习。
  • Deep Understanding. 深度理解。现阶段基于神经网络的对话系统极大地依赖于大量标注好的数据,结构化的知识库以及对话语料数据。在某种意义上产生的回复仍然缺乏多样性,有时并没有太多的意义,因此对话系统必须能够更加有效地深度理解语言和真实世界。
  • Privacy Protection. 目前广泛应用的对话系统服务于越来越多的人。很有必要注意到的事实是我们使用的是同一个对话助手。通过互动、理解和推理的学习能力,对话助手可以无意中隐蔽地存储一些较为敏感的信息。因此,在构建更好的对话机制时,保护用户的隐私是非常重要的。

论文笔记-Using monoligual data in machine transaltion

Monolingual Data in NMT

Why Monolingual data enhancement

  • Large scale source-side data:

enhancing encoder network to obtain high quality context vector

representation of source sentence.

  • Large scale target-side data:

boosting fluency for machine translation when decoding.

The methods of using monolingual data

Multi-task learning

Target-side language model: Integrating Language Model into the Decoder

shallow fusion

both an NMT model (on parallel corpora) as well as a recurrent neural network language model (RNNLM, on larger monolingual corpora) have been pre-trained separately before being integrated.

Shallow fusion: rescore the probability of the candidate words.

deep fusion

multi-task learning

Using Target-side Monolingual Data for Neural Machine Translation through Multi-task Learning, EMNLP, 2017

利用 target-side 的单语多了一个训练语言模型的任务。事实上(b)就是上一张 PPT 中的方法,这篇paper在这个基础上增加了语言模型的 loss。

$\sigma$ 参数在两个任务训练时都会更新。而 $\theta$ 参数仅仅在训练翻译模型时才会更新参数。

auto-encoder

通过 自编码 的形式,重构对应的 mono-data,作为辅助任务,与 NMT 模型共享 encoder 参数。

Semi-Supervised Learning for Neural Machine Translation, ACL, 2016

Back-translation

What is back-translation?

Synthetic pseudo parallel data from target-side monolingual data using a reverse translation model.

why back-translation and motivation?

It mitigates the problem of overfitting and fluency by exploiting additional data in the target language.

目标语言必须始终是真实句子才能让翻译模型翻译的结果更流畅、更准确,而源语言即便有少量用词不当、语序不对、语法错误,只要不影响理解就无所谓。其实人做翻译的时候也是一样的:翻译质量取决于一个人译出语言的水平,而不是源语言的水平(源语言的水平只要足够看懂句子即可)

Different aspects of the BT which influence the performance of translation:

  • Size of the Synthetic Data

  • Direction of Back-Translation

  • Quality of the Synthetic Data

Size of the Synthetic Data

Direction of Back-Translation

Quality of the Synthetic Data

copy mechanism

作者的实验设置:用 target-side mono-data 来构建伪平行语料,一部分是直接 copy,另一部分是通过 back-translate 得到的。也就是 mono-data 出现了两次。

总觉得哪里不对。。。

Dummy source sentence

Pseudo parallel data:

+ target-side mono-data

The downside:

the network ‘unlearns’ its conditioning on the source context if the ratio of monolingual training instances is too high.

Improving Neural Machine Translation Models with Monolingual Data, Sennrich et al, ACL 2016

Self-learning

Synthetic target sentences from source-side mono-data:

  • Build a baseline machine translation (MT) system on parallel data

  • Translate source-side mono-data into target sentences

  • Real parallel data + pseudo parallel data

reference

  1. Improving Neural Machine Translation Models with Monolingual Data, Sennrich et al, ACL 2016

  2. Using Monolingual Data in Neural Machine Translation: a Systematic Study, Burlot et al. ACL 2018

  3. Copied Monolingual Data Improves Low-Resource Neural Machine Translation, Currey et al. 2017 In Proceedings of the Second Conference on Machine Translation

  4. Semi-Supervised Learning for Neural Machine Translation, Cheng et al. ACL 2016

  5. Exploiting Source-side Monolingual Data in Neural Machine Translation, Zhang et al. EMNLP 2016

  6. Using Target-side Monolingual Data for Neural Machine Translation through Multi-task Learning, Domhan et al. EMNLP 2018

On Using Monolingual Corpora in Neural Machine Translation, Gulcehre, 2015

  1. Back-Translation Sampling by Targeting Difficult Words in Neural Machine Translation, EMNLP 2018

  2. Understanding Back-Translation at Scale, Edunov et al. EMNLP 2018

论文笔记-sentence embedding

句子的向量表示方法主要分为两类。 一类是通过无监督的方法得到 universal sentence embedding, 另一类是基于特定的任务,有标签的情况下,通过有监督学习得到 sentence embedding.

supervised learning

a structured self-attentive sentence embedding

paper: A Structured Self-attentive Sentence Embedding, ICLR 2017

传统的基于 RNN/LSTM 得到 sentence 的向量表示的方法通常是利用隐藏状态的最后一个状态,或者是所有时间步的隐藏状态,然后采用 sum/average/max pooling 的的方式得到 sentence embedding.

本文使用的方法就是在 LSTM 上加上一层 attention,通过注意力机制自动选择 sentence 中的某些方面,也就是赋予 sentence 中的每一个词一个权重,然后加权求和得到一个 vector. 本文另一个创新点在于,不仅仅得到一个 vector,而是一个 matrix,用来表示一个 sentence 中的不同方面。

Model Architecture:

模型也很简单,输入 sentence n tokens.

word embedding: $S\in R^{n\times d}$, d 表示词向量维度

$$S=(w_1,w_2,…,w_n)$$

bidirection-LSTM: $H\in R^{n\times 2u}$, u 表示隐藏状态维度

$$H=(h_1,h_2,…,h_n)$$

single self-attention: $a\in R^n$, 表示 sentence 中对应位置的权重。与 encoder 之后的 sentence 加权求和得到 attention vector $m\in R^{2u}$.

$$a=softmax(w_{s2}tanh(W_{s1}H^T))$$

r-dim self-attention:有 r 个上述的 attention vector,并转换成矩阵形式,$A\in R^{n\times r}$ 与 encode 之后的句子表示 H 加权求和得到 embedding matrix $M\in R^{r\times 2u}$

$$A=softmax(W_{s2}tanh(W_{s1}H^T))$$

$$M=AH$$

penalization term

上面模型中使用 r 个 attention,很可能会出现冗余的情况,也就是得到的 r 个 attention vector( 论文中说的是 summation weight vectors) 可能得到的是同一个东西,所以需要 diversity.

The best way to evaluate the diversity is definitely the Kullback Leibler divergence between any 2 of the summation weight vectors. However, we found that not very stable in our case. We conjecture it is because we are maximizing a set of KL divergence (instead of minimizing only one, which is the usual case), we are optimizing the annotation matrix A to have a lot of sufficiently small or even zero values at different softmax output units, and these vast amount of zeros is making the training unstable. There is another feature that KL doesn’t provide but we want, which is, we want each individual row to focus on a single aspect of semantics, so we want the probability mass in the annotation softmax output to be more focused. but with KL penalty we cant encourage that.

一个最直观的方法是 Kullback Leibler divergence,也就是相对熵。因为得到的 attention vector 是一个概率分布 (distribution ), 任意两个分布差异越大,对应的相对熵越大。但是作者实验发现这种方法不稳定,原因作者推测是这里需要最大化的是多个 KL 散度的集合,并且在优化 annotation matrix A 时,在不同的softmax输出单元上有很多足够小甚至零值,而这些大量的零点使得训练不稳定. 另一方面,KL 散度不能 focus on 语义中的单个方面。

针对上面这两点,作者提出了一个新的正则项:

$$P=||(AA^T-I)||^2_{F}$$

$AA^T$ 是协方差矩阵,对角线元素是同一向量的内积,非对角线元素不同向量的内积。将其作为惩罚项加到 original loss 上,期望得到的是不同 vector 内积越小越好(内积越小,差异越大),并且向量的模长越大越好(概率分布更集中于某一两个词)。

最终得到矩阵级别的句子向量表示。

training

3 different datasets:

  • the Age dataset

  • the Yelp dataset

  • the Stanford Natural Language Inference (SNLI) Corpus

根据不同的任务有监督的训练。

unsupervised learning

sent2vec

paper: Unsupervised Learning of Sentence Embeddings using Compositional n-Gram Features

论文笔记-Explicit Semantic Analysis

paper:

Motivation

对于自然语言的语义表示,需要的大量的 common sense 和 world knowledge. 前人的研究使用统计的方法,例如 WordNet,仅仅只利用了有限的词典知识(lexicographic knowledge),并不能有效的利用语言本身背后的背景知识( background knowledge)。

作者提出了 Explicit Semantic Analysis (ESA),能够对文本或单词进行可解释性的细粒度的语义表示。

Our method represents meaning in a high-dimensional space of concepts derived from Wikipedia, the largest encyclopedia in existence. We explicitly represent the meaning of any text in terms of Wikipedia-based concepts.

显示的使用 wiki 中的概念(concepts)来表示任意长度的 text.

作者通过文本分类和计算自然语言的文本片段之间的相似度来验证 ESA 的有效性。由于语义表示使用的是 natural concepts,ESA 模型的可解释性非常强。

传统的方法:

  1. 词袋模型: 将 text 看作是 unordered bags of words, 每一个单词看作是一维特征。但是这并不能解决 NLP 中的两个主要问题: 一词多义和同义词(polysemy and synonymy)。
  1. 隐语义分析:Latent Semantic Analysis (LSA)

LSA is a purely statistical technique, which leverages word co-occurrence information from a large unlabeled corpus of text. LSA does not use any explicit human-organized knowledge; rather, it “learns” its representation by applying Singular Value Decomposition (SVD) to the words-by-documents co-occurrence matrix. LSA is essentially a dimensionality reduction technique that identifies a number of most prominent dimensions in the data, which are assumed to correspond to “latent concepts”. Meanings of words and documents are then represented in the space defined by these concepts.

LSA 是一种纯粹的统计技术,它利用来自大量未标记文本语料库的单词共现信息。 LSA不使用任何明确的人类组织知识; 相反,它通过将奇异值分解(SVD)应用于逐个文档的共现矩阵来“学习”其表示。 LSA本质上是一种降维技术,它识别数据中的许多最突出的维度,假设它们对应于“潜在概念”。 然后,在这些概念定义的空间中表示单词和文档的含义。

  1. 词汇数据库,WordNet.

However, lexical resources offer little information about the different word senses, thus making word sense disambiguation nearly impossible to achieve.Another drawback of such approaches is that creation of lexical resources requires lexicographic expertise as well as a lot of time and effort, and consequently such resources cover only a small fragment of the language lexicon. Specifically, such resources contain few proper names, neologisms, slang, and domain-specific technical terms. Furthermore, these resources have strong lexical orientation in that they predominantly contain information about individual words, but little world knowledge in general.

词汇资源几乎没有提供关于不同词义的信息,因此几乎不可能实现词义消歧。这种方法的另一个缺点是词汇资源的创建需要词典专业知识以及大量的时间和精力,因此 资源只涵盖语言词典的一小部分。 具体而言,此类资源包含很少的专有名称,新词,俚语和特定于域的技术术语。 此外,这些资源具有强烈的词汇取向,因为它们主要包含关于单个单词的信息,但总体上缺乏世界知识。

concept 定义

Observe that an encyclopedia consists of a large collection of articles, each of which provides a comprehensive exposition focused on a single topic. Thus, we view an encyclopedia as a collection of concepts (corresponding to articles), each accompanied with a large body of text (the article contents).

维基百科中每一个词条对应一个 concept.

example:

对于文本:”Bernanke takes charge” 通过算法我们可以找到维基百科中相关的 concept:

Ben Bernanke, Federal Reserve, Chairman of the Federal Reserve, Alan Greenspan (Bernanke’s predecessor), Monetarism (an economic theory of money supply and central banking), inflation and deflation.

对于文本:”Apple patents a Tablet Mac”

相关的 concept: Apple Computer 2 , Mac OS (the Macintosh operating system) Laptop (the general name for portable computers, of which Tablet Mac is a specific example), Aqua (the GUI of Mac OS X), iPod (another prominent product by Apple), and Apple Newton (the name of Apple’s early personal digital assistant).

ESA 对一个 texts 的表示是 wiki 中所有的 concept 的 weighted combination,这里为了展示方便,只列举了最相关的一些 concept.

ESA(explicit semantic analysis)

通过 wiki 得到一个 basic concepts: $C_1, C_2,…, C_n$, 其中 $C_k$ 都是来源于 wiki. 表示一个通用的 n 维语义空间。

然后将任意长度的文本 t 表示成与上述向量长度相同的 权重向量 $w_1, w_2,…, w_n$ 分别表示 t 与 $C_k$ 之间的相关程度。

接下来两个步骤就是:

  1. the set of basic concepts

  2. the algorithm that maps text fragments into interpretation vectors

如何构建 concept 集合

1.using Wikipedia as a Repository of Basic Concepts

维基百科词条中的内容也很关键,用来计算 concept 与输入文本中单词的相似度。

2.building a semantic interpreter

根据 wiki 得到基本的 concept,以及对应的文档, $d_1,..,d_n$. 构建一个 sparse 表格 T, 其中,列表示 concept,行表示文档中的单词对应的 TDIDF 值。也就是计算文档中的单词与所有文档 $\bigcup_{i=1..n}d_i$ 的频率关系。

$$T[i,j]=tf(t_i, d_j)\cdot log\dfrac{n}{df_i}$$

其中,Term Frequency - Inverse Document Frequency:

TF 表示在文档 $d_j$ 中,单词 $t_i$ 出现的频率。

$$tf(t_i, d_j)=\begin{cases}

1 + log\ count(t_i, d_j), &\text{if count(t_i, d_j) > 0} \

0, &\text{otherwise}

\end{cases}$$

IDF 表示逆文档频率。反应一个词在不同的文档中出现的频率越大,那么它的 IDF 值应该低,比如介词“to”。而反过来如果一个词在比较少的文本中出现,那么它的 IDF 值应该高。

$$IDF=log\dfrac{n}{df_i}$$

$df_i=|{d_k:t_i\in d_k}|$ 表示出现该单词的文档个数,n 表示总的文档个数。

正则化,cosine normalization:

$$T[i,j]\leftarrow \dfrac{T[i,j]}{\sqrt{\sum_{l=1}^r T[i,j]^2}}$$

r 表示单词的总量。也就是除以所有单词对应的向量二范数之和平方。

得到 table T 之后,一个单词的向量 $t_i$ 表示就是第 i 行。一个文本片段 $<t_1,..,t_k>$ 的向量表示是文本中所有单词的质心。

如何将文本片段映射成向量表示

论文笔记-再看 Capsules 以及 capsules 在文本分类上的应用

参考:

再看 Capsules

苏剑林同学在他的那篇博客中对 capsule 的理解很有道理,胶囊也就是用 “vector in vector out” 取代了 “scaler in scaler out”。

在我的上一篇 blog 中在 PrimaryCaps 模块中,将前一步通过卷积得到的输出是 [batch, 20, 20, 256]. 经过 PrimaryCaps 第一步 affine-transform 转换成 [batch, 6, 6, 32, 8]. 实际上就是在这一步将一个像素点的特征转换成了一个 8d-vector 的胶囊。

事实上,在 NLP 的任务中,这种用向量来表示一维特征的做法确实最基本的。比如 one-hot 向量,word2vec 将词转换成 dense vector.

在传统的神经网络中,从低层次的特征逐步抽象,归纳为高层次的特征,是通过权重加权求和得到的,比如卷积啊,全连接都是这样,然后通过梯度反向传播,更新这些权重参数。

这个过程某种程度上模拟了人的层次分类做法,从而完成对最终目标的输出,并且具有比较好的泛化能力。的确,神经网络应该是这样做的,然而它并不能告诉我们它确确实实是这样做的,这就是神经网络的难解释性,也就是很多人会将深度学习视为黑箱的原因之一。

而 Hiton 提出了 Capsule 就具有很好的可解释性,那么其中的 “抛弃梯度下降” 又是怎么一回事呢?苏神在 blog 中给了很好的解释。

胶囊的计算

在前面的 blog 中我们已经理解了什么是“胶囊”。神经元是标量,胶囊就是向量!Hinton的理解是:每一个胶囊表示一个属性,而胶囊的向量则表示这个属性的“标架”。也就是说,我们以前只是用一个标量表示有没有这个特征(比如有没有羽毛),现在我们用一个向量来表示,不仅仅表示有没有,还表示“有什么样的”(比如有什么颜色、什么纹理的羽毛),如果这样理解,就是说在对单个特征的表达上更丰富了。不仅如此,上一篇 blog 中有提到的 CNN 中的不足,主要在于两点,一是 max pooling 丢失了部分信息(这在低层次的layer中可能影响不大,但是在高层次的layer就会有比较大的影响),二是 CNN 不能提取低维特征与高维特征之间在空间中的相对位置信息。而胶囊的方向能表示这一部分信息。比如下面这张图就很明显的表示出来了。

从低层次胶囊到高层次胶囊的计算细节,主要分为 3 个步骤:

  • affine transform

  • weighting and sum

  • squash

如果考虑更多的胶囊,可以抽象到下面这张图。

我们只关注其中的某一部分就是:

关于从低层次特征如何整合到高层次特征以及这样做的原因是啥,苏同学这里说的是相同透彻了。

动态路由

在前面的blog中我们差不多能理解:动态路由实际上就是 低层次的胶囊将部分的自己交付给高层次的胶囊,而这个部分的权重却又取决于 低层次胶囊和高层次胶囊的相关性。

我们原本也是可以通过反向传播来解决这个问题的(不显示的计算出相关性,而是直接用神经网络来代替,不知是否可用梯度下降来处理胶囊?),而 Hinton 使用的动态路由算法可解释更强。

动态路由算法就是来解决这个权重分配的问题。

对于动态路由的理解,苏同学给上了两道小菜。总的理解就是,高层胶囊在启动阶段,我们并不知道它是多少,那么前面的相似度也就没法计算。于是,我们只能初始化一个值,也就是取低层次胶囊的均值。如同上图中第二步将 $b_ij$ 设置成 0,那么低层次胶囊分配给高层次胶囊的权重 $c_{ij}$ 就都是相等的。

$$c_{ij}=\dfrac{exp(b_{ij})}{\sum_k exp(b_ik)}$$

然后反复迭代。说白了,输出是输入的聚类结果,而聚类通常都需要迭代算法,这个迭代算法就称为“动态路由”。至于这个动态路由的细节,其实是不固定的,取决于聚类的算法,比如关于Capsule的新文章《MATRIX CAPSULES WITH EM ROUTING》就使用了Gaussian Mixture Model来聚类。

共享版 or 全连接版

全连接版

在 Capsule 中,低层次特征是通过普通的卷积神经网络提取,然后通过一个矩阵变换得到的。其中的 $W$ 是需要学习的参数。$v_j$ 是作为输入 $u_i$ 的某种聚类中心出现的,而从不同角度看输入,得到的聚类结果显然是不一样的。那么为了实现“多角度看特征”,于是可以在每个胶囊传入下一个胶囊之前,都要先乘上一个矩阵做变换.

$$v_j = \text{squash}\sum_i\dfrac{e^{<\hat u_{j|i}, v_j>}}{\sum_k e^{<\hat u_{k|i}, v_k>}}\hat u_{j|i}, \hat u_{j|i}=W_{ij}u_i$$

共享版

全连接层只能处理定长输入,全连接版的Capsule也不例外。而CNN处理的图像大小通常是不定的,提取的特征数目就不定了,这种情形下,全连接层的Capsule就不适用了。因为在前一图就可以看到,参数矩阵的个数等于输入胶囊数目乘以输出胶囊数目,既然输入数目不固定,那么就不能用全连接了。

所以跟CNN的权值共享一样,我们也需要一个权值共享版的Capsule。所谓共享版,是指对于固定的上层胶囊j,它与所有的底层胶囊的连接的变换矩阵是共用的,即 $W_{ji}≡W_j$.

采用 Hiton 论文中的参数来计算就是:

  • 输入 [batch, 6, 6, 32, 8]=[batch, 1152, 8], 输入有 6x6x32=1152 个 capsules.

  • 输出 [batch, 16, 10], 输出有 10 个 capsules.

对于全连接版,权重参数是 $1152\times 8\times 16\times N + 1152\times N + 1152\times N$. N 表示 low-level capsules 的数目。

对于共享版, 权重参数是 $8\times 16\times 1152 + 1152 + 1152$.

反向传播

现在又有了 $W_{ji}$,那么这些参数怎么训练呢?答案是反向传播。读者也许比较晕的是:现在既有动态路由,又有反向传播了,究竟两者怎么配合?其实这个真的就最简单不过了。从形式上来看,就是往模型中添加了三层罢了,剩下的该做什么还是什么,最后构建一个loss来反向传播。

这样看来,Capsule里边不仅有反向传播,而且只有反向传播,因为动态路由已经作为了模型的一部分,都不算在迭代算法里边了。

capsules 在文本分类上的应用

Investigating Capsule Networks with Dynamic Routing for Text Classification

Model Architecture

N-gram Convolutional Layer

普通的卷积操作。

输入:[batch, L, embed_size, 1]

输出:[batch, L-k1+1, 1, B]

其中:

  • kernel: [k1, embed_size, 1, B]

  • B 表示卷积核的个数

  • k1 是sentence 长度维度上的 sliding-window 尺寸

Primary Capsule Layer

初始化成 capsules, 但依然只是简单的卷积操作。

输入:[batch, L-k1+1, 1, B]

输出:[batch, L-k1+1, 1, C, d]

其中:

  • d 表示 capsule 的维度

  • 实际上依然是普通的卷积操作,不同的是,原本是从 channels B 到 channels C.现在每个 channels C 对应的有 d 个。也就是初始化的 capsules.

  • kernel: [1, 1, B, Cd], 实现时先生成 Cd channels, 然后 split.

Convolutional Capsule Layer

从低层次 feature 到高层次 feature, 在 Hinton 中是capsules版的全连接,在这里是 capsules 版的卷积操作,其中涉及到动态路由算法。

输入:[batch, L-k1+1, 1, C, d]

输出:[batch, L-k1-k2+2, 1, D, d]

其中:

  • 输出的 capsules 维度依旧是 d

  • 但是 capsules 的个数发生了变化,在 Hinton 论文中是通过全连接维度的变换,这里是通过卷积的操作来实现 capsules 个数的变换的。

与 Hinton 的论文类似,第一步是 affine transform 矩阵变换操作,在这篇 paper 中,作者提出了两种方式,实际上就是苏同学博客中的全连接版和共享版(低层次的 capsules 是否共享同样的矩阵变换参数)。

  • shared: $W\in R^{N\times d\times d}$. N 是 capsules 的个数

  • no-shared: $W\in R^{H\times N\times d\times d}$.H 是低维的 capsules 的个数。

Dynamic Routing Between Capsules

Part 1, Intution

CNN 是如何工作的?

  • 浅层的卷积层会检测一些简单的特征,例如边缘和颜色渐变。

  • 更高层的 layer 使用卷积操作将简单的特征加权合并到更复杂的特征中。

  • 最后,网络顶部的网络层会结合这些非常高级的特征去做分类预测。

在第二步中,需要理解的是,CNN 是通过加权求和的方式将低层次的特征组合到高层次的特征的(weighted, added, nonlinear)。在这个过程中,简单的特征在组合成更复杂的特征之前,他们之间是存在位置关系的(pose translation and ratational)。

对于这个位置关系的问题,CNN 是通过 max pooling/successive convolution layer 来解决这个问题的。通过减小图像的尺寸,增加高层神经元的感受野(field of view),这使得他们能在更大的区域内检测出更高阶的特征。

CNN 存在的问题

但是不要被 CNN 的表现好所迷惑,尽管 CNN 的表现优于其他模型。Hinton认为:max pooling工作得这么好其实是一个大灾难。

Hinton: “The pooling operation used in convolutional neural networks is a big mistake and the fact that it works so well is a disaster.”

就算你不使用max pooling,传统CNN依然存在这样的关键问题,学习不到简单与复杂对象之间的重要的空间层次特征。

Internal data representation of a convolutional neural network does not take into account important spatial hierarchies between simple and complex objects.

  • CNN只关注要检测的目标是否存在,而不关注这些组件之间的位置和相对的空间关系。如下例,CNN判断人脸只需要检测出它是否存在两个眼睛,两个眉毛,一个鼻子和一个嘴唇,现在我们把右眼和嘴巴换个位置,CNN依然认为这是个人。

个人理解:神经网络能否具备模糊识别的能力?比如仅仅是鼻子和眼睛调换了位置,但是大致看起来依然是一张人脸。神经网络能否像我们人类一样,知道这张图片想去表达一张人脸,只不过有些地方除了问题,那么它是否知道问题出在哪儿了呢?而不仅仅是识别的问题对吧?

再比如在文本领域,一两个字颠倒顺序并不影响我们人类阅读,神经网络也能理解它的意思,但是能否准确的知道这两个字顺序是颠倒的呢?

这能否作为一个课题。。神经网络纠错。。当然,如果给出了错误的数据集,那也就是监督学习以及分类的问题,能不能在没有给出这个有部分错误的数据情况下,依旧识别出来呢?

  • CNN 对旋转不具备不变性,学不到 3D 空间信息。例如下面的自由女神,我们只看自由女神的一张照片,我们可能没有看过其它角度的照片,还是能分辨出这些旋转后的照片都是自由女神,也就是说,图像的内部表征不取决于我们的视角。但是CNN做这个事情很困难,因为它无法理解3D空间。

  • 另外,神经网络一般需要学习成千上万个例子。人类学习数字,可能只需要看几十个个例子,最多几百个,就能区别数字。但是CNN需要成千上万个例子才能达到比较好的效果,强制去学习。并且关于前面的旋转不变性,CNN可以通过增强数据的手段去改善,但是这也就需要用到大量的数据集。

Hardcoding 3D World into a Neural Net: Inverse Graphics Approach

Capsules 就是为了解决这些问题。其灵感来源于计算机图形学中的渲染技术。

Computer graphics deals with constructing a visual image from some internal hierarchical representation of geometric data.

在计算机图形领域,是通过几何数据的内部层次表示来重构一个视觉图像的。这项技术叫 “渲染 (rendering)”.

Inspired by this idea, Hinton argues that brains, in fact, do the opposite of rendering. He calls it inverse graphics: from visual information received by eyes, they deconstruct a hierarchical representation of the world around us and try to match it with already learned patterns and relationships stored in the brain. This is how recognition happens. And the key idea is that representation of objects in the brain does not depend on view angle.

Hiton 认为大脑是反向渲染的一个过程。接受视觉信息,然后对这样一个具有层次的信息表示进行解构,并与我们已知的模式进行匹配。这里的关键是对象信息的表示在大脑中是不依赖于某一个视角的。

So at this point the question is: how do we model these hierarchical relationships inside of a neural network?

那么我们如何通过神经网络对一个层次信息进行建模呢?

Capsules

Capsules introduce a new building block that can be used in deep learning to better model hierarchical relationships inside of internal knowledge representation of a neural network.

  • Capsule可以学习到物体之间的位置关系,例如它可以学习到眉毛下面是眼睛,鼻子下面是嘴唇,可以减轻前面的目标组件乱序问题。

  • Capsule可以对3D空间的关系进行明确建模,capsule可以学习到上面和下面的图片是同一个类别,只是视图的角度不一样。Capsule可以更好地在神经网络的内部知识表达中建立层次关系

  • Capsule只使用CNN数据集的一小部分,就能达到很好的结果,更加接近人脑的思考方式,高效学习,并且能学到更好的物体表征。

小结:这一节引用了capsule的概念,可以用于深度学习,更好地在神经网络的内部知识表达中建立层次关系,并用不同的方法去训练这样一个神经网络。

Part2, How Capsules Work

What is a Capsule?

CNN 在解决视角的不变性时是通过 max pooling 解决的。选择一块区域的最大值,这样我们就能得到激活的不变性(invariance of activities). 不变性意味着,稍微改变输入的一小部分,输出依旧不变。并且,在图像中移动我们识别的目标,我们依然能检测出这个目标来。

但是 max pooling 会丢失很多信息,并且 CNN 不能编码特征之间的相对空间关系。所以采用 capsules.

Capsules encapsulate all important information about the state of the feature they are detecting in vector form.

  • Capsule 是一个神经元向量(activity vector)

  • 这个向量的模长表示某个entity存在的概率,entity可以理解为比如鼻子,眼睛,或者某个类别,因为用vector的模长去表示概率,所以我们要对vector进行压缩,把vector的模长压缩到小于1,并且不改变orientation,保证属性不变化。

  • 这个向量的方向表示entiry的属性(orientation),或者理解为这个vector除了长度以外的不同形态的instantiation parameter,比如位置,大小,角度,形态,速度,反光度,颜色,表面的质感等等。

How does a capsule work?

传统神经元是一个 scaler, 神经元与神经元之间通过加权求和的方式连接。其计算方式:

  • 计算输入标量 $x_i$ 的权重 $w_i$

  • 对输入标量 $x_i$ 进行加权求和

  • 通过非线性激活函数,进行标量与标量之间的变换,得到新标量 $h_j$

capsule 的前向转换的计算方式:

  • matrix multiplication of input vectors(输入向量 $u_i$ 的矩阵 W 乘法)

  • scalar weighting of input vectors(输入向量 $\hat u_i$ 的标量加权 $c_i$)

  • sum of weighted input vectors(输入向量的加权求和)

  • vector-to-vector nonlinearity(向量到向量的非线性变换)

输入向量 $u_i$ 的矩阵 W 乘法

Affine transform: 

$$\hat u_{j|i}=W_{ij}u_i$$

  • 向量的长度表示低维的胶囊能检测出对应实体的概率。向量的方向则编码了检测对象的中间状态表示。我们可以假设低维胶囊 $u_i$ 分别表示眼睛,嘴巴,鼻子这三个低层次的特征,高维胶囊 $u_j$ 检测脸部高层次特征。

  • 矩阵 W 编码了低层次特征之间或低层次特征与高层次特征之间的重要的空间或其他关系。

  • $u_i$ 乘以相应的权重矩阵 W 得到prediction vector(注意这个图里只画了一个 prediction vector,也就是 $\hat u_i$,因为这里只对应了一个 capsule 输出,如果下一层有 j 个 capusles,$u_i$ 就会生成 j 个 prediction vectors)

例如,矩阵 $W_{2j}$ 可以对鼻子和面部的关系进行编码:面部以鼻子为中心,其大小是鼻子的10倍,而在空间上的方向与鼻子的方向一致。矩阵 $W_{1j}$ 和 $W_{3j}$ 也是类似的。经过矩阵相乘之后,我们可以得到更高层次特征的预测位置。比如,$\hat u_1$ 根据眼睛预测人脸位置,$\hat u_2$ 根据嘴巴预测人脸位置,$\hat u_3$ 根据鼻子预测人脸位置。最后如果这3个低层次特征的预测指向面部的同一个位置和状态,那么我们判断这是一张脸

输入向量 $\hat u_i$ 的标量加权 $c_i$

weighting:

$$s_{j|i} = c_{ij}\hat u_{j|i}$$

$$s_{k|i} = c_{ik}\hat u_{k|i}$$

前面提到的传统神经元在这一步对输入进行加权,这些权重是在反向传播过程中得到的,但 Capsule 是通过 dynamic routing 的方式进行交流的。在这一步,低层次 capsule 需要决定怎么把自己的输出分配给高层次capsule。

$c_{ij}$ 是耦合系数 (coupling coefficients), 通过迭代动态路由过程来决定。比如上图中的,高层次有两个胶囊 capsule J 和 capsule K. 那么对于 capsule i 通过上一步的矩阵 W 就可以得到 $\hat u_{j|i}, \hat u_{k|i}$, 他们对应的权重分别是 $c_{ij}, c_{ik}$, 并且有 $c_{ij} + c_{ik} = 1$.

在动态路由的过程中是如何确定权重的呢,Routing by agreement:

  • 在这张图片中,我们现在有一个低层次的已经被激活的capsule,它对下层每个capsule会生成一个prediction vector,所以这个低层次capsule现在有两个prediction vector,对这两个prediction vectors分配权重分别输入到高层次capsule J和K中。

  • 现在,更高层次的capsule已经从其他低层次的capsule中获得了许多输入向量,也就是图片中的点,标红的部分是聚集的点,当这些聚集点意味着较低层次的capsule的预测是相互接近的。

  • 低层次capsule希望找到高一层中合适的capsule,把自己更多的vector托付给它。低层次capsule通过dynamic routing的方式去调整权重c。

例如,如果低层次capsule的prediction vector远离capsule J中“correct”预测的红色集群,并且接近capsule K 中的“true”预测的红色集群,那么低层次capsule就会调高capsule K对应的权重,降低capsule J对应的权重。最后,如果高层次capsule接收到的这些prediction都agree这个capsule,那么这个capsule就会被激活,处于active状态,这就叫Routing by agreement。

加权输入向量的总和

sum:

$$s_j = \sum_i c_{ij}\hat u_{j|i}$$

高层次capsule根据前面计算的权重c,对所有低层次capsule的prediction vectors进行加权,得到一个向量。

向量到向量的非线性变换

Squashing是一种新的激活函数,我们对前面计算得到的向量施加这个激活函数,把这个向量的模长压缩到1以下,同时不改变向量方向,这样我们就可以利用模长去预测概率,并且保证属性不变化。

这个公式的左边是变换尺度,右边是单位向量。

小结:这一节介绍了capsule的基本概念,capsule把单个神经元扩展到神经元向量,有更强大的特征表征能力,并且引入矩阵权重来对不同layer特性之间的重要层次关系进行编码,结果说明了以下两种性质:

  • Invariance 不变性:物体表示不随变换变化,例如空间的 Invariance,是对物体平移之类不敏感(物体不同的位置不影响它的识别)

  • Equivariance同变性:用变换矩阵进行转换后,物体表示依旧不变,这是对物体内容的一种变换

Part 3, Dynamic Routing Between Capsules

算法的核心思想:

Lower level capsule will send its input to the higher level capsule that “agrees” with its input. This is the essence of the dynamic routing algorithm.

动态路由算法的设计是为了动态调整 $c_{ij}$ 的值:

  • $c_{ij}$ 为非负 scalar

  • 对于每一个的 low level capsule i,所有的权重之和 $c_{ij}$ 为 1,j 表示 high-level capsule j.

  • 对于每一个 low-level capsule, 对应的权重数量等于 high-level 的数量

  • 权重由动态路由算法确定

下面我们逐行解释伪代码:

  1. 这个过程的输入是 第 $l$ 层的 capsule 经过矩阵变换之后的 prediction vector $\hat u$. 迭代步数 r

  2. 初始化 $b_{ij}$ 为 0, $b_{ij}$ 是用来计算 $c_{ij}$ 的

  3. 对接下来4-6行代码迭代r次,计算第 $l+1$ 层 capsule j 的 output

  4. 在第 $l$ 层,每个 capsule i 对 $b_{ij}$ 做 softmax 得到 $c_{ij}$,$c_{ij}$ 是第 $l$ 层 capsule i 给第 $l+1$ 层 capsule j 分配的权重。在第一次迭代的时候,所有的 $b_{ij}$ 都初始化为 0,所以这里得到的 $c_{ij}$ 都是相等的概率,当然后面迭代多次后,$c_{ij}$ 的值会有更新。

  5. 在第 $l+1$ 层,每个 capsule j 利用 $c_ij$ 对 $\hat u_j|i$ 进行加权求和,得到输出向量 $s_j$

  6. 在第 $l+1$ 层,使用squash激活函数对 $s_j$ 做尺度的变换,压缩其模长不大于1

  7. 我们在这一步更新参数,对所有的 $l$ 层 capsule i和 $l+1$ 层 capsule j,迭代更新 $b_{ij}$,更新 $b_{ij}$ 为旧 $b_{ij}$ + capsule j 的输入和输出的点乘,这个点乘是为了衡量这个 capsule 的输入和输出的相似度,低层 capsule 会把自己的输出分给跟它相似的高层 capsule。

经过r次循环,高层capsule可以确定低层分配的权重以及计算其输出,前向传播可以继续连接到下一个网络层。这个r一般推荐设置为3,次数太多了可能会过拟合。

susht 大佬画的图,不过没有把 $b_{ij}$ 表示出来。 $b_{ij}$ 的参数量和 $c_{ij}$ 以及 $u_{ij}$ 的个数是一致的。

  • 假设有两个高层capsule,紫色向量v1和v2分别是这两个capsule的输出,橙色向量是来自低层中某个capsule的输入,黑色向量是低层其它capsule的输入。

  • 左边的capsule,橙色u_hat跟v1方向相反,也就是这两个向量不相似,它们的点乘就会为负,更新的时候会减小对应的c_11数值。右边的capsule,橙色u_hat跟v2方向相近,更新的时候就会增大对应的c_12数值。

  • 那么经过多次迭代更新,所有的routing权重c都会更新到这样一种程度:对低层capsule的输出与高层capsule的输出都进行了最佳匹配。

小结:这节介绍了 dynamic routing algorithm by agreement 的方式去训练 capsNet,主要 idea 是通过点乘去衡量两个 capsule 输出的相似度,并且更新routing的权重参数。

CapsNet Architecture

论文给出了一个简单的CapsNet模型,第一层是个普通的conv层,第两层也结合了conv操作去构建初始的capsule,再通过routing的方式和第三层的DigitCaps交流,最后利用DigitCaps的capsule去做分类。

  • ReLU Conv1: 这是一个普通的卷积层,参数量是 $9\times 9\times 256$, 假设输入是 $28\times 28\times 1$, 得到的输出是 $20\times 20\times 256$.
  • PrimaryCaps: 这里构建了 32 个 channels 的 capsules, 每个 capsule 的向量维度是 8. 依旧是采用卷积的方法,每一个 channels 使用 8 个卷积核 $9\times 9$. 所以总的参数量是 $9\times 9\times 256 \times 32\times 8 + 32 \times 8= 5308672$。 一个 channels 对应一个 feature map,在这里是 $6\times 6$ 个 8 维的 capsules. 所以最后是 $6\times 6\times 32=1152$ 个 capsules。
  • DigitCaps: 对前面1152个capules进行传播与routing更新,输入是1152个capsules,输出是10个capules,每个 capsule 的维度由 8 变成了 16,表示10个数字类别,最后我们用这10个capules去做分类. 总的参数量是 $1152\times 8\times 16+1152+1152=149760$. 后面两个 1152 分别表示 $b_{ij}, c_{ij}$.

loss function

在 dynamic routing 过程中我们更新了 $c_{ij}$ 参数,其余参数是通过反向传播进行更新,这里对于每一个capsule k我们都计算它的 Margin loss损失函数 $L_k$

跟 SVM 的 loss function 非常类似。

$$L_i = \sum_{j\neq y_i} \max(0, s_j - s_{y_i} + \Delta)$$

  • 不同的是,这里设定了 正类的概率 越小于 $m^+=0.9$ 其贡献的 loss 越小,负类的概率越大于 $m^-=0.1$ 其贡献的 loss 越大。

  • $\lambda$ 参数设置为0.5,这是为了防止负例减小了所有capsule向量的模长。

Decoder: reconstruction as a regularization method

这里会mask掉一些capsule,用有代表性的capsule去重构图像,通过几层全连接层得到784维的输出,也就是原始图像的像素点个数,以这个输出跟原始像素点的欧几里得距离作为重构损失函数。

CapsNet与CNN的联系

相同之处:CNN可以上下左右平移在图像上进行扫描,也就是它在这个地方学到的东西可以用到下一个地方,可以有效识别图片的内容,所以capsule也采用了convolution的特点,最后一层只用capsule.

不同之处:capsule不采用max pooling的做法,因为Max pooling只保留了区域内最好的特征,而忽视了其它的特征,routing并不会丢失这些信息,它可以高效处理高度层叠的例子。浅层capsule会把位置信息通过place-coded的方式记录在激活的capsule中,高层的capsule会通过rate-coded的方式记录在capsule vector的值当中。

Capsules做分类的优点

适合输出有多个类别的多分类问题,softmax只适合只有一个输出的多分类问题,因为softmax会提高某一类的概率,而压低其余所有类别的概率。

另外,我们也可以用k sigmoid去代替softmax,把多分类任务转换成K个二分类任务.

论文笔记-预训练语言模型2-ULMFiT

Motivation

对比之前的几种模型

concatenate embeddings: ELMo

Recent approaches that concatenate embeddings derived from other tasks with the input at different layers (Peters et al., 2017; McCann et al., 2017; Peters et al., 2018) still train the main task model from scratch and treat pretrained embeddings as fixed parameters, limiting their usefulness.

这篇 paper 是在 elmo 之后,而 elmo 虽然相对出名,影响力更大,但是 elmo 仍旧只是一种 word embedding 的预训练,在下游任务中还是需要从头训练模型。

ELMo有以下几个步骤:

  • 利用LM任务进行预训练

  • 再利用目标领域的语料对LM模型做微调

  • 最后针对目标任务进行 concatenate embedding,然后训练模型

pretraining LM:

In light of the benefits of pretraining (Erhan et al., 2010), we should be able to do better than randomly initializing the remaining parameters of our models. However, inductive transfer via finetuning has been unsuccessful for NLP (Mou et al., 2016). Dai and Le (2015) first proposed finetuning a language model (LM) but require millions of in-domain documents to achieve good performance, which severely limits its applicability.

直接使用在 general-domain 上预训练好的语言模型,然后通过 fine-tune 进行迁移学习, 仍旧需要大量的 in-domain 的文档才能获得比较好的 performance.

ULMFiT

We show that not the idea of LM fine-tuning but our lack of knowledge of how to train them effectively has been hindering wider adoption. LMs overfit to small datasets and suffered catastrophic forgetting when fine-tuned with a classifier. Compared to CV, NLP models are typically more shallow and thus require different fine-tuning methods.

作者认为,预训练语言模型的方式并不是不好,只是训练方法的问题导致了他们表现局限性。想对于 CV, NLP 中的很多任务所需要的语义更浅层。而将 LMs 在小数据集上 fine-tune 时会导致严重的遗忘。

于是,作者提出了 Universal Language Model Fine-tuning(ULMFiT)

  • 通用的语言模型微调

  • discriminative fine-tuning, slanted triangular learning rates

  • gradual unfreezing

Universal Language Model Fine-tuning

主要分为 3 部分:

  • General-domain LM pretraining

  • Target task LM fine-tuning

  • Target task classifier fine-tuning

General-domain LM pretraining

Wikitext-103 (Merity et al., 2017b) consisting of 28,595 preprocessed Wikipedia articles and 103 million words.

在足够大的 general-domain 语料库上进行预训练。

Target task LM fine-tuning

discriminative fine-tunin

在目标语料库 in-domain 上进行 fine-tune. 这部分会收敛的很快,并且在小数据集上依旧会有很好的泛化性。

As different layers capture different types of information (Yosinski et al., 2014), they should be fine-tuned to different extents.

不同的 layer 能捕捉不同程度的信息,于是,作者提出了 discriminative fine-tuning. 不同的 layer 具有不同的 learning rate. L 表示总的 layer 数目。

$${\theta^1,\theta^2, …, \theta^L}$$

$${\eta^1,\eta^2, …, \eta^L}$$

Instead of using the same learning rate for all layers of the model, discriminative fine-tuning allows us to tune each layer with different learning rates.

原本的 SGD 是这样的:

$$\theta_t = \theta_{t-1}-\eta\cdot\nabla_{\theta}J(\theta)$$

改进之后:

$$\theta_t^l = \theta_{t-1}^l-\eta^l\cdot\nabla_{\theta^l}J(\theta)$$

作者通过经验发现:先选择最后一层的学习率 $\eta^L$,然后计算每一层的学习率 $\eta^{l-1}=\eta^l/2.6$

Slanted triangular learning rates

  • T 是迭代次数,这里实际上是 $epochs \times \text{number of per epoch}$

  • cut_frac 是增加学习率的迭代步数比例

  • cut 是学习率增加和减少的临界迭代步数

  • p 是一个分段函数,分别递增和递减

  • ratio 表示学习率最小时,与最大学习率的比例。比如 t=0时,p=0, 那么 $\eta_0=\dfrac{\eta_{max}}{ratio}$

作者通过实验发现,cut_frac=0.1, ratio=32, $\eta_max=0.01$

Target task classifier fine-tuning

针对分类任务,加上 two additional linear blocks.

concat pooling

gradul unfreezing

逐渐 unfreeze layers:

We first unfreeze the last layer and fine-tune all unfrozen layers for one epoch. We then unfreeze the next lower frozen layer and repeat, until we finetune all layers until convergence at the last iteration.

BPTT for Text Classification

backpropagation through time(BPTT)

We divide the document into fixed length batches of size b. At the beginning of each batch, the model is initialized with the final state of the previous batch; we keep track of the hidden states for mean and max-pooling; gradients are back-propagated to the batches whose hidden states contributed to the final prediction. In practice, we use variable length backpropagation sequences (Merity et al., 2017a).

什么意思?并不是一个 batch 更新一次梯度,而是累加一定的 batch 之后在更新梯度?

能增加泛化性?

Bidirectional language model

独立的对 forward-LM, backward-LM 进行 fine-tune, 然后平均。

experiment

与其他模型对比

ablations

“from scratch”: 没有 fine-tune

“supervised”: 表示仅仅在 label examples 进行 fine-tune

“semi-supervised”: 表示在 unable examples 上也进行了 fine-tune

对 tricks 进行分析

“full” :fine-tuning the full model

“discr”: discriminative fine-tuning

“stlr”: slanted triangular learning rates

论文笔记-GAN tutorial NIPS 2016

为什么要学习 GAN?

  • High-dimensional probability distributions, 从高维概率分布中训练和采样的生成模型具有很强的能力来表示高维概率分布。
  • Reinforcement learning. 和强化学习结合。
  • Missing data. 生成模型能有效的利用无标签数据,也就是半监督学习 semi-supervised learning。

生成模型如何工作的

Maximum likehood estimation

极大似然估计就是在给定数据集的情况下,通过合理的模型(比如语言模型)计算相应的似然(概率),使得这个概率最大的情况下,估计模型的参数。

$$\sum_i^mp_{\text{model}}(x^{(i)}; \theta)$$

m 是样本数量。

将上诉概率转换到 log 空间(log 函数是单调递增的),可以将乘积转换为相加,简化了计算。

同样的,也可以把上诉似然估计的极大化看做是最小化 KL 散度(或者交叉熵)。这样一来,相当于把无监督问题转换成了有监督问题。(不知理解的是否正确?)

相对熵

熵是信息量 $log{\dfrac{1}{p(i)}}$ (概率越大信息量越少)。

p 是真实分布, q 是非真实分布。

交叉熵是用 q 分布来估计 p 分布所需要消除的代价 cost:

$$H(p,q) = \sum_ip(i)log{\dfrac{1}{q(i)}}$$

用真实分布 p 估计真实分布所需要的 cost:

$$H(p) = \sum_ip(i)log{\dfrac{1}{p(i)}}$$

从这里也能看出,当概率 p 为 1 时,所需要的 cost 就为 0 了。

相对熵,又称 KL 散度(Kullback–Leibler divergence),就是指上诉两者所需要消耗的 cost 的差值:

$$D(p||q) = H(p,q)-H(p) = \sum_ip(i)log{\dfrac{p(i)}{q(i)}}$$

GAN 是如何工作的?

GAN 框架

  • 判别器 discriminator

  • 生成器 gererator

在左边场景,判别器学习如何分别样本是 real or fake. 所以左边的输入是 half real and half fake.

在右边的v场景,判别器和生成器都参与了。G 用来生成 G(z), D 用来判别 G(z) 是 real or fake.

结构化概率模型 Structured Probabilistic Modelsfor Deep Learning

containing latent variables z and observed variables x.

z 是需要学习的隐藏变量,x 是可观察到的变量。

判别器 D 的输入是 x,其需要学习的参数是 $\theta^{(D)}$. 生成器 G 的输入是 z, 其需要学习的参数是 $\theta^{(G)}$.

两个玩家都有各自的损失函数。 $J^{(D)}(\theta^{(D)}, \theta^{(G)})$, 但是 $J^{(D)}$ 并不影响参数 $\theta^{(G)}$. 同样的道理,反过来也是 $J^{(G)}(\theta^{(G)}, \theta^{(D)})$.

每个玩家的损失函数依赖于另一个玩家的参数,但是确不能控制它的参数。所以这是一种 Nash equilibrium 问题。找到这样一个局部最优解 $tuple(\theta^{(G)}, \theta^{(D)})$ 使得 $J^{(D)}$ 关于 $\theta^{(D)}$ 局部最小,$J^{(G)}$ 关于 $\theta^{(G)}$ 局部最小。

Generator

differentiable function G, 可微分函数 G. 实际上就是 神经网络。z 来自简单的先验分布,G(z) 通过模型 $p_{model}$ 生成样本 x. 实践中,对于 G 的输入不一定只在第一层 layer, 也可以在 第二层 等等。总之,生成器的设计很灵活。

Training process

两个 minibatch 的输入: x 来自 training dataset. z 来自先验隐藏变量构成的模型 $p_\text{model}$。通过优化算法 SGD/Adam 对两个损失 $J^{(D)} J^{(G)}$ 通过进行优化。梯度下降一般是同步的,也有人认为两者的迭代步数可以不一样。在这篇 tutorial 的时候,得到的共识是同步的。

cost function

目前大多数 GAN 的损失函数,$J(D)$ 都是一样的。区别在于 $J(G)$.

The discriminator’s cost, J (D)

这是个标准的用于二分类的交叉熵损失函数。只不过这里,正分类都来自于训练集,正分类的概率是 $\dfrac{1}{2}E_{x~d_{data}}$, 负分类来自于生成器,则其概率是 $\dfrac{1}{2}E_z$

通过训练判别器,我们可以得到这样一个比例:

$$\dfrac{p_{data}(x)}{p_{\text{model}}(x)}$$

GANs 通过监督学习来获得这个 ratio 的估计,这也是 GANs 不同于 变分自编码 和 波尔兹曼机 (variational autoencoders and Boltzmann machines) 的区别。

但是 GANs 通过监督学习来估计这个 ratio,会向监督学习一样遇到同样的问题:过拟合和欠拟合。但是通过足够的数据和完美的优化可以解决这个问题。

Minimax, zero-sum game

设计 cost function for generator.

前面我们知道,两个玩家 player 或者说 神经网络 G,D 实际上是一种博弈,D 希望能找出 G(z) 是 fake,而 G 希望能让 G(z) 尽可能像 real. 所以最简单的一种方式就是 all player’s cost is always zero.

$$J^{(G)} = -J^{(D)}$$

这样 $J^{(G)}, J^{(D)}$ 都可以用 value function 表示:

$$V(\theta^{(D)}, \theta^{(G)})=-J^{(D)}(\theta^{(D)}, \theta^{(G)})$$

那么整个 game 也就是一个 minmax 游戏:

outer loop 是关于 $\theta^{(G)}$ 的最小化,inner loop 是关于 $\theta^{(D)}$ 的最大化。

但是这种 function 在实际中并不能使用,因为其非凸性。

In practice, the players are represented with deep neural nets and updates are made in parameter space, so these results, which depend on convexity, do not apply

Heuristic, non-saturating game

Minimizing the cross-entropy between a target class and a classifier’s predicted distribution is highly effective because the cost never saturates when the classifier has the wrong output.

对一个分类器,最小化 目标类和预测概率的交叉熵 是一个非常有效的方法,因为当 分类器 存在误分类时,损失函数就永远不可能饱和。

所以,对于生成器的 cost 依旧使用交叉熵,但如果使用和 判别器一模一样的 cost(这里应该就是把正负分类反过来?):

$$J^{(G)}(\theta^{(D)}, \theta^{(G)})=-\dfrac{1}{2}E_zlogD(G(z))-\dfrac{1}{2}E_{x~p_{data}}log(1-D(x))$$

猜想应该是这样,文中没有给出。

不幸的是这样的在是实际中,也并不可行。当 判别器 拒绝一个高置信度(high confidence) 的样本时,生成器会出现梯度消失。

所以,改进之后就是:

$$J^{(G)}(\theta^{(D)}, \theta^{(G)})=-\dfrac{1}{2}E_zlogD(G(z))$$

In the minimax game, the generator minimizes the log-probability of the discriminator being correct. In this game, the generator maximizes the logprobability of the discriminator being mistaken.

在 Minmax,zero-game 中,生成器的目的是最小化 判别器 自认为自己判别对了的 log-probability, 而在 non-saturating game 中,生成器是最大化 判别器判别错误 的 log-probability.

Maximum likelihood game

前面提到极大似然估计是最小化模型与数据之间的 KL 散度。 GANs 使用极大似然估计则是对比不同的模型。

$$J^{(G)}=-\dfrac{1}{2}E_zexp(\sigma^{-1}(D(G(z))))$$

in practice, both stochastic gradient descent on the KL divergence and the GAN training procedure will have some variance around the true expected gradient due to the use of sampling (of x for maximum likelihood and z for GANs) to construct the estimated gradient.

在实践中,由于使用采样(x表示最大似然,z表示GAN)来构建估计的梯度,因此KL散度和GAN训练过程的随机梯度下降都会在真实预期梯度附近产生一些变化。

Is the choice of divergence a distinguishing feature of GANs?

Jensen-Shannon divergence, reverse KL

许多人认为 GANs 能够生成更加清晰、逼真的样本是因为他们最小化的是 Jensen-Shannon divergence. 而 VAEs 生成模糊的样本是因为他们最小化的是 KL divergence between the data and the model.

KL 散度并不是对称的。$D_{KL}(p_{data}||q_{model})$ 与 $D_{KL}(p_{model}||q_{data})$ 是不一样的。极大似然估计是前者,最小化 Jensen-Shannon divergence 则更像后者。

比较 $D_{KL}(p_{data}||q_{model})$ 与 $D_{KL}(p_{model}||q_{data})$ 区别。在模型能力不足以拟合数据的分布时,表现的尤为明显,如上图。给定的数据是两个高斯分布混合的分布。而模型是一个高斯模型。然后分别用极大似然 Maximum likehood 、reverse KL 散度作为 criterion,也就是 cost.

可以看到前者选择去平均两个模态,并希望在两个模态上都能得到较高的概率。而后者只选择其中一个模态,也有可能是另外一个模态,两个模态对于 reverse KL 都含有局部最优解。

所以,从这个视角来看, Maximum likehood 倾向于给 data 出现的位置更高的概率,而 reverse KL 则倾向于给没有出现 data 的位置较低的概率。所以 $D_{KL}(p_{model}||q_{data})$ 可以生成更棒的样本,因为模型不会生成不常见的样本,因为数据之间具有欺骗性的模态。

然而,也有一些新的研究表明,Jensen-Shannon divergence 并不是 GANs 能生成更清晰样本的原因。

f-GAN 证明,KL 散度也能生成清晰的sample,并且也只选择少量的modes, 说明 Jensen-Shannon divergence 并不是 GANs 不同于其他模型的特征。

GANs 通常选择少量的 mode 来生成样本,这个少量指的是小于模型的能力。 而 reverse KL 则是选择更可能多的 mode of the data distribution 在模型能力范围内。它通常不会选择更少的 mode. 这也解释了 mode collapse 并不是散度选择的原因。

Altogether, this suggests that GANs choose to generate a small number of modes due to a defect in the training procedure, rather than due to the divergence they aim to minimize.

所以,GANs 选择少量的 mode 是因为训练过程中的其他缺陷,而不是 散度 选择的问题。

Comparison of cost functions

生成对抗网络可以看做一种 reinforcement learning. 但是$j^{(G)}$ 并没有直接参考 training data,所有关于 training data 的信息都来自于 判别器 的学习。

所以和传统的强化学习是有区别的:

比较不同的 cost function:

$D(G(z))$ 表示 判别器 给 generate sample 为真的概率。

在左侧,Minimax 和 Maximum likehood 都趋向于饱和。也就是说,当一个样本很明显为 fake 时,cost 接近于 0.

似然估计还有个问题,cost 主要来源于 特别像真 的少部分样本,这也是不好的。需要用到 variance reduction techniques.

Maximum likelihood also suffers from the problem that nearly all of the gradient comes from the right end of the curve, meaning that a very small number of samples dominate the gradient computation for each minibatch. This suggests that variance reduction techniques could be an important research area for improving the performance of GANs, especially GANs based on maximum likelihood.

The DCGAN architecture

DCGAN 的结构。

GAN,NCE, MLE 的对比

相同点:

  • MiniMax GAN 和 NCE 的 cost function 相同

不同点:

  • 更新策略不一样,GAN 和 MLE 都是梯度下降,而 MLE copies the density model learned inside the discriminator and converts it into a sampler to be used as the generator. NCE never updates the generator; it is just a fixed source of noise.

Tips and Tricks

How to train a GAN: https://github.com/soumith/ganhacks

Research Frontiers

Non-convergence

mode collapse

论文笔记-Contextual Augmentation

paper 1

Contextual Augmentation: Data Augmentation by Words with Paradigmatic Relations

在 NLP 领域,数据增强比图像领域要复杂的多。它很难有一个统一的规则的去适用于各种 domain. 目前常用的方法是 基于 WordNet 的同义词替换,以及根据距离计算的词的相似度。但是,同义词是很少的,并且,一个词本身也是多义的,它在 WordNet 中的同义词也许并不适合当前的语境,而这一限制也是很难通过一个规则去限定。所以,传统的方法都很难发挥。

传统的数据增强方法:

作者提出了一种新的方法,基于语言模型的 contextual augmentation. 根据上下文预测得到的不同的词具有范式关系 paradigmatic relations. 更进一步的,为了让生成的词与当前句子的 label 是兼容的 (compatible),作者加入了 label-conditional.

根据上文预测 target position i $w_i$, $P(\cdot|S/{w_i})$. 加上 label 限制条件之后就是 $P(\cdot|y, S/{w_i})$

作者并不是直接使用 top-k. 而是利用的退火的方法,temperature parameter $\tau$, 这样预测分布就是

$$P(\cdot|y, S/{w_i})^{1/\tau}$$

当 $\tau \rightarrow \infty$ 时,那么对应的预测词分布是 uniform distribution. 当 $\tau \rightarrow 0$ 时,预测得到的就是概率最大的词。我猜作者这样做的目的是让生成的词更丰富,避免单一化。

在不同任务上的对比实验,与 synonym 同义词替换进行的对比,分类模型都用的 CNN.

效果还可以,但是并不明显。而 w/synonym 反而会有反作用。。

其中某个样本的效果展示:

paper 2

Conditional BERT Contextual Augmentation

看完paper真的想吐槽下中国人写的论文真的给人一种粗制滥造的感觉。。尽管paper出来的很及时,与 Bert 结合也很赞,但是 。。。其实还可以好好写,还可以多分析分析,看 paper 都能感觉到一种为了发论文而发论文的感觉,我自己又何尝不是呢。。。

Bert 想对于 LSTM 更获得更深层的含义。

将 segmentation embedding 换成 label embedding. 然后使用预训练的 BERT 模型进行 fine-tune. 迭代直到收敛,生成新的句子后,在进行下游任务。

When the task-specific dataset is with more than two different labels,we should re-train a label size compatible label embeddings layer instead of directly fine-tuning the pre-trained one.

对于多标签任务,作者是这么说的,不太明白。

论文笔记-baseline for OOD

paper: A baseline for detecting misclassified and out-of-distribution examples

Motivation

文章开头先说到,通过 softmax 预测得到的各个类别的概率分布 (prediction probability) 和 置信度之间的对应关系并不是很直接 (have a poor direct correspondence to confidence)。这是因为 softmax 的计算使用了指数函数(fast-growing exponential function),这就会导致一个很小的额外附加输入,都会使得接下来的输出分布(output distribution) 发生改变。事实上,之前也有人做了相当一部分实验,证明了一个高斯随机噪声加入到一个 MNIST 图像之后,会让这个图像获得 91% 的预测概率。

尽管如此,然而,这篇文章作者依旧认为 错误的类别 或 OOD(incorrect and out-of-distribution) 更倾向于具有较低的预测概率,相对于正确的样本。因此,获得关于正确的或者 in-sample 样本的预测概率的统计,通常来说足够去检测出 错误或不正常(error or abnormal),即使单独来看预测概率可能会有误导。也就是从统计的角度,softmax 得到的概率分布还是可信的。

这篇文章在很多任务上进行了实验,并不都是 SOTA, 所以只是提供了一个新的方法用来验证一个神经网络能否有效的区分出 abnormal,作为 baseline method.

除了这个 baseline method,作者还制定了标准的任务和指标,用来评价对 错误和OOD 的自动检测

.

所以看这篇文章的目的就是

  • baseline mathod 是什么?也就是怎么去评价一个模型自动区分出 OOD 的能力。

  • 作者给出的标准任务和数据

Baseline method

这篇文章的主要解决的两个问题:

  • error and success prediction: 能否正确的对一个样本分类

  • in- and out-of-distribution detection: 能否正确的检测出 OOD

通常来说,OOD 和 in sample 来说,样本数量差异会很大,比如疾病检测,未见过的罕见疾病 OOD 就很少; 又比如对一个猫狗分类器,他在测试时,OOD 就很大。所以对于这种数据不均衡的问题,accuracy 已经无法满足这类问题了。

metric1: AUROC

作者使用了 AUROC(Area Under the Receiver Operating Characteristic curve). 其实这个在前面的笔记中有详细介绍过,这里再复习遍~ 机器学习-常用指标总结

ROC 曲线是依赖于阈值的性能验证指标 (metric which is a threshold-independent performance evalution). 因为在这类不均衡问题中,我们关注的是 positive label. 所以我们关注的指标是 真正类率 TPR, 负正类率 FPR.

  • TPR, 真正类率(true positive rate ,TPR),: 如果一个实例是正类并且也被 预测成正类,即为真正类(True positive),真正类率是指分类器所识别出来的 正实例占所有正实例的比例。就是正类的 Recall 吧~ TPR = TP / (TP + FN)

  • FPR, 负正类率: 分类器错认为正类的负实例占所有负实例的比例,FPR = FP / (FP + TN)

还是不太明白为啥 TPR + FPR = 1????

metric2: AUPR

Area Under the Precision-Recall curve (AUPR)

The PR curve plots the precision (tp=(tp+fp)) and recall

(tp=(tp + fn)) against each other. 对于 PR 曲线,选择哪个类别作为 positive 类,非常重要。

论文笔记 Deep Transition Architecture

paper 1

paper: Self-Attention: A Better Building Block for Sentiment Analysis Neural Network Classifiers, 2018 WASSA@EMNLP

将 self-attention 和 LSTM,CNN 进行对比. 因为单纯只是为了比较三者作为一个 building block 的性能,所以保证公平性的情况下,只用了 1 layer 和 2-layer.

整篇文章并没有看到其他的创新性,不知道是不是看错了。。所以这样也能发 EMNLP?

但是看了还是有点收获,复习了一下 multi-head self-attention. 以及文中提到了三种 position encoding:

  • Sinusoidal Position Encoding

  • Learned Position Encoding

  • Relative Position Representations

Sinusoidal 是在 Transformer 中使用的, 好处在于即使是测试集中出现 sentence 的长度比训练集中所有的 sentence 都要长,也能计算其 position encoding.

Relative 是效果最好的,作者和 Tansformer 的作者是一样的,值得一看。Self-attention with relative position representations

For this method, the self-attention mechanism is modified to explicitly learn the relative positional information between every two sequence positions. As a result, the input sequence is modeled as a labeled, directed, fully-connected graph, where the labels represent positional information. A tunable parameter k is also introduced that limits the maximum distance considered between two sequence positions. [Shaw et al., 2018] hypothesized that this will allow the model to generalize to longer sequences at test time.

paper 2

DTMT: A Novel Deep Transition Architecture for Neural Machine Translation AAAI 2019

腾讯 WeChat AI 的一篇机器翻译的 paper,同样也是 encoder-decoder, 但是改进了 Deep transition RNN.

先了解何为 deep transition RNN, 注意与 deep stacked architectures 的区别。

也就是在传统的 RNN 迭代之前,先对 state 进行 transition。而这篇 paper 改进的就是这种 transition 的方式,目的就是为了减轻其中因为非线性操作带来的梯度消失的问题。

模型结构图:

  • encoder transition

  • multi-head attention

  • query transition

  • decoder transition

其中提出了 GRU 以及其变体 T-GRU 和 L-GRU.

GRU

回顾下 GRU

$$h_t = (1-z_t)\odot h_{t-1} + z_t\odot \tilde h_t$$

其中:

candidate state:

$$\tilde h_t = tanh(W_{xh}x_t + r_t\odot (W_{hh}h_{t-1}))$$

reset gate:

$$r_t = \sigma(W_{xr}x_t+W_{hr}h_{t-1})$$

update gate:

$$z_t=\sigma(W_{xz}x_t+W_{hz}h_{t-1})$$

T-GRU (transition GRU)

对 GRU 做了简化,因为只针对于 state 的变化,去掉了 $x_t$ 的输入.

$$h_t = (1-z_t)\odot h_{t-1} + z_t\odot \tilde h_t$$

candidate state:

$$\tilde h_t = tanh(r_t\odot (W_{hh}h_{t-1}))$$

reset gate:

$$r_t = \sigma(W_{hr}h_{t-1})$$

update gate:

$$z_t=\sigma(W_{hz}h_{t-1})$$

L-GRU( Linear Transformation enhanced GRU)

$$h_t = (1-z_t)\odot h_{t-1} + z_t\odot \tilde h_t$$

candidate state:

$$\tilde h_t = tanh(W_{xh}x_t + r_t\odot (W_{hh}h_{t-1}))+ l_t\odot H(x_t)$$

增加了一个基于 x_t 的线性的变换 H(x_t), 并由 $l_t$ 控制信息量的多少。

$$H(x_t)=W_xx_t$$

$$l_t=\sigma(W_{xl}x_t+W_{hl}h_{t-1})$$

这个模块相对于 $W_{xh}x_t$ 多了一个线性控制器,其实他与第二个模块 $r_t\odot (W_{hh}h_{t-1}))$ 倒是对称的,只不过 $h_{t-1}$ 换成了 $x_t$.

所以我可不可以再加个这样的?

$\tilde h_t = tanh(W_{xh}x_t +W_{hh2}h_{t-1} +l_t\odot W_{xh2}x_t+ r_t\odot (W_{hh}h_{t-1}))$

DNMT

Decoder

$L_s$ 表示 encoder transition 的深度 depth. $j$ 表示 current time step.

$$\overrightarrow h_{j,0}=L-GRU(x_j, \overrightarrow h_{j-1,L_s})$$

$$\overrightarrow h_{j,k}=T-GRU(\overrightarrow h_{j, k-1}),\text{ for } 1\le k\le L_s$$

很好理解,就是 k=0 transition 的第一步需要输入 $x_t$,使用 L-GRU. transition 的剩余步骤使用 T-GRU.

双向 bi-direction GRU: $C=[\overrightarrow h_{j, L_s}, \overleftarrow h_{j, L_s}]$

Decoder

  • query transition: depth $L_q$

  • decoder transition: depth $L_d$

对于 query transition: 输入是上一步的输出 $y_{t-1}$ 和 上一步的隐藏状态 $s_{t-1}$.

然后得到 $S_{t, L_q}$ 与 encoder 进行交互, multi-head attention:

得到 attention vector $c_t$ 之后,$c_t$ 类似于输入, $s_{t,L_q}$ 是隐藏状态,进一步进行 transition state 转换。

得到 $s_{t, L_q+L_d+1}$ 就是当前时间步的最终隐藏状态,通过映射到词表空间,即可预测当前时间步的词。

Tricks

还是有很多可以借鉴的地方的~

论文笔记-BERT

BERT(Bidirectional Encoder Representations from Transformers.)

对于 BERT 重点在于理解 Bidirectional 和 masked language model.

Why Bidirectional?

对于预训练的表示,单向语言模型因为无法融合下文的信息,其能力是非常有限的,尤其是对类似于 SQuAD 这样需要结合上下文信息的任务。

对比 OpenAI GPT 和 BERT. 为什么 OpenAI GPT 不能采用双向 self-attention 呢?

传统的语言模型的定义,计算句子的概率:

$$P(S)=p(w_1,w_2, …, w_n)=p(w1)p(w_2|w_1)…p(w_n|w_1…w_{n-1})=\prod_{i=1}^m p(w_i|w_1…w_{i-1})$$

前向 RNN 语言模型:

$$P(S)=\prod_{i=1}^m p(w_i|w_1…w_{i-1})$$

也就是当前词的概率只依赖前面出现词的概率。

后向 RNN 语言模型

$$P(S)=\prod_{i=1}^m p(w_i|w_{i+1}…w_{m})$$

也就是当前词的概率只依赖后面出现的词的概率。

ELMo 就是这样的双向语言模型(BiLM)

但是 RNN 相比 self-attention 对上下文信息 (contextual information)的利用相对有限,而且 ELMo 只能是一层双向,并不能使用多层。其原因和 GPT 无法使用 双向 编码的原因一样。

对于 GPT 如果它使用双向,那么模型就能准确的学到到句子中的下一个词是什么,并能 100% 的预测出下一个词。比如 “I love to work on NLP.” 在预测 love 的下一个词时,模型能看到 to,所以能很快的通过迭代学习到 “to” 100% 就是 love 的下一个词。所以,这导致模型并不能学到想要的东西(句法、语义信息)。

那么 BERT 是怎么处理双向这个问题的呢? 它改变了训练语言模型的任务形式。提出了两种方式 “masked language model” and “next sentence generation”. 再介绍这两种训练方式之前,先说明下输入形式。

Input representation

  • position embedding: 跟 Transformer 类似

  • sentence embedding, 同一个句子的词的表示一样,都是 $E_A$ 或 $E_B$. 用来表示不同的句子具有不同的含义

  • 对于 [Question, Answer] 这样的 sentence-pairs 的任务,在句子末尾加上 [SEP].

  • 对于文本分类这样的 single-sentence 的任务,只需要加上 [CLS], 并且 sentence embedding 只有 $E_A$.

masked language model

何为 “masked LM”? idea 来源于 closed tasked. 原本的语言模型是预测所有语料中的下一个词,而 MLM 是在所有的 tokens 中随机选取 15% 的进行 mask,然后只需要预测被 mask 的词。这样以来,就能训练双向语言模型了。

但是存在一个问题,这样 pre-training 训练出来的语言模型并不能拿去做 fine-tune. 原因是在 fine-token 中从来没有见过 <MASK> 这个词。作者采用这样的策略:

具体的操作,以 “My dog is hairy” 为例,mask “hairy” 这个词:

  • “My dog is <MASK>“. 80% 被 代替

  • “My dog is apple”. 10% 被一个随机的 token 代替

  • “My dog is hairy”. 10% 保持原来的样子

为什么不用 <MASK> 代替所有的 token?

If the model had been trained on only predicting ‘<MASK>’ tokens and then never saw this token during fine-tuning, it would have thought that there was no need to predict anything and this would have hampered performance. Furthermore, the model would have only learned a contextual representation of the ‘<MASK>’ token and this would have made it learn slowly (since only 15% of the input tokens are masked). By sometimes asking it to predict a word in a position that did not have a ‘<MASK>’ token, the model needed to learn a contextual representation of all the words in the input sentence, just in case it was asked to predict them afterwards.

如果模型在预训练的时候仅仅只预测 <MASK>, 然后在 fine-tune 的时候从未见过 <MASK> 这个词,那么模型就不需要预测任何词,在 fine-tune 时会影响性能。

更严重的是,如果仅仅预测 <MASK>, 那么模型只需要学习 <MASK> 的上下文表示,这会导致它学习的很慢。

如果让模型在某个位置去预测一个不是 <MASK> 的词,那么模型就需要学习所有 tokens 的上下文表示,因为万一需要预测这个词呢。

只需要 random tokens 足够吗?为什么还需要 10% 的完整的 sentence?

Well, ideally we want the model’s representation of the masked token to be better than random. By sometimes keeping the sentence intact (while still asking the model to predict the chosen token) the authors biased the model to learn a meaningful representation of the masked tokens.

使得模型具有偏置,更倾向于获得有意义的 masked token.

在知乎上问了这个问题,大佬的回复跟这篇 blog 有点差异,但实际上意思是一样的:

总结下:

为什么不能完全只有 <MASK> ? 如果只有 <MASK>, 那么这个预训练模型是有偏置的,也就是学到一种方式,用上下文去预测一个词。这导致在 fine-tune 时,会丢一部分信息,也就是知乎大佬第一部分所说的。

所以加上 random 和 ture token 是让模型知道,每个词都是有意义的,除了上下文信息,还要用到它本身的信息,即使是 <MASK>. 也就是知乎上说的,提取这两方面的信息。

再回过头,从语言模型的角度来看,依然是需要预测每一个词,但是绝大多数词它的 cross entropy loss 会很小,而主要去优化得到 <MASK> 对应的词。而 random/true token 告诉模型,你需要提防每一个词,他们也需要好好预测,因为他们不一定就是对的。

感谢知乎大佬!

random tokens 会 confuse 模型吗?

不会, random tokens 只占 15% * 10% = 1.5%. 这不会影响模型的性能。

还有一个问题, <MASK> 所占的比例很小,主要优化对象迭代一次对整个模型影响会很小,因而需要更多次迭代.

next sentence generation

对于下游是 Question Answering(QA), Natural Language Inference(NLI) 这样需要理解句子之间的相关性的任务,仅仅通过语言模型并不能获得这方面的信息。为了让模型能够理解句子之间的关系,作者提出了一个 binarized next sentence prediction.

具体方式是:

50% 是正确的相邻的句子。 50% 是随机选取的一个句子。这个任务在预训练中能达到 97%-98% 的准确率,并且能很显著的提高 QA NLI 的任务。

pre-training procudure

作者预训练使用的语料:BooksCorpus (800M words),English Wikipedia (2,500M words)。 使用文档级别的语料很关键,而不是 shffule 的句子级别的语料,这样可以获得更长的 sentence.

获得训练样本:从预料库中抽取句子对,其中 50% 的两个句子之间是确实相邻的,50% 的第二个句子是随机抽取的。具体操作看代码吧

  • batch_size 256.

  • 每一个 sentences 对: 512 tokens

  • 40 epochs

  • Adam lr=1e-4, $\beta_1=0.9$, $\beta_2=0.999$, L2 weight decay 0.01

  • learning rate warmup 10000 steps

  • 0.1 dropout

  • gelu instead of relu

Fine-tune procedure

sequence-level tasks

  • 比如 sentences pairs 的 Quora Question Pairs(QQP) 预测两个句子之间语义是否相同。如下图中(a).

  • 如果是 single sentence classification 比如 Stanford Sentiment Treebank(SST-2)和 Corpus of Linguistic Acceptability(CoLA)这种分类问题。如下图(b)

只需要输出 Transformer 最后一层的隐藏状态中的第一个 token,也就是 [CLS]. 然后接上一个全链接映射到相应的 label 空间即可。

fine-tune 时的超参数跟 pre-training 时的参数大致相同。但是训练速度会很快

  • Batch size: 16, 32

  • Learning rate (Adam): 5e-5, 3e-5, 2e-5

  • Number of epochs: 3, 4

语料库越大,对参数的敏感度越小。

token-level tasks.

对于token-level classification(例如NER),取所有token的最后层transformer输出,喂给softmax层做分类。

如何使用 BERT

文本分类

https://github.com/huggingface/pytorch-pretrained-BERT/blob/master/examples/run_classifier.py

主要涉及到两个 类:

  • 数据预处理

  • 预训练模型加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

from pytorch_pretrained_bert import BertTokenizer, BertForSequenceClassification, BertConfig, BertAdam, PYTORCH_PRETRAINED_BERT_CACHE



tokenizer = BertTokenizer.from_pretrained(args.bert_model, do_lower_case=args.do_lower_case)

tokenizer = BertTokenizer.from_pretrained("./pre_trained_models/bert-base-uncased-vocab.txt")



model = BertForSequenceClassification.from_pretrained('bert-base-uncased',

cache_dir=PYTORCH_PRETRAINED_BERT_CACHE / 'distributed_{}'.format(args.local_rank),

num_labels = num_labels)

model = BertForSequenceClassification.from_pretrained("pre_trained_models/bert-base-uncased.tar.gz", num_labels=2)

其中 bert-base-uncased 可以分别用具体的 词表文件 和 模型文件 代替。从源代码中提供的链接下载即可。

数据处理

1
2
3
4
5
6
7
8
9

from pytorch_pretrained_bert import BertTokenizer, BertForSequenceClassification, BertConfig, BertAdam, PYTORCH_PRETRAINED_BERT_CACHE



tokenizer = BertTokenizer.from_pretrained(args.bert_model, do_lower_case=args.do_lower_case)

tokenizer = BertTokenizer.from_pretrained("./pre_trained_models/bert-base-uncased-vocab.txt")

前一种方式是根据代码中提供的 url 去下载词表文件,然后缓存在默认文件夹下 /home/panxie/.pytorch_pretrained_bert 。后者是直接下载词表文件后,放在本地。相对来说,后者更方便。

这部分代码相对比较简单,根据自己的任务,继承 DataProcessor 这个类即可。

作为模型的输入,features 主要包括三个部分:

  • input_ids 是通过词典映射来的

  • input_mask 在 fine-tune 阶段,所有的词都是 1, padding 的是 0

  • segment_ids 在 text_a 中是 0, 在 text_b 中是 1, padding 的是 0

这里对应了前面所说的,input_idx 就是 token embedding, segment_ids 就是 Sentence Embedding. 而 input_mask 则表示哪些位置被 mask 了,在 fine-tune 阶段都是 1.

加载预训练模型

1
2
3
4
5
6
7
8
9

!tar -tf pre_trained_models/bert-base-uncased.tar.gz



./pytorch_model.bin

./bert_config.json

下载好的文件包中含有两个文件,分别是 config 信息,以及模型参数。

如果不用具体的文件,则需要从代码中提供的 url 下载,并缓存在默认文件夹 PYTORCH_PRETRAINED_BERT_CACHE = /home/panxie/.pytorch_pretrained_bert

作为分类任务, num_labels 参数默认为 2.

运行时会发现提取预训练模型会输出如下信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

12/26/2018 17:00:41 - INFO - pytorch_pretrained_bert.modeling -

loading archive file pre_trained_models/bert-base-uncased.tar.gz

12/26/2018 17:00:41 - INFO - pytorch_pretrained_bert.modeling -

extracting archive file pre_trained_models/bert-base-uncased.tar.gz to temp dir /tmp/tmpgm506dcx

12/26/2018 17:00:44 - INFO - pytorch_pretrained_bert.modeling -

Model config {

"attention_probs_dropout_prob": 0.1,

"hidden_act": "gelu",

"hidden_dropout_prob": 0.1,

"hidden_size": 768,

"initializer_range": 0.02,

"intermediate_size": 3072,

"max_position_embeddings": 512,

"num_attention_heads": 12,

"num_hidden_layers": 12,

"type_vocab_size": 2,

"vocab_size": 30522

}



12/26/2018 17:00:45 - INFO - pytorch_pretrained_bert.modeling -

Weights of BertForSequenceClassification not initialized from pretrained model:

['classifier.weight', 'classifier.bias']

12/26/2018 17:00:45 - INFO - pytorch_pretrained_bert.modeling -

Weights from pretrained model not used in BertForSequenceClassification:

['cls.predictions.bias', 'cls.predictions.transform.dense.weight',

'cls.predictions.transform.dense.bias', 'cls.predictions.decoder.weight',

'cls.seq_relationship.weight', 'cls.seq_relationship.bias',

'cls.predictions.transform.LayerNorm.weight', 'cls.predictions.transform.LayerNorm.bias']

不得不去观察 from_pretrained 的源码:https://github.com/huggingface/pytorch-pretrained-BERT/blob/8da280ebbeca5ebd7561fd05af78c65df9161f92/pytorch_pretrained_bert/modeling.py#L448

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

missing_keys = []

unexpected_keys = []

error_msgs = []

# copy state_dict so _load_from_state_dict can modify it

metadata = getattr(state_dict, '_metadata', None)

state_dict = state_dict.copy()

if metadata is not None:

state_dict._metadata = metadata



def load(module, prefix=''):

local_metadata = {} if metadata is None else metadata.get(prefix[:-1], {})

module._load_from_state_dict(

state_dict, prefix, local_metadata, True, missing_keys, unexpected_keys, error_msgs)

for name, child in module._modules.items():

if child is not None:

load(child, prefix + name + '.')

load(model, prefix='' if hasattr(model, 'bert') else 'bert.')

if len(missing_keys) > 0:

logger.info("Weights of {} not initialized from pretrained model: {}".format(

model.__class__.__name__, missing_keys))

if len(unexpected_keys) > 0:

logger.info("Weights from pretrained model not used in {}: {}".format(

model.__class__.__name__, unexpected_keys))

if tempdir:

# Clean up temp dir

shutil.rmtree(tempdir)

return model

这部分内容解释了如何提取模型的部分参数.

missing_keys 这里是没有从预训练模型提取参数的部分,也就是 classifier ['classifier.weight', 'classifier.bias']层,因为这一层是分类任务独有的。

unexpected_keys 则是对于分类任务不需要的,但是在预训练的语言模型中是存在的。查看 BertForMaskedLM 的模型就能看到,cls 层,是专属于语言模型的,在下游任务中都需要去掉。

所以这部分代码实际上学到了如何选择预训练模型的部分参数~~棒啊!

rejection系列3 OpenMax

paper: Towards Open Set Deep Networks. CVPR

Motivation

closed set recognition 天然的特性使得它必须选择一个类别作为预测对象。但是实际场景下, recognition system 必须学会 reject unknown/unseen classes 在 testing 阶段。

于是乎,作者提出了一个新的 model layer, OpenMax, 能够估计一个样本输入是来自于 unknown class 的概率。

A key element of estimating the unknown probability is adapting Meta-Recognition concepts to the activation patterns in the penultimate layer of the network.

所以关键词是 meta-recohnition, activation pattern/vector.

Introduction

很多工作是基于 threshold 来找出 unknown 的,他们认为 unknwon 通过 softmax 会得到 low probability/confidence. 但是实际上很多 “fooling” “rubbish” 也会拥有 high

probability/confidence scores. 比如通过对抗学习得到的 adversarial images. 作者在后面也提到了, threshold 实际上拒绝的不是 unknown, 而是 uncertain predictions.

OpenMax incorporates likelihood of the recognition system failure. This likelihood is used to estimate the probability for a given input belonging to an unknown class. For this estimation, we adapt the concept of Meta-Recognition[22, 32, 9] to deep networks. We use the scores from the penultimate layer of deep networks (the fully connected layer before SoftMax, e.g., FC8) to estimate if the input is “far” from known training data. We call scores in that layer the activation vector(AV).

关于 OpenMax 如果实现的简单总结,回过头在看。

A key insight in our opening deep networks is noting that “open space risk” should be measured in feature space rather than in pixel space.

一个重要的观点是,在 open deep networks 里面, open space risk 应该是从特征空间 feature space 的角度出发的, 而不是 pixel space. 也就是神经网络判断是不是 unknown, 应该是从 feature 的角度来看的。

We show that an extreme-value meta-recognition inspired distance normalization process on the overall activation patterns of the penultimate network layer provides a rejection probability for OpenMax normalization for unknown images, fooling images and even for many adversarial images.

Open set deep networks

Building on the concepts of open space risk, we seek to choose a layer (feature space) in which we can build a compact abating probability model that can be thresholded to limit open space risk.

基于 open space risk 的概念,提出了 compact abating probability model 能限制 open space risk.

multi-classes meta-recognition

作者先简单介绍了一下前人的工作:

. Prior work on meta-recognition used the final system scores, analyzed their distribution based on Extreme Value Theory (EVT) and found these distributions follow Weibull distribution.

感觉看懂这部分先要理解极值理论(Extreme value theory).

from wikipedia:

It seeks to assess, from a given ordered sample of a given random variable, the probability of events that are more extreme than any previously observed.

它试图从给定随机变量的给定有序样本中评估比先前观察到的任何事件更极端的事件的概率.

然后是 极值分布 的一种 Weibull distribution

所以 Weibull distribution 就是从整个分布中取最极端的例子 sampling top-n score,然后的到的分布。

将极值理论运用到视觉特征的提取中。具体的我也不太清楚了。。这也是前人的研究。作者也并没有采取这种方法。

We take the approach that the network values from penultimate layer (hereafter the Activation Vector (AV)), are not an independent per-class score estimate, but rather they provide a distribution of what classes are “related.”

作者采用的方法是 倒数第二层,也就是 (Activation Vector) 提供不同 classes 之间的相关性分布,而不是每一个类对应的独立的分布。

interpretation of activation vector

OpenMax

rejection系列1-overview

关于 open set recognition 的一片综述。

paper: Recent Advances in Open Set Recognition: A Survey

Motivation

In real-world recognition/classification tasks, limited by various objective factors, it is usually difficult to collect training samples to exhaust all classes when training a recognizer or classifier. A more realistic scenario is open set recognition (OSR), where incomplete knowledge of the world exists at training time, and unknown classes can be submitted to an algorithm during testing, requiring the classifiers not only to accurately classify the seen classes, but also to effectively deal with the unseen ones.

现实中对于分类任务,不可能在训练集中穷尽所有类别。更实际的情况是 open set recognition (OSR). 在训练阶段包含的是不完整的 knowledge of world. 在测试阶段会出现 unknown 类别。这需要分类器不仅能准确的识别在训练阶段已经见到过的类别,也能有效的处理没有见过的类别, 比如 rejection 或者归类为 unknown.

This paper provides a comprehensive survey of existing open set recognition techniques covering various aspects ranging from related definitions, representations of models, datasets, experiment setup and evaluation metrics. Furthermore, we briefly analyze the relationships between OSR and its related tasks including zero-shot, one-shot (few-shot) recognition/learning techniques, classification with reject option, and so forth. Additionally, we also overview the open world recognition which can be seen as a natural extension of OSR. Importantly, we highlight the limitations of existing approaches and point out some promising subsequent research directions in this field.

这篇综述覆盖了相关的定义、模型、实验以及验证指标。更多地,还分析了 与OSR 相关的任务 zero-shot, one-shot 识别,以及 rejection. 额外地,还概述了 open world recognition 可以看作 OSR 的扩展。更重要的是,作者说明了当前一些方法的限制,并指出了未来研究的一些方向。

Introduction

a more realistic scenario is usually open and non-stationary such as driverless, fault/medical diagnosis, etc., where unseen situations can emerge unexpectedly, which drastically weakens the robustness of these existing methods.

更现实的场景是 开放的和非静态 的。

To meet this challenge, several related research directions actually have been explored including lifelong learning [1], [2], transfer learning [3]–[5], domain adaptation [6], zero-shot [7]–[9], one-shot (few-shot) [10]–[16] recognition/learning and open set recognition/classification [17]–[19], and so forth.

涉及到的领域: lifelong learning, transfer learning, domain adaption, zero-shot, one-shot, open set recogntion.

recognition should consider four basic categories of classes as follows:

  • known known: train/dev 中有标签的样本,包括正负类别,并且有相关的语义信息。

  • known unknown: train/dev 中有标签的样本,负类,没有相关的语义信息。

  • unknown known: test 中没有出现在 train 中的样本,但是有相关的语义信息。比如,train 中有猫,然后 test 中有另外一种猫科动物,那么动物这个样本是有意义的吧???

  • unknown unknown: test 中没有出现在 train 中的样本,并且没有任何相关的语义信息。

Unlike the traditional classification, zero-shot learning (ZSL) can identify unseen classes which have no available observations in training. However, the available semantic/attribute information shared among all classes including seen and unseen ones are needed.

zero-shot 是针对 unknown known, 也就是包含了语义信息。

The ZSL mainly focuses on the recognition of the unknown known classes defined above. Actually, such a setting is rather restrictive and impractical, since we usually know nothing about the testing samples which may come from known known classes or not.

unknown known 这种设定很有限,并且不切实际。因为我们很难知道 test 中的样本是否是包含了语义信息,无法判断是 unknown known or unknown unknown.

comparision between open set recognition and traditional classification

Via these decision boundaries, samples from an unknown unknown class are labeled as ”unknown” or rejected rather than misclassified as known known classes.

经验风险函数:

$L(x, y, f(x)) \ge 0$ 是 loss function. P(x,y) 是对应样本 (x, y) 的概率,通常这个联合分布的概率我们是不知道的,因为我们无法确定自然界中样本空间(label space)到底是个什么分布。

[李航,机器学习] 中关于风险函数的定义:

损失函数度量一次模型预测的好坏,风险函数度量平均意义下模型预测的好坏。

以前看不懂这一部分,现在只想说: Perfect!

Therefore, traditional recognition/classification approaches minimize the empirical risk instead of the ideal risk RI by using other knowledge, such as assuming that the label space is at least locally smooth and regularizing the empirical risk minimization.

传统的分类方法是根据其他的外部知识来最小化经验风险,比如 label space 是光滑的,然后使用正则化最小经验风险(也就是上面所说的结构风险函数)。

Note that traditional recognition problem is usually performed under the closed set assumption. When the assumption switches to open environment/set scenario with the open space, other things should be added since intuitively there is some risk in labeling sample in the open space as any known known classes. This gives such an insight for OSR that we do know something else: we do know where known known classes exist, and we know that in open space we do not have a good basis for assigning labels for the unknown unknown classes.

传统的识别是假设在固定的样本空间下(known known). 当转换到开放式场景下,我们很敏感的意识到需要给 label space 加点 risk。。我们知道 known known classes 是存在的,我们也知道我们并没有这样一个 basis 去给 unknown unknown 打标签。

open space risk

这部分的内容主要引自这篇 paper: 17. Toward Open Set Recognition

这篇 paper 是把 class of interest 当作一个类,然后所有的 unknown/known 当作很多 classes, 也就是 1-vs-set.

To improve the overall open set recognition error, our 1-vs-set formulation balances the unknown classes by obtaining a core margin around the decision boundary A from the base SVM, specializing the resulting half-space by adding another plane $\Omega$ and then generalizing or specializing the two planes (shown in Fig. 2) to optimize empirical and open space risk. This process uses the open set training data and the risk model to define a new “open set margin.” The second plane $\Omega$ allows the 1-vs-set machine to avoid the overgeneralization that would misclassify the raccoon in Fig. 2. The overall optimization can also adjust the original margin with respect to A to reduce open space risk, which can avoid negatives such as the owl.

使用了两个超平面,去分隔 Negatives/positivecs/unknown.

While we do not know the joint distribution $P(x, y)$ in, one way to look at the open space risk is as a weak assumption: Far from the known data the Principle of Indifference [8] suggests that if there is no known reason to assign a probability, alternatives should be given equal probability. In our case, this means that at all points in open space, all labels (both known and unknown) are equally

likely, and risk should be computed accordingly. However, we cannot have constant value probabilities over infinite spaces—the distribution must be integrable and integrate to 1. We must formalize open space differently (e.g., by ensuring the problem is well posed and then assuming the probability is proportional to relative Lebesgue measure [9]). Thus, we can consider the measure of the open space to the full space, and define our risk penalty proportional to such a ratio.

无法知道联合分布 $P(x, y)$, 作者假设所有的样本概率是相等的,但是向量空间中样本总数是不确定的,所以作者定义一个比例来描述 在 open space 中出现 unknown 的危险惩罚系数。

where open space risk is considered to be the fraction (in terms of Lebesgue measure) of positively labeled open space compared to the overall measure of positively labeled space (which includes the space near the positive examples).

open space risk 是开放空间中 positive label 的总数与总体空间中 positive label 的总体度量。

不太懂。。问题还是不知道怎么度量? unknown 的类别能确定???

openness

openness,用来表征数据集的开放程度:

  • $C_{TR}$ 是训练集中的类别数,越大,开放程度越小。

  • $C_{TE}$ 测试集中的类别数。

The Open Set Recognition Problem

our goal is to balance the risk of the unknown in open space with the empirical (known) risk. In this sense, we formally define the open set recognition problem as follows:

我们的目的是平衡 the risk of unknown 出现在基于 known classes 计算的到的 open space 的 empirical risk。

怎么理解呢?就是传统的风险函数都是只考虑了经验风险,也就是完全基于训练数据的。但是在 open space 里面,我们还要测试时会出现的 unknown,所以在 风险函数的设置的同时,就要考虑到 unknown 的存在。也就是前面的 open space risk.

a categorization of OSR techniques

问题的关键在于如何将 公式(4)open space risk 合并到模型中去。然后大佬们提出各式各样的模型,主要分为 discriminative model and generative models.

更进一步,可以分为:five categories (Table II):

  • Traditional ML-based

  • Deep Network-based

  • Adversarial Learning-based

  • EVT-based

  • Dirichlet Process-based OSR models

Deep Neural Network-based OSR Models

大佬们的杰作,感觉都挺新的,新坑?

提出了 OpenMax,使用 deep networks, 还是用 softmax 损失函数来最小化 交叉熵 cross entropy loss. 然后在网络的倒数第二层(softmax 的前一层?)得到每一个正分类的 mean activate vector(MAV).

然后是根据 Weibull districution 去 redistribution 以及重新分类等等接下来的操作还是看相应 的 paper 吧。

the OpenMax effectively addressed the challenge of the recognition for fooling/rubbish and unrelated open set images. However, as discussed in [71], the OpenMax fails to recognize the adversarial images which are visually indistinguishable from training samples but are designed to make deep networks produce high confidence but incorrect answers [96], [98].

OpenMax 有效的解决了 不相关的 open set images 的问题,但是却无法有效区分对抗生成样本。

Actually, the authors in [72] have indicated that the OpenMax is susceptible to the adversarial generation techniques directly working on deep representations. Therefore, the adversarial samples are still a serious challenge for open set recognition. Furthermore, using the distance from MAV, the cross entropy loss function in OpenMax does not directly incentivize projecting class samples around the MAV. In addition to that, the distance function used in testing is not used in training, possibly resulting in inaccurate measurement in that space [73]. To address this limitation, Hassen and Chan [73] learned a neural network based representation for open set recognition, which is similar in spirit to the Fisher Discriminant, where samples from the same class are closed to each other while the ones from different classes are further apart, leading to larger space among known known classes for unknown unknown classes’ samples to occupy.

交叉熵并不能有效的将类别映射到相应的 MAV 中,因为在测试集中的 distence function 跟在 training set 里面是不一样的,这会导致不准确的判别。基于此,[73]提出了 Fisher 判别,从同一个类别中采样,使得unknown unknown 和 known known 的间距很大。

  • OpenMax to text classification

  • Deep Open classifier

  • tWiSARD

  • hidden unknown unknown classes

Adversarial Learning-based OSR Models

Note that the main challenge for open set recognition is the incomplete class knowledge existing in training, leading to the open space risk when classifiers encounter unknown unknown classes during testing. Fortunately, the adversarial learning technique can account for open space to some extent by adversarially generating the unknown unknown class data according to the known known class knowledge, which undoubtedly provides another way to tackle the challenging multiclass OSR problem.

open set recognition 最大的挑战是 training 中不完整的 knowledge, 在 testing 中遇到 unknown unknown 导致 open space risk.

而对抗训练网络在某种程度上根据 known known 生成 unknown unknown,提供了另外一种方式解决 OSR 问题。

EVT-based OSR Models

As a powerful tool to increase the classification performance, the statistical Extreme Value Theory (EVT) has recently achieved great success due to the fact that EVT can effectively model the tails of the distribution of distances between training observations using the asymptotic theory[100].

不是很懂这个理论,给出几篇 paper 吧

Remark: As mentioned above, almost all existing OSR methods adopt the threshold-based classification scheme, where recognizers in decision either reject or categorize the input samples to some known known class using empirically set threshold. Thus the threshold plays a key role. However, the selection for it usually depends on the knowledge of known known classes, inevitably incurring risks due to lacking available information from unknown unknown classes [57]. This indicates the threshold-based OSR methods still face serious challenges.

基于 known known 得到的 threshold 因为缺乏 unknown unknown 的信息,不可避免的会造成 risk, 这也是基于 threshold 这类方法所面临的困难。

Dirichlet Process-based OSR Models (生成模型)

Dirichlet process (DP) [104]–[108] considered as a distribution over distributions is a stochastic process, which has been widely applied in clustering and density estimation problems as a nonparametric prior defined over the number of mixture components. Furthermore, this model does not overly depend on training samples and can achieve adaptive change as the data changes, making it naturally adapt to the open set recognition scenario. In fact, researchers have begun the related research

Dirichlet 过程作为一种基于混合模型的非参数方法广泛用于聚类,参数估计。这种模型不需要依赖于 training,可以随着 dataset 的变化而自适应的变化,这使得它能有效的适用于 open set 的场景。

对生成模型不是很熟。。

Remark: Instead of addressing the OSR problem from the discriminative model perspective, CD-OSR actually reconsiders this problem from the generative model perspective due to the use of HDP, which provides another research direction for open set recognition. Furthermore, the collective decision strategy for OSR is also worth further exploring since it not only takes the correlations among the testing samples into account but also provides a possibility for new class discovery, whereas single-sample decision strategy2 adopted by other existing OSR methods can not do such a work since it can not directly tell whether the single rejected sample is an outlier or from new class.

Beyond open set Recognition

关于 open set recognition 如果仅仅考虑静态的 set,意义不是很大。以及,只对 unknown unknown 进行 rejection 也是不够的。为此,有人提出 open world recognition.

open world recognition (OWR), where a recognition system should perform four tasks:

  • detecting unknown unknown classes

  • choosing which samples to label for addition to the model

  • labelling those samples

  • updating the classifier

Remark: As a natural extension of OSR, the OWR faces more serious challenges which require it not only to have the ability to handle the OSR task, but also to have minimal

downtime, even to continuously learn, which seems to have the flavor of lifelong learning to some extent. Besides, although some progress regarding the OWR has been made, there is still a long way to go.

终身学习。。666

Dataset and evalution metrics

dataset

Experiment Setup: In open set recognition, most existing experiments are carried out on a variety of recastes multi-class benchmark datasets. Specifically, taking the Usps dataset as an example, when it is used for OSR problem, one can randomly choose S distinct labels as the known known classes, and vary openness by adding a subset of the remaining labels.

可以增加减少类别数来改变 openness.

Evaluation Metrics for Open Set Recognition

  • TP: true positive

  • FP: false positive

  • TN: true negative

  • FN: false negative

  • TU: true unknown

  • FU: false unknown

accuracy

对于 closed set :

$$\text{accuracy}=\dfrac{TP+TN}{TP+TN+FP+FN}$$

对于 open set:

$$\text{accuracy}_O=\dfrac{(TP+TN)+TU}{(TP+TN+FP+FN)+(TU+FU)}$$

对于不均衡情况,accuracy 并不能客观的评价模型好坏。比如在testing 中,unknown unknown 样本数量很多,那么如果分类器把所有的类别都判为 unknown unknown,它的准确率依旧很高。

于是,有人提出了 normalized accuracy(NA).

$0\le \lambda \le 1$ 是正则化常数。

F-measure

F1:

$$F1=\dfrac{2\text{precision} \text{recall}}{\text{precision}+\text{recall}}$$

$$precision=\dfrac{TP}{TP+FP}$$

精度: 预测得到的 positive 中真正是 positive 的概率。

$$recall=\dfrac{TP}{TP+FN}$$

召回: 所有真正 positive 的样本被预测为 positive 的概率。

在 open set 场景下,F1 值无法考虑 unknown unknown.

Instead, the computations of Precision and Recall in it are only for available known known classes. Additionally, the work [67] has indicated that although the computations of Precision and Recall are only for available known known classes, the FN and FP also consider the false unknown unknown classes and false known known classes by taking into account the false negative and the false positive, and we refer the reader to [67] for more details.

事实上,在 FP 和 FN 中可能也包括 false unknown unknown, 这就有问题了是吧。。

详细参考这篇 paper Nearest neighbors distance ratio open-set classifier

Note that the Precision

contains the macro-Precision and micro-Precision while Recall includes the macro-Recall and micro-Recall, which leads to the corresponding macro-F-measure and micro-F-measure. Nevertheless, whether it is macro-F-measure or micro-F-measure, the higher their values, the better the performance of the corresponding OSR model.

Youden’s index for OSR

$$J= \text{Recall}+S-1$$

其中 S 是真负类率: $S=\dfrac{TN}{TN+FP}$

future research directions

About modeling

  • 大部分工作都是基于判别模型来做的,只有少部分是基于生成模型,也许生成模型会更有探索空间。

  • OSR 的主要挑战是传统的分类器是在 closed-set 场景下获得的,一旦 unknown unknown class 落入这个空间,将永远无法被正确的分类。

modeling known known classes

如果得到的 known known class 没有被过拟合,那么这样的分类器就能有效的区分出 unknown unknown. 所以聚类和分类算法的结合会是不错的方向。关于 clustering 和 classification 的 unified learning framework:

这两篇 paper 依旧是在 closed-set 下做的,所以需要你去尝试。。。

modeling unknown unknown classes

似乎在只有 known known classes 的情况下是很难去学习 unknown unknown 的类的性质的。但是可以通过对抗学习来生成 unknown unknown 也是不错的方向。

顺便作者还提了下 transductive leanring,以及基于 Dirichlet process 的自适应行,CD-OSR、Dirichlet processed-based OSR 也是值得探索的。

About rejecting

大部分的工作都是 reject unknown unknown classes,而没有后续的工作了。只有少量的 [66][67]进行了后续的工作,比如 new classes discovery.

About the decision

所有的 OSR 模型都是用来识别单个样本的,但是一个决策的决定并没有考虑样本之间的相关性。所以 collective decision 不仅在 testing 时考虑相关性,同时还能发现 new classes.

Open set + ‘sth’

As open set scenario is a more practical assumption for the real-world classification/recognition tasks, it can naturally be combined with various fields involving classification/recognition such as semi-supervised learning, domain adaptation, active learning, multi-task learning, multi-label learning, multi-view learning, and so forth. For example, [124]–[126] recently introduced this scenario into domain adaptation, while [127] explored the open set classification in active learning field. Therefore, many interesting works are worth looking forward to.

看起来是个不错的方向。。

Generalized Open Set Recognition

利用 side-information,比如 unknown unknwon 和 known known 会有共同的语义信息(semantic/attribute information).

Appending semantic/attribute information

In fact, a lot

of semantic/attibute information is shared between the known known and the unknown unknown classes. Therefore, we can fully utilize this kind of information to ’cognize’ the unknown unknown classes, or at least to provide a rough semantic/attribute description for the corresponding unknown unknown classes instead of simply rejecting them.

利用语义信息去意识到 unknown unknwon,而不是简单的 reject.

但是要注意区分 open set recognition 和 ZSL(zero-shot learning) 的区别:

The $\text{side-information}^1$ in ZSL denotes the semantic/attribute information shared among all classes including known known and unknown known classes.

where the $\text{side-information}^4$ denotes the available semantic/attribute information only for known known classes

感觉这个 side-information 的界限很难确定啊?Generalized Open Set Recognition 的这个范围似乎很难实现, 怎么可能出现在 training 中的 semantice information 完全不出现在 unknown unknown 中呢。。

还有一些相似的工作:

Using other available side-information

**The main reason for open space risk is that the traditional classifiers trained under closed set scenario usually divide over-occupied space for known known classes, thus inevitably resulting in misclassifications once the unknown unknown class samples

fall into the space divided for some known known class.** From this perspective, the open space risk will be reduced as the space divided for those known known classes decreases by

using other side-information like universum [135], [136] to shrink their regions as much as possible.

虽然感觉很扯淡。。但是还是有人做啊,不过关于 open space risk 的定义可以在看一遍。。

Relative Open Set Recognition

感觉这个还挺有意思的。疾病的诊断,所有的样本空间都可以区分为 sick or no sick, 所以仅仅是判断有没有病,那么这是个 closed set 问题。但是如果我们要进一步判断疾病的类型,那么有可能出现 unseen disease in training.

Knowledge Integration for Open Set Recognition

In fact, the incomplete knowledge of the world is universal, especially for the single individuals: something you know does not mean I also know.

how to integrate the classifiers trained on each sub-knowledge set to further reduce the open space risk will be an interesting yet challenging topic in the future work, especially for such a situation: we can only obtain the classifiers trained on corresponding sub-knowledge sets, yet these sub-knowledge sets are not available due to the privacy protection of data.

利用知识库来减小 open space risk。

似乎这个看起来比较靠谱,因为 unknown 范围确实很难定义,如果给个外部知识库给你,把跟知识库相关的 unknown 识别出来,就很棒了吧

相关的一些开源工具和代码:

论文笔记-CoQA

paper: CoQA: A Conversational Question Answering Challenge

Motivation

We introduce CoQA, a novel dataset for building Conversational Question Answering systems.1 Our dataset contains 127k questions with answers, obtained from 8k conversations about text passages from seven diverse domains.

CoQA, 对话式阅读理解数据集。从 7 个不同领域的 8k 对话中获取的 127k 问答对。

The questions are conversational, and the answers are free-form text with their corresponding evidence highlighted in the passage.

We analyze CoQA in depth and show that conversational questions have challenging phenomena not present in existing reading comprehension datasets, e.g., coreference and pragmatic reasoning.

CoQA 跟传统的 RC 数据集所面临的挑战不一样,主要是指代和推理。

We ask other people a question to either seek or test their knowledge about a subject. Depending on their answer, we follow up with another question and their answer builds on what has already been discussed. This incremental aspect makes human conversations succinct. An inability to build up and maintain common ground in this way is part of why virtual assistants usually don’t seem like competent conversational partners.

我们问其他人一个问题,来寻求或者测试他们对某一个主题的知识。然后依赖于他的答案,我们提出一个新的问题,他根据刚才我们讨论的来回答这个新的问题。

这使得对话变得很简短。而正是这种建立和维持共同点的能力缺失,使得虚拟助手看起来并不是一个有能力的对话者。

而 CoQA 就是要测试这种能力。

Introduction

In CoQA, a machine has to understand a text passage and answer a series of questions that appear in a conversation. We develop CoQA with three main goals in mind.

The first concerns the nature of questions in a human conversation. Posing short questions is an effective human conversation strategy, but such questions are a pain in the neck for machines.

第一点:人类在对话时,会提出很简短的问题,但这对于机器来说却很难。比如 Q5 “Who?”

The second goal of CoQA is to ensure the naturalness of answers in a conversation. Many existing QA datasets restrict answers to a contiguous span in a given passage, also known as extractive answers (Table 1). Such answers are not always natural, for example, there is no extractive answer for Q4 (How many?) in Figure 1. In CoQA, we propose that the answers can be free-form text (abstractive answers), while the extractive spans act as rationales for the actual answers. Therefore, the answer for Q4 is simply Three while its rationale is spanned across multiple sentences.

第二点:答案不是抽取式的 extractive,而是总结性的 abstractive, free-from text. 比如 Q4. 好难啊!!!

The third goal of CoQA is to enable building QA systems that perform robustly across domains. The current QA datasets mainly focus on a single domain which makes it hard to test the generalization ability of existing models.

第三点:数据来自多种 domain,提高泛化性。

Dataset collection

数据集具体详情:

  1. It consists of 127k conversation turns collected from 8k conversations over text passages (approximately one conversation per

passage). The average conversation length is 15 turns, and each turn consists of a question and an answer.

  1. It contains free-form answers. Each answer has an extractive rationale highlighted in the passage.
  1. Its text passages are collected from seven diverse domains — five are used for in-domain evaluation and two are used for out-of-domain

evaluation.

Almost half of CoQA questions refer back to conversational history using coreferences, and a large portion requires pragmatic reasoning making it challenging for models that rely on lexical cues alone.

大部分涉及到对话历史的问题都用到了指代和逻辑推理,这对于仅仅是依赖于词汇提示(语义匹配)的模型来说会很难。

The best-performing system, a reading comprehension model that predicts extractive rationales which are further fed into a sequence-to-sequence model that generates final answers, achieves a F1 score of 65.1%. In contrast, humans achieve 88.8% F1, a superiority of 23.7% F1, indicating that there is a lot of headroom for improvement.

Baseline 是将抽取式阅读理解模型转换成 seq2seq 形式,然后从 rationale 中获取答案,最终得到了 65.1% 的 F1 值。

question and answer collection

We want questioners to avoid using exact words in the passage in order to increase lexical diversity. When they type a word that is already present in the passage, we alert them to paraphrase the question if possible.

questioner 提出的问题应尽可能避免使用出现在 passage 中的词,这样可以增加词汇的多样性。

For the answers, we want answerers to stick to the vocabulary in the passage in order to limit the number of possible answers. We encourage this by automatically copying the highlighted text into the answer box and allowing them to edit copied text in order to generate a natural answer. We found 78% of the answers have at least one edit such as changing a word’s case or adding a punctuation.

对于答案呢,尽可能的使用 passage 中出现的词,从而限制出现很多中答案的可能性。作者通过复制 highlighted text(也就是 rationale 吧) 到 answer box,然后让 answerer 去生成相应的 answer. 其中 78% 的答案是需要一个编辑距离,比如一个词的大小写或增加标点符号。

passage collection

Not all passages in these domains are equally good for generating interesting conversations. A passage with just one entity often result in questions that entirely focus on that entity. Therefore, we select passages with multiple entities, events and pronominal references using Stanford CoreNLP (Manning et al., 2014). We truncate long articles to the first few paragraphs that result in around 200 words.

如果一个 passage 只有一个 entity,那么根据它生成的对话都会是围绕这个 entity 的。显然这不是这个数据集想要的。因此,作者使用 Stanford CoreNLP 来对 passage 进行分析后选择多个 entity 和 event 的 passage.

Table 2 shows the distribution of domains. We reserve the Science and Reddit domains for out-ofdomain evaluation. For each in-domain dataset, we split the data such that there are 100 passages in the development set, 100 passages in the test set, and the rest in the training set. For each out-of-domain dataset, we just have 100 passages in the test set.

In domain 中包含 Children, Literature, Mid/HIgh school, News, Wikipedia. 他们分出 100 passage 到开发集(dev dataset), 其余的在训练集 (train dataset). out-of-diomain 包含 Science Reddit ,分别有 100 passage 在开发集中。

test dataset:

Collection multiple answers

Some questions in CoQA may have multiple valid answers. For example, another answer for Q4 in Figure 2 is A Republican candidate. In order to

account for answer variations, we collect three additional answers for all questions in the development and test data.

一个问题可能出现多种回答,因此在dev dataset 和 test dataset 中有三个候选答案。

In the previous example, if the original answer was A Republican Candidate, then the following question Which party does he

belong to? would not have occurred in the first place. When we show questions from an existing conversation to new answerers, it is likely they will deviate from the original answers which makes the conversation incoherent. It is thus important to bring them to a common ground with the original answer.

比如上图中 Q4, 如果回答是 A Republican candidate. 但是整个对话是相关的,所以接下来的问题就会使整个对话显得混乱了。

We achieve this by turning the answer collection task into a game of predicting original answers. First, we show a question to a new answerer, and when she answers it, we show the original answer and ask her to verify if her answer matches the original. For the next question, we ask her to guess the original answer and verify again. We repeat this process until the conversation is complete. In our pilot experiment, the human F1 score is increased by 5.4% when we use this verification setup.

因为机器在学习的时候是有 original answer 进行对比的,同样的这个过程在人工阶段也是需要的,可以减少上诉的混乱情况,answerer 在给出一个答案后,作者会告诉他们是否与 original 匹配,然后直到整个过程完成。

Dataset Analysis

What makes the CoQA dataset conversational compared to existing reading comprehension datasets like SQuAD? How does the conversation flow from one turn to the other? What linguistic phenomena do the questions in CoQA exhibit? We answer these questions below.

在 question 中:

  1. 指代词(he, him, she, it, they)出现的更为频繁, SQuAD 则几乎没有。

  2. SQuAD 中 what 几乎占了一半,CoQA 中问题类型则更为多样, 比如 did, was, is, does 的频率很高。

  3. CoQA 的问题更加简短。见图 3.

  4. answer 有 33% 的是 abstractive. 考虑到人工因素,抽取式的 answer 显然更好写,所以这高于作者预期了。yes/no 的答案也有一定比重。

Conversation Flow

A coherent conversation must have smooth transitions between turns.

一段好的对话是具有引导性的,不断深入挖掘 passage 的信息。

作者将 passage 均匀分成 10 chunks,然后分析随着对话 turn 的变化,其对应的 passage chunks 变化的情况。

Linguistic Phenomena

Relationship between a question and its passage:

  • lexical match: question 和 passage 中至少有一个词是匹配的。

  • Paraphrasing: 解释型。虽然 question 没有与 passage 的词,但是确实对 rationale 的一种解释,也就是换了一种说法,当作问题提出了。通常这里面包含: synonymy(同义词), antonymy(反义词), hypernymy(上位词), hyponymy(下位词) and negation(否定词).

  • Pragmatics: 需要推理的。

Relationship between a question and its conversation history:

  • No coref

  • Explicit coref.

  • Implicit coref.

论文笔记-dropblock

paper:

dropblock 是关于 CNN 的,后两篇是关于 RNN 的正则化。

DropBlock

Motivation

Deep neural networks often work well when they are over-parameterized and trained with a massive amount of noise and regularization, such as weight decay and dropout. Although dropout is widely used as a regularization technique for fully connected layers, it is often less effective for convolutional layers. This lack of success of dropout for convolutional layers is perhaps due to the fact that

activation units in convolutional layers are spatially correlated so information can still flow through convolutional networks despite dropout.

通常深度神经网络在过参数化,并在训练时加上大量的噪声和正则化,比如权重衰减和 dropout,这个时候神经网络能很好的 work. 但是 dropout 对于全链接网络是一个非常有效的正则化技术,它对于卷积神经网络却没啥效果。这可能是因为卷积神经网络的激活是空间相关的,即使 drop 掉部分 unit,信息仍然会传递到下一层网络中去。

Thus a structured form of dropout is needed to regularize convolutional networks. In this paper, we introduce DropBlock, a form of structured dropout, where units in a contiguous region of a feature map are dropped together. We found that applying DropBlock in skip connections in addition to the convolution layers increases the accuracy. Also, gradually increasing number of dropped units during training leads to better accuracy and more robust to hyperparameter choices.

作者为卷积神经网络提出了专门的正则化方式, dropblock. 同时 drop 掉一个连续的空间。作者发现将 dropblock 应用到 ResNet 能有效的提高准确率。同时增加 drop 的概率能提高参数的鲁棒性。

回顾了一下 skip/shortcut connection: 目的是避免梯度消失。可以直接看 GRU 的公式:参考笔记

dropblock

In this paper, we introduce DropBlock, a structured form of dropout, that is particularly effective to regularize convolutional networks. In DropBlock, features in a block, i.e., a contiguous region of a feature map, are dropped together. As DropBlock discards features in a correlated area, the networks must look elsewhere for evidence to fit the data (see Figure 1).

具体的算法很简单,主要关注两个参数的设置: block_size 和 $\gamma$.

  • block_size is the size of the block to be dropped

  • $\gamma$ controls how many activation units to drop.

We experimented with a shared DropBlock mask across different feature channels or each feature channel has its DropBlock mask. Algorithm 1 corresponds to the latter, which tends to work better in our experiments.

对于 channels, 不同的 feature map 具有不同的 dropblock 相比所有的 channels 共享 dropblock 效果要好。

Similar to dropout we do not apply DropBlock during inference. This is interpreted as evaluating an averaged prediction across the exponentially-sized ensemble of sub-networks. These sub-networks include a special subset of sub-networks covered by dropout where each network does not see contiguous parts of feature maps.

关于 infer 时, dropblock 的处理和 dropout 类似。

block_size:

In our implementation, we set a constant block_size for all feature maps, regardless the resolution of feature map. DropBlock resembles dropout [1] when block_size = 1 and resembles SpatialDropout [20] when block_size covers the full feature map.

block_size 设置为 1 时, 类似于 dropout. 当 block_size 设置为整个 feature map 的 size 大小时,就类似于 SpatialDropout.

setting the value of $\gamma$:

In practice, we do not explicitly set $\gamma$. As stated earlier, $\gamma$ controls the number of features to drop. Suppose that we want to keep every activation unit with the probability of keep_prob, in dropout [1] the binary mask will be sampled with the Bernoulli distribution with mean 1 − keep_prob. However, to account for the fact that every zero entry in the mask will be expanded by block_size2 and the blocks will be fully contained in feature map, we need to adjust $\gamma$ accordingly when we sample the initial binary mask. In our implementation, $\gamma$ can be computed as

作者并没有显示的设置 $\gamma$. 对于 dropout,每一个 unit 满足概率为 keep_prob 的 Bernoulli 分布,但是对于 dropblock, 需要考虑到 block_size 的大小,以及其与 feature map size 的比例大小。

  • keep_prob 是传统的 dropout 的概率,通常设置为 0.75-0.9.

  • feat_size 是整个 feature map 的 size 大小。

  • (feat_size - block_size + 1) 是选择 dropblock 中心位置的有效区域。

The main nuance of DropBlock is that there will be some overlapped in the dropped blocks, so the above equation is only an approximation.

最主要的问题是,会出现 block_size 的重叠。所以上诉公式也只是个近似。

Scheduled DropBlock:

We found that DropBlock with a fixed keep_prob during training does not work well. Applying small value of keep_prob hurts learning at the beginning. Instead, gradually decreasing keep_prob over time from 1 to the target value is more robust and adds improvement for the most values of keep_prob.

定制化的设置 keep_prob, 在网络初期丢失特征会降低 preformance, 所以刚开始设置为 1,然后逐渐减小到 target value.

所以是随着网络深度加深而变化,还是随着迭代步数变化,应该是后者吧,类似于 scheduled learning rate.

Experiments

In the following experiments, we study where to apply DropBlock in residual networks. We experimented with applying DropBlock only after convolution layers or applying DropBlock after both convolution layers and skip connections. To study the performance of DropBlock applying to different feature groups, we experimented with applying DropBlock to Group 4 or to both Groups 3 and 4.

实验主要在讨论在哪儿加 dropblock 以及 如何在 channels 中加 dropblock。

Variational Dropout

深度学习-优化算法

paper: An overview of gradient descent optimization algorithms

Gradient descent variants

Batch gradient descent

computes the gradient of the cost function to the parameters $\theta$ for the entire training dataset.

$$\theta= \theta - \delta_{\theta}J(\theta)$$

1
2
3
4
5
6
7

for i in range ( nb_epochs ):

params_grad = evaluate_gradient ( loss_function , data , params )

params = params - learning_rate * params_grad

Batch gradient descent is guaranteed to converge to the global minimum for convex error surfaces and to a local minimum for non-convex surfaces.

Stochastic gradient descent

Stochastic gradient descent (SGD) in contrast performs a parameter update for each training example x(i) and label y(i):

$$\theta= \theta - \delta_{\theta}J(\theta; x^{(i)}; y^{(i)})$$

1
2
3
4
5
6
7
8
9
10
11

for i in range ( nb_epochs ):

np. random . shuffle ( data )

for example in data :

params_grad = evaluate_gradient ( loss_function , example , params )

params = params - learning_rate * params_grad

Batch gradient descent performs redundant computations for large datasets, as it recomputes gradients for similar examples before each parameter update. SGD does away with this redundancy by performing one update at a time. It is therefore usually much faster and can also be used to learn

online. SGD performs frequent updates with a high variance that cause the objective function to fluctuate heavily.

批梯度下降的计算过于冗余,它在每一次参数更新之前的计算过程中会计算很多相似的样本。随机梯度下降则是每一次参数更新计算一个样本,因此更新速度会很快,并且可以在线学习。但是用于更新的梯度的方差会很大,导致 loss 曲线波动很大。

While batch gradient descent converges to the minimum of the basin the parameters are placed in, SGD’s fluctuation, on the one hand, enables it to jump to new and potentially better local minima. On the other hand, this ultimately

complicates convergence to the exact minimum, as SGD will keep overshooting. However, it has been shown that when we slowly decrease the learning rate, SGD shows the same convergence behaviour as batch gradient descent, almost

certainly converging to a local or the global minimum for non-convex and convex optimization respectively.

批梯度下降收敛到的最小值与相应的参数关系很大(也就是说跟权重的初始化会有很大影响)。而 SGD 由于loss波动很大,更有效的跳出局部最优区域,从而获得更好的局部最优值。但另一方面,这也会使得 SGD 难以收敛。实验表明,缓慢的降低学习率, SGD 和 BatchGD 能获得同样的局部最优解。

Mini-batch gradient descent

Mini-batch gradient descent finally takes the best of both worlds and performs an update for every mini-batch of n training examples.

$$\theta= \theta - \delta_{\theta}J(\theta; x^{(i+n)}; y^{(i+n)})$$

1
2
3
4
5
6
7
8
9
10
11

for i in range ( nb_epochs ):

np. random . shuffle ( data )

for batch in get_batches (data , batch_size =50):

params_grad = evaluate_gradient ( loss_function , batch , params )

params = params - learning_rate * params_grad

  • reduces the variance of the parameter updates, which can lead to more stable convergence;

减小参数更新的方差,使得收敛更稳定。

  • can make use of highly optimized matrix optimizations common to state-of-the-art deep learning libraries that make computing the gradient mini-batch very efficient.

能非常好的利用矩阵优化的方式来加速计算,这在各种深度学习框架里面都很常见。

Challenges

  • Choosing a proper learning rate.

选择合适的学习率。

  • Learning rate schedules. try to adjust the learning rate during training by e.g. annealing, i.e. reducing the learning rate according to a pre-defined schedule or when the change in objective between epochs falls below a threshold. These schedules and thresholds, however, have to be defined in advance and are thus unable to adapt to a dataset’s characteristics.

学习率计划。在训练过程中调整学习率,譬如退火,预先定义好的计划,当一个 epoch 结束后,目标函数(loss) 减小的值低于某个阈值时,可以调整学习率。

  • the same learning rate applies to all parameter updates. If our data is sparse and our features have very different frequencies, we might not want to update all of them to the same extent, but perform a larger update for rarely occurring

features.

对所有的参数使用相同的学习率。如果你的数据是稀疏的,并且不同的特征的频率有很大的不同,这个时候我们并不希望对所有的参数使用相同的学习率,而是对更罕见的特征执行更大的学习率。

  • Another key challenge of minimizing highly non-convex error functions common for neural networks is avoiding getting trapped in their numerous suboptimal local minima. Dauphin et al. [5] argue that the difficulty arises in fact not from local minima but from saddle points, i.e. points where one dimension slopes up and another slopes down. These saddle points are usually surrounded by a plateau of the same error, which makes it notoriously hard for SGD to escape, as the gradient is close to zero in all dimensions.

对于非凸损失函数的优化问题,需要避免陷入其众多的次优局部极小值。Dauphin et al. [5] 则认为, 相比局部极小值,鞍点的是更难解决的问题。鞍点是一个维度上升,一个维度下降。详细的关于鞍点以及 SGD 如何逃离鞍点可参考:知乎:如何逃离鞍点 .

Gradient descent optimization algorithms

Momentum [17] is a method that helps accelerate SGD in the relevant direction and dampens oscillations as can be seen in Figure 2b. It does this by padding a fraction $gamma$ of the update vector of the past time step to the current

update vector.

Momentum

paper: [Neural networks :

the official journal of the International Neural Network Society]()

without Momentum:

$$\theta += -lr * \nabla_{\theta}J(\theta)$$

with Momentum:

$$v_t=\gamma v_{t-1}+\eta \nabla_{\theta}J(\theta)$$

$$\theta=\theta-v_t$$

动量梯度下降的理解:

The momentum term increases for dimensions whose gradients point in the same directions and reduces updates for dimensions whose gradients change directions.

如上图中垂直方向的梯度方向是一致的,那么它的动量会累积,并在这个方向的速度越来越大。而在某个水平方向,其梯度方向总是变化,那么它的速度会减小,也就是在这个方向的波动幅度会得到抑制。

其实就是把梯度看做加速度,参数的更新量看做速度。速度表示一个step更新的大小。加速度总是朝着一个方向,速度必然越来越快。加速度方向总是变化,速度就会相对较小。

$\gamma$ 看做摩擦系数, 通常设置为 0.9。$\eta$ 是学习率。

Nesterov accelerate gradient(NAG)

paper: [Yurii Nesterov. A method for unconstrained convex minimization problem

with the rate of convergence o(1/k2).]()

We would like to have a smarter ball, a ball that has a notion of where it is going so that it knows to slow down before the hill slopes up again. Nesterov accelerated gradient (NAG) [14] is a way to give our momentum term this kind of prescience.

如果采用 momentum,在接近目标函数最优值时,由于速度在垂直方向是一直增加的,所以速度会很大,这个时候就会越过最小值,然后还得绕回来,增加了训练时间。所以我们需要参数的更新具有先见之明,知道在接近最优解时,降低参数更新的速度大小。

$$v_t=\gamma v_{t-1}+\eta \nabla_{\theta}J(\theta-\gamma v_{t-1})$$

$$\theta=\theta-v_t$$

在 momentum 中,我们用速度 $\gamma v_{t-1}$ 来更新参数。 事实上在接近局部最优解时,目标函数对于 $\theta$ 的梯度会越来越小,甚至接近于 0. 也就是说,尽管速度在增加,但是速度增加的程度越来越小。我们可以通过速度增加的程度来判断是否要接近局部最优解了。$\nabla_{\theta}J(\theta-\gamma v_{t-1})$ 就表示速度变化的程度,代替一直为正的 $\nabla_{\theta}J(\theta)$,在接近局部最优解时,这个值应该是负的,相应的参数更新的速度也会减小.

在代码实现时,对于 $J(\theta-\gamma v_{t-1})$ 的梯度计算不是很方便,可以令:

$$\phi = \theta-\gamma v_{t-1}$$

然后进行计算,具体可参考 tensorflow 或 pytorch 中代码。

Adagrad

paper: [Adaptive Subgradient Methods for Online Learning

and Stochastic Optimization]()

Adagrad [8] is an algorithm for gradient-based optimization that does just this: It adapts the learning rate to the parameters, performing larger updates for infrequent and smaller updates for frequent parameters. For this reason, it is well-suited for dealing with sparse data.

对于不同的参数,自适应的调整对应的梯度大小。对低频参数或特征,使其更新的梯度较大,对高频的参数或特征,使其更新的梯度较小。比如在训练 Glove 词向量时,低频词在某一步迭代中可能并没有参与 loss 的计算,所以更新的会相对较慢,所以需要人为的增大它的梯度。

不同的时间步 t,不同的参数 i 对应的梯度:

$$g_{t,i}=\nabla_{\theta_t}J(\theta_t,i)$$

$$\theta_{t+1,i}=\theta_{t,i}-\eta \cdot g_{t,i}$$

$$\theta_{t+1,i}=\theta_{t,i}-\dfrac{\eta}{\sqrt G_{t,ii}+\epsilon} g_{t,i}$$

$G_{t,ii}$ 是对角矩阵,对角元素是对应的梯度大小。

1
2
3
4
5

cache += dx**2

x += -lr * dx/(np.sqrt(cache) + 1e-7)

RMSprop

Geoff Hinton Lecture 6e

Adagrad 中随着 cache 的累积,最后的梯度会变为 0,RMSprop 在此基础上进行了改进,给了 cache 一个衰减率,相当于值考虑了最近时刻的梯度值,而很早之前的梯度值经过衰减后影响很小。

$$E[g^2]_ t=0.9E[g^2]_ {t-1}+0.1g^2_t$$

$$\theta_{t+1}=\theta_t-\dfrac{\eta}{E[g^2]_ t+\epsilon}g_t$$

1
2
3
4
5

cache = decay_rate*cache + (1-decay_rate)*dx**2

x += -lr * dx/(np.sqrt(cache) + 1e-7)

使用指数衰减的形式来保存 cache 能有效的节省内存,只需要记录当前的梯度值即可,而不用保存所有的梯度值。

Adam(Adaptive Moment Estimation)

Adam: a Method for Stochastic Optimization.

In addition to storing an exponentially decaying average of past squared gradients $v_t$ like Adadelta and RMSprop, Adam also keeps an exponentially decaying average of past gradients $m_t$, similar to momentum:

similar like momentum:

$$m_t=\beta_1m_{t-1}+(1-\beta_1)g_t$$

similar like autograd/RMSprop:

$$v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^2$$

$m_t$ and $v_t$ are estimates of the first moment (the mean) and the second moment (the uncentered variance) of the gradients respectively, hence the name of the method. As $m_t$ and $v_t$ are initialized as vectors of 0’s, the authors of Adam observe that they are biased towards zero, especially during the initial time steps, and especially when the decay rates are small (i.e. β1 and β2 are close to 1). They counteract these biases by computing bias-corrected first and second moment estimates:

$$\hat m_t=\dfrac{m_t}{1-\beta^t_1}$$

$$\hat v_t=\dfrac{v_t}{1-\beta^t_2}$$

They then use these to update the parameters just as we have seen in Adadelta and RMSprop, which

yields the Adam update rule:

$$\theta_{t+1}=\theta_t-\dfrac{\eta}{\sqrt{\hat a}+ \epsilon}{\hat m_t}$$

  • $m_t$ 是类似于 Momentum 中参数更新量,是梯度的函数. $\beta_1$ 是摩擦系数,一般设为 0.9.

  • $v_t$ 是类似于 RMSprop 中的 cache,用来自适应的改变不同参数的梯度大小。

  • $\beta_2$ 是 cache 的衰减系数,一般设为 0.999.

AdaMax

Adam: a Method for Stochastic Optimization.

在 Adam 中, 用来归一化梯度的因子 $v_t$ 与过去的梯度(包含在 $v_{t-1}$ 中)以及当前的梯度 $|g_t|^2$ 的 l2 范式成反比。

$$v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^2$$

可以将其泛化到 $l_p$ 范式。同样的 $\beta_2$ 变为 $\beta_2^p$.

Norms for large p values generally become numerically unstable, which is why $l_1$ and $l_2$ norms are most common in practice. However, $l_{\infty}$ also generally exhibits stable behavior. For this reason, the authors propose AdaMax [10] and show that $v_t$ with $l_{\infty}$ converges to the following more stable value. To avoid confusion with Adam, we use ut to denote the infinity norm-constrained $v_t$:

$$\mu_t=\beta_2^{\infty}v_{t-1}+(1-\beta_2^{\infty})|g_t|^{\infty}$$

$$=max(\beta_2\cdot v_{t-1}, |g_t|)$$

然后用 $\mu_t$ 代替 Adam 中的 $\sqrt(v_t)+\epsilon$:

$$\theta_{t+1}=\theta_t-\dfrac{\eta}{\mu_t}{\hat m_t}$$

Note that as $\mu_t$ relies on the max operation, it is not as suggestible to bias towards zero as $m_t$ and $v_t$ in Adam, which is why we do not need to compute a bias correction for ut. Good default values are again:

$$\eta = 0.002, \beta_1 = 0.9, \beta_2 = 0.999.$$

Visualization of algorithms

we see the path they took on the contours of a loss surface (the Beale function). All started at the same point and took different paths to reach the minimum. Note that Adagrad, Adadelta, and RMSprop headed off immediately in the right direction and converged similarly fast, while Momentum and NAG were led off-track, evoking the image of a ball rolling down the hill. NAG, however, was able to correct its course sooner due to its increased responsiveness by looking ahead and headed to the minimum.

如果目标函数是 Beale 这种类型的函数,自适应优化算法能更直接的收敛到最小值。而 Momentum 和 NAG 则偏离了轨道,就像球从山上滚下一样,刹不住车。但是 NAG 因为对未来具有一定的预见性,所以能更早的纠正从而提高其响应能力。

shows the behaviour of the algorithms at a saddle point, i.e. a point where one dimension has a positive slope, while the other dimension has a negative slope, which pose a difficulty for SGD as we mentioned before. Notice here that SGD, Momentum, and NAG find it difficulty to break symmetry, although the latter two eventually manage to escape the saddle point, while Adagrad, RMSprop, and Adadelta quickly head down the negative slope, with Adadelta leading the charge.

各种优化算法鞍点的表现。 Momentum, SGD, NAG 很难打破平衡,而自适应性的算法 Adadelta, RMSprop, Adadelta 能很快的逃离鞍点。

example

model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

import torch

import torch.nn as nn

import torch.optim as optim



class TestNet(nn.Module):

def __init__(self):

super(TestNet, self).__init__()

self.linear1 = nn.Linear(10, 5)

self.linear2 = nn.Linear(5, 1)

self.loss = nn.BCELoss()



def forward(self, x, label):

"""

x: [batch, 10]

label: [batch]

"""

out = self.linear2(self.linear1(x)).squeeze()

loss = self.loss(out, label)

return out, loss

1
2
3
4
5

model = TestNet()

model

TestNet(

  (linear1): Linear(in_features=10, out_features=5, bias=True)

  (linear2): Linear(in_features=5, out_features=1, bias=True)

  (loss): BCELoss()

)
1
2
3

list(model.named_parameters())

[('linear1.weight', Parameter containing:

  tensor([[ 0.2901, -0.0022, -0.1515, -0.1064, -0.0475, -0.0324,  0.0404,  0.0266,

           -0.2358, -0.0433],

          [-0.1588, -0.1917,  0.0995,  0.0651, -0.2948, -0.1830,  0.2356,  0.1060,

            0.2172, -0.0367],

          [-0.0173,  0.2129,  0.3123,  0.0663,  0.2633, -0.2838,  0.3019, -0.2087,

           -0.0886,  0.0515],

          [ 0.1641, -0.2123, -0.0759,  0.1198,  0.0408, -0.0212,  0.3117, -0.2534,

           -0.1196, -0.3154],

          [ 0.2187,  0.1547, -0.0653, -0.2246, -0.0137,  0.2676,  0.1777,  0.0536,

           -0.3124,  0.2147]], requires_grad=True)),

 ('linear1.bias', Parameter containing:

  tensor([ 0.1216,  0.2846, -0.2002, -0.1236,  0.2806], requires_grad=True)),

 ('linear2.weight', Parameter containing:

  tensor([[-0.1652,  0.3056,  0.0749, -0.3633,  0.0692]], requires_grad=True)),

 ('linear2.bias', Parameter containing:

  tensor([0.0450], requires_grad=True))]

add model parameters to optimizer

1
2
3
4
5
6
7
8
9

import torch.optim as optim



# parameters = model.parameters()

parameters_filters = filter(lambda p: p.requires_grad, model.parameters())

1
2
3
4
5
6
7
8
9
10
11
12
13

optimizer = optim.Adam(

params=parameters_filters,

lr=0.001,

betas=(0.8, 0.999),

eps=1e-8,

weight_decay=3e-7)

1
2
3

optimizer.state_dict

<bound method Optimizer.state_dict of Adam (

Parameter Group 0

    amsgrad: False

    betas: (0.8, 0.999)

    eps: 1e-08

    lr: 0.001

    weight_decay: 3e-07

)>

不同的模块设置不同的参数

1
2
3
4
5

parameters = [{"params": model.linear1.parameters()},

{"params":model.linear2.parameters(), "lr": 3e-4}]

1
2
3
4
5
6
7
8
9
10
11
12
13

optimizer2 = optim.Adam(

params=parameters,

lr=0.001,

betas=(0.8, 0.999),

eps=1e-8,

weight_decay=3e-7)

1
2
3

optimizer2.state_dict

<bound method Optimizer.state_dict of Adam (

Parameter Group 0

    amsgrad: False

    betas: (0.8, 0.999)

    eps: 1e-08

    lr: 0.001

    weight_decay: 3e-07



Parameter Group 1

    amsgrad: False

    betas: (0.8, 0.999)

    eps: 1e-08

    lr: 0.0003

    weight_decay: 3e-07

)>

zero_grad

在进行反向传播之前,如果不需要梯度累加的话,必须要用zero_grad()清空梯度。具体的方法是遍历self.param_groups中全部参数,根据grad属性做清除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

def zero_grad(self):

r"""Clears the gradients of all optimized :class:`torch.Tensor` s."""

for group in self.param_groups:

for p in group['params']:

if p.grad is not None:

p.grad.detach_()

p.grad.zero_()

1
2
3
4
5

group_parameters = [{"params": model.linear1.parameters()},

{"params":model.linear2.parameters(), "lr": 3e-4}]

1
2
3
4
5
6
7
8
9

x = torch.randn(2, 10)

label = torch.Tensor([1,0])

out, loss = model(x, label)

loss.backward()

1
2
3

optimizer2.zero_grad()

1
2
3
4
5
6
7
8
9
10
11

for group in group_parameters:

for p in group["params"]:

if p.grad is not None:

p.grad.detach_()

p.grad.zero_()

这里并没有使用 backward() 所以暂时不存在梯度。

在反向传播 backward() 计算出梯度之后,就可以调用step()实现参数更新。不过在 Optimizer 类中,step()函数内部是空的,并且用raise NotImplementError 来作为提醒。后面会根据具体的优化器来分析step()的实现思路。

辅助类lr_scheduler

lr_scheduler用于在训练过程中根据轮次灵活调控学习率。调整学习率的方法有很多种,但是其使用方法是大致相同的:用一个Schedule把原始Optimizer装饰上,然后再输入一些相关参数,然后用这个Schedule做step()。

1
2
3
4
5
6
7

# lambda1 = lambda epoch: epoch // 30

lambda1 = lambda epoch: 0.95 ** epoch

scheduler = optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda1)

1
2
3

scheduler.step()

warm up scheduler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

import math

parameters = filter(lambda p: p.requires_grad, model.parameters())



lr_warm_up_num = 1000



optimizer = optim.Adam(

params=parameters,

lr=0.001,

betas=(0.8, 0.999),

eps=1e-8,

weight_decay=3e-7)



cr = 1.0 / math.log(lr_warm_up_num)



scheduler = optim.lr_scheduler.LambdaLR(

optimizer,

lr_lambda=lambda ee: cr * math.log(ee + 1)

if ee < lr_warm_up_num else 1)

论文笔记-Multi-cast Attention Networks

paper: [Multi-Cast Attention Networks for Retrieval-based Question

Answering and Response Prediction](https://arxiv.org/abs/1806.00778)

Motivation

Our approach performs a series of soft attention

operations, each time casting a scalar feature upon the inner word embeddings. The key idea is to provide a real-valued hint (feature) to a subsequent encoder layer and is targeted at improving the representation learning process.

在 encoder layer 之前将 document 和 query 进行交互,然后将权重赋予到 document 和 query 之后,在通过 contextual/encoder layer 编码融合了上下文信息的向量表示。这样做的目地,是为后续层提供提示(特征),提升表示学习的性能。

The key idea of attention is to extract only the most relevant information that is useful for prediction. In the context of textual data, attention learns to weight words and sub-phrases within documents based on how important they are. In the same vein, co-attention mechanisms [5, 28, 50, 54] are a form of attention mechanisms that learn joint pairwise attentions, with respect to both document and query.

attention 注意力的关键思想是仅提取对预测有用的最相关信息。在文本数据的上下文中,注意力学习根据文档中的单词和子短语的重要性来对它们进行加权。

Attention is traditionally used and commonly imagined as a feature extractor. It’s behavior can be thought of as a dynamic form of pooling as it learns to select and compose different words to form the final document representation.

传统的 attention 可以看做为一个特征提取器。它的行为可以被认为是一种动态的pooing形式,因为它学习选择和组合不同的词来形成最终的文档表示,。

This paper re-imagines attention as a form of feature augmentation method. Attention is casted with the purpose of not compositional learning or pooling but to provide hints for subsequent layers. To the best of our knowledge, this is a new way to exploit attention in neural ranking models.

这篇 paper 将 attention 重新设想为一种特征增强的方式,Attention的目的不是组合学习或汇集,而是为后续层提供提示(特征)。这是一种在神经排序模型中的新方法。

不管这篇paper提供的新的 attention 使用方式是否是最有效的,但这里对 attention 的很多解释让人耳目一新,可以说理解的很透彻了。

An obvious drawback which applies to many existing models is that they are generally restricted to one attention variant. In the case where one or more attention calls are used (e.g., co-attention and intra-attention, etc.), concatenation is generally used to fuse representations [20, 28]. Unfortunately, this incurs cost in subsequent layers by doubling the representation size per call.

很多 paper 中只受限于一种 attention,这明显是不够好的。也有使用多种 attention 的,比如 co-attention 和 intra-attention, 然后直接拼接起来。这样会使得接下来的 modeling layer 维度加倍。。(在 ai challenge 的比赛中就是这么干的。。没啥不好啊。。)

The rationale for desiring more than one attention call is intuitive. In [20, 28], Co-Attention and Intra-Attention are both used because each provides a different view of the document pair, learning high quality representations that could be used for prediction. Hence, this can significantly improve performance.

直觉上,使用多种 multi-attention 是靠谱的。 co-attention 和 intra-attention 提供了不同的视角去审视 document,用以学习高质量的向量表示。

关于各种 attention:

Network for Sentence Pair Modeling](https://aclanthology.info/pdf/D/D17/D17-1122.pdf)

Moreover, Co-Attention also comes in different flavors and can either be used with extractive max-mean pooling [5, 54] or alignment-based pooling [3, 20, 28]. Each co-attention type produces different document representations. In max-pooling, signals are extracted based on a word’s largest contribution to the other text sequence. Mean-pooling calculates its contribution to the overall sentence. Alignment-pooling is another flavor of co-attention, which aligns semantically similar sub-phrases together.

co-attention可以用于提取max-mean pooling或alignment-based pooling。每种co-attention都会产生不同的文档表示。在max-pooling中,基于单词对另一文本序列的最大贡献来提取特征;mean-pooling计算其对整个句子的贡献;alignment-based pooling是另一种协同注意力机制,它将语义相似的子短语对齐在一起。因此,不同的pooling操作提供了不同的句子对视图。

Decomposable Attention Model for Natural Language Inference](https://arxiv.org/abs/1606.01933)

Our approach is targeted at serving two important purposes: (1) It removes the need for architectural engineering of this component by enabling attention to be called for an arbitrary k times with hardly any consequence and (2) concurrently it improves performance by modeling multiple views via multiple attention calls. As such, our method is in similar spirit to multi-headed attention, albeit efficient. To this end, we introduce Multi-Cast Attention Networks (MCAN), a new deep learning architecture for a potpourri of tasks in the question answering and conversation modeling domains.

两个方面的贡献:

(1)消除调用任意k次注意力机制所需架构工程的需要,且不会产生任何后果。

(2)通过多次注意力调用建模多个视图以提高性能,与multi-headed attention相似。

In our approach, attention is casted, in contrast to the most other works that use it as a pooling operation. We cast co-attention multiple times, each time returning a compressed scalar feature that is re-attached to the original word representations. The key intuition is that compression enables scalable casting of multiple attention calls, aiming to provide subsequent layers with a hint of not only global knowledge but also cross sentence knowledge.

与大多数其他用作池化操作的工作相反,在我们的方法中,注意力被投射。通过多次投射co-attention,每次返回一个压缩的标量特征,重新附加到原始的单词表示上。压缩函数可以实现多个注意力调用的可扩展投射,旨在不仅为后续层提供全局知识而且还有跨句子知识的提示(特征)。

Model Architecture: Multi-cast Attention Networks

Figure 1: Illustration of our proposed Multi-Cast Attention Networks (Best viewed in color). MCAN is a wide multi-headed attention architecture that utilizes compression functions and attention as features.

模型输入是 document/query 语句对。

Input Encoder

embedding layer

映射到向量空间: $w\in W^d$

Highway Encoder:

Highway Networks可以对任意深度的网络进行优化。这是通过一种控制穿过神经网络的信息流的闸门机制所实现的。通过这种机制,神经网络可以提供通路,让信息穿过后却没有损失,将这种通路称为information highways。即highway networks主要解决的问题是网络深度加深、梯度信息回流受阻造成网络训练困难的问题。

highway encoders can be interpreted as data-driven word filters. As such, we can imagine them to parametrically learn which words have an inclination to be important and not important to the task at hand. For example, filtering stop words and words that usually do not contribute much to the prediction. Similar to recurrent models that are gated in nature, this highway encoder layer controls how much information (of each word) is flowed to the subsequent layers.

在本文模型中,每个词向量都通过highway编码器层。highway网络是门控非线性变换层,它控制后续层的信息流。许多工作都采用一种训练过的投影层来代替原始词向量。这不仅节省了计算成本,还减少了可训练参数的数量。本文将此投影层扩展为使用highway编码器,可以解释为数据驱动的词滤波器,它们可以参数化地了解哪些词对于任务具有重要性和重要性。例如,删除通常对预测没有多大贡献的停用词和单词。与自然门控的循环模型类似,highway编码器层控制每个单词流入下一层多少信息。

$$y=H(x,W_H)\cdot T(x,W_T) + (1-T(x,W_T))\cdot x$$

其中 $W_H, W_T\in R^{r\times d}$ 是可学习参数. H(.) 和 T(.) 分别是全连接加上 relu 和 sigmoid 的函数,用以控制信息的流向下一层。

co-attention

Co-Attention [50] is a pairwise attention mechanism that enables

attending to text sequence pairs jointly. In this section, we introduce four variants of attention, i.e., (1) max-pooling, (2) mean-pooling, (3) alignment-pooling, and finally (4) intra-attention (or self attention).

协同注意力机制是成对的注意力机制,能够同时关注文本序列对。作者引入了 4 中注意力机制。

1.affinity/similarity matrix

$$s_{ij}=F(q_i)^TF(d_j)$$

其中,F(.) 是多层感知机,通常可选择的计算相似矩阵的方式有:

$$s_{ij}=q_i^TMd_j, s_{ij}=F[q_i;d_j]$$

以及在 BiDAF 和 QANet 中使用的 $s_{ij}=F[q_i;d_j;q_i\circ d_j]$.

2. Extractive pooling

max-pooling

关注于另一个序列交互后,最匹配的那个词。

$$q’=soft(max_{col}(s))^Tq, d’=soft(max_{row}(s))^Td$$

soft(.) 是 softmax 函数。$q’,d’$ 是 co-attentive representations of q and d respectively.

mean-pooling

关注另一个句子的全部,取平均值。

$$q’=soft(mean_{col}(s))^Tq, d’=soft(mean_{row}(s))^Td$$

each pooling operator has different impacts and can be intuitively understood as follows: max-pooling selects each word based on its maximum importance of all words in the other text. Mean-pooling is a more wholesome comparison, paying attention to a word based on its overall influence on the other text. This is usually dataset-dependent, regarded as a hyperparameter and is tuned to see which performs best on the held out set.

不同的 pooling 操作有不同的影响,获取的信息也不一样。 max-pooling根据每个单词在其他文本中所有单词的最大重要性选择每个单词。mean-pooling是基于每个词在其他文本上的总体影响来关注每个词。

这其实是与数据集和任务相关的。可以看作超参数,然后调整看哪个在对应的任务和数据集上表现更佳。

3. Alignment-Pooling

$$d_i’:=\sum^{l_q}{j=1}\dfrac{exp(s{ij})}{\sum_{k=1}^{l_q}exp(s_{ik})}q_j$$

其中 $d_i’$ 是 q 和 $d_i$ 的软对齐。直观的说,$d_i’$ 是关于 $d_i$ 的 ${q_j}^{l_q}_{j=1}$ 的加权和。

$$q_i’:=\sum^{l_d}{j=1}\dfrac{exp(s{ij})}{\sum_{k=1}^{l_d}exp(s_{ik})}d_j$$

$q_i’$ 是 $q_i$ 和 d 的软对齐。也就是,$q_i’$ 是 关于 $q_i$ 的 ${d_j}^{l_d}_{j=1}$ 的加权和。

4. intra-Attention

$$x_i’:=\sum^{l}{j=1}\dfrac{exp(s{ij})}{\sum_{k=1}^{l}exp(s_{ik})}x_j$$

也就是自注意力机制。相比 attention is all your need,可能就是相似矩阵不一样吧。

Multi-Cast Attention

Casted Attention

用 $x$ 来表示 q 或 d,$\overline x$ 表示 经过 co-attention 和 soft-attention alignment 后的序列表示 $q’, d’$.

$$f_c=F_c[\overline x, x]$$

$$f_m=F_m[\overline x \circ x]$$

$$f_s=F_m[\overline x-x]$$

其中 $\circ$ 是 Hadamard product. $F(.)$ 是压缩函数,将特征压缩到 scalar.

Intuitively, what is achieved here is that we are modeling the influence of co-attention by comparing representations before and after co-attention. For soft-attention alignment, a critical note here is that x and $\overline x$ (though of equal lengths) have ‘exchanged’ semantics. In other words, in the case of q, $\overline q$ actually contains the aligned representation of d.

Compression Function

The rationale for compression is simple and intuitive - we do not want to bloat subsequent layers with a high dimensional vector which consequently incurs parameter costs in subsequent layers. We investigate the usage of three compression functions, which are capable of reducing a n dimensional vector to a scalar.

本节定义了Fc(.) 使用的压缩函数,不希望使用高维向量膨胀后续层,这会在后续层中会产生参数成本。因此本文研究了三种压缩函数的用法,它们能够将n维向量减少到标量。

  • Sum

Sum(SM)函数是一个非参数化函数,它对整个向量求和,并输出标量

$$F(x)=\sum_i^nx_i, x_i\in x$$

  • Neural networks

$$F(x)=RELU(W_cx+b)$$

其中 $W_c\in R^{n\times 1}$

  • Factorization Machines

因子分解机是一种通用机器学习技术,接受实值特征向量 $x\in R^n$ 并返回标量输出。

FM是表达模型,使用分解参数捕获特征之间的成对相互作用。 k是FM模型的因子数。

Multi-Cast

我们的架构背后的关键思想是促进k个注意力投射,每个投射都用一个实值注意力提示来增强原始词向量。 对于每个query-document对,应用Co-Attention with mean-pooling,Co-Attention with max-Pooling和Co-Attention with alignment-pooling。 此外,将Intra-Attention分别单独应用于query和document。 每个注意力投射产生三个标量(每个单词),它们与词向量连接在一起。最终的投射特征向量是 $z\in R^{12}$。

因此,对于每个单词 w_{i} ,新的表示成为 $\bar{w_{i}}=[w_{i};z_{i}]$

Long Short-Term Memory Encoder

接下来,将带有casted attetnion的单词表示 $\bar{w_{1}},\bar{w_{2}},…,\bar{w_{l}}$ 传递到序列编码器层。采用标准的长短期记忆(LSTM)编码器.

As such, the key idea behind casting attention as features right before this layer is that it provides the LSTM encoder with hints that provide information such as (1) longterm and global sentence knowledge and (2) knowledge between sentence pairs (document and query).

LSTM在document和query之间共享权重。 关键思想是LSTM编码器通过使用非线性变换作为门控函数来学习表示序列依赖性的表示。因此,在该层之前引人注意力作为特征的关键思想是它为LSTM编码器提供了带有信息的提示,例如长期和全局句子知识和句子对(文档和查询)之间的知识。

  • Pooling Operation

最后,在每个句子的隐藏状态 $h_{1},…h_{l}$ 上应用池化函数。将序列转换为固定维度的表示。

$$h=MeanMax[h_1,…,h_l]$$

所以得到的 q 和 d 的最终表示是 [1, hiden_size]?

Prediction Layer and Optimization

$$y_{out} = H_2(H_1([x_q; x_d ; x_q \circ x_d ; x_q − x_d ]))$$

其中 $H_1,H_2$ 是具有 ReLU 激活的 highway 网络层。然后将输出传递到最终线性 softmax 层。

$$y_{pred} = softmax(W_F · y_{out} + b_F )$$

其中 $W_F\in R^{h\times 2}, b_F\in R^2$.

使用 multi-class cross entropy,并带有 L2 正则化。

论文笔记-CNN与自然语言处理

最近在参加 AI challenge 观点型阅读理解的比赛。数据集形式如下:

最开始尝试的模型主要包括几个部分:

  • Embedding: 使用预训练的中文词向量。

  • Encoder: 基于 Bi-GRU 对 passage,query 和 alternatives 进行编码处理。

  • Attention: 用 trilinear 的方式,并 mask 之后得到相似矩阵,然后采用类似于 BiDAF 中的形式 bi-attention flow 得到 attened passage.

  • contextual: 用 Bi-GRU 对 attened passage 进行编码,得到 fusion.

  • match 使用 attention pooling 的方式将 fusion 和 enc_answer 转换为单个 vector. 然后使用 cosin 进行匹配计算得到最相似的答案。

目前能得到的准确率是 0.687. 距离第一名差了 0.1…其实除了换模型,能提升和改进的地方是挺多的。

  • 可以用 ELMO 或 wordvec 先对训练集进行预训练得到自己的词向量。

  • attention 层可以使用更丰富的方式,很多paper 中也有提到。甚至可以加上人工提取的特征。比如苏剑林 blog 中提到的。

  • 还有个很重要的就是 match 部分, attention pooling 是否可以换成其他更好的方式?

但是,不断尝试各种模型的前提也要考虑速度吧。。rnn 实在是太慢了,所以决定试试 CNN 的方式来处理 NLP 的任务。

关于使用 CNN 来处理阅读理解的任务的大作还是挺多的,这里主要介绍这两篇:

ConvS2S

paper: Convolutional Sequence to Sequence Learning

这篇 paper 对应的 NLP 任务是机器翻译,除了用 CNN 对 sentence 进行编码之外,其核心是在 decoder 的时候也使用 CNN. 对于阅读理解来说,能够借用的是其编码 sentence 的方式。但这里作为学习,也多了解一下 decoder 吧~

对文本来说,看到 CNN 我们首先想到的是 cnn 能有效利用局部信息,提取出局部特征,所以适合做文本分类。但是对于 机器翻译、阅读理解这样的需要考虑全局信息的任务,CNN 似乎看起来并不那么有效。而且在 decoder 的时候,词的生成是 one by one 的,下一个词的生成是依赖于上一个词的。所以在 decoder 中使用 RNN 也是很自然而然的。

Facebook 的这篇 paper 就改变了这些传统的思维,不仅用 CNN 编码全局信息,而且还能 decoder.

Motivation

Multi-layer convolutional neural networks create hierarchical representations over the input sequence in which nearby input elements interact at lower layers while distant elements interact at higher layers.

多层 CNN 具有层级表示结构,相邻的词之间在较低层的 layer 交互,距离较远的词在较高层的 layer 交互(交互的目的就是语义消歧)。

Hierarchical structure provides a shorter path to capture long-range dependencies compared to the chain structure modeled by recurrent networks, e.g. we can obtain a feature representation capturing relationships within a window of n words by applying only O(n/k) convolutional operations for kernels of width k, compared to a linear number O(n) for recurrent neural networks.

层级结构提供了一个更短的路径来获取长期依赖。比如相距为 n 的两个词,在 rnn 中交互需要的步数是 O(n),在层级 CNN 中需要 O(n/k).这样减少了非线性的操作,降低了梯度消失的情况。所以这两个词的交互效果会更好~

Inputs to a convolutional network are fed through a constant number of kernels and non-linearities, whereas recurrent networks apply up to n operations and non-linearities to the first word and only a single set of operations to the last word. Fixing the number of nonlinearities applied to the inputs also eases learning.

输入到 CNN 中每个词都会经历固定的 kernel 和 非线性操作。而输入到 RNN 的,第一个词需要经过 n 个 operations,最后一个词只经历了一个 operations. 作者认为固定的操作更容易学习。

这一点我个人认为并不一定就是合理的,本来一个句子中不同词的重要性就是不一样的。

Model Architecture

模型分为以下几个部分:

  • position embedding

  • convolution block structure

  • Multi-step attention

position encoding

这部分在很多地方都出现过了,在没有 rnn 的情况下,都会用 PE 来编码位置信息。但是在这篇 paper 中,作者通过实验发现,PE 作用似乎并不是很重要。

convolution blocks

作者使用的是门激活机制, GLU, gate linear units.

来自于 paper: Language modeling with gated convolutional networks

在这篇 paper 中,作者用无监督的方式,来训练语言模型,将 CNN 得到的语言模型与 LSTM 进行对比。

也就是:

$$h_l=(XW+b)\otimes \sigma(XV+c)$$

The output of each layer is a linear projection X ∗ W + b modulated by the gates σ(X ∗ V + c). Similar to LSTMs, these gates multiply each element of the matrix X ∗W+b

and control the information passed on in the hierarchy.

如果是 LSTM-style,应该是 GTU:

$$h_i^l=tanh(XW+b)\otimes \sigma(XV+c)$$

作者将两者进行了对比,发现 GLU 效果更好。

residual connection: 为了得到更 deep 的卷积神经网络,作者增加了残差链接。

$$h_i^l=v(W^l[h_{i-k/2}^{l-1},…,h_{i+k/2}^{l-1}]+b_w^l)+h_i^{l-1}$$

卷积的整个过程:

论文中举了这样一个例子:

For instance, stacking 6 blocks with k = 5 results in an input field of 25 elements, i.e. each output depends on 25 inputs. Non-linearities allow the networks to exploit the full input field, or to focus on fewer elements if needed.

这个怎么算的呢?看下图:

从上图中可以看到,当 k=3 时,3 个 blocks,第三层中的每一个输入都与输入中的 7 列有关。所以计算方式是 k + (k-1)* (blocks-1).

一维卷积和二维卷积的区别:

  • ConvS2S 是 1D 卷积,kernel 只是在时间维度上平移,且 stride 的固定 size 为1,这是因为语言不具备图像的可伸缩性,图像在均匀的进行降采样后不改变图像的特征,而一个句子间隔着取词,意思就会改变很多了。

  • 在图像中一个卷积层往往有多个 filter,以获取图像不同的 pattern,但是在 ConvS2S 中,每一层只有一个 filter。一个句子进入 filter 的数据形式是 [1, n, d]. 其中 n 为句子长度, filter 对数据进行 n 方向上卷积,而 d 是词的向量维度,可以理解为 channel,与彩色图片中的 rgb 三个 channel 类似。

Facebook 在设计时,并没有像图像中常做的那样,每一层只设置一个 filter。这样做的原因,一是为了简化模型,加速模型收敛,二是他们认为一个句子的 pattern 要较图像简单很多,通过每层设置一个 filter,逐层堆叠后便能抓到所有的 pattern. 更有可能的原因是前者。因为在 transorfmer 中,multi-head attention 多头聚焦取得了很好的效果,说明一个句子的 pattern 是有多个的.

这段话是有问题的吧? filter 的个数难道不是 2d吗? 只不过这里说的 transorfmer 的多头聚焦是值得聚焦到一个词向量中的部分维度。记得在 cs224d 中 manning 曾经讲过一个例子,经过训练或词与词之间的交互后,词向量中的部分维度发生了变化。

在 paper 中,卷积核的尺寸大小是 $W\in R^{2d\times kd}$.

For encoder networks we ensure that the output of the convolutional layers matches the input length by padding the input at each layer. However, for decoder networks we have to take care that no future information is available to the decoder (Oord et al., 2016a). Specifically, we pad the input by k − 1 elements on both the left and right side by zero vectors, and then remove k elements from the end of the convolution output.

在 encoder 和 decoder 网络中,padding 的方式是不一样的。因为在 decoder 的时候不能考虑未来信息.

在 encoder 时,将 (k-1) pad 到左右两边,保证卷积层的长度不变。

在 decoder 中,将 (k-1) pad 到句子的左边。因此生成的词依旧是 one by one.

Multi-step Attention

$$d_i^l=W_d^lh_i^l+b_d^l+g_i$$

$$a_{ij}^l=\dfrac{exp(d_i^l\cdot z_j^u)}{\sum_{t=1}^mexp(d_i^l\cdot z_j^u)}$$

$$c_i^l=\sum_{j=1}^ma_{ij}^l(z_j^u+e_j)$$

上式中,l 表示 decoder 中卷积层的层数,i 表示时间步。

实际上跟 rnn 的 decoder 还是比较接近的。

  • 在训练阶段是 teacher forcing, 卷积核 $W_d^l$ 在 target sentence $h^l$ 上移动做卷积得到 $(W_d^lh_i^l + b_d^l)$,类似与 rnn-decoder 中的隐藏状态。然后加上上一个词的 embedding $g_i$,得到 $d_i^l$.

  • 与 encdoer 得到的 source sentence 做交互,通过 softmax 得到 attention weights $a_{ij}^l$.

  • 得到 attention vector 跟 rnn-decoder 有所不同,这里加上了 input element embedding $e_j$.

至于这里为什么要加 $e_j$?

We found adding e_j to be beneficial and it resembles key-value memory networks where the keys are the z_j^u and the values are the z^u_j + e_j (Miller et al., 2016). Encoder outputs z_j^u represent potentially large input contexts and e_j provides point information about a specific input element that is useful when making a prediction. Once c^l_i has been computed, it is simply added to the output of the corresponding decoder layer h^l_i.

$z_j^u$ 表示更丰富的信息,而 $e_j$ 能够能具体的指出输入中对预测有用的信息。还是谁用谁知道吧。。

关于 multi-hop attention:

This can be seen as attention with multiple ’hops’ (Sukhbaatar et al., 2015) compared to single step attention (Bahdanau et al., 2014; Luong et al., 2015; Zhou et al., 2016; Wu et al., 2016). In particular, the attention of the first layer determines a useful source context which is then fed to the second layer that takes this information into account when computing attention etc. The decoder also has immediate access to the attention history of the k − 1 previous time steps because the conditional inputs $c^{l-1}_{i−k}, . . . , c^{l-1}i$ are part of $h^{l-1}{i-k}, . . . , h^{l-1}_i$ which are input to $h^l_i$. This makes it easier for the model to take into account which previous inputs have been attended to already compared to recurrent nets where this information is in the recurrent state and needs to survive several non-linearities. Overall, our attention mechanism considers which words we previously attended to (Yang et al., 2016) and performs multiple attention ’hops’ per time step. In Appendix §C, we plot attention scores for a deep decoder and show that at different layers, different portions of the source are attended to.

这个跟 memory networks 中的 multi-hop 是有点类似。

FAST READING COMPREHENSION WITH CONVNETS

Gated Linear Dilated Residual Network (GLDR):

a combination of residual networks (He et al., 2016), dilated convolutions (Yu & Koltun, 2016) and gated linear units (Dauphin et al., 2017).

text understanding with dilated convolution

kernel:$k=[k_{-l},k_{-l+1},…,k_l]$, size=$2l+1$

input: $x=[x_1,x_2,…,x_n]$

dilation: d

卷积可以表示为:

$$(k*x)_ t=\sum_{i=-l}^lk_i\cdot x_{t + d\cdot i}$$

为什么要使用膨胀卷积呢? Why Dilated convolution?

Repeated dilated convolution (Yu & Koltun, 2016) increases the receptive region of ConvNet outputs exponentially with respect to the network depth, which results in drastically shortened computation paths.

能够显著缩短两个词之间的计算路径。

作者将 GLDR 和 self-attention,以及 RNN 进行了对比,input sequence length n, network width w, kernel size k, and network depth D.

model Architecture

作者与 BiDAF 和 DrQA 进行了对比,将 BiDAF 和 DrQA 中的 BiLSTM 部分替换成 GLDR Convolution.

The receptive field of this convolutional network grows

exponentially with depth and soon encompasses a long sequence, essentially enabling it to capture

similar long-term dependencies as an actual sequential model.

感受野的尺寸大小指数增加,能够迅速压缩 long sentence,并 capture 长期依赖。

Convolutional BiDAF. In our convolutional version of BiDAF, we replaced all bidirectional LSTMs with GLDRs . We have two 5-layer GLDRs in the contextual layer whose weights are un-tied. In the modeling layer, a 17-layer GLDR with dilation 1, 2, 4, 8, 16 in the first 5 residual blocks is used, which results in a reception region of 65 words. A 3-layer GLDR replaces the bidirectional LSTM in the output layer. For simplicity, we use same-padding and kernel size 3 for all convolutions unless specified. The hidden size of all GLDRs is 100 which is the same as the LSTMs in BiDAF.

具体网络结构,实际参数可以看 paper 实验部分。

论文笔记-batch,layer,weights normalization

paper:

Batch Normalization

在之前的笔记已经详细看过了:深度学习-Batch Normalization

Layer Normalization

Motivation

batch normalization uses the distribution of the summed input to a neuron over a mini-batch of training cases to compute a mean and variance which are then used to normalize the summed input to that neuron on each training case.

关于 batch normalisztion.

从 Ng 的课上截来的一张图,全链接层相比卷积层更容易理解点,但形式上是一样的.

样本数量是 m,第 l 层经过激活函数输出是第 l+1 层的输入,其中第 i 个神经元的值:

线性输出: $z_i^l={w_i^l}^Th^l$.

非线性输出: $h_i^{l+1} = a_i^l=f(z_i^l+b_i^l)$

其中 f 是非线性激活函数,$a_i^l$ 是下一层的 summed inputs. 如果 $a_i^l$ 的分布变化较大(change in a highly correlated way),下一层的权重 $w^{l+1}$ 的梯度也会相应变化很大(反向传播中 $w^{l+1}$ 的梯度就是 $a_i^l$)。

Batch Normalization 就是将线性输出归一化。

其中 $u_i^l$ 是均值,$\sigma_i^l$ 是方差。 $\overline a_i^l$ 是归一化之后的输出。 $g_i^l$ 是需要学习的参数,也就是 scale.

有个疑问?为什么 BN 要在激活函数之前进行,而不是之后进行呢?

上图中是单个样本,而所有的样本其实是共享层与层之间的参数的。样本与样本之间也存在差异,所以在某一个特征维度上进行归一化,(每一层其中的一个神经元可以看作一个特征维度)。

batch normalization requires running averages of the summed input statistics. In feed-forward networks with fixed depth, it is straightforward to store the statistics separately for each hidden layer. However, the summed inputs to the recurrent neurons in a recurrent neural network (RNN) often vary with the length of the sequence so applying batch normalization to RNNs appears to require different statistics for different time-steps.

BN 不是用于 RNN 是因为 batch 中的 sentence 长度不一致。我们可以把每一个时间步看作一个维度的特征提取,如果像 BN 一样在这个维度上进行归一化,显然在 RNN 上是行不通的。比如这个 batch 中最长的序列的最后一个时间步,他的均值就是它本身了,岂不是出现了 BN 在单个样本上训练的情况。

In this paper, we transpose batch normalization into layer normalization by computing the mean and variance used for normalization from all of the summed inputs to the neurons in a layer on a single training case.

所以作者在这篇 paper 中提出了 Layer Normalization. 在单个样本上计算均值和方差进行归一化。然而是怎么进行的呢?

Layer Normalization

layer normalization 并不是在样本上求平均值和方差,而是在 hidden units 上求平均值和方差。

其中 H 是 hidden units 的个数。

BN 和 LN 的差异:

Layer normalisztion 在单个样本上取均值和方差,所以在训练和测试阶段都是一致的。

并且,尽管求均值和方差的方式不一样,但是在转换成 beta 和 gamma 的方式是一样的,都是在 channels 或者说 hidden_size 上进行的。

Layer normalized recurrent neural networks

RNN is common among the NLP tasks to have different sentence lengths for different training cases. This is easy to deal with in an RNN because the same weights are used at every time-step. But when we apply batch normalization to an RNN in the obvious way, we need to to compute and store separate statistics for each time step in a sequence. This is problematic if a test sequence is longer than any of the training sequences. Layer normalization does not have such problem because its normalization terms depend only on the summed inputs to a layer at the current time-step. It also has only one set of gain and bias parameters shared over all time-steps.

这一部分也解释了 BN 不适用于 RNN 的原因,从 test sequence longer 的角度。RNN 的每个时间步计算共享参数权重.

$a^t=W_{hh}h^{t-1}+W_{xh}x^t$

其中 b 和 g 是可学习的参数。

layer normalize 在 LSTM 上的使用:

tensorflow 实现

batch Normalization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

tf.reset_default_graph()

from tensorflow.python.training.moving_averages import assign_moving_average

from tensorflow.contrib.layers import batch_norm

### batch normalization

def batch_norm(inputs, decay=0.9, is_training=True, epsilon=1e-6):

"""



:param inputs: [batch, length, width, channels]

:param is_training:

:param eplison:

:return:

"""

pop_mean = tf.Variable(tf.zeros(inputs.shape[-1]), trainable=False, name="pop_mean")

pop_var = tf.Variable(tf.ones(inputs.shape[-1]), trainable=False, name="pop_variance")



def update_mean_and_var():

axes = list(range(inputs.shape.ndims))

batch_mean, batch_var = tf.nn.moments(inputs, axes=axes)

moving_average_mean = tf.assign(pop_mean, pop_mean * decay + batch_mean * (1-decay))

# 也可用 assign_moving_average(pop_mean, batch_mean, decay)

moving_average_var = tf.assign(pop_var, pop_var * decay + batch_var * (1-decay))

# 也可用 assign_moving_average(pop_var, batch_var, decay)

with tf.control_dependencies([moving_average_mean, moving_average_var]):

return tf.identity(batch_mean), tf.identity(batch_var)



mean, variance = tf.cond(tf.equal(is_training, True), update_mean_and_var,

lambda: (pop_mean, pop_var))

beta = tf.Variable(initial_value=tf.zeros(inputs.get_shape()[-1]), name="shift")

gamma = tf.Variable(initial_value=tf.ones(inputs.get_shape()[-1]), name="scale")

return tf.nn.batch_normalization(inputs, mean, variance, beta, gamma, epsilon)

layer normalization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

import tensorflow as tf



batch = 60

hidden_size = 64

whh = tf.random_normal(shape=[batch, hidden_size], mean=5.0, stddev=10.0)



whh_norm = tf.contrib.layers.layer_norm(inputs=whh, center=True, scale=True)

with tf.Session() as sess:

sess.run(tf.global_variables_initializer())

print(whh)

print(whh_norm)

print(sess.run([tf.reduce_mean(whh[0]), tf.reduce_mean(whh[1])]))

print(sess.run([tf.reduce_mean(whh_norm[0]), tf.reduce_mean(whh_norm[5]), tf.reduce_mean(whh_norm[59])]))

print(sess.run([tf.reduce_mean(whh_norm[:,0]), tf.reduce_mean(whh_norm[:,1]), tf.reduce_mean(whh_norm[:,63])]))

print("\n")

for var in tf.trainable_variables():

print(var)

print(sess.run(var))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

Tensor("random_normal:0", shape=(60, 64), dtype=float32)

Tensor("LayerNorm/batchnorm/add_1:0", shape=(60, 64), dtype=float32)

[5.3812757, 4.607581]

[-1.4901161e-08, -2.9802322e-08, -3.7252903e-09]

[-0.22264712, 0.14112064, -0.07268284]





<tf.Variable 'LayerNorm/beta:0' shape=(64,) dtype=float32_ref>

[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

<tf.Variable 'LayerNorm/gamma:0' shape=(64,) dtype=float32_ref>

[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.

1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.

1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]

发现一个很奇怪的问题, layer norm 是在每一个训练样本上求均值和方差,为啥 beta 和 gamma 的shape却是 [hidden_size]. 按理说不应该是 [batch,] 吗? 带着疑问去看了源码,原来是这样的。。

将源码用简介的方式写出来了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

import tensorflow as tf

def layer_norm_mine(inputs, epsilon=1e-12, center=True, scale=True):

"""

inputs: [batch, sequence_len, hidden_size] or [batch, hidden_size]

"""

inputs_shape = inputs.shape

inputs_rank = inputs_shape.ndims

params_shape = inputs_shape[-1:]

beta, gamma = None, None

if center:

beta = tf.get_variable(

name="beta",

shape=params_shape,

initializer=tf.zeros_initializer(),

trainable=True

)

if scale:

gamma = tf.get_variable(

name="gamma",

shape=params_shape,

initializer=tf.ones_initializer(),

trainable=True

)

norm_axes = list(range(1, inputs_rank))

mean, variance = tf.nn.moments(inputs, norm_axes, keep_dims=True) # [batch]

inv = tf.rsqrt(variance + epsilon)

inv *= gamma

return inputs*inv + ((beta-mean)*inv if beta is not None else - mean * inv)



batch = 60

hidden_size = 64

whh = tf.random_normal(shape=[batch, hidden_size], mean=5.0, stddev=10.0)



whh_norm = layer_norm_mine(whh)

layer_norm_mine 得到的结果与源码一致。可以发现 计算均值和方差时, tf.nn.momentsaxes=[1:-1]. (tf.nn.moments 中 axes 的含义是在这些维度上求均值和方差). 也就是说得到的均值和方差确实是 [batch,]. 只是在转换成 beta 和 gamma 的分布时,依旧是在最后一个维度上进行的。有意思,所以最终的效果应该和 batch normalization 效果是一致的。只不过是否符合图像或文本的特性就另说了。

LayerNormBasicLSTMCell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245

class LayerNormBasicLSTMCell(rnn_cell_impl.RNNCell):

"""LSTM unit with layer normalization and recurrent dropout.



This class adds layer normalization and recurrent dropout to a

basic LSTM unit. Layer normalization implementation is based on:



https://arxiv.org/abs/1607.06450.



"Layer Normalization"

Jimmy Lei Ba, Jamie Ryan Kiros, Geoffrey E. Hinton



and is applied before the internal nonlinearities.

Recurrent dropout is base on:



https://arxiv.org/abs/1603.05118



"Recurrent Dropout without Memory Loss"

Stanislau Semeniuta, Aliaksei Severyn, Erhardt Barth.

"""



def __init__(self,

num_units,

forget_bias=1.0,

input_size=None,

activation=math_ops.tanh,

layer_norm=True,

norm_gain=1.0,

norm_shift=0.0,

dropout_keep_prob=1.0,

dropout_prob_seed=None,

reuse=None):

"""Initializes the basic LSTM cell.



Args:

num_units: int, The number of units in the LSTM cell.

forget_bias: float, The bias added to forget gates (see above).

input_size: Deprecated and unused.

activation: Activation function of the inner states.

layer_norm: If `True`, layer normalization will be applied.

norm_gain: float, The layer normalization gain initial value. If

`layer_norm` has been set to `False`, this argument will be ignored.

norm_shift: float, The layer normalization shift initial value. If

`layer_norm` has been set to `False`, this argument will be ignored.

dropout_keep_prob: unit Tensor or float between 0 and 1 representing the

recurrent dropout probability value. If float and 1.0, no dropout will

be applied.

dropout_prob_seed: (optional) integer, the randomness seed.

reuse: (optional) Python boolean describing whether to reuse variables

in an existing scope. If not `True`, and the existing scope already has

the given variables, an error is raised.

"""

super(LayerNormBasicLSTMCell, self).__init__(_reuse=reuse)



if input_size is not None:

logging.warn("%s: The input_size parameter is deprecated.", self)



self._num_units = num_units

self._activation = activation

self._forget_bias = forget_bias

self._keep_prob = dropout_keep_prob

self._seed = dropout_prob_seed

self._layer_norm = layer_norm

self._norm_gain = norm_gain

self._norm_shift = norm_shift

self._reuse = reuse



@property

def state_size(self):

return rnn_cell_impl.LSTMStateTuple(self._num_units, self._num_units)



@property

def output_size(self):

return self._num_units



def _norm(self, inp, scope, dtype=dtypes.float32):

shape = inp.get_shape()[-1:]

gamma_init = init_ops.constant_initializer(self._norm_gain)

beta_init = init_ops.constant_initializer(self._norm_shift)

with vs.variable_scope(scope):

# Initialize beta and gamma for use by layer_norm.

vs.get_variable("gamma", shape=shape, initializer=gamma_init, dtype=dtype)

vs.get_variable("beta", shape=shape, initializer=beta_init, dtype=dtype)

normalized = layers.layer_norm(inp, reuse=True, scope=scope)

return normalized



def _linear(self, args):

out_size = 4 * self._num_units

proj_size = args.get_shape()[-1]

dtype = args.dtype

weights = vs.get_variable("kernel", [proj_size, out_size], dtype=dtype)

out = math_ops.matmul(args, weights)

if not self._layer_norm:

bias = vs.get_variable("bias", [out_size], dtype=dtype)

out = nn_ops.bias_add(out, bias)

return out



def call(self, inputs, state):

"""LSTM cell with layer normalization and recurrent dropout."""

c, h = state

args = array_ops.concat([inputs, h], 1)

concat = self._linear(args)

dtype = args.dtype



i, j, f, o = array_ops.split(value=concat, num_or_size_splits=4, axis=1)

if self._layer_norm:

i = self._norm(i, "input", dtype=dtype)

j = self._norm(j, "transform", dtype=dtype)

f = self._norm(f, "forget", dtype=dtype)

o = self._norm(o, "output", dtype=dtype)



g = self._activation(j)

if (not isinstance(self._keep_prob, float)) or self._keep_prob < 1:

g = nn_ops.dropout(g, self._keep_prob, seed=self._seed)



new_c = (

c * math_ops.sigmoid(f + self._forget_bias) + math_ops.sigmoid(i) * g)

if self._layer_norm:

new_c = self._norm(new_c, "state", dtype=dtype)

new_h = self._activation(new_c) * math_ops.sigmoid(o)



new_state = rnn_cell_impl.LSTMStateTuple(new_c, new_h)

return new_h, new_state

论文笔记-character embedding and ELMO

character embedding

Motivation

A language model is formalized as a probability distribution over a sequence of strings (words), and traditional methods usually involve making an n-th order Markov assumption and estimating n-gram probabilities via counting and subsequent smoothing (Chen and Goodman 1998). The count-based models are simple to train, but probabilities of rare n-grams can be poorly estimated due to data sparsity (despite smoothing techniques).

对语言模型的描述:语言模型是 一个单词序列的概率分布 的形式化描述(什么意思?就是比如这个句子长度为 10, 那么每个位置可能是词表中的任意一个词,而出现当前词是有一个概率的, 这个概率是依赖于之前的词的)。

在传统的方法主要是运用 n阶马尔可夫假设来估计 n-gram 的概率,通过统计计数,以及子序列平滑的方式。这种基于计数的模型虽然简单,但是在数据稀疏的情况下,对不常见的 n-gram 的概率估计会很差。

While NLMs have been shown to outperform count-based n-gram language models (Mikolov et al. 2011), they are blind to subword information (e.g. morphemes). For example, they do not know, a priori, that eventful, eventfully, uneventful, and uneventfully should have structurally related embeddings in the vector space. Embeddings of rare words can thus be poorly estimated, leading to high perplexities for rare words (and words surrounding them). This is especially problematic in morphologically rich languages with long-tailed frequency distributions or domains with dynamic vocabularies (e.g. social media).

neural language models 将词嵌入到低维的向量中,使得语义相似的词在向量空间的位置也是相近的。然后 Mikolov word2vec 这种方式不能有效的解决子单词的信息问题,比如一个单词的各种形态,也不能认识前缀。这种情况下,不可避免的会造成不常见词的向量表示估计很差,对于不常见词会有较高的困惑度。这对于词语形态很丰富的语言是一个难题,同样这种问题也是动态词表的问题所在(比如社交媒体)。

Recurrent Neural Network Language Model

给定词表为 V,之前的序列是 $w_{1:t}=[w_1,..,w_t]$,在 RNN-LM 中通过全链接 affine transformation 计算 $w_{t+1}$ 个词的概率分布:

$$Pr(w_{t+1}=j|w_{1:t})=\dfrac{exp(h_t\cdot p^j+q^j)}{\sum_{j’\in V}exp(h_t\cdot p^{j’}+q^{j’})}$$

其中 $h_t$ 是当前 t 时刻的隐藏状态。也就是先通过全链接映射到词表的 V 的维度,然后通过 softmax 计算其是词表中第 j 个词的概率。

然后假设训练预料库的 sentence 是 $w_{1:T}=[w_1,…,w_T]$,那么训练也就是最小化这个序列的 似然概率的负对数:

$$NLL=-\sum_{T}^{t=1}logPr(w_t|w_{1:t-1})$$

Chracter-level Convolution Neural Network

以单词 absurdity 为例,有 l 个字符(通常会 padded 到一个固定size),通过 character embedding 映射成矩阵 $C\in R^{d\times l}$. d 是 embedding size. 图中 embedding size 为 4.

然后使用卷积核 kernel H 做卷积运算, $H\in R^{d\times w}$,所以得到的 feature map $f^k\in R^{l-w+1}$. 跟之前 CNN 做文本分类其实挺像的, kernel 的长是 embedding size d, 宽度 w 分别是 2,3,4. 上图中蓝色区域为例,filter 宽度为 2 的个数是3, 那么卷积得到的 featur map 是 $3 \times (9-2+1) = 3\times 8$.

$$f^k[i]=tanh(<C^k[* ,i:i-w+1], H> +b)$$

<>表示做卷积运算(Frobenius inner product). 然后加上 bias 和 非线性激活函数 tanh.

接着基于 times 维度做 max pooling. 上图中 filter 宽度为 3,2,4 的个数分别为 4,3,5.所以得到长度为 4+3+5=12 的向量。

这里每一个 filter matrix 得到一个相应的特征 feature. 在通常的 NLP 任务中这些 filter 的总数 $h\in[100, 1000]$

Highway Network

通过卷积层得到单词 k 的向量表示为 $y^k$.

Highway Network 分为两层 layer.

  • one layer of an MLP applies an affine transformation:

$$z=g(W_y+b)$$

  • one layer 有点类似 LSTM 中的 gate 机制:

$$z=t\circ g(W_Hy+b_H)+(1-t)\circ y$$

其中 g 是非线性函数。$t=\sigma(W_Ty+b_T)$. t 成为 transform gate, (1-t) 是 carry gate. 同 LSTM 类似, highway network 允许输出能自适应的从 $y^k$ 中直接获取信息。

ELMo

传统的提取 word embedding 的方法,比如 word2vec 和 language model, 前者是通过词与词之间的共现,后者是 contextual,但他们都是获得固定的 embedding,也就是每一个词对应一个单一的 embedding. 而对于多义词显然这种做法不符合直觉, 而单词的意思又和上下文相关, ELMo的做法是我们只预训练 language model, 而 word embedding 是通过输入的句子实时输出的, 这样单词的意思就是上下文相关的了, 这样就很大程度上缓解了歧义的发生. 且 ELMo 输出多个层的 embedding 表示, 试验中已经发现每层 LM 输出的信息对于不同的任务效果不同, 因此对每个 token 用不同层 embedding 表示会提升效果.

个人觉得,可以从这个角度去理解。RNN 可以看做一个高阶马尔可夫链,而不同于 马尔可夫模型,RNN 中的状态转移矩阵是用神经网络来模拟的,也就是我们计算隐藏层所用的 $h_t=tanh(w_{hh}h_{t-1}+w_{hx}x_t)$. 这个状态转移是动态的,也是不断更新的。而使用 语言模型 来训练 RNN/LSTM 目的就是得到这样的一套参数,使得它能学习到任何 合理的,自然的 sentence. 所以,这个语料库越大越好。事实上,有监督的训练也可以达到这个目的,但是有监督的数据有限,并且整个模型是有偏置的,比如文本分类的任务去训练,那么它更倾向于 局部信息。相比之下,机器翻译作为有监督的效果会更好,最好的还是语言模型呢,不仅可用的数据量很大,而且因为要预测每一个词的信息,它会努力结合每一个词的上下文去学习这个词的表示。这也正是我们需要的。ELMo 和 BERT 都是这样的道理,而 BERT 的优势前一篇 blog 说过了。

Bidirectional language models

给定 sentence $t_1, t_2,…,t_N$, 通过前面的词 $t_1,..,t_{k-1}$ 计算 token $t_k$ 的概率分布:

反向:

语言模型的训练就是采用极大似然估计,最大化这个概率:

传统的方法就是 提取出对应位置的向量表示作为对应位置的词向量 context-independent token representation $x_k^{LM}$.

ELMo

ELMo is a task specific combination of the intermediate layer representations in the biLM.

ELMo 实际上只是下游任务的中间层,跟 BERT 一样。但也有不同的是, ELMo 每一层的向量表示会获得不同的 信息。底层更能捕捉 syntax and semantics 信息,更适用于 part-of-speech tagging 任务,高层更能获得 contextual 信息,更适用于 word sense disambiguation 任务。所以对不同的任务,会对不同层的向量表示的利用不同。

在使用 ELMo 进行下游有监督训练时,通常是这样 $[x_k; ELMo_k^{task}]$. 对于 SQuAD 这样的任务,$[h_k, ELMo_k^{task}]$.

Model architecture

The final model uses L = 2 biLSTM layers with 4096 units and 512 dimension projections and a residual connection from the first to second

layer. The context insensitive type representation uses 2048 character n-gram convolutional filters followed by two highway layers and a linear projection down to a 512 representation.

具体模型还是得看代码。

论文笔记-QANet

paper:

combining local convolution with local self-attention for reading comprehension

Motivation

Its encoder consists exclusively of convolution and self-attention, where convolution models local interactions and self-attention models global interactions. On the SQuAD dataset, our model is 3x to 13x faster in training and 4x to 9x faster in inference, while achieving equivalent accuracy to recurrent models.

encoder 编码方式仅仅由 卷积 和 自注意力 机制构成,没了 rnn 速度就是快。

The key motivation behind the design of our model is the following: convolution captures the local structure of the text, while the self-attention learns the global interaction between each pair of words.

这篇论文最主要的创新点:使用 CNN 来捕捉文本结构的局部信息,使用 self-attention 来学习全局中每两个词之间的交互信息,使得其能耦合上下文信息。相比 RNN,attention 能够有效的解决长期依赖问题。只是相比少了词序信息。说到底,也是一种 contextualize 的 encoder 方式。

we propose a complementary data augmentation technique to enhance the training data. This technique paraphrases the examples by translating the original sentences from English to another language and then back to English, which not only enhances the number of training instances but also diversifies the phrasing.

使用了一种数据增强的方式,先将源语言转换成另一种语言,然后再翻译回英语。这样能有效增加训练样本,同时也丰富了短语的多样性。

Model

模型分为5部分:

  • an embedding layer

  • an embedding encoder layer

  • a context-query attention layer

  • a model encoder layer

  • an output layer.

the combination of convolutions and self-attention is novel, and is significantly better than self-attention alone and gives 2.7 F1 gain in our experiments. The use of convolutions also allows us to take advantage of common regularization methods in ConvNets such as stochastic depth (layer dropout) (Huang et al., 2016), which gives an additional gain of 0.2 F1 in our experiments.

CNN 和 self-attention 的结合比单独的 self-attention 效果要好。同时使用了 CNN 之后能够使用常用的正则化方式 dropout, 这也能带来一点增益。

Input embedding layer

obtain the embedding of each word w by concatenating its word embedding and character embedding.

由词向量和字符向量拼接而成。其中词向量采用预训练的词向量 Glove,并且不可训练,fixed. 只有 OOV (out of vocabulary) 是可训练的,用来映射所有不在词表内的词。

Each character is represented as a trainable vector of dimension p2 = 200, meaning each word can be viewed as the concatenation of the embedding vectors for each of its characters. The length of each word is either truncated or padded to 16. We take maximum value of each row of this matrix to get a fixed-size vector representation of each word.

字符向量的处理。每个字母是可训练的,对应的维度是 200 维。然后每个词都 truncated 或者 padded 成16个字母,保证每个词的向量维度是一样大小。

所以一个词的向量维度是 $300+200=500$.

Embedding encoding layer

The encoder layer is a stack of the following basic building block: [convolution-layer × # + self-attention-layer + feed-forward-layer]

其中:

  • convolution: 使用 depthwise separable convolutions 而不是用传统的 convolution,因为作者发现 it is memory efficient and has better generalization. 怎么理解这个,还得看原 paper. The kernel size is 7, the number of filters is d = 128.

Each of these basic operations (conv/self-attention/ffn) is placed inside a residual block, shown lower-right in Figure 1. For an input x and a given operation f, the output is f(layernorm(x))+x.

在 cnn/self-attention/ffn 层都有 layer normalization.

为什么要用 CNN:

用来获取局部信息 k-gram features

相信看了这个图能对 QANet 中的 cnn 怎么实现的更清楚了。上图中每个卷积核的尺寸分别是 [2, embed_size], [3, embed_size], [3, embed_size]. padding参数 使用的是 “SAME”. 得到 3 个 [1, sequence_len],然后拼接起来, 得到最终结果 [filters_num, sequence_len].

在 QANet 的实现中,kernel_size 都设置为7, num_filters=128.

为什么要用 self-attention

用来获取全局信息。

上图中的这种方式显然不太好,复杂度高且效果不好。于是有了 self-attention.

矩阵内部向量之间作內积,并通过 softmax 得到其他词对于 “The” 这个词的权重大小(权重比例与相似度成正比,这里看似不太合理 similarity == match??,但实际上效果很不错,可能跟词向量的训练有关)。

然后将对应的权重大小 $[w_1,w_2,w_3,w_4,w_5]$ 与对应的词相乘,累和得到蕴含了上下文信息的 contextualized “The”.

并且,这是可以并行化的。大大加速了训练速度。

Context-Query Attention Layer

跟 BIDAF 是一样的。来,不看笔记把公式过一遍。

content: $C={c_1, c_2,…,c_n}$

query: $Q={q_1,q_2,…q_m}$.

所以 embeded 之后,

  • content: [batch, content_n, embed_size]

  • query: [batch, query_m, embed_size]

做矩阵相乘得到相似矩阵 similarity matrix $S\in R^{n\times m}$:

sim_matrix: [batch, content_n, query_m]

The similarity function used here is the trilinear function (Seo et al., 2016). $f(q,c)=W_0[q,c,q\circ c]$.

相似矩阵的计算可以不是直接矩阵相乘,而是加个前馈神经网络。毕竟 similarity 不一定等于 match.

content-to-query

对 S 每一行 row 做 softmax 得到对应的概率,得到权重矩阵 $\tilde S\in R^{n\times m}$, shape = [batch, content_n, query_m].

然后与 query $Q^T$ [batch, query_m, embed_size] 矩阵相乘得到编码了 query 信息的 content:

$A = \tilde SQ^T$, shape = [batch, content_n, embed_size]

query_to_content

Empirically, we find that, the DCN attention can provide a little benefit over simply applying context-to-query attention, so we adopt this strategy.

这里没有采用 BiDAF 里面的方法,而是采用 DCN 中的方式,利用了 $\tilde S$.

对 S 每一列 column 做 softmax 得到矩阵 $\overline S$, shape = [batch, content_n, query_n].

然后矩阵相乘得到 $B=\tilde S \overline S^T C^T$.

$\tilde S$.shape=[batch, content_n, query_m]

$\overline S^T$.shape=[batch, query_m, content_n]

$C^T$.shape=[batch, query_m, embed_size]

所以最后 B.shape=[batch, content_n, embed_size]

Model Encoder Layer

同 BiDAF 一样输入是 $[c,a,c\circ a,c\circ b]$, 其中 a, b 分别是 attention matrix A,B 的行向量。不过不同的是,这里不同 bi-LSTM,而是类似于 encoder 模块的 [conv + self-attention + ffn]. 其中 conv 层数是 2, 总的 blocks 是7.

Ouput layer

$$p^1=softmax(W_1[M_0;M_1]), p^2=softmax(W_2[M_0;M_2])$$

其中 $W_1, w_2$ 是可训练的参数矩阵,$M_0, M_1, M_2$ 如图所示。

然后计算交叉熵损失函数:

$$L(\theta)=-\dfrac{1}{N}\sum_i^N[log(p^1_{y^1})+log(p^2_{y^2})]$$

QANet 哪里好,好在哪儿?

  • separable conv 不仅参数量少,速度快,还效果好。将 sep 变成传统 cnn, F1 值减小 0.7.

  • 去掉 CNN, F1值减小 2.7.

  • 去掉 self-attention, F1值减小 1.3.

  • layer normalization

  • residual connections

  • L2 regularization

参考文献

论文笔记 Pointer Networks and copy mechanism

paper:

Pointer Network

Motivation

We introduce a new neural architecture to learn the conditional probability of an output sequence with elements that are discrete tokens corresponding to positions in an input sequence.

提出来了一种新的架构来学习得到这样的输出序列的条件概率,其中输出序列中的元素是输入序列中离散的 tokens.

Such problems cannot be trivially addressed by existent approaches such as sequence-to-sequence [1] and Neural Turing Machines [2], because the number of target classes in each step of the output depends on the length of the input, which is variable.

这样简单的从输入序列中 copy 输出相关的序列在 seq2seq 或是神经图灵机都很难实现,因为在 decoder 的每一步输出的次的类别依赖于输入序列的长度,这个长度是变化的。

Problems such as sorting variable sized sequences, and various combinatorial optimization problems belong to this class.

和这类问题类似的还有给不定长序列的排序,组合优化等问题。

It differs from the previous attention attempts in that, instead of using attention to blend hidden units of an encoder to a context vector at each decoder step, it uses attention as a pointer to select a member of the input sequence as the output.

同之前的 attention 不同的是,之前的 attention 是 decoder 时每一步计算通过 RNN 编码后的输入序列的隐藏变量与当前向量表示的 attention vector,然后生成当前词。而 Ptr-Net 则是使用 attention 作为指针,从输入序列中选择成员作为输出。

We show Ptr-Nets can be used to learn approximate solutions to three challenging geometric problems – finding planar convex hulls, computing Delaunay triangulations, and the planar Travelling Salesman Problem – using training examples

alone.

Ptr-Net 可以用来学习类似的三个几何问题。

Ptr-Nets not only improve over sequence-to-sequence with input attention, but also allow us to generalize to variable size output dictionaries. We show that the learnt models generalize beyond the maximum lengths they were trained on.

Ptr-Net 不仅可以提升 seq2seq with attention,而且能够泛化到变化的 dictionayies.

从摘要以及 Introduction 来说, Ptr-Net 主要是解决两个方面的问题。

  • 一是,简单的 copy 在传统的方法中很难实现,而 Ptr-Net 则是直接从输入序列中生成输出序列。

  • 而是,可以解决输出 dictionary 是变化的情况。普通的 Seq2Seq 的 output dictionary 大小是固定的,对输出中包含有输入单词(尤其是 OOV 和 rare word) 的情况很不友好。一方面,训练中不常见的单词的 word embedding 质量也不高,很难在 decoder 时预测出来,另一方面,即使 word embedding 很好,对一些命名实体,像人名等,word embedding 都很相似,也很难准确的 reproduce 出输入提到的单词。Point Network 以及在此基础上后续的研究 CopyNet 中的 copy mechanism 就可以很好的处理这种问题,decoder 在各 time step 下,会学习怎样直接 copy 出现在输入中的关键字。

Model Architecture

在介绍 Ptr-Net 之前,作者先回顾了一下基本模型 seq2seq 和 input-attention.

sequence-to-sequence Model

实际上 seq2seq 解决的问题是在当前样本空间里面,给定输入下,使得输出序列的概率最大化。其实类似的 MT,QA,Summarization 都可以看作是这一类问题。只不过根据输入和输出之间的关系,调整相应的模型。

$$p(C^P|P;\theta)=\sum_{i=1}^m(P)p_{\theta}(C_i|C_1,…,C_{i-1},P;\theta)$$

通过训练学习得到参数使得条件概率最大:

$$\theta^* = {argmax}{\theta}\sum{P,C^P}logp(C^P|P;\theta)$$

其中类和是在训练样本上。

In this sequence-to-sequence model, the output dictionary size for all symbols $C_i$ is fixed and equal to n, since the outputs are chosen from the input. Thus, we need to train a separate model for each n. This prevents us from learning solutions to problems that have an output dictionary with a size that depends on the input sequence length.

在 seq2seq 模型中,输出的 dictionary 是固定大小的。因为不能解决 dictionary 是变化的情况。

Content Based Input Attention

在每一个 decoder step,先计算 $e_{ij}$ 得到对齐概率(或者说 how well input position j matches output position i),然后做一个 softmax 得到 $a_{ij}$,再对 $a_{ij}$ 做一个加权和作为 context vector $c_i$,得到这个 context vector 之后在固定大小的 output dictionary 上做 softmax 预测输出的下一个单词。

This model performs significantly better than the sequence-to-sequence model on the convex hull problem, but it is not applicable to problems where the output dictionary size depends on the input.

Nevertheless, a very simple extension (or rather reduction) of the model allows us to do this easily.

Ptr-Net

seq2seq 模型的输出词是在固定的 dictionary 中进行 softmax,并选择概率最大的词,从而得到输出序列。但这里的输出 dictionary size 是取决于 input 序列的长度的。所以作者提出了新的模型,其实很简单。

$$u_j^i=v^Ttanh(W_1e_j+W_2d_i) ,j\in(1,…,n)$$

$$p(C_i|C_1,…,C_{i-1},P)=softmax(u^i)$$

i 表示decoder 的时间步,j 表示输入序列中的index. 所以$e_j$ 是 encoder 编码后的隐藏向量,$d_i$ 是 decoder 当前时间步 i 的隐藏向量。跟一般的 attention 基本上一致。只不过得到的 softmax 概率应用在输入序列 $C_1,…,C_{i-1}$ 上。

Dataset Structure

CopyNet

Motivation

We address an important problem in sequence-to-sequence (Seq2Seq) learning referred to as copying, in which certain segments in the input sequence are selectively replicated in the output sequence. A similar phenomenon is observable in human language communication. For example, humans tend to repeat entity names or even long phrases in conversation.

还是前面提到的问题,seq2seq 很难解决简单的 copy 问题。而在人类的对话中,出现 copy 的现象是很常见的。尤其是 命令实体 或者是长短语。

The challenge with regard to copying in Seq2Seq is that new machinery is needed to decide when to perform the operation.

这也是 seq2seq 模型所需面对的挑战。

For example:

可以看到,对于 Chandralekha 这类实体词,可能是 OOV,也可能是其他实体或者是日期等很难被 decoder “还原” 出来的信息,CopyNet 可以更好的处理这类的信息。

那么问题来了:

  • What to copy: 输入中的哪些部分应该被 copy?

  • Where to paste: 应该把这部分信息 paste 到输出的哪个位置?

Model Architecture

作者从两个角度来理解 CopyNet:

  • From a cognitive perspective, the copying mechanism is related to rote memorization, requiring less understanding but ensuring high literal fidelity. 从认知学角度,copy机制近似于死记硬背,不需要太多的理解,但是要保证文字的保真度。

  • From a modeling perspective, the copying operations are more rigid and symbolic, making it more difficult than soft attention mechanism to integrate into a fully differentiable neural model. 从模型的角度,copy 操作更加死板和符号化,这也使得相比 soft attention 机制更难整合到一个完整的可微分的神经模型中去。

整体还是基于 encoder-decoder 模型。

Encoder:

LSTM 将 source sequence 转换为隐藏状态 M(emory) $h_1,…,h_{T_S}$.

Decoder:

同 cannonical 的 decoder 一样,使用 RNN 读取 encoder 的隐藏状态 M. 但和传统的 decoder 不一样,他有如下区别:

  • Prediction: COPYNET predicts words based on a mixed probabilistic model of two modes, namely the generate-mode and the copymode, where the latter picks words from the source sequence. 下一个词的预测由两种模式混合而成。生成 generate-mode 和 copy-mode. 后者就像前面 Ptr-Net 所说的,在 source sentence 获取词。
  • State Update: the predicted word at time t−1 is used in updating the state at t, but COPYNET uses not only its word-embedding but also its corresponding location-specific hidden state in M (if any). 更新 decoder 中的隐藏状态时,t 时间步的隐藏状态不仅与 t-1 步生成词的 embedding vector 有关,还与这个词对应于 source sentence 中的隐藏状态的位置有关。
  • Reading M: in addition to the attentive read to M, COPYNET also has“selective read” to M, which leads to a powerful hybrid of

content-based addressing and location-based addressing. 什么时候需要 copy,什么时候依赖理解来回答,怎么混合这两种模式很重要。

个人思考: 感觉不管要不要 copy 都应该是在基于理解的基础上进行的。但是因为 OOV 或者当前词的 embedding vector 训练的不好,那就无法理解了对吧? 是否可以添加 gate 机制呢? 机器到底还是没理解语言对吧? 貌似是个可以创新的点。

接下来会详细讲解这三个不同之处怎么实现的。

Prediction with Copying and Generation:$s_t\rightarrow y_t$

这部分是从 decoder 隐藏状态 $s_t$ 到输出词 $y_t$ 的过程。传统的encoder-decoder 是一个线性映射就可以了。

词表 $\mathcal{V}={v_1,…,v_N}$, 未登录词 OOV(out of vocabulary) 用 UNK 来表示(unk应该也会有对应的 embedding vector). 以及用来表示输入序列中的 unique words $X={x_1,…,x_{T_S}}$. 其中 X 使得 copynet 输出 OOV.

对于三者有这样的集合关系(先不要看公式,后面会说到):

简而言之(In a nutshell), 对于当前 source sentence X 输出的词表范围 $\mathcal{V}\cup \text{UNK} \cup X$.

给定 decoder 中当前时间步的隐藏状态 $s_t$, 以及 encoder 的隐藏状态序列 M.

$$p(y_t|s_t,y_{t-1},c_t,M)=p(y_t,g|s_t,y_{t-1},c_t,M) + p(y_t,c|s_t,y_{t-1},c_t,M)$$

其中 g 代表 generate mode. c 代表 copy mode.

我们知道对于 encoder 部分的输出 $h_1,…,h_{T_S}$, 记做 M,M 其实同时包含了语义和位置信息。那么 decoder 对 M 的读取有两种形式:

  • Content-base

Attentive read from word-embedding

  • location-base

Selective read from location-specific hidden units

两种模式对应的概率计算,以及 score function:

$$p(y_t,g|\cdot)=\begin{cases} \dfrac{1}{Z}e^{\psi_g(y_t)}&y_t\in V\

0,&y_t\in X \bigcap \overline V\

\dfrac{1}{Z}e^{\psi_g(UNK)},&y_t\notin V\cup X

\end{cases}$$

$$p(y_t,c|\cdot)=\begin{cases}\dfrac{1}{Z}\sum_{j:x_j=y_t}{e^{\psi_c(x_j)}},&y_t\in X\0&\text {otherwise}\end{cases}$$

上面两个公式叠加(相加)可以表示为下图(可以将目标词看作类别为 4 的分类。):

其中 $\psi_g(\cdot)$ 和 $\psi_c(\cdot)$ 是 generate mode 和 copy mode 的 score function.

Z 是两种模型共享的归一化项,$Z=\sum_{v\in V\cup{UNK}}e^{\psi_g(v)}+\sum_{x\in X}e^{\psi_c(x)}$.

然后对相应的类别计算对应的 score.

Generate-Mode:

$$\psi_g(y_t=v_i)=\nu_i^TW_os_t, v_i\in V\cup UNK$$

  • $W_o\in R^{(N+1)\times d_s}$

  • $\nu_i$ 是 $v_i$ 对应的 one-hot 向量. 得到的结果是当前词的概率。

generate-mode 的 score $\psi(y_t=v_i)$ 和普通的 encoder-decoder 是一样的。全链接之后的 softmax.

copy-mode:

$$\psi(y_t=x_j)=\sigma(h_j^TW_c)s_t,x_j\in \mathcal{V}$$

  • $h_j$ 是 encoder hidden state. j 表示输入序列中的位置。

  • $W_c\in R^{d_h\times d_s}$ 将 $h_j$ 映射到跟 $s_t$ 一样的语义空间。

  • 作者发现使用 tanh 非线性变换效果更好。同时考虑到 $y_t$ 这个词可能在输入中出现多次,所以需要考虑输入序列中所有的为 $y_t$ 的词的概率的类和。

state update

上面一部分讲的是怎么从 decoder 中的隐藏状态计算对应的 vocabulary,也就是 $s_t\rightarrow y_t$. 那么怎么计算当前时间步的隐藏状态呢? 我们知道传统的 encoder-decoder 中隐藏状态就是 content-based atention vector. 但是在 copynet 里面,作者对 $y_{t-1}\rightarrow s_t$ 这个计算方式做了一定的修改。

先回顾下基本的 attention 模块,decoder 中隐藏状态的更新 $s_t=f(y_{t-1},s_{t-1},c_t)$, 其中 $c_t$ 也就是 attention 机制:

$$c_t=\sum_{\tau=1}^{T_S}\alpha_{t\tau}$$

$$\alpha_{t\tau}=\dfrac{e^{\eta(s_{t-1},h_{\tau})}}{\sum_{\tau’}e^{\eta(s_{t-1},h_{\tau’})}}$$

CopyNet 的 $y_{t-1}$ 在这里有所不同。不仅仅考虑了词向量,还使用了 M 矩阵中特定位置的 hidden state,或者说,$y_{t−1}$ 的表示中就包含了这两个部分的信息 $[e(y_{t−1});\zeta(y_{t−1})]$,$e(y_{t−1})$ 是词向量,后面多出来的一项 $\zeta(y_{t−1})$ 叫做 selective read, 是为了连续拷贝较长的短语。和attention 的形式差不多,是 M 矩阵中 hidden state 的加权和.

$$\zeta(y_{t-1})=\sum_{\tau=1}^{T_S}\rho_{t\tau}h_{\tau}$$

$$\rho_{t\tau}=\begin{cases}\dfrac{1}{K}p(x_{\tau},c|s_{t-1},M),& x_{\tau}=y_{t-1}\

0,& \text{otherwise}

\end{cases}$$

  • 当 $y_{t-1}$ 没有出现在 source sentence中时, $\zeta(y_{t-1})=0$.

  • 这里的 $K=\sum{\tau’:x_{\tau’}=y_{t-1}}p(x_{\tau’},c|s_{t-1},M)$ 是类和。还是因为输入序列中可能出现多个当前词,但是每个词在 encoder hidden state 的向量表示是不一样的,因为他们的权重也是不一样的。

  • 这里的 p 没有给出解释,我猜跟前面计算 copy 的 score 是一致的?

  • 直观上来看,当 $\zeta(y_{t-1})$ 可以看作是选择性读取 M (selective read). 先计算输入序列中对应所有 $y_{t-1}$ 的权重,然后加权求和,也就是 $\zeta(y_{t-1})$.

Hybrid Adressing of M

包括两种 Addressing 方式: content-based and location-based assressing.

location-based Addressing:

$$\zeta(y_{t-1}) \longrightarrow{update} \ s_t \longrightarrow predict \ y_t \longrightarrow sel. read \zeta(y_t)$$

Learning

最小化概率的负对数:

$$L=-\dfrac{1}{N}\sum_{k=1}^N\sum_{t=1}^Tlog[p(y_t^{(k)}|y_{<t}^{(k)}, X^{(k)})]$$

N 是batch size,T 是 object sentence 长度。

论文笔记-Match LSTM

Motivation

SQuAD the answers do not come from a small set of candidate

answers and they have variable lengths. We propose an end-to-end neural architecture for the task.

针对 SQuAD 这样的阅读理解式任务提出的端到端的模型。 SQuAD 的答案不是从候选词中提取,而是类似于人类的回答,是不同长度的句子。

The architecture is based on match-LSTM, a model we proposed

previously for textual entailment, and Pointer Net, a sequence-to-sequence model proposed by Vinyals et al. (2015) to constrain the output tokens to be from the input sequences.

主要是基于 Pointer Networks

关于阅读理解的数据集 benchmark dataset:

  • MCTest: A challenge dataset for the open-domain machine comprehension of text.

  • Teaching machines to read and comprehend.

  • The Goldilocks principle: Reading children’s books with explicit memory representations.

  • Towards AI-complete question answering: A set of prerequisite toy tasks.

  • SQuAD: 100,000+ questions for machine comprehension of text.

SQuAD

Traditional solutions to this kind of question answering tasks rely on NLP pipelines that involve multiple steps of linguistic analyses and feature engineering, including syntactic parsing, named entity recognition, question classification, semantic parsing, etc. Recently, with the advances of applying neural network models in NLP, there has been much interest in building end-to-end neural architectures for various NLP tasks, including several pieces of work on machine comprehension.

传统的智能问答任务整个流程包括 句法分析、命名实体识别、问题分类、语义分析等。。随着深度学习的发展,端到端的模型开始出现。

End-to-end model architecture:

  • Teaching machines to read and comprehend.

  • The Goldilocks principle: Reading children’s books with explicit memory representations.

  • Attention-based convolutional neural network for machine comprehension

  • Text understanding with the attention sum reader network.

  • Consensus attention-based neural networks for chinese reading comprehension.

However, given the properties of previous machine comprehension datasets, existing end-to-end neural architectures for the task either rely on the candidate answers (Hill et al., 2016; Yin et al., 2016) or assume that the answer is a single token (Hermann et al., 2015; Kadlec et al., 2016; Cui et al., 2016), which make these methods unsuitable for the SQuAD dataset.

之前的模型的 answer 要么是从候选答案中选择,要么是一个简单的符号。这都不适合 SQuDA.

模型是基于作者早期提出的用于 textual entailment 的 match-LSTMLearning natural language inference with LSTM,然后进一步应用了 Pointer Net(https://papers.nips.cc/paper/5866-pointer-networks), 从而允许预测的结果能够从输入中获得,而不是从一个固定的词表中获取。

We propose two ways to apply the Ptr-Net model for our task: a sequence model and a boundary model. We also further extend the boundary model with a search mechanism.

作者提出的两种模型。

Model Architecture

Match-LSTM

Pointer Network

Pointer Network (Ptr-Net) model : to solve a special kind of problems where we want to generate an output sequence whose tokens must come from the input sequence. Instead of picking an output token from a fixed vocabulary, Ptr-Net uses attention mechanism as a pointer to select a position from the input sequence as an output symbol.

从输入 sentences 中生成 answer.

类似于 Pointer Network 的模型:

MATCH-LSTM AND ANSWER POINTER

模型主要分为3部分:

  • An LSTM preprocessing layer that preprocesses the passage and the question using LSTMs. 使用 LSTM 处理 question 和 passage.

  • A match-LSTM layer that tries to match the passage against the question. 使用 match-LSTM 对lstm编码后的 question 和 passage 进行匹配。

  • An Answer Pointer (Ans-Ptr) layer that uses Ptr-Net to select a set of tokens from the passage as the answer. The difference between the two models only lies in the third layer. 使用 Pointer 来选择 tokens.

LSTM preprocessing Layer

$$H^p=\overrightarrow {LSTM}(P), H^q=\overrightarrow {LSTM}(Q)$$

直接使用单向LSTM,每一个时刻的隐含层向量输出 $H^p\in R^{l\times P}, H^q\in R^{l\times Q}$ 只包含左侧上下文信息.

Match-LSTM Layer

$$\overrightarrow G_i=tanh(W^qH^q+(W^pH_i^p+W^r\overrightarrow {h^r}_{i-1}+b^p)\otimes e_Q)\in R^{l\times Q}$$

$$\overrightarrow \alpha_i=softmax(w^T\overrightarrow G_i + b\otimes e_Q)\in R^{1\times Q}$$

the resulting attention weight $\overrightarrow α_{i,j}$ above indicates the degree of matching between the

$i^{th}$ token in the passage with the $j^{th}$ token in the question.

其中 $W^q,W^p,W^r \in R^{l\times l}, b^p,w\in R^l, b\in R$

所以 $\overrightarrow α_{i}$ 表示整个 question 与 passage 中的第 i 个词之间的 match 程度,也就是通常理解的 attention 程度。

传统的 attention 就是将 passage 和 question 矩阵相乘,比如 transformer 中 query 和 keys 相乘。复杂一点可能就是 dynamic memory networks 中的将 两个需要 match 的向量相减、element-wise相乘之后,使用两层的前馈神经网络来表示。

这里的 attention score 的计算方式又不一样了。 $\overrightarrow{h^r_{i-1}}$ 是通过 LSTM 耦合 weighted queston 和 passage 中上一个词得到的信息。

其中:

$$\overrightarrow z_i=\begin{bmatrix} h^p \ H^q\overrightarrow {\alpha_i^T} \ \end{bmatrix} $$

$$h^r=\overrightarrow{LSTM}(\overrightarrow{z_i},\overrightarrow{h^r_{i-1}})$$

然后类似于LSTM将 $\overrightarrow{h_{i-1}^r}$ 和 当前 passage 的表示 $H^p_i$ 耦合得到的 $R^{l\times 1}$ 的向量重复Q 次,得到 $R^{l\times Q}$,所以 $\overrightarrow G_i\in R^{l\times Q}$, 在通过一个softmax-affine网络得到 attention weights.

整个思路下来,就是 attention score 不是通过矩阵相乘,也不是向量 $h^p_i, H^q$ 相减之后通过神经网络得到。但是也相似,就是对当前要匹配的两个向量 $h^p_i, H^q$ 通过两层神经网络得到,其中的对当前向量 $H_i^p$ 和 $\overrightarrow {h_{i-1}^r}$ 要重复 Q 次。。。其实跟 DMN 还是相似的,只不过不是简单的 attention 当前的向量,还用了 LSTM 来耦合之前的信息。

最终得到想要的结合了 attention 和 LSTM 的输出 $\overrightarrow h^r$.

作者做了一个反向的 LSTM. 方式是一样的:

$$\overleftarrow G_i=tanh(W^qH^q+(W^pH_i^p+W^r\overleftarrow {h^r}_{i-1}+b^p)\otimes e_Q)$$

$$\overleftarrow \alpha_i=softmax(w^T\overleftarrow G_i + b\otimes e_Q)$$

同样得到 $\overleftarrow {h_i^r}$.

  • $\overrightarrow {H^r}\in R^{l\times P}$ 表示隐藏状态 $[\overrightarrow {h^r_1}, \overrightarrow {h^r_2},…,\overrightarrow {h^r_P}]$.

  • $\overleftarrow {H^r}\in R^{l\times P}$ 表示隐藏状态 $[\overleftarrow {h^r_1}, \overleftarrow {h^r_2},…,\overleftarrow {h^r_P}]$.

然后把两者堆叠起来得到通过 question 匹配之后的 passage 向量表示: $H^r=\begin{bmatrix} \overrightarrow H^r \ \overleftarrow H^r \end{bmatrix} \in R^{2l\times P}$

Answer Pointer Layer

The Sequence Model

The answer is represented by a sequence of integers $a=(a_1,a_2,…)$ indicating the positions of the selected tokens in the original passage.

再一次利用 attention,$\beta_{k,j}$ 表示 answer 中第 k 个token选择 passage 中第 j 个次的概率。所以 $\beta_k\in R^{P+1}$.

$$F_k=tanh(V\tilde {H^r}+(W^ah^a_{k-1}+b^a)\otimes e_{P+1})\in R^{l\times P+1}$$

$$\beta_k=softmax(v^TF_k+c\otimes e_{P+1}) \in R^{1\times (P+1)}$$

其中 $\tilde H\in R^{2l\times (P+1)}$ 表示 $H^r$ 和 zero vector 的叠加, $\tilde H=[H^r, 0], V\in R^{l\times 2l}, W^a\in R^{l\times l}, b^a,v\in R, c\in R$.

所以还是跟 match-LSTM 一样,先对 $H^r$ 中的每一个词通过全链接表示 $W^ah^a_{k+1}+b^a$, 然后重复 P+1 次,得到 $R^{l\times (P+1)}$. 在通过激活函数 tanh, 再通过一个全连接神经网络,然后使用 softmax 进行多分类。

$$h_k^a=\overrightarrow{LSTM}(\tilde {H^r}\beta_k^T, h^a_{k-1})$$

这里是把 $\tilde H^r$ 与权重 $\beta_k$ 矩阵相乘之后的结果作为 LSTM k 时刻的输入。很玄学, 感觉可以看作是 self-attention 结合了 LSTM.

对生成 answer sequence 的概率进行建模:

$$p(a|H^r)=\prod_k p(a_k|a_1,a_2,…,a_{k-1}, H^r)$$

其中:

$$p(a_k=j|a_1,a_2,…,a_{k-1})=\beta_{k,j}$$

目标函数 loss function:

$$-\sum_{n=1}^N logp(a_n|P_n,Q_n)$$

The Boundary Model

So the main difference from the sequence model above is that in the boundary model we do not need to add the zero padding to Hr, and the probability of generating an answer is simply modeled as:

$$p(a|H^r)=p(a_s|H^r)p(a_e|a_s, H^r)$$

Search mechanism, and bi-directional Ans-Ptr.

Training

Dataset

SQuAD: Passages in SQuAD come from 536 articles from Wikipedia covering a wide range of topics. Each passage is a single paragraph from a Wikipedia article, and each passage has around 5 questions associated with it. In total, there are 23,215 passages and 107,785 questions. The data has been split into a training set (with 87,599 question-answer pairs), a development set (with 10,570 questionanswer pairs) and a hidden test set

configuration

  • dimension l of the hidden layers is set to 150 or 300.

  • Adammax: $\beta_1=0.9, \beta_2=0.999$

  • minibatch size = 30

  • no L2 regularization.

Result

论文笔记-QA BiDAF

paper:

Motivation

Machine comprehension (MC), answering a query about a given context paragraph, requires modeling complex interactions between the context and the query.

机器阅读的定义,query 和 context 之间的交互。

Typically these methods use attention to focus on a small portion of the context and summarize it with a fixed-size vector, couple attentions temporally, and/or often form a uni-directional attention.

传统的使用 attention 机制的方法。

In this paper we introduce the Bi-Directional Attention Flow (BIDAF) network, a multi-stage hierarchical process that represents the context at different levels of granularity and uses bidirectional attention flow mechanism to obtain a query-aware context representation without early summarization.

本文提出的方法 BiDAF. 使用多阶层次双向 attention flow 机制来表示内容的不同 levels 的粒度,从而获得 query-aware 的 context,而不使用 summarization.

Introduction

Attention mechanisms in previous works typically have one or more of the following characteristics. First, the computed attention weights are often used to extract the most relevant information from the context for answering the question by summarizing the context into a fixed-size vector. Second, in the text domain, they are often temporally dynamic, whereby the attention weights at the current time step are a function of the attended vector at the previous time step. Third, they are usually uni-directional, wherein the query attends on the context paragraph or the image.

对 atention 在以前的研究中的特性做了一个总结。

  • 1.attention 的权重用来从 context 中提取最相关的信息,其中 context 压缩到一个固定 size 的向量。

  • 2.在文本领域,context 中的表示在时间上是动态的。所以当前时间步的 attention 权重依赖于之前时间步的向量。

  • 3.它们通常是单向的,用 query 查询内容段落或图像。

Model Architecture

BiDAF 相比传统的将 attention 应用于 MC 任务作出如下改进:

  • First, our attention layer is not used to summarize the context paragraph into a fixed-size vector. Instead, the attention is computed for every time step, and the attended vector at each time step, along with the representations from previous layers, is allowed to flow through to the subsequent modeling layer. This reduces the information loss caused by early summarization.

1)并没有把 context 编码到固定大小的向量表示中,而是让每个时间步计算得到的 attended vactor 可以流动(在 modeling layer 通过 biLSTM 实现)这样可以减少早期加权和造成的信息丢失。

  • Second, we use a memory-less attention mechanism. That is, while we iteratively compute attention through time as in Bahdanau et al. (2015), the attention at each time step is a function of only the query and the context paragraph at the current time step and does not directly depend on the attention at the previous time step.

2)memory-less,在每一个时刻,仅仅对 query 和当前时刻的 context paragraph 进行计算,并不直接依赖上一时刻的 attention.

We hypothesize that this simplification leads to the division of labor between the attention layer and the modeling layer. It forces the attention layer to focus on learning the attention between the query and the context, and enables the modeling layer to focus on learning the interaction within the query-aware context representation (the output of the attention layer). It also allows the attention at each time step to be unaffected from incorrect attendances at previous time steps.

也就是对 attention layer 和 modeling layer 进行分工,前者关注于 context 和 query 之间的交互。而后者则关注于 query-aware context 中词于词之间的交互,也就是加权了 attention weights 之后的 context 表示。这使得 attention 在每个时间步不受之前错误的影响。

  • Third, we use attention mechanisms in both directions, query-to-context and context-to-query, which provide complimentary information to each other.

计算了 query-to-context(Q2C) 和 context-to-query(C2Q)两个方向的 attention 信息,认为 C2Q 和 Q2C 实际上能够相互补充。实验发现模型在开发集上去掉 C2Q 与 去掉 Q2C 相比,分别下降了 12 和 10 个百分点,显然 C2Q 这个方向上的 attention 更为重要

论文提出6层结构:

Character Embedding Layer and Word Embedding Layer -> Contextual Embedding Layer -> Attention Flow Layer -> Modeling Layer -> Output Layer

Character Embedding Layer and word embedding alyer

  • charatter embedding of each word using CNN.The outputs of the CNN are max-pooled over the entire width to obtain a fixed-size vector for each word.

  • pre-trained word vectors, GloVe

  • concatenation of them above and is passed to a two-layer highway networks.

context -> $X\in R^{d\times T}$

query -> $Q\in R^{d\times J}$

contextual embedding layer

model the temporal interactions between words using biLSTM.

context -> $H\in R^{2d\times T}$

query -> $U\in R^{2d\times J}$

前三层网络是在不同的粒度层面来提取 context 和 query 的特征。

attention flow layer

the attention flow layer is not used to summarize the query and context into single feature vectors. Instead, the attention vector at each time step, along with the embeddings from previous layers, are allowed to flow through to the subsequent modeling layer.

输入是 H 和 G,输出是 query-aware vector G, 以及上一层的 contextual layer.

这一层包含两个 attention,Context-to-query Attention 和 Query-to-context Attention. 它们共享相似矩阵 $S\in R^{T\times J}$(不是简单的矩阵相乘,而是类似于 Dynamic Memory Networks 中的计算方式).

$$S_{tj}=\alpha(H_{:t},U_{:j})\in R$$

其中 $\alpha(h,u)=w_{(S)}^T[h,u,h\circ u]$, $w_{(S)}\in R^{6d}$

Context-to-query Attention:

计算对每一个 context word 而言哪些 query words 和它最相关。所以 计算 t-th context word 对应的 query 每个词的权重:

$$a_t=softmax(S_{t:})\in R^J$$

然后将权重赋予到 query 上然后再加权求和(叠加赋予了权重的 query 中的每一个词),得到 t-th 对应的 query-aware query:

$$\tilde U_{:t}=\sum_j a_{tj}U_{:j}\in R^{2d}$$

然后 context 中的每一个词都这样计算,$\tilde U\in R^{2d\times T}$

就是通过 context 和 query 计算相似性后,通过 sortmax 转化为概率,然后作为权重赋予到 query 上,得到 context 每一个词对应的 attended-query.

Query-to-context Attention:

跟 C2Q 一样计算相似矩阵 S 后,计算对每一个 query word 而言哪些 context words 和它最相关,这些 context words 对回答问题很重要。

先计算相关性矩阵每一列中的最大值,max function $max_{col}(S)\in R^T$, 然后softmax计算概率:

$$b=softmax(max_{col}(S))\in R^T$$

权重 b 表示与整个 query 比较之后,context 中每一个词的重要程度,然后与 context 加权和:

$$\tilde h = \sum_tb_tH_{:t}\in R^{2d}$$

在 tile T 次后得到 $\tilde H\in R^{2d\times T}$.

比较 C2Q 和 Q2C,显然 Q2C 更重要,因为最终我们要找的答案是 context 中的内容。而且两者的 attention 计算方式有区别是:对 query 进行加权和时,我们考虑的是 context 中的每一个词,而在对 context 进行加权和时,我们要考虑所有的 query 中相关性最大的词,是因为 context 中某个词只要与 query 中任何一个词有关,都需要被 attend.

将三个矩阵拼接起来,得到 G:

$$G_{:t}=\beta (H_{:t},\tilde U_{:t}, \tilde H_{:t})\in R^{d_G}$$

function $\beta$ 可以是 multi-layers perceptron. 在作者的实验中:

$$\beta(h,\tilde u,\tilde h)=[h;\tilde u;h\circ \tilde u;h\circ \tilde h]\in R^{8d\times T}$$

Modeling Layer

captures the interaction among the context words conditioned on the query.

使用 biLSTM, 单向 LSTM 的输出维度是d,所以最终输出: $M\in R^{2d\times T}$.

Output Layer

输出 layer 是基于应用确定的。如果是 QA,就从段落中找出 start p1 和 end p2.

计算 start index:

$$p^1=softmax(W^T(p^1)[G;M])$$

其中 $w_{(p^1)}\in R^{10d}$

计算 end index,将 M 通过另一个 biLSTM 处理,得到 $M^2\in R^{2d\times T}$

$$p^2=softmax(W^T(p^2)[G;M^2])$$

Training

目标损失函数:

$$L(\theta)=-{1 \over N} \sum^N_i[log(p^1_{y_i^1})+log(p^2_{y_i^2})]$$

$\theta$ 包括参数:

  • the weights of CNN filters and LSTM cells

  • $w_{S}$,$w_{p^1},w_{p^2}$

$y_i^1,y_i^2$ 表示i样本中开始可结束位置在 context 中的 index.

$p^1,p^2\in R^T$ 是经过 softmax 得到的概率,可以将 gold truth 看作是 one-hot 向量 [0,0,…,1,0,0,0],所以对单个样本交叉熵是:

$$- log(p^1_{y_i^1})-log(p^2_{y_i^2})$$

Test

The answer span $(k; l)$ where $k \le l$ with the maximum value of $p^1_kp^2_l$ is chosen, which can be computed in linear time with dynamic programming.

深度学习-Batch Normalization

Paper Reading

Motivation

Training Deep Neural Networks is complicated by the fact that the distribution of each layer’s inputs changes during training, as the parameters of the previous layers change. This slows down the training by requiring lower learning rates and careful parameter initialization, and makes it notoriously hard to train models with saturating nonlinearities. We refer to this phenomenon as internal covariate shift.

神经网络训练过程中参数不断改变导致后续每一层输入的分布也发生变化,而学习的过程又要使每一层适应输入的分布,这使得不得不降低学习率、小心地初始化,并且使得那些具有易饱和非线性激活函数的网络训练臭名昭著。作者将分布发生变化称之为 internal covariate shift。

stochastic gradient is simple and effective, it requires careful tuning of the model hyper-parameters, specifically the learning rate and the initial parameter values. The training is complicated by the fact that the inputs to each layer are affected by the parameters of all preceding layers – so that small changes to the network parameters amplify as the network becomes deeper.

在深度学习中我们采用SGD取得了非常好的效果,SGD简单有效,但是它对超参数非常敏感,尤其是学习率和初始化参数。

The change in the distributions of layers’ inputs presents a problem because the layers need to continuously adapt to the new distribution. When the input distribution to a learning system changes, it is said to experience covariate shift (Shimodaira, 2000). This is typically handled via domain adaptation (Jiang, 2008). However, the notion of covariate shift can be extended beyond the learning system

as a whole, to apply to its parts, such as a sub-network or a layer.

因为学习的过程中每一层需要去连续的适应每一层输入的分布,所以输入分布发生变化时,会产生一些问题。这里作者引用了 covariate shiftdomain adaptation 这两个概念。

Therefore, the input distribution properties that aid the network generalization – such as having the same distribution between the training and test data – apply to training the sub-network as well.As such it is advantageous for the distribution of x to remain fixed over time.

有助于网络泛化的输入分布属性:例如在训练和测试数据之间具有相同的分布,也适用于训练子网络

Fixed distribution of inputs to a sub-network would have positive consequences for the layers outside the subnetwork, as well.

固定输入分布对该子网络其他部分的网络的训练会产生积极的影响。

总结下为什么要使用 BN

在训练的过程中,因为前一层的参数改变,将会导致后一层的输入的分布不断地发生改变,这就需要降低学习速率同时要注意参数的初始化,也使具有饱和非线性(saturating nonlinearity)结构的模型非常难训练(所谓的饱和就是指函数的值域是个有限值,即当函数自变量趋向无穷时,函数值不趋向无穷)。深度神经网络之所以复杂是因为它每一层的输出都会受到之前层的影响,因此一个小小的参数改变都会对网络产生巨大的改变。作者将这种现象称为internal covariate shift,提出了对每个输入层进行规范化来解决。在文中,作者提到使用BN可以在训练的过程中使用较高的学习速率,可以比较随意的对参数进行初始化,同时BN也起到了一种正则化的作用,在某种程度上可以取代dropout的作用。

考虑一个以sigmoid为激活函数的神经层:

$z=g(Wu+b)$

其中 u 是输入, g 是 sigmoid 激活函数 $g(x)=\dfrac{1}{1+exp(x)}$,当 |x| 增加时,$g’(x)$ 趋近于0, 这意味着 $x=Wu+b$ 的所有维度,除了绝对值较小的维度,其他的流向输入 u 的梯度都会消失,也就是进入非线性的饱和区域,这会降低模型训练速度。

在实际应用中,对于非线性饱和的情况,已经有很有对应策略:

  • ReLU

  • 初始化 Xavier initialization.

  • 用一个较小的学习速率进行学习

If, however, we could ensure that the distribution of nonlinearity inputs remains more stable as the network trains, then the optimizer would be less likely to get stuck in the saturated regime, and the training would accelerate.

如果保证非线性输入的分布稳定,优化器也就不会陷于饱和区域了,训练也会加速。

We refer to the change in the distributions of internal nodes of a deep network, in the course of training, as Internal Covariate Shift. Eliminating it offers a promise of faster training. We propose a new mechanism, which we call Batch Normalization, that takes a step towards reducing internal covariate shift, and in doing so dramatically accelerates the training of deep neural nets. It accomplishes this via a normalization step that fixes the means and variances of layer inputs.

作者把这种输入分布的变化叫做内部协方差偏移。并提出了 Batch Normalization,通过固定输入的均值和方差。

Batch Normalization also has a beneficial effect on the gradient flow through the network, by reducing the dependence of gradients on the scale of the parameters or

of their initial values. This allows us to use much higher learning rates without the risk of divergence. Furthermore, batch normalization regularizes the model and reduces the need for Dropout (Srivastava et al., 2014). Finally, Batch Normalization makes it possible to use saturating nonlinearities by preventing the network from getting stuck in the saturated modes.

BN 除了能解决 internal covariate shift 的问题,还能够降低梯度对学习率,初始化参数设置的依赖。这使得我们可以使用较大的学习率,正则化模型,降低对 dropout 的需求,最后还保证网络能够使用具有饱和性的非线性激活函数。

Towards Reducing Internal Covariate Shift

whitening 白化操作

It has been long known (LeCun et al., 1998b; Wiesler & Ney, 2011) that the network training converges faster if its inputs are whitened – i.e., linearly transformed to have zero means and unit variances, and decorrelated.

使用白化 whitening 有助于模型收敛,白化是线性变化,转化为均值为0,方差为1,并且去相关性。

However, if these modifications are interspersed with the optimization steps, then the gradient descent step may attempt to update the parameters in a way that requires the normalization to be updated, which reduces the effect of the gradient step.

如果将白化与基于梯度下降的优化混合在一起,那么在执行梯度下降的过程中会受到标准化的参数更新的影响,这样会减弱甚至抵消梯度下降的产生的影响。

作者举了这样一个例子:

考虑一个输入 u 和一个可学习的参数 b 相加作为一个 layer. 通过减去均值进行标准化 $\hat x=x-E[x]$, 其中 x=u+b. 则前向传播的过程:

$x=u+b \rightarrow \hat x = x-E[x] \rightarrow loss$

反向传播对参数 b 求导(不考虑 b 和 E[x] 的相关性):

$\dfrac{\partial l}{\partial b}=\dfrac{\partial l}{\partial \hat x}\dfrac{\partial \hat x}{\partial b} = \dfrac{\partial l}{\partial \hat x}$

那么 $\Delta b = -\dfrac{\partial l}{\partial \hat x}$, 则对于参数 b 的更新: $b \leftarrow \Delta b + b$.

那么经过了标准化、梯度下降更新参数之后:

$u+(b+\Delta b)-E[u+(b+\Delta b)]=u+b-E[u+b]$

这意味着这个 layer 的输出没有变化,损失 $\dfrac{\partial l}{\partial \hat x}也没有变化$, 那么随着训练的进行,**b会无限的增长???**,而loss不变。

This problem can get worse if the normalization not only centers but also scales the activations. We have observed this empirically in initial experiments, where the model blows up when the normalization parameters are computed outside the gradient descent step.

如果规范化不仅中心处理(即减去均值),而且还对激活值进行缩放,问题会变得更严重。通过实验发现, 当归一化参数在梯度下降步骤之外进行,模型会爆炸。

进行白化操作,并且在优化时考虑标准化的问题

The issue with the above approach is that the gradient descent optimization does not take into account the fact that the normalization takes place. To address this issue, we would like to ensure that, for any parameter values, the network always produces activations with the desired distribution.Doing so would allow the gradient of the loss with respect to the model parameters to account for the normalization, and for its dependence on the model parameters Θ.

之所以会产生以上的问题,主要是梯度优化的过程中没有考虑到标准化操作的进行(不好实现)。为了解决这一问题,作者提出我们需要保证网络产生的激活总是有相同的分布。这样做允许损失值关于模型参数的梯度考虑到标准化。

再一次考虑 x 是一个 layer 的输入,看作一个向量,$\chi$ 是整个训练集,则标准化:

$\hat x = Norm(x, \chi)$

这时标准化的参数不仅取决于当前的输入x,还和整个训练集 $\chi$ 有关,当x来自其它层的输出时,那么上式就会和前面层的网络参数 $\theta$ 有关,反向传播时需要计算:

$$\frac{\partial{Norm(x,\chi)}}{\partial{x}}\text{ and }\frac{\partial{Norm(x,\chi)}}{\partial{\chi}}$$

如果忽略上边第二项就会出现之前说到的问题。但是直接在这一架构下进行白话操作很非常的费时,代价很大。主要是需要计算协方差矩阵,进行归一化,以及反向传播时也需要进行相关的计算。因此这就需要寻找一种新的方法,既可以达到类似的效果,又不需要在每个参数更新后分析整个训练集。

Normalization via Mini-Batch Statistics

对比于白化的两个简化

Since the full whitening of each layer’s inputs is costly, we make two necessary simplifications. The first is that instead of whitening the features in layer inputs and outputs jointly, we will normalize each scalar feature independently, by making it have zero mean and unit variance.

既然白化操作这么费时费力,作者考虑两点必要的简化。第一点,对输入特征的每一维 $x=(x^{(1)},…,x^{(d)})$ 进行去均值和单位方差的处理。

$$\hat x^{(k)} = \dfrac{x^{(k)}-E[x^{(k)}]}{\sqrt {Var[x^{(k)}]}}$$

where the expectation and variance are computed over the

training data set.

其中均值和方差是基于整个训练集计算得到的。

Note that simply normalizing each input of a layer may change what the layer can represent. For instance, normalizing the inputs of a sigmoid would constrain them to the linear regime of the nonlinearity.

但是如果仅是简单的对每一层的输入进行标准化可能会对该层的表达造成能力改变。比如对一个sigmoid激活函数的输入标准化会将输入固定在线性区域。

为了解决这一问题,作者提出了这样的改变,引入一对参数 $\gamma^{(k)}$, $\beta^{(k)}$ 来对归一化之后的值进行缩放和平移。

$$y^{(k)} = \gamma^{(k)}\hat x^{(k)} + \beta^{(k)}$$

$\gamma^{(k)}$, $\beta^{(k)}$ 是可学习的参数,用来回复经过标准化之后的网络的表达能力。如果 $\gamma^{(k)}=\sqrt {Var[x^{(k)}]}$, $\beta^{(k)}=E[x^{(k)}]$

In the batch setting where each training step is based on the entire training set, we would use the whole set to normalize activations. However, this is impractical when using stochastic optimization. Therefore, we make the second simplification: since we use mini-batches in stochastic gradient training, each mini-batch produces estimates of the mean and variance of each activation.

在batch中使用整个训练集的均值和方差是不切实际的,因此,作者提出了 第二个简化,用 mini-batch 来估计均值和方差。

Note that the use of mini-batches is enabled by computation of per-dimension variances rather than joint covariances; in the joint case, regularization would be required since the mini-batch size is likely to be smaller than the number of activations being whitened, resulting in singular covariance matrices.

注意到 mini-batches 是计算每一维的方差,而不是联合协方差。使用协方差就需要对模型进行正则化,mini-batches 的大小往往小于需要白化的激活值的数量,会得到 奇异协方差矩阵(singular vorariance matrices)???.

BN 核心流程

batch size m, 我们关注其中某一个维度 $x^{k}$, k 表示第k维特征。那么对于 batch 中该维特征的 m 个值:

$$B={x_{1,…,m}}$$

经过线性转换:

$$BN_{\gamma, \beta}:x_{1,..,m}\rightarrow y_{1,..,m}$$

  • 对于输入的 mini-batch 的一个维度,计算均值和方差

  • 标准化(注意 epsilon 避免0错误)

  • 使用两个参数进行平移和缩放

这里有点疑惑:为什么在第三步已经完成标准化的情况下还要进行4操作,后来发现其实作者在前文已经说了。首先 $\hat x$ 是标准化后的输出,但是如果仅以此为输出,其输出就被限定为了标准正态分布,这样很可能会限制原始网络能表达的信息,前文已用sigmoid函数进行了举例说明。因为 $\gamma, \beta$ 这两个参数是可以学习的,所以的标准化后的”恢复”程度将在训练的过程中由网络自主决定。

利用链式法则,求损失函数对参数 $\gamma, \beta$ 求导:

Thus, BN transform is a differentiable transformation that introduces normalized activations into the network. This ensures that as the model is training, layers can continue learning on input distributions that exhibit less internal covariate shift, thus accelerating the training.

BN 是可微的,保证模型可训练,网络可以学习得到输入的分布,来减小 internal covarite shift, 从而加速训练。

Training and Inference with Batch-Normalized Networks

The normalization of activations that depends on the mini-batch allows efficient training, but is neither necessary nor desirable during inference; we want

the output to depend only on the input, deterministically. For this, once the network has been trained, we use the normalization

$\hat x = \dfrac{x-E[x]}{\sqrt{Var[x]+\epsilon}}$

using the population, rather than mini-batch, statistics.

在训练阶段和推理(inference)阶段不一样,这里的推理阶段指的就是测试阶段,在测试阶段使用总体的均值,而不是 mini-batch 的均值。

Using moving averages instead, we can track the accuracy of a model as it trains. Since the means and variances are fixed during inference, the normalization is simply a linear transform applied to each activation.

Batch-Normalized Convolutional Networks

  • 第1-5步是算法1的流程,对每一维标准化,得到 $N_{BN}^{tr}$

  • 6-7步优化训练参数 $\theta \bigcup {\gamma^{k}, \beta^{k}}$,在测试阶段参数是固定的

  • 8-12步骤是将训练阶段的统计信息转化为训练集整体的统计信息。因为完成训练后在预测阶段,我们使用的是模型存储的整体的统计信息。这里涉及到通过样本均值和方差估计总体的均值和方差的无偏估计,样本均值是等于总体均值的无偏估计的,而样本均值不等于总体均值的无偏估计。具体可看知乎上的解答 https://www.zhihu.com/question/20099757

Batch Normalization enables higher learning rates

In traditional deep networks, too high a learning rate may result in the gradients that explode or vanish, as well as getting stuck in poor local minima.

学习率过大容易发生梯度消失和梯度爆炸,从而陷入局部最小值。

By normalizing activations throughout the network, it prevents small changes in layer parameters from amplifying as the data propagates through a deep network.

通过规范化整个网络中的激活,可以防止层参数的微小变化在数据通过深层网络传播时放大。

Batch Normalization also makes training more resilient to the parameter scale. Normally, large learning rates may increase the scale of layer parameters, which then amplify the gradient during backpropagation and lead to the model explosion. However, with Batch Normalization, backpropagation through a layer is unaffected by the scale of its parameters.

BN 能让训练时的参数更有弹性。通常,学习率过大会增大网络参数,在反向传播中导致梯度过大而发生梯度爆炸。而 BN 使得网络不受参数的大小的影响。

正则化

除了可以更快地训练网络,BN层还有对模型起到正则化的作用。因为当训练一个BN网络的时候,对于一个给定的样本,它还可以”看到”一个batch中其他的情况,这样网络对于一个给定的样本输入每次就可以产生一个不确定的输出(因为标准化的过程和batch中其他的样本均有关联),作者通过实验证明这对减少模型的过拟合具有作用。

代码实现

tensorflow 已经封装好了 BN 层,可以直接通过 tf.contrib.layers.batch_norm() 调用,如果你想知道函数背后的具体实现方法,加深对BN层的理解,可以参考这篇文章Implementing Batch Normalization in Tensorflow

reference:

机器学习-过拟合

过拟合的原理以及解决方法。

Overfitting

过拟合(overfitting)是指在模型参数拟合过程中的问题,由于训练数据包含抽样误差,训练时,复杂的模型将抽样误差也考虑在内,将抽样误差也进行了很好的拟合。

具体表现就是最终模型在训练集上效果好;在测试集上效果差。模型泛化能力弱。

为什么要解决过拟合

为什么要解决过拟合现象?这是因为我们拟合的模型一般是用来预测未知的结果(不在训练集内),过拟合虽然在训练集上效果好,但是在实际使用时(测试集)效果差。同时,在很多问题上,我们无法穷尽所有状态,不可能将所有情况都包含在训练集上。所以,必须要解决过拟合问题。

为什么在机器学习中比较常见?这是因为机器学习算法为了满足尽可能复杂的任务,其模型的拟合能力一般远远高于问题复杂度,也就是说,机器学习算法有「拟合出正确规则的前提下,进一步拟合噪声」的能力。

而传统的函数拟合问题(如机器人系统辨识),一般都是通过经验、物理、数学等推导出一个含参模型,模型复杂度确定了,只需要调整个别参数即可。模型「无多余能力」拟合噪声。

解决方法

获取更多数据

这是解决过拟合最有效的方法,只要给足够多的数据,让模型「看见」尽可能多的「例外情况」,它就会不断修正自己,从而得到更好的结果:

如何获取更多数据,可以有以下几个方法:

  • 从数据源头获取更多数据:这个是容易想到的,例如物体分类,我就再多拍几张照片好了;但是,在很多情况下,大幅增加数据本身就不容易;另外,我们不清楚获取多少数据才算够;

  • 根据当前数据集估计数据分布参数,使用该分布产生更多数据:这个一般不用,因为估计分布参数的过程也会代入抽样误差。

  • 数据增强(Data Augmentation):通过一定规则扩充数据。如在物体分类问题里,物体在图像中的位置、姿态、尺度,整体图片明暗度等都不会影响分类结果。我们就可以通过图像平移、翻转、缩放、切割等手段将数据库成倍扩充;

使用合适的模型

前面说了,过拟合主要是有两个原因造成的:数据太少+模型太复杂。所以,我们可以通过使用合适复杂度的模型来防止过拟合问题,让其足够拟合真正的规则,同时又不至于拟合太多抽样误差。

(PS:如果能通过物理、数学建模,确定模型复杂度,这是最好的方法,这也就是为什么深度学习这么火的现在,我还坚持说初学者要学掌握传统的建模方法。)

对于神经网络而言,我们可以从以下四个方面来限制网络能力:

网络结构 Architecture

这个很好理解,减少网络的层数、神经元个数等均可以限制网络的拟合能力;

训练时间 Early stopping

对于每个神经元而言,其激活函数在不同区间的性能是不同的:

当网络权值较小时,神经元的激活函数工作在线性区,此时神经元的拟合能力较弱(类似线性神经元)。

有了上述共识之后,我们就可以解释为什么限制训练时间(early stopping)有用:因为我们在初始化网络的时候一般都是初始为较小的权值。训练时间越长,部分网络权值可能越大。如果我们在合适时间停止训练,就可以将网络的能力限制在一定范围内。

限制权值 Weight-decay,也叫正则化(regularization)

原理同上,但是这类方法直接将权值的大小加入到 Cost 里,在训练的时候限制权值变大。以 L2 regularization为例:

训练过程需要降低整体的 Cost,这时候,一方面能降低实际输出与样本之间的误差 ,也能降低权值大小。

增加噪声 Noise

给网络加噪声也有很多方法:

在输入中加噪声:

噪声会随着网络传播,按照权值的平方放大,并传播到输出层,对误差 Cost 产生影响。推导直接看 Hinton 的 PPT 吧:

在输入中加高斯噪声,会在输出中生成 的干扰项。训练时,减小误差,同时也会对噪声产生的干扰项进行惩罚,达到减小权值的平方的目的,达到与 L2 regularization 类似的效果(对比公式)。

在权值上加噪声

在初始化网络的时候,用0均值的高斯分布作为初始化。Alex Graves 的手写识别 RNN 就是用了这个方法

Graves, Alex, et al. “A novel connectionist system for unconstrained handwriting recognition.” IEEE transactions on pattern analysis and machine intelligence 31.5 (2009): 855-868.

  • It may work better, especially in recurrent networks (Hinton)

对网络的响应加噪声

如在前向传播过程中,让默写神经元的输出变为 binary 或 random。显然,这种有点乱来的做法会打乱网络的训练过程,让训练更慢,但据 Hinton 说,在测试集上效果会有显著提升 (But it does significantly better on the test set!)。

结合多种模型

简而言之,训练多个模型,以每个模型的平均输出作为结果。

从 N 个模型里随机选择一个作为输出的期望误差 ,会比所有模型的平均输出的误差 大(我不知道公式里的圆括号为什么显示不了):

大概基于这个原理,就可以有很多方法了:

Bagging

简单理解,就是分段函数的概念:用不同的模型拟合不同部分的训练集。以随机森林(Rand Forests)为例,就是训练了一堆互不关联的决策树。但由于训练神经网络本身就需要耗费较多自由,所以一般不单独使用神经网络做Bagging。

Boosting

既然训练复杂神经网络比较慢,那我们就可以只使用简单的神经网络(层数、神经元数限制等)。通过训练一系列简单的神经网络,加权平均其输出。

Dropout

在训练时,每次随机(如50%概率)忽略隐层的某些节点;这样,我们相当于随机从2^H个模型中采样选择模型;同时,由于每个网络只见过一个训练数据(每次都是随机的新网络),所以类似 bagging 的做法,这就是我为什么将它分类到「结合多种模型」中;

此外,而不同模型之间权值共享(共同使用这 H 个神经元的连接权值),相当于一种权值正则方法,实际效果比 L2 regularization 更好。

贝叶斯方法

总结

论文笔记 - Attention 综述

Attention and Augmented Recurrent Neural Networks

循环神经网络是深度学习的根基之一,她允许神经网络对序列数据进行处理,比如文本,语音和视频。

这句话形容特别贴切,意思就是rnn能将序列转换成包含了理解,语义的表示。

They can be used to boil a sequence down into a high-level understanding, to annotate sequences, and even to generate new sequences from scratch!

基本的 rnn 在解决 long sequence 时非常挣扎,其变体 LSTM 有效的解决这一问题(但问题依然存在)。

随着时间的发展,出现了各种 augument RNNs. 其中以下4种 stand out exciting.

这些变体都是 RNN 有力的拓展,更令人惊奇的是,他们还能有效的结合在一起,似乎只是广阔空间中的一点。除此之外,他们都依赖于同样的 underlying trick — attention.

Neural Turing Machines

Neural Turing Machines 神经图灵机将 RNNs 和外部 memory bank 结合在一起。向量用来表示神经网络中的自然语言,memory 是向量的数组。

如上图所示,能够看出其原理是将每一个词的向量表示存储在 memory 中。那么从 memory 中读、以及写入 memory 是怎么操作的呢?

最大的难点在于让整个过程可微(differentiable).特别的是,我们希望在读出和写入的位置具有差异性,以便我们可以知道从哪儿读和写。这很棘手(tricky),因为 memory 地址基本上是离散的。

NMTs 采取了一个非常聪明的方法,每一步读和写都包括 memory 中的所有位置,只是对于不同的位置,读和写的程度不同。

举个例子,这里我们只关注 reading. RNN 输出一个 “attention distribution”,表示对于 memory 不同位置的读取程度。这样,读入的操作可以看作加权求和。

$$r \leftarrow \sum_ia_iM_i$$

类似的,在读入的过程中也是对 memory 中所有位置。再一次,输出一个 “attention distribution” 用来表示对每个位置的写入程度。我们在一个 memory 位置获得新的 value 是旧的 memory 和写入值的 凸结合(convex combination).

$$M_i \leftarrow a_iw+(1-a_i)M_i$$

其中 $w$ 是写入值(write value)。

但是 NTMs 如何确定去注意 memory 中的那一个位置呢? 他们使用了两种不同的方法的结合: content-based attention 和 location-based attention. 前者允许 NMTs 通过匹配 memory 中的每一个位置,并 focus on 最 match 的位置。后者允许 memory 中的相对移动,保证 NMT 能循环。

这种读和写的能力允许 NTM 执行许多简单的算法,而这些算法以前超越了神经网络。 例如,他们可以在 memory中存储一个长序列,然后遍历它,反向重复它。 当他们这样做时,我们可以看他们读和写的地方,以更好地理解他们在做什么:

关于 repeat copy 的实验,可以参考这篇论文Show, attend and tell: Neural image caption generation with visual attention

他们能够模仿一个 lookup table,甚至可以 sort numbers(althought they kind of cheat). 但另一方面,他们仍然不能做很多基本的事儿,比如 add or multiply numbers.

自从 NTM 这篇论文之后,又出现了很多相同方向的令人 exciting 的文章.

The Neural GPU 4 overcomes the NTM’s inability to add and multiply numbers.

Zaremba & Sutskever 5 train NTMs using reinforcement learning instead of the differentiable read/writes used by the original.

Neural Random Access Machines 6 work based on pointers.

Some papers have explored differentiable data structures, like stacks and queues [7, 8].

memory networks [9, 10] are another approach to attacking similar problems.

Code

关于这篇 paper 真的很难看懂,

Attention Interfaces

当我翻译一个句子时,我特别注意我正在翻译的单词。 当我录制录音时,我会仔细聆听我正在积极写下的片段。 如果你要求我描述我正在坐的房间,那么我会浏览我正在描述的物体。

神经网络能够通过 attention 机制完成上述行为,也就是 focusing on 给出信息的部分内容。举个例子,一个 RNN 能够 attend over 另一个 RNN 的输出,并在每一个时间步, focus on 另一个 RNN 的不同的位置。

为了让 attention 可微,我们采用跟 NTM 同样的方法,focus 所有的位置,每个位置的程度不同。

上图中颜色的深浅表示注意的程度。

其中 attention distribution 是由 content-based attention 生成的。具体过程还是看英文描述吧:

The attending RNN generates a query describing what it wants to focus on. Each item is dot-producted with the query to produce a score, describing how well it matches the query. The scores are fed into a softmax to create the attention distribution.

最经典的使用 RNNs 之间的 attention 就是机器翻译了,Neural machine translation by jointly learning to align and translate. 传统的 seq2seq 模型通过 RNN 将整个输入序列转化为单个向量(也就是最后一层的隐藏状态),然后将其展开得到输出(word by word). 注意力机制避免了这一点,它允许 RNN 在生成输出时,能看到所有输入中的每一个词,并且根据他们之间的相关性,来选择性注意部分词。

原图是可以操作的,大牛们的技术真是厉害。。。可视化也很6。。

这种类型的 RNN 还有很多其他的应用,比如在 语音识别上的使用Listen, Attend and Spell, 使用一个 RNN 来处理音频,然后用另一个 RNN 来遍历它,并在生成一个抄本(transcript)时重点关注相关的部分。

这个图看不出来,不能截出那种效果。 其实可以看出对语音的识别,在生成对应的词时更关注的是对应的音频,并不像文本那种需要长时间依赖。

还有很多其他的应用:

Then an RNN runs, generating a description of the image. As it generates each word in the description, the RNN focuses on the conv net’s interpretation of the relevant parts of the image. We can explicitly visualize this:

图片来自于Show, attend and tell: Neural image caption generation with visual attention

More broadly, attentional interfaces can be used whenever one wants to interface with a neural network that has a repeating structure in its output.

Adaptive Computation time

Standard RNNs do the same amount of computation for each time step. This seems unintuitive. Surely, one should think more when things are hard? It also limits RNNs to doing O(n) operations for a list of length n.

标准的 RNN 在每一个时间步都做着相同的大量的计算。它貌似是很合理的,但当处理的信息很复杂时,是否可以在一个时间步考虑更多?这样同样的计算量的方式限制了 RNN 在处理长度为 n 的序列时,其复杂度也为 O(n).

Adaptive Computation Time [15] is a way for RNNs to do different amounts of computation each step. The big picture idea is simple: allow the RNN to do multiple steps of computation for each time step.

自适应计算时间步(ACT) 能让 RNN 在每一个时间步做不同的计算量. 它的大致原理很简单:允许 RNN 在每一个时间步做多步运算。

In order for the network to learn how many steps to do, we want the number of steps to be differentiable. We achieve this with the same trick we used before: instead of deciding to run for a discrete number of steps, we have an attention distribution over the number of steps to run. The output is a weighted combination of the outputs of each step.

为了让网络学习得到每一个时间步的计算步数,我们希望这个计算步数是可微的(也就是把其步数当作学习得到的参数,然后通过反向传播来学习这个参数)。为了实现这个 trick,我们采用类似之前 NTM 的方式,相比每次计算一个离散的步数,我们使用注意力分布的机制来选择步数,输出的结果是所有步的加权求和。

There are a few more details, which were left out in the previous diagram. Here’s a complete diagram of a time step with three computation steps.

上图中还有更多的细节。下图是 RNN 中的在一个时间步中有3个步数的计算量。

That’s a bit complicated, so let’s work through it step by step. At a high-level, we’re still running the RNN and outputting a weighted combination of the states:

这个图看起来有点复杂,我们会一步一步的解释它。在更高的层次,我们依然运行 RNN 并输出一个状态的加权之和。

S 表示 RNN 中的隐藏状态。

The weight for each step is determined by a “halting neuron.” It’s a sigmoid neuron that looks at the RNN state and gives a halting weight, which we can think of as the probability that we should stop at that step.

每一步的权重由一个“停止神经元”确定。这是一个sigmoid神经元,用来关注当前的 RNN 的状态以及赋予它一个权重。我们可以看作是这一步是否应该停止的概率。

We have a total budget for the halting weights of 1, so we track that budget along the top. When it gets to less than epsilon, we stop

我们设总的停止权重为 1,依次减去每步输出的 halt 值,直到剩余的 halt 值小于 epsilon 后就停止。

When we stop, might have some left over halting budget because we stop when it gets to less than epsilon. What should we do with it? Technically, it’s being given to future steps but we don’t want to compute those, so we attribute it to the last step.

当我们结束后,应该还会遗留一些停止值,因为我们在停止值小于epsilon时停止的。我们该怎么处理这些剩余的停止值?从技术上讲,它们应该传递到后面的计算步骤中去,但我们不想计算这些值,所以我们就把这些剩余的停止值归总到最后一步。

When training Adaptive Computation Time models, one adds a “ponder cost” term to the cost function. This penalizes the model for the amount of computation it uses. The bigger you make this term, the more it will trade-off performance for lowering compute time.

当训练 ACT 模型时,需要给损失函数加上一个惩罚项。用来惩罚整个模型中的总的计算量。这一项越大时,它会在模型性能和计算量的折衷中倾向与减小计算量。

Code:

The only open source implementation of Adaptive Computation Time at the moment seems to be Mark Neumann’s (TensorFlow).

reference:

论文笔记 memory networks

Memory Networks 相关论文笔记。

  • Memory Network with strong supervision

  • End-to-End Memory Network

  • Dynamic Memory Network

Paper reading 1: Memory Networks, Jason Weston

Motivation

RNNs 将信息压缩到final state中的机制,使得其对信息的记忆能力很有限。而memory work的提出就是对这一问题进行改善。

However, their memory (encoded by hidden states and weights) is typically too small, and is not compartmentalized enough to accurately remember facts from the past (knowledge is compressed into dense vectors). RNNs are known to have difficulty in performing memorization.

Memory Networks 提出的基本动机是我们需要 长期记忆(long-term memory)来保存问答的知识或者聊天的语境信息,而现有的 RNN 在长期记忆中表现并没有那么好。

Memory Networks

four components:

  • I:(input feature map)

把输入映射为特征向量,可以包括各种特征工程,比如parsing, coreference, entity resolution,也可以是RNN/LSTM/GRU。通常以句子为单位,将sentence用向量表示,一个句子对应一个sparse or dense feature vector.

  • G:(generalization)

使用新的输入数据更新 memories

  • O:(output feature map)

给定新的输入和现有的 memory state,在特征空间里产生输出

  • R:(response)

将输出转化为自然语言

详细推导过程

1.I component: :encode input text to internal feature representation.

可以选择多种特征,比如bag of words, RNN encoder states, etc.

2.G component: generalization 就是结合 old memories和输入来更新 memories. $m_i=G(m_i, I(x),m), ∀i$

最简单的更新memory的方法是 $m_{H(x)}=I(x)$, $H(x)$ 是一个寻址函数slot selecting function,G更新的是 m 的index,可以把新的memory m,也就是新的输入 I(x) 保存到下一个空闲的地址 $m_n$ 中,并不更新原有的memory. 更复杂的 G 函数可以去更新更早的memory,甚至是所有的memory.

这里的新的input,如果在QA中就是question 和 old memmory的组合 $[I(x), m_i]$.

3.O component: reading from memories and performing inference, calculating what are the relevant memories to perform a good response.

给定新的输入和memory,在memories中寻找最相关的k个记忆

如果k=2:

$$o_1=O_1(q,m)=argmax_{i=1,2,..,N}s_O(q,m_i)$$

$$o_2=O_2(q,m)=argmax_{i=1,2,..,N}s_O([q,o_1],m_i)$$

output: $[q,o_1, o_2]$ 也是module R的输入.

$s_O$ is a function that scores the match between the pair of sentences x and mi. $s_O$ 用来表征 question x 和 记忆 $m_i$ 的相关程度。

$$s_O=qUU^Tm$$

$s_O$ 表示问题q和当前memory m的相关程度

U:bilinear regression参数,相关事实的 $qUU^Tm_{true}$ 的score高于不相关事实的分数 $qUU^Tm_{random}$

4.R component : 对 output feature o 进行解码,得到最后的response: r=R(o)

$$r=argmax_{w\in W}s_R([q,m_{o_1},m_{o_2}],w)$$

W 是词典,$s_R$ 表示与output feature o 最相关的单词。

$s_R$ 和 $s_O$ 的形式是相同的。

$$s(x,y)=xUU^Ty$$

Huge Memory 问题

如果memory太大,比如 Freebase or Wikipedia,

  • 可以按 entity 或者 topic 来存储 memory,这样 G 就不用在整个 memories 上操作了

  • 如果 memory 满了,可以引入 forgetting 机制,替换掉没那么有用的 memory,H 函数可以计算每个 memory 的分数,然后重写

  • 还可以对单词进行 hashing,或者对 word embedding 进行聚类,总之是把输入 I(x) 放到一个或多个 bucket 里面,然后只对相同 bucket 里的 memory 计算分数

损失函数

损失函数如下,选定 2 条 supporting fact (k=2),response 是单词的情况:

多类支持向量机损失:

minimize: $L_i = \sum_{j\ne y_i}max(0,s_j - s_{y_i}+\Delta)$

其中 $\overline f, \overline f’,\overline r$ 表示负采样。比如(8)式中r表示 true response, 而 $\overline r$ 表示随机抽样词典中的其他词。

QA实例:

(6) 有没有挑选出正确的第一句话

(7) 正确挑选出了第一句话后能不能正确挑出第二句话

(6)+(7) 合起来就是能不能挑选出正确的语境,用来训练 attention 参数

(8) 把正确的 supporting fact 作为输入,能不能挑选出正确的答案,来训练 response 参数

Paper reading 2 End-To-End Memory Networks

motivation

上一篇paper中的缺陷:

The model in that work was not easy to train via backpropagation, and required supervision at each layer of the network.

这篇论文可以看作是上一篇论文memory networks的改进版。

Our model can also be seen as a version of RNNsearch with multiple computational steps (which we term “hops”) per output symbol.

也可以看做是将multiple hops应用到RNNsearch这篇论文上 Neural Machine Translation by Jointly Learning to Align and Translate

Model architecture

Single layer

输入:

  • input: $x_1,…,x_i$

  • query: q

  • answer: a

对于单层网络,主要分为以下几个步骤:

1.将input和query映射到特征空间

  • memory vector {$m_i$}: ${x_i}\stackrel A\longrightarrow {m_i}$

  • internal state u: $q\stackrel B \longrightarrow u$

2.计算attention,也就是query的向量表示u,和input中各个sentence的向量表示 $m_i$ 的匹配度。compute the match between u and each memory mi by taking the inner product followed by a softmax.

$$p_i=softmax(u^Tm_i)$$

p is a probability vector over the inputs.

3.得到context vector

  • output vector: ${x_i}\stackrel C\longrightarrow {c_i}$

The response vector from the memory o is then a sum over the transformed inputs ci, weighted by the probability vector from the input:

$$o = \sum_ip_ic_i$$

和 Memory Networks with Strong Supervision 版本不同,这里的 output 是加权平均而不是一个 argmax

4.预测最后答案,通常是一个单词

$$\hat a =softmax(Wu^{k+1})= softmax(W(o^k+u^k))$$

W可以看做反向embedding,W.shape=[embed_size, V]

5.对 $\hat a$ 进行解码,得到自然语言的response

$$\hat a \stackrel C \longrightarrow a$$

其中:

A: intput embedding matrix

C: output embedding matrix

W: answer prediction matrix

B: question embedding matrix

单层网络实例:

这里的 memory {$m_i$} 直接用于输出向量 $c_i$. 其实我也疑惑,为啥要重新用一个output embedding C,直接用 $m_i$ 不好吗。其实这些小tricks也说不准好不好,都是试出来的吧,因为怎么说都合理。。。

Multiple Layers/ Multiple hops

多层结构(K hops)也很简单,相当于做多次 addressing/多次 attention,每次 focus 在不同的 memory 上,不过在第 k+1 次 attention 时 query 的表示需要把之前的 context vector 和 query 拼起来,其他过程几乎不变。

$$u_{k+1}=u^k+o^k$$

对比上一篇paper来理解

多层网络也可以看做是四个组件构成的:

  • input components: 就是将query和sentences映射到特征空间中

  • generalization components: 更新memory,这里的memory也是在变化的,${m_i}=AX$, 但是embedding matrix A 是逐层变化的

  • output components: attention就是根据inner product后softmax计算memory和query之间的匹配度,然后更新input,也就是[u_k,o_k], 可以是相加/拼接,或者用RNN. 区别是,在上一篇论文中是argmax,$o_2=O_2(q,m)=argmax_{i=1,2,..,N}s_O([q,o_1],m_i)$, 也就是选出匹配程度最大的 memory $m_i$, 而这篇论文是对所有的memory进行加权求和

  • response components: 跟output components类似啊,上一篇论文是与词典中所有的词进行匹配,求出相似度最大的 $r=argmax_{w\in W}s_R([q,m_{o_1},m_{o_2}],w)$,而这篇论文是 $\hat a=softmax(Wu^{k+1})=softmax(W(u^k+o^k))$ 最小化交叉熵损失函数训练得到 answer prediction matrix W.

Overall, it is similar to the Memory Network model in [23], except that the hard max operations within each layer have been replaced with a continuous weighting from the softmax.

一些技术细节

每一层都有 mebedding matrices $A^k, C^k$,用来embed inputs {$x_i$},为了减少训练参数.作者尝试了以下两种情况:

  1. Adjacent
  • 上一层的output embedding matrix 是下一层的 input embedding matrix, 即 $A^{k+1}=C^k$

  • 最后一层的output embedding 可用作 prediction embedding matrix, 即 $W^T=C^k$

  • question embedding matrix = input embedding matrix of the first layer, $B=A^1$

  1. Layer-wise (RNN-like)
  • $A^1=A^2=…=A^k, C^1=C^2=…C^k$

  • $u^{k+1} = Hu^k+o^k$

Experiments

Dataset

数据集来源:Towards AI-complete question answering: A set of prerequisite toy tasks

总共有 20 QA tasks,其中每个task有 $I(I\le 320)$ 个sentence {$x_i$}, 词典大小 V=170, 可以看做这是个玩具级的任务。每个task有1000个problems

Modle details

Sentence representations

也就是将input和query映射到特征空间,有两种方式:

1.Bag of words(BOW) representation

$$m_i=\sum_jAx_{ij}$$

$$c_i=\sum_jCx_{ij}$$

$$u=\sum_jBq_j$$

分别对每个词embed,然后sum,缺点是没有考虑词序

2.encodes the position of words within the sentence 考虑词序的编码

$$m_i=\sum_jl_j\cdot Ax_{ij}$$

i表示第i个sentence,j表示这个sentence中的第j个word

$$l_{kj}=(1-j/J)-(k/d)(1-2j/J)$$

查看源码时发现很多代码的position encoder与原paper不一样,比如domluna/memn2n中公式是:

$$l_{kj} = 1+4(k- (d+1)/2)(j-(J+1)/2)/d/J$$

原本词 $x_{ij}$ 的向量表示就是embeded后的 $Ax_{ij},(shape=[1, embed_size])$, 但现在要给这个向量加一个权重 $l_j$,而且这个权重不是一个值,而是一个向量,对 $Ax_{ij}$ 中每一个维度的权重也是不一样的。

令J=20, d=50. 具体两个公式的差别可以查看

wolframalpha1

wolframalpha2

也就是说不仅跟word在sentence中的位置有关,还和embed_size中的维度有关。这就很难理解了。。。

好像跟句子的结构相关,北大有篇相关的论文A Position Encoding Convolutional Neural Network Based on Dependency Tree for Relation Classification

其中 J 表示sentence的长度,d表示 dimension of the embedding. 这种sentence representation称为 position encoding(PE).也就是词序会影响memory $m_i$.

position encoding 代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

def position_encoding(sentence_size, embedding_size):

"""

Position Encoding described in section 4.1 [1]

"""

encoding = np.ones((embedding_size, sentence_size), dtype=np.float32)

le = embedding_size+1

ls = sentence_size + 1

for k in range(1, le):

for j in range(1, ls):

# here is different from the paper.

# the formulation in paper is: l_{kj}=(1-j/J)-(k/d)(1-2j/J)

# here the formulation is: l_{kj} = 1+4(k- (d+1)/2)(j-(J+1)/2)/d/J,

# 具体表现可查看 https://www.wolframalpha.com/input/?i=1+%2B+4+*+((y+-+(20+%2B+1)+%2F+2)+*+(x+-+(50+%2B+1)+%2F+2))+%2F+(20+*+50)+for+0+%3C+x+%3C+50+and+0+%3C+y+%3C+20

encoding[k-1, j-1] = (k - (embedding_size+1)/2) * (j - (sentence_size+1)/2)

encoding = 1 + 4 * encoding / embedding_size / sentence_size

# Make position encoding of time words identity to avoid modifying them

encoding[:, -1] = 1.0 # 最后一个sentence的权重都为1

return np.transpose(encoding) # [sentence_size, embedding_size]

Temporal Encoding

将memory改进为:

$$m_i=\sum_jAx_{ij}+T_A(i)$$

其中 $T_A(i)$ is the ith row of a special matrix $T_A$ that encodes temporal information. 用一个特殊的矩阵 $T_A$ 来编码时间信息。$T_A(i)$ i表示第i个sentence的包含时间信息??

同样的output embedding:

$$c_i=\sum_jCx_{ij}+T_C(i)$$

Learning time invariance by injecting random noise

we have found it helpful to add “dummy” memories to regularize TA.

Training Details

1.learning rate decay

2.gradient clip

3.linear start training

4.null padding, zero padding

完整代码实现

https://github.com/PanXiebit/text-classification/blob/master/06-memory%20networks/memn2n_model.py

Paper reading 3 Ask Me Anything: Dynamic Memory Networks for Natural Language Processing

Motivation

Most tasks in natural language processing can be cast into question answering (QA) problems over language input.

大部分的自然语言处理的任务都可以看作是QA问题,比如QA, sentiment analysis, part-of-speech tagging.

Model Architecture

可以分为以下4个模块:

  • Input Module: 将输入文本编码为distribution representations

  • Question Module: 将question编码为distribution representations

  • Episodic Memory Module: 通过attention机制选择focus on输入文本中的某些部分,然后生成memory vector representation.

  • Answer Module: 依据the final memory vector生成answer

Detailed visualization:

Input Module

主要分为两种情况:

1.输入是single sentence,那么input module输出的就是通过RNN计算得到的隐藏状态 $T_C= T_I$, $T_I$ 表示一个sentence中的词的个数。

2.输入是a list of sentences,在每个句子后插入一个结束符号 end-of-sentence token, 然后每个sentence的final hidden作为这个sentence的representation. 那么input module输出 $T_C$, $T_C$等于sequence的sentence个数。

然后RNN使用的是GRU,作者也尝试过LSTM,发现效果差不多,但LSTM计算量更大。

Question Module

同样的使用GRU编码,在t时间步, 隐藏状态

$$q_t=GRU(L[w_t^Q],q_{t-1})$$

L代表embedding matrix.

最后输出 final hidden state.

$$q=q_{T_Q}$$

$T_Q$ 是question的词的个数。

Episodic Memory Module

由 internal memory, attention mechansim, memory update mechanism 组成。 输入是 input module 和 question module 的输出。

把 input module 中每个句子的表达(fact representation c)放到 episodic memory module 里做推理,使用 attention 原理从 input module 中提取相关信息,同样有 multi-hop architecture。

1.Needs for multiple Episodes: 通过迭代使得模型具有了传递推理能力 transitive inference.

2.Attention Mechanism: 使用了一个gating function作为attention机制。相比在 end-to-end MemNN 中attention使用的是linear regression,即对inner production通过softmax求权重。 这里使用一个两层前向神经网络 G 函数.

$$g_t^i=G(c_t,m^{i-1},q)$$

$c_t$ 是candidate fact, $m_{i-1}$ 是previous memory, question q. t 表示sentence中的第t时间步,i表示episodic的迭代次数。

这里作者定义了 a large feture $z(c,m,q)$ 来表征input, memory, question之间的相似性。

$$z_t^i=[c_t, m^{i-1},q, c_t\circ q,c_t\circ m^{i-1},|c_t-q|,|c_t-m^{i-1}|, c_t^TW^{(b)}q, c_t^TW^{(b)}m^{i-1}]$$

总的来说,就是根据向量内积,向量相减来表示相似度。 跟cs224d-lecture16 dynamic Memory networkRichard Socher本人讲的有点区别,不过这个既然是人工定义的,好像怎么说都可以。

然后通过G函数,也就是两层前向神经网络得到一个scale score.

$$G = \sigma(W^{(2)}tanh(W^{(1)}z_i^t+b^{(1)})+b^{(2)})$$

将 $c_t$, $m^{i-1}, q 带入到G函数,即可求得$$g_i^t$,也就是candidate fact $c_i$ 的score.

计算完每一次迭代后的分数后,来更新episode $e^i$, 相当于 context vector,

soft attention

在之前的attention机制中,比如cs224d-lecture10-机器翻译和注意力机制介绍的attention得到的context vector,在end-to-end MemNN中attention也是fact representation的加权求和。

attention based GRU

但这篇论文中应用了GRU,对fact representation c 进行处理,然后加上gate

$$h_t^i=g_t^iGRU(c_t,h_{t-1}^i)+(1-g_t^i)h_{i-1}^t$$

所以这里的GRU应该是 $T_C$步吧??

每次迭代的context vector是对 input module 的输出进行 attention-based GRU编码的最后的隐藏状态:

$$e^i=h_{T_C}^i$$

总结一下:

这部分attention mechanism目的就是生成episode $e^i$,$e^i$ 是第i轮迭代的所有input相关信息的summary.也就是 context vector,将input text压缩到一个向量表示中,end-to-end MemNN用了soft attention,就是加权求和。而这里用了GRU,各个时间步的权重不是直接相乘,而是作为一个gate机制。

3.Memory Update Mechanism

上一步计算的episode $e^i$ 以及上一轮迭代的memory $m^{i-1}$ 作为输入来更新memory $m_i$

$$m_i=GRU(e^i,m^{i-1})$$

$m^0=q$, 所以这里的GRU是单步的吧

经过 $T_M$ 次迭代: $m=m^{T_M}$, 也就是episodic memory module的输出,即answer module的输入。

在end-to-end MemNN的memory update中,$u_{k+1}=u^k+o^k$, 而在这篇论文中,如果也采用这种形式的话就是 $m^{i}=e^i+m^{i-1}$,但作者采用了 RNN 做非线性映射,用 episode $e_i$ 和上一个 memory $m_{i−1}$ 来更新 episodic memory,其 GRU 的初始状态包含了 question 信息,$m_0=q$。

4.Criteria for stopping

Episodic Memory Module 需要一个停止迭代的信号。一般可以在输入中加入一个特殊的 end-of-passes 的信号,如果 gate 选中了该特殊信号,就停止迭代。对于没有显性监督的数据集,可以设一个迭代的最大值。

Answer Module

使用了GRU的decoder。输入是question module的输出q和上一个时刻的hidden state $a_{t-1}$,初始状态是episodic memory module的输出 $a_0=m^{T_M}$.

$$y_t=softmax(W^{(a)}a_t)$$

$$a_t=GRU([y_{t-1},q],a_{t-1})$$

这里应该就是单步GRU吧,毕竟question的向量表示q只有一个呀。

Train

使用 cross-entroy 作为目标函数。如果 数据集有 gate 的监督数据,还可以将 gate 的 cross-entroy 加到总的 cost上去,一起训练。训练直接使用 backpropagation 和 gradient descent 就可以。

总结:对比上一篇论文End-to-end memory networks

  • input components: end2end MemNN 采用embedding,而DMN使用GRU

  • generalization components: 也就是memory update,End2End MemNN采用线性相加 $u^{k+1}=u^k+o^k$,其中的 $o^k$ 就是经过attention之后得到的memory vector

  • output components: end2end MemNN采用的是对比memory和query,用内积求相似度,然后softmax求权重,最后使用加权求和得到context vector. 而DMN采用的是人工定义相似度的表示形式,然后用两层前向神经网络计算得到score,再对score用softmax求权重,再然后把权重当做gate机制,使用GRU求context vector

  • response components: end2end MemNN 直接使用最后的 top memory layer 预测,而DMN是把top memory 当做init hidden state

总之,DMN实在是太太太复杂了。。每一个module都用到了RNN

Paper reading 4 DMN+

paper:Dynamic Memory Networks for Visual and Textual Question Answering (2016)

Motivate

提出了DMN+,是DMN的改进版,同时将其应用到 Visual Question Answering 这一任务上。

However, it was not shown whether the architecture achieves strong results for question answering when supporting facts are not marked during training or whether it could be applied to other modalities such as images.

这段话是描述DMN的缺点的,在没有标注 supporting facts的情况下表现不好。但是DMN貌似也并不需要标注 supporting facts啊。。。

Like the original DMN, this memory network requires that supporting facts are labeled during QA training. End-toend memory networks (Sukhbaatar et al., 2015) do not have this limitation.

Based on an analysis of the DMN, we propose several improvements to its memory and input modules. Together with these changes we introduce a novel input module for images in order to be able to answer visual questions.

这篇文章对DMN中的 input module进行了修改,并且提出了新的模型架构适用于图像的。

DMN 存在的两个问题:

输入模块只考虑了过去信息,没考虑到将来信息

只用 word level 的 GRU,很难记忆远距离 supporting sentences 之间的信息。

总的来说这篇文章贡献主要还是在应用到图像上了,至于作者所说的 input module的改进,只是为了减少计算量,而且改进版中的 bi-RNN 和 position encoding 都是在别人的论文中出现了的。

Model Architecture

同DMN一样,也分为 input module, question module, episodic module 和 answer module.

Input Module

input module for text QA

主要分为两个组件: sentence reader 和 input fusion layer.

sentence reader: 用encoding position代替RNN对单个sentence进行编码。用 positional encoding 的原因是在这里用 GRU/LSTM 编码句子计算量大而且容易过拟合(毕竟 bAbI 的单词量很小就几十个单词。。),这种方法反而更好。

input fusion layer: 使用 bi-directional GRU 来得到context 信息,兼顾过去和未来的信息。

总的来说: DMN+ 把 single GRU 替换成了类似 hierarchical RNN 结构,一个 sentence reader 得到每个句子的 embedding,一个 input infusion layer 把每个句子的 embedding 放入另一个 GRU 中,得到 context 信息,来解决句子远距离依赖的问题。

input module for VQA

1.Local region feature extraction:

获取局部特征信息,使用VGG预训练得到的特征。局部特征 feature vector 通过一个linear layer 和 tanh activation 得到 feature embedding.

2.Input fusion layer:

将 feature embedding 放入到 bi-GRU 中。

Without global information, their representational power is quite limited, with simple issues like object scaling or locational variance causing accuracy problems. 强调了为什么要使用 input fusion layer.

Question Module

这部分跟DMN是一样的, question 都是文本,用RNN编码。

Episodic Module

score mechanism

input module 的输出是:

$$\overleftrightarrow F=[\overleftrightarrow f_1, …,\overleftrightarrow f_N]$$

同DMN一样,作者也是用了人工特征,相比DMN简化一点:

$$z_i^t=[\overleftrightarrow f_i\circ q,\overleftrightarrow f_i\circ m^{t-1},|\overleftrightarrow f_i-q|,|\overleftrightarrow f_i-m^{i-1}|]$$

这里与前面DMN的公式有点区别,就是这里的i表示input module中的时间步, t 表示episodic迭代次数。

同样使用一个两层前向神经网络:

$$G = W^{(2)}tanh(W^{(1)}z_i^t+b^{(1)})+b^{(2)}$$

但是这里不是使用 sigmoid 函数来求的 score,而是使用softmax 来求score $g_i^t$.

$$g_i^t=\dfrac{Z_i^t}{\sum_{k=1}^{M_i}exp(Z_k^t)}$$

attention mechanism

比较了 soft attention 和 attention-based-GRU.相比DMN那篇论文,这里给出了详细的比较。

soft attention, 就是简单的加权求和。

$$c^t=\sum_{i=1}^Ng_i^t\overleftrightarrow f_i$$

其缺点在于丢失了位置信息和词序信息。

感觉简单的attention已经很好了吧。。前面 $\overleftrightarrow f_i$ 不就是考虑了词序信息的么,然后再用GRU对 $\overleftrightarrow f_i$ 处理不会过拟合吗???

attention based GRU

使用attention gate $g_i^t$ 代替 update gate $u_i$. 我们知道 $u_i$ 是通过 current input 和 previous hidden state得到的。 而使用 attention gate $g_i^t$ 能够考虑到 question 和 previous memory. 因为我们这里是要更新memory, 所以这样很合理呀。。厉害了

$$h_i=g_i^t\circ \tilde h_i+(1-g_i^t)\circ h_{i-1}$$

memory update mechanism

在DMN中,更新memory在基于 previous memory 和 当前的 context vector 的GRU编码得到的。 DMN+采用的是将 previous memory $m^{t-1}$, 当前 context $c^t$,和question q 拼接起来,然后通过全连接层,以及relu激活函数得到的:

$$m_t = ReLU(W^t[m^{t-1},c^t,q]+b)$$

使用relu的全连接层能提升0.5%的准确率。

Answer Module

同DMN.

reference:

论文笔记, Attention Is All You Need

Attention Is All You Need

1. paper reading

1.1 Introduction

Recurrent models typically factor computation along the symbol positions of the input and output sequences. Aligning the positions to steps in computation time, they generate a sequence of hidden states ht, as a function of the previous hidden state ht−1 and the input for position t.

This inherently sequential nature precludes parallelization within training examples, which becomes critical at longer sequence lengths, as memory constraints limit batching across examples.

RNN模型有两个很致命的缺点:

$$y_t=f(y_{t-1},x_t)$$

  • 一是无法解决长句子的长期依赖的问题(这是因为反向传播,loss的梯度很难传递到比较靠前的位置,造成前面的词对整体的影响偏小,[Gradient flow in

recurrent nets: the difficulty of learning long-term dependencies](http://www.bioinf.jku.at/publications/older/ch7.pdf));

  • 二是计算无法并行化的问题(后一个时刻的计算依赖于前一个时刻的计算),导致训练速度很慢。

Attention mechanisms have become an integral part of compelling sequence modeling and transduction models in various tasks, allowing modeling of dependencies without regard to their distance in the input or output sequences. In all but a few cases, however, such attention mechanisms are used in conjunction with a recurrent network.

Attention机制能够有效解决RNN无法长时间依赖的问题,但是对于无法并行化计算的问题依旧存在。

2. Background

2.1 Extended Neural GPU [16], ByteNet [18] and ConvS2S [9]
2.2 Self-attention

Self-attention, sometimes called intra-attention is an attention mechanism relating different positions of a single sequence in order to compute a representation of the sequence.

A structured self-attentive sentence embedding

2.3 End-to-end memory networks

End-to-end memory networks are based on a recurrent attention mechanism instead of sequence aligned recurrence and have been shown to perform well on simple-language question answering and language modeling tasks.

End-to-end memory networks

2.4 Transformer

Transformer is the first transduction model relying

entirely on self-attention to compute representations of its input and output without using sequence aligned RNNs or convolution.

本文主要和以下三篇文章对比:

Model Architecture

在以往的encoder-decoder模型中:

the encoder maps an input sequence of symbol representations $(x_1,…,x_n)$ to a sequence of continuous representations $z = (z_1,…,z_n)$. Given z, the decoder then generates an output sequence $(y_1,…,y_m)$ of symbols one element at a time. At each step the model is auto-regressive [10], consuming the previously generated symbols as additional input when generating the next.

以往的attention虽然也能解决long dependecy的问题,但是受制于RNN的原因,每一步的计算必须在上一时间步完成后进行。因此无法并行计算。

Transformer 也是由 encoder 和 decoder 组成。

Encoder

其中 Encoder 由6个完全相同的layer堆叠(stack)而成。每一层layer由两个 sub-layer 组成,分别是 multi-head self-attention mechanismpoint-wise fully connected feed-forward network. 每一个 sub-layer 应用一个残差连接(residual connection),然后再连接一个 normalization 层。

Decoder

跟 encoder 非常类似,同样由6由6个完全相同的layer堆叠而成,但是每一层有3个 sub-layer, 增加了一个 multi-head attention. 同样的也有残差链接和normalization层。

对 self-attention 进行了修改,masking:

We also modify the self-attention sub-layer in the decoder stack to prevent positions from attending to subsequent positions. This masking, combined with fact that the output embeddings are offset by one position, ensures that the predictions for position i can depend only on the known outputs at positions less than i.

目的应该就是让下一个t时刻的生成词只依赖于t时刻之前的词。

Attention

Really love this short description of attention:

An attention function can be described as mapping a query and a set of key-value pairs to an output, where the query, keys, values, and output are all vectors. The output is computed as a weighted sum of the values, where the weight assigned to each value is computed by a compatibility function of the query with the corresponding key.

Scaled Dot-Product Attention

  • queries: $Q\in R^{n\times d_k}$

  • keys: $K\in R^{n\times d_k}$

  • values: $V\in R^{n\times d_v}$

计算向量內积作为相似度,并使用softmax计算权重,然后加权求和。 这种 attention 其实也很常见了,这里 google 算是给这种结构一个官方的名字吧。

论文中作者还对比了比较常用的另一种attention机制, additive attention (Neural Machine Translation by Jointly Learning to Align and Translate 这篇非常经典的文章中提出的),additive 是使用的前馈神经网络来计算 (具体公式可以看这里cs224d-lecture10 机器翻译和注意力机制). 虽然从计算复杂度上来讲,两者是差不多的,但在实际应用中 dot-product 更快,而且空间复杂度更低,因为可以通过矩阵优化计算。关于attention机制的对比可参考Massive Exploration of Neural Machine Translation Architectures

有一点需要注意的是,这里使用了归一化,也就是 Scaled. 当 $d_k$ 很大时, additive attention 的效果要优于 dot-product attention, 作者怀疑(suspect)是当 $d_k$ 太大时,通过 softmax 计算得到的权重都会很接近0或1,导致梯度很小。

$q\cdot k=\sum_{i=1}^{d_k}q_ik_i$

当 $d_k$ 很大时,$q\cdot k$ 的方差也会很大。

Multi-Head Attention

接下来按照整个模型的数据流过程来介绍模型中的每一个模块。

Components and Training

前面三部分 Encoder, Decoder, Attention 组成了 Transformer 模型的基本架构。其中具体细节,以及 Training 实现过程将通过代码实现。

Encoder

Stage1

Training data and batching

WMT 2014 English-German dataset consisting of about 4.5 million sentence pairs.

作者使用了:

这里我将使用创新工厂举办的 challenge.ai 的中英文比赛数据:https://challenger.ai/datasets/translation

这里暂时先不管数据预处理,在模型中使用占位符 placeholder.

1
2
3
4
5
6
7
8
9
10
11
12
13

# add placeholders

self.input_x = tf.placeholder(dtype=tf.int32, shape=[None, self.sentence_len])

self.input_y = tf.placeholder(dtype=tf.int32, shape=[None, self.sentence_len])



# define decoder inputs

self.decoder_inputs = tf.concat([tf.ones_like(self.input_y[:,:1])*2, self.input_y[:,:-1]],axis=-1) # 2:<S>

  • 这里的sentence_len 指的是源语言句子的最大长度和目标语言句子的最大长度。长度不足的需要zero padding.
  • decoder 中self-attention的 query, keys, values 都是相同的,初始值是随机初始化的,shape 与 self.input_y 一致即可。
Embedding

we use learned embeddings to convert the input tokens and output tokens to vectors of dimension $d_{model}$. In our model, we share the same weight matrix between the two embedding layers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

def embedding(inputs,

vocab_size,

num_units,

zero_pad=True,

scale=True,

reuse=None):

"""



:param inputs: A `Tensor` with type `int32` or `int64` containing the ids

to be looked up in `lookup table`. shape is [batch, sentence_len]

:param vocab_size: vocabulary size

:param num_units: Number of embedding hidden units. in the paper, it is called d_model

:param zero_pad: If True, all the values of the fist row (id 0)

should be constant zeros.

:param scale: If True. the outputs is multiplied by sqrt num_units.

:param reuse: Boolean, whether to reuse the weights of a previous layer

by the same name.

:return:

A `Tensor` with one more rank than inputs's. The last dimensionality

should be `num_units`.



"""

with tf.variable_scope("embedding-layer", reuse=reuse):

embedding = tf.get_variable("embedding", [vocab_size, num_units],

initializer=xavier_initializer())

if zero_pad:

embedding = tf.concat([tf.zeros([1, num_units]),

embedding[1:, :]], axis=0) # index=0 for nil word

output = tf.nn.embedding_lookup(embedding, inputs) # [batch, sentence_len, num_units]

if scale:

output = output * np.sqrt(num_units)



return output

  • 通常embedding我们在写的参数输入 vocab_size 和 num_units(也就是 embed_size),但机器翻译中设计到两种语言,直接定义一个函数,并将input作为输入会让程序更简洁吧。。
  • 这里将vocabulary 中index=0的设置为 constant 0, 也就是作为 input 中的 zero padding 的词向量。
  • 归一化,除以 np.sqrt(num_units). 不懂为何要这么做?有论文研究过吗?
position encoding

pos 是word在句子中的位置, i 是对应 $d_{model}$ 词向量中的第 i 维。

That is, each dimension of the positional encoding corresponds to a sinusoid. The wavelengths form a geometric progression from 2π to 10000 · 2π.

也就是说,位置编码的每个维度对应于正弦曲线。波长形成从2π到10000·2π的几何级数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

def position_encoding_mine(n_position, d_model):

""" Init the sinusoid position encoding table.



:param n_position: the lenght of sentence

:param d_model: the same with embedding

:return:

"""

# keep dim -1 for padding token position encoding zero vector

# pos=-1 用于 padded zero vector

encoding = np.zeros([n_position, d_model], np.float32)

for pos in range(1, n_position):

for i in range(0, d_model):

encoding[pos, i] = pos /np.power(10000, 2.*i/d_model)



encoding[1:-2, 0::2] = np.sin(encoding[1:-2, 0::2]) # dim 2i

encoding[1:-2, 1::2] = np.cos(encoding[1:-2, 1::2]) # dim 2i+1

return encoding



def positional_encoding(inputs,

num_units,

zero_pad=True,

scale=True,

scope="positional_encoding",

reuse=None):

'''Sinusoidal Positional_Encoding.



Args:

inputs: A 2d Tensor with shape of (N, T).

num_units: Output dimensionality

zero_pad: Boolean. If True, all the values of the first row (id = 0) should be constant zero

scale: Boolean. If True, the output will be multiplied by sqrt num_units(check details from paper)

scope: Optional scope for `variable_scope`.

reuse: Boolean, whether to reuse the weights of a previous layer

by the same name.



Returns:

A 'Tensor' with one more rank than inputs's, with the dimensionality should be 'num_units'

'''



N, T = inputs.get_shape().as_list() # N means batch_size, T means the sentence length.

with tf.variable_scope(scope, reuse=reuse):

position_ind = tf.tile(tf.expand_dims(tf.range(T), 0), [N, 1]) # [N, T]

# First part of the PE function: sin and cos argument

position_enc = np.array([

[pos / np.power(10000, 2.*i/num_units) for i in range(num_units)]

for pos in range(T)]) # [T, num_units]



# Second part, apply the cosine to even columns and sin to odds.

position_enc[:, 0::2] = np.sin(position_enc[:, 0::2]) # dim 2i

position_enc[:, 1::2] = np.cos(position_enc[:, 1::2]) # dim 2i+1



# Convert to a tensor

lookup_table = tf.convert_to_tensor(position_enc, dtype=tf.float32)



if zero_pad:

lookup_table = tf.concat((tf.zeros(shape=[1, num_units]),

lookup_table[1:, :]), axis=0)

outputs = tf.nn.embedding_lookup(lookup_table, position_ind) # [N, T, num_units]



if scale:

outputs = outputs * num_units**0.5



return outputs

关于 position encoding 的解释,可以参考这篇blog

The Transformer – Attention is all you need.

In RNN (LSTM), the notion of time step is encoded in the sequence as inputs/outputs flow one at a time. In FNN, the positional encoding must be preserved to represent the time in some way to preserve the positional encoding. In case of the Transformer authors propose to encode time as sine wave, as an added extra input. Such signal is added to inputs and outputs to represent time passing.

In general, adding positional encodings to the input embeddings is a quite interesting topic. One way is to embed the absolute position of input elements (as in ConvS2S). However, authors use “sine and cosine functions of different frequencies”. The “sinusoidal” version is quite complicated, while giving similar performance to the absolute position version. The crux is however, that it may allow the model to produce better translation on longer sentences at test time (at least longer than the sentences in the training data). This way sinusoidal method allows the model to extrapolate to longer sequence lengths.

说真的,还是不太理解。。。

可视化 encoding 矩阵:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

import numpy as np

import matplotlib.pyplot as plt



num_units = 100

sentence_len = 10



i = np.tile(np.expand_dims(range(num_units), 0), [sentence_len, 1]) # (100,)-> (1, 100) ->(10, 100)



pos = np.tile(np.expand_dims(range(sentence_len), 1), [1, num_units]) #(10,)-> (10, 1) -> (10, 100)



pos = np.multiply(pos, 1/10000.0)

i = np.multiply(i, 2.0/num_units)



matrix = np.power(pos, i)



matrix[:, 1::2] = np.sin(matrix[:, 1::2])

matrix[:, ::2] = np.cos(matrix[:, ::2])



im = plt.imshow(matrix, aspect='auto')

plt.show()

Stage2

scaled dot-product attention

$$Attention(Q,K,V)=softmax\dfrac{QK^T}{\sqrt d_k}V$$

Multi-head attention

Transformer reduces the number of operations required to relate (especially distant) positions in input and output sequence to a O(1). However, this comes at cost of reduced effective resolution because of averaging attention-weighted positions.

  • h = 8 attention layers (aka “heads”): that represent linear projection (for the purpose of dimension reduction) of key K and query Q into $d_k$-dimension and value V into $d_v$-dimension:

$$head_i = Attention(Q W^Q_i, K W^K_i, V W^V_i) , i=1,\dots,h$$

其中:

$$W^Q_i, W^K_i\in\mathbb{R}^{d_{model}\times d_k}, W^V_i\in\mathbb{R}^{d_{model}\times d_v}, for\ d_k=d_v=d_{model}/h = 64$$

  • scaled-dot attention applied in parallel on each layer (different linear projections of k,q,v) results in $d_v$-dimensional output.
  • concatenate outputs of each layer (different linear projection; also referred as ”head”): Concat$(head_1,…,head_h)$
  • linearly project the concatenation result form the previous step:

$$MultiHeadAttention(Q,K,V) = Concat(head_1,\dots,head_h) W^O$$

where $W^0\in\mathbb{R}^{d_{hd_v}\times d_{model}}$

关于 attention 在模型中的应用,有三种情况
  • 1.In “encoder-decoder attention” layers, the queries come from the previous decoder layer, and the memory keys and values come from the output of the encoder。
  • 2.The encoder contains self-attention layers. In a self-attention layer all of the keys, values and queries come from the same place, in this case, the output of the previous layer in the encoder. Each position in the encoder can attend to all positions in the previous layer of the encoder.
  • 3.Similarly, self-attention layers in the decoder allow each position in the decoder to attend to all positions in the decoder up to and including that position. We need to prevent leftward information flow in the decoder to preserve the auto-regressive property. We implement this

inside of scaled dot-product attention by masking out (setting to −1) all values in the input of the softmax which correspond to illegal connections.

总结下就是:

Transformer 中的attention机制总共有三种情况:

  • 1.encoder模块中的 self-attention,其中 queries, keys, values 都是来自 input_x, 也就是源语言的词表示。通过多层 multi-head attention, FFN, 得到最后的 input sentence 的向量表示,在没有使用RNN,CNN的情况下,其中的每个词都包含了其他所有词的信息,而且效果比 RNN,CNN 得到的向量表示要好。
  • 2.encoder-encoder模块中的 attention. 其中 queries 来自上一个sub-layer, 也就是 decoder 中 masked multi-head attention 的输出,keys-values 来自 encoder 的输出。
  • 3.decoder模块中的 self-attention,其中 queries, keys, values 都是来自于上一个 decoder 的输出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193

def multiheadattention(q,

k,

v,

d_model,

heads,

keys_mask=None,

causality=None,

dropout_keep_prob=0.1,

is_training=True):

""" multi scaled dot product attention



:param q: A 3d tensor with shape of [batch, length_q, d_k].

:param k: A 3d tensor with shape of [batch, lenght_kv, d_k].

:param v:

:param heads:An int. Number of heads.

:param dropout_keep_prob:

:param causality: If true, units that reference the future are masked.

:return:

"""

# 1. Linear projections

with tf.variable_scope('linear-projection-multiheads'):

q_proj = tf.layers.dense(q, d_model) # [batch, lenght_q, d_model]

k_proj = tf.layers.dense(k, d_model) # [batch, lenght_kv, d_model]

v_proj = tf.layers.dense(v, d_model) # [batch, lenght_kv, d_model]



with tf.variable_scope("multihead-attention"):

# d_k = d_v = d_model/heads

if d_model % heads != 0:

raise ValueError("Key\values\query depth (%d) must be divisible by"

"the number of attention heads (%d)" %(d_model, heads))



# 2. split and concat

q_ = tf.concat(tf.split(q_proj, heads, axis=2), axis=0) # [batch*heads, length_q, d_k]

k_ = tf.concat(tf.split(k_proj, heads, axis=2), axis=0) # [batch*heads, length_kv, d_k]

v_ = tf.concat(tf.split(v_proj, heads, axis=2), axis=0) # [batch*heads, length_kv, d_v]



# 3. attention score

# outputs.shape=[batch*heads, length_q, length_kv]

# 要理解这个矩阵运算,对一个keys的句子长度为length_kv,需要计算的其中的每一个词与query中每一个词的內积。所以最后的score是[length_q, lenght_kv]

scalar = tf.rsqrt(d_model/heads) # 1/sqrt(d_k)

outputs = tf.matmul(q_*scalar, k_, transpose_b=True) # [batch*heads, length_q, lenght_kv]



# 4. mask

if keys_mask is not None:

# `y = sign(x) = -1` if `x < 0`; 0 if `x == 0` or `tf.is_nan(x)`; 1 if `x > 0`.

key_masks = tf.sign(tf.abs(tf.reduce_sum(k, axis=-1))) # (batch, length_kv)

key_masks = tf.tile(key_masks, [heads, 1]) # (batch*heads, length_kv)

key_masks = tf.tile(tf.expand_dims(key_masks, 1), [1, q.get_shape()[1], 1]) # (batch*heads, length_q, length_kv)



# def where(condition, x=None, y=None, name=None)

# The `condition` tensor acts as a mask that chooses, based on the value at each

# element, whether the corresponding element / row in the output should be taken

# from `x` (if true) or `y` (if false).

paddings = tf.ones_like(outputs) * (-2 ** 32 + 1)

outputs = tf.where(tf.equal(key_masks, 0), paddings, outputs) # [batch*heads, length_q, lenght_kv]



# Causality = Future blinding

# causality参数告知我们是否屏蔽未来序列的信息(解码器self attention的时候不能看到自己之后的那些信息),

# 这里即causality为True时的屏蔽操作。

if causality:

diag_vals = tf.ones_like(outputs[0, :, :]) # [length_q, lenght_kv]

tril = LinearOperatorLowerTriangular(diag_vals).to_dense() # [length_q, lenght_kv] 得到一个三角阵,下标index大于当前行的值都变为0

masks = tf.tile(tf.expand_dims(tril, 0), [tf.shape(outputs)[0], 1, 1]) # [batch*heads, length_q, lenght_kv]



paddings = tf.ones_like(masks) * (-2 ** 32 + 1)

outputs = tf.where(tf.equal(masks, 0), paddings, outputs) # [batch*heads, length_q, lenght_kv]



# 将socre转换为概率

outpts = tf.nn.softmax(outputs)



# Query Masking

query_mask = tf.sign(tf.abs(tf.reduce_sum(q, axis=-1, keepdims=False))) # [batch, lenght_q]

query_mask = tf.tile(query_mask, [heads, 1]) # [batch*heads, length_q] # 目的是为了让query和outputs保持形状一致

query_mask = tf.tile(tf.expand_dims(query_mask, axis=-1), [1, 1, tf.shape(k)[-1]]) # [batch*heads, length_q, length_kv]



paddings = tf.ones_like(outputs) * (-2 ** 32 + 1)

outputs = tf.where(tf.equal(query_mask, 0), paddings, outputs) # [batch*heads, length_q, length_kv]



# Dropout

if is_training:

outputs = tf.layers.dropout(outputs, dropout_keep_prob, )



# weights sum

outputs = tf.matmul(outputs, v_) # [batch*heads, length_q, k_v]





# restore shape

outputs = tf.concat(tf.split(outputs, heads, axis=0), axis=-1) #[batch,length_q, k_v*heads] = [batch, lenght_q, d_model]



# Residual connection

outputs += q # [batch, lenght_q, d_model]



# Normalize

outputs = Normalize(outputs)



return outputs # [batch, length_q, d_model]

关于代码的详细解析,可以看这篇blog 机器翻译模型Transformer代码详细解析.

Stage3: Position-wise Feed-Forward Networks

$$FFN(x) = MAX(0, xW_1+b_1)W_2+b_2$$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

def position_wise_feed_forward(inputs,

num_units1=2048,

num_units2=512,

reuse=None):

""" Point-wise feed forward net.



:param inputs: A 3D tensor with shape of [batch, length_q, d_model]

:param num_units1: A integers.

:param num_units2: A integers

:param reuse: Boolean, whether to reuse the weights of a previous layer

by the same name.

:return: A 3d tensor with the same shape and dtype as inputs

"""

with tf.variable_scope("feed-forward-networks"):

# inner layers

params1 = {"inputs":inputs, "filters":num_units1, "kernel_size":1,

"activation":tf.nn.relu, "use_bias":True, "strides":1}

outputs = tf.layers.conv1d(**params1)



# readout layer

params2 = {"inputs":outputs, "filters":num_units2, "kernel_size":1,

"activation":None, "use_bias":True, "strides":1}

outputs = tf.layers.conv1d(**params2)



# residual connection

outputs += inputs



# Normalize

outputs = Normalize(outputs)



return outputs





def position_wise_feed_forward_mine(inputs,

num_units1=2048,

num_units2=512,

reuse=None):

with tf.variable_scope("feed-forward-networks"):

W1 = tf.get_variable("weight1", [inputs.get_shape()[-1], num_units1],initializer=xavier_initializer())

b1 = tf.get_variable('bias1', [num_units1], initializer=tf.constant_initializer(0.1))

outputs = tf.einsum('aij,jk->aik', inputs, W1) + b1 # [batch, length_q, num_units1]



W2 = tf.get_variable("weight1", [outputs.get_shape()[-1], num_units2], initializer=xavier_initializer())

b2 = tf.get_variable('bias1', [num_units2], initializer=tf.constant_initializer(0.1))

outputs = tf.einsum('aij,jk->aik', inputs, W2) + b2 # [batch, length_q, num_units1]





# residual connection

outputs += inputs



# Normalize

outputs = Normalize(outputs)



return outputs

encoder 各模块组合在一起

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

def _encoder(self):

with tf.variable_scope("encoder"):

# 1. embedding

with tf.variable_scope("embedding-layer"):

self.enc = embedding(inputs=self.input_x,

vocab_size=self.vocab_size_cn,

num_units=self.d_model,

scale=True) # [batch, sentence_len, d_model]



# 2. position encoding

with tf.variable_scope("position_encoding"):

encoding = position_encoding_mine(self.enc.get_shape()[1], self.d_model)

self.enc *= encoding



# 3.dropout

self.enc = tf.layers.dropout(self.enc,

rate=self.dropout_keep_prob,

training=self.is_training)



# 4. Blocks

for i in range(self.num_layers):

with tf.variable_scope("num_layer_{}".format(i)):

# multihead attention

# encoder: self-attention

self.enc = multiheadattention(q=self.enc,

k=self.enc,

v=self.enc,

d_model=self.d_model,

heads=self.heads,

causality=False,

dropout_keep_prob=self.dropout_keep_prob,

is_training=True)

# Feed Froward

self.enc = position_wise_feed_forward(self.enc,

num_units1= 4*self.d_model,

num_units2= self.d_model,

reuse=False)

return self.enc

Decoder

decoder 模块中 self-attention 的初始输入:

1
2
3
4
5

# define decoder inputs

self.decoder_inputs = tf.concat([tf.ones_like(self.input_y[:,:1])*2, self.input_y[:,:-1]],axis=-1) # 2:<S>

与encoder 不同的是,分为 encoder-decoder attention 和 self-attention.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

def _decoder(self):

with tf.variable_scope("decoder"):

# embedding

self.dec = embedding(self.decoder_inputs,

vocab_size=self.vocab_size_en,

num_units=self.d_model) # [batch, sentence_len, d_model]



# position decoding

encoding = position_encoding_mine(self.dec.get_shape()[1], self.d_model)

self.dec *= encoding



# blocks

for i in range(self.num_layers):

with tf.variable_scope("num_layers_{}".format(i)):

# self-attention

with tf.variable_scope("self.attention"):

self.dec = multiheadattention(q=self.dec,

k=self.dec,

v=self.dec,

d_model=self.d_model,

heads=self.heads,

keys_mask=True,

causality=True)



# encoder-decoder-attention

with tf.variable_scope("encoder-decoder-attention"):

self.dec = multiheadattention(q=self.dec,

k=self.enc,

v=self.enc,

d_model=self.d_model,

heads=self.heads,

keys_mask=True,

causality=True)



self.dec = position_wise_feed_forward(self.dec,

num_units1= 4*self.d_model,

num_units2= self.d_model) # [batch, sentence_len, d_model]



return self.dec

Optimizer

1
2
3
4
5
6
7
8
9

def add_train_op(self):

self.optimizer = tf.train.AdamOptimizer(self.lr, beta1=0.9, beta2=0.98, epsilon=1e-9)

self.train_op = self.optimizer.minimize(self.loss, global_step=self.global_step)

return self.train_op

Regularization

Residual Dropout
label smoothing

During training, we employed label smoothing of value ls = 0:1 [36]. This hurts perplexity, as the model learns to be more unsure, but improves accuracy and BLEU score.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

def label_smoothing(inputs, epsilon=0.1):

""" Applies label smoothing. See https://arxiv.org/abs/1512.00567



:param inputs: A 3d tensor with shape of [N, T, V], where V is the number of vocabulary.

:param epsilon: Smoothing rate.

For example,

"""

K = inputs.get_shape().as_list()[-1] # number of channels

return ((1-epsilon) * inputs) + (epsilon/K)

Reference:

深度学习-权重初始化

  • 为什么要权重初始化

  • Xavier初始化的推导

权重初始化

In order to avoid neurons becoming too correlated and ending up in poor local minimize, it is often helpful to randomly initialize parameters. 为了避免神经元高度相关和局部最优化,常常需要采用随机初始化权重参数,最常用的就是Xavier initiazation.

为什么我们需要权重初始化?

如果权重参数很小的话,输入信号在前向传播过程中会不断减小(在0到1之间),那么每一层layer都会使得输入变小。同样的道理,如果权重参数过大的话,也会造成前向输入越来越大。这样会带来什么样的后果呢?以激活函数sogmoid为例:

如果以sigmoid为激活函数,我们可以发现,在每一层layer输出 $W^Tx$ ,也就是激活函数的输入,其值越接近于0的时候,函数近似于线性的,因而就失去了非线性的性质。这种情况下,我们就失去了多层神经网络的优势了。

如果初始权重过大,在前向传播的过程中,输入数据的方差variance会增长很快。怎么理解这句话?

以one layer为例,假设输入是 $x\in R^{1000}$, 线性输出是 $y\in R^{100}$.

$$y_j=w_{j,1}x_1+w_{j,2}x_2+…+w_{(j,1000)}x_{1000}$$

x可以看作是1000维的正态分布,每一维 $x_i\sim N(0,1)$, 如果 $w_j$值很大,比如 $w_j=[100,100,…,100]$,那么输出神经元 $y_i$ 的方差就是10000,所以就会很大,均值还是0.

那么激活函数的输入很有可能是一个远小于-1或远大于1的数,通过激活函数所得的值会非常接近于0或者1,也就是隐藏层神经元处于饱和状态(saturated),其梯度也就接近于0了。

所以初始化权重狠狠狠重要。那么应该如何初始化呢,也就是需要保证经过每一层layer,要保证线性输出的方差保持不变。这样就可以避免数值溢出,或是梯度消失。

Xavier Initialization

我们的目的是保持线性输出的方差不变。

以线性输出的一个神经元为例,也就是y的一个维度:

$$y_j=w_{j,1}x_1+w_{j,2}x_2+…+w_{j,N} x_N+b$$

其方差:

$$var(y_j) = var(w_{j,1}x_1+w_{j,2}x_2+…+w_{j,N} x_N+b)$$

其中每一项根据方差公式可得:

$$var(w_{j,i}x_i) = E(x_i)^2var(w_{j,i}) + E(w_{j,i})^2var(xi) + var(w_{j,i})var(x_i)$$

来自维基百科: https://en.wikipedia.org/wiki/Variance

其中我们假设输入和权重都是来自于均值为0的正态分布。

$$var(w_{j,i}x_i)=var(w_{j,i})var(x_i)$$

其中b是常量,那么:

$$var(y_j) = var(w_{j,1})var(x_1) + … + var(w_{j,N})var(x_N)$$

因为 $x_1,x_2,..,x_N$ 都是相同的分布,$W_{j,i}$ 也是,那么就有:

$$var(y_j) = N * var(w{j,i}) * var(x_i)$$

可以看到,如果输入神经元数目N很大,参数权重W的值也很大的话,会造成线性输出的值的方差很大。

我们需要保证 $y_j$ 的方差和 $x_j$ 的方差一样,所以:

$$N*var(W_{j,i})=1$$

$$var(W_{j,i})=1/N$$

There we go! 这样我们就得到了Xavier initialization的初始化公式,也就是说参数权重初始化为均值为0,方差为 1/N 的高斯分布,其中N表示当前层输入神经元的个数。在caffe中就是这样实现的。

更多初始化方式

Understanding the difficulty of training deep feedforward neural networks 在这篇paper中提出

$$var(w)=2/(N_{in}+N_{out})$$

Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification 针对一种专门的初始化方式,使得 $var(w)=2.0/N$, 在实际工程中通常使用这种方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

### 正态分布

w = np.random.randn(N) * sqrt(2.0/N)

### 均匀分布

def _xavier_initializer(shape, **kwargs):

"""

Args:

shape: Tuple or 1-d array that species dimensions of requested tensor.

Returns:

out: tf.Tensor of specified shape sampled from Xavier distribution.

"""

epsilon = np.sqrt(6/np.sum(shape))

out = tf.Variable(tf.random_uniform(shape=shape, minval=-epsilon, maxval=epsilon))

return out

均匀分布[a,b]的方差:$\dfrac{(b-a)^2}{12}$

参考资料:

深度学习-Dropout

dropout的数学原理。

Dropout

随机失活(Dropout)

是一个简单又极其有效的正则化方法。该方法由Srivastava在论文Dropout: A Simple Way to Prevent Neural Networks from Overfitting中提出的,与L1正则化,L2正则化和最大范式约束等方法互为补充。在训练的时候,随机失活的实现方法是让神经元以超参数p的概率被激活或者被设置为0。

在训练过程中,随机失活可以被认为是对完整的神经网络抽样出一些子集,每次基于输入数据只更新子网络的参数(然而,数量巨大的子网络们并不是相互独立的,因为它们都共享参数)。在测试过程中不使用随机失活,可以理解为是对数量巨大的子网络们做了模型集成(model ensemble),以此来计算出一个平均的预测。

关于dropout的理解:知乎上的回答

python代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

""" 普通版随机失活: 不推荐实现 (看下面笔记) """



p = 0.5 # 激活神经元的概率. p值更高 = 随机失活更弱



def train_step(X):

""" X中是输入数据 """



# 3层neural network的前向传播

H1 = np.maximum(0, np.dot(W1, X) + b1)

U1 = np.random.rand(*H1.shape) < p # 第一个随机失活遮罩,rand() [0,1)的随机数

H1 *= U1 # drop!

H2 = np.maximum(0, np.dot(W2, H1) + b2)

U2 = np.random.rand(*H2.shape) < p # 第二个随机失活遮罩

H2 *= U2 # drop!

out = np.dot(W3, H2) + b3



# 反向传播:计算梯度... (略)

# 进行参数更新... (略)



def predict(X):

# 前向传播时模型集成

H1 = np.maximum(0, np.dot(W1, X) + b1) * p # 注意:激活数据要乘以p

H2 = np.maximum(0, np.dot(W2, H1) + b2) * p # 注意:激活数据要乘以p

out = np.dot(W3, H2) + b3

在上面的代码中,train_step函数在第一个隐层和第二个隐层上进行了两次随机失活。在输入层上面进行随机失活也是可以的,为此需要为输入数据X创建一个二值的遮罩。反向传播保持不变,但是肯定需要将遮罩U1和U2加入进去。

注意:在predict函数中不进行随机失活,但是对于两个隐层的输出都要乘以p,调整其数值范围。这一点非常重要,因为在测试时所有的神经元都能看见它们的输入,因此我们想要神经元的输出与训练时的预期输出是一致的。以p=0.5为例,在测试时神经元必须把它们的输出减半,这是因为在训练的时候它们的输出只有一半。为了理解这点,先假设有一个神经元x的输出,那么进行随机失活的时候,该神经元的输出就是px+(1-p)0,这是有1-p的概率神经元的输出为0。在测试时神经元总是激活的,就必须调整x\to px来保持同样的预期输出。在测试时会在所有可能的二值遮罩(也就是数量庞大的所有子网络)中迭代并计算它们的协作预测,进行这种减弱的操作也可以认为是与之相关的。

反向随机失活

它是在训练时就进行数值范围调整,从而让前向传播在测试时保持不变。这样做还有一个好处,无论你决定是否使用随机失活,预测方法的代码可以保持不变。反向随机失活的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

"""

反向随机失活: 推荐实现方式.

在训练的时候drop和调整数值范围,测试时不做任何事.

"""



p = 0.5 # 激活神经元的概率. p值更高 = 随机失活更弱



def train_step(X):

# 3层neural network的前向传播

H1 = np.maximum(0, np.dot(W1, X) + b1)

U1 = (np.random.rand(*H1.shape) < p) / p # 第一个随机失活遮罩. 注意/p!

H1 *= U1 # drop!

H2 = np.maximum(0, np.dot(W2, H1) + b2)

U2 = (np.random.rand(*H2.shape) < p) / p # 第二个随机失活遮罩. 注意/p!

H2 *= U2 # drop!

out = np.dot(W3, H2) + b3



# 反向传播:计算梯度... (略)

# 进行参数更新... (略)



def predict(X):

# 前向传播时模型集成

H1 = np.maximum(0, np.dot(W1, X) + b1) # 不用数值范围调整了

H2 = np.maximum(0, np.dot(W2, H1) + b2)

out = np.dot(W3, H2) + b3

在随机失活发布后,很快有大量研究为什么它的实践效果如此之好,以及它和其他正则化方法之间的关系。如果你感兴趣,可以看看这些文献:

Dropout paper by Srivastava et al. 2014.

Dropout Training as Adaptive Regularization:“我们认为:在使用费希尔信息矩阵(fisher information matrix)的对角逆矩阵的期望对特征进行数值范围调整后,再进行L2正则化这一操作,与随机失活正则化是一阶相等的。”

机器学习中的一些 tricks

L2正则化的数学原理

L2正则化:

To avoid parameters from exploding or becoming highly correlated, it is helpful to augment our cost function with a Gaussian prior: this tends to push parameter weights closer to zero, without constraining their direction, and often leads to classifiers with better generalization ability.

If we maximize log-likelihood (as with the cross-entropy loss, above), then the Gaussian prior becomes a quadratic term 1 (L2 regularization):

$$J_{reg}(\theta)=\dfrac{\lambda}{2}[\sum_{i,j}{W_1}{i,j}^2+\sum{i’j’}{W_2}_{i,j}^2]$$

可以证明: 

$$W_{ij} ∼ N (0; 1=λ)$$

从两种角度理解正则化:知乎

RNN为什么容易出现梯度消失和梯度爆炸问题

relu为啥能有效的解决梯度消失的问题

很难理解为啥用relu能很好的解决梯度消失的问题,的确relu的梯度为1,但这也太简单了吧。。。所以得看看原论文 A Simple Way to Initialize Recurrent Networks of Rectified Linear Units