Perplexity in language model

1.PPL

PPL是用在自然语言处理领域(NLP)中,衡量语言模型好坏的指标。它主要是根据每个词来估计一句话出现的概率,并用句子长度作normalize,公式为

 

由公式可知,perplexity越小,模型越好。从公式最后一部分,感觉更像是描述GPT这种生成模型。

2.Language Model

  • autoregressive (AR) language model

GPT:

 

  • autoencoding (AE)language model

BERT(denoising auto-encoding):

where mt = 1 indicates xt is masked.

3.Reference

[论文笔记][2020-WWW]Enhanced-RCNN: An Efficient Method for Learning Sentence Similarity

前面的Related可以用来做综述

一、Architecture

二、Detail

1.Input Encoding

(a)RNN Encoder

(b)CNN Encoder

2.Interactive Sentence Representation

(a)Soft-attention Alignment(类似于ESIM)

(b)Interaction Modeling

3.Similarity Modeling

(a)Fusion Layer

(b)Label Prediction

MLP+softmax

三、Reference

文本生成中的解码策略

一.Language model decoding

given a sequence of m tokens as context, the task is to generate the next n continuation tokens to obtain the completed sequence . We assume that models compute using the common left-to-right decomposition of the text probability,

which is used to generate the generation token-by-token using a particular decoding strategy

二.Decoding Strategies

1.Maximization-based decoding

解码器的输出层后面通常会跟一个softmax函数来将输出概率归一化。如果词表比较大的话,softmax的计算复杂度会比较高(分母需要计算整个词表大小的维度)

  • Greedy decoding

每次选最高概率的一项作为输出,直到遇到结束符号,将这些输出的概率相乘,得到该sequence的概率。

缺点:每次选择都是最大的,但是整体的概率不一定是最大的,有可能错过最优的结果

考虑到`Beam Size=2`,第一步选择概率最大的两个A和B,第二步选择AB和BB(橙色大箭头)。然后以选择的AB和BB继续向上传播,又出现了四种情况ABA/ABB/BBA/BBB,依然是选择综合概率最大的两个ABB/BBB。以此类推,直至句子结束。

缺点:

    • 由于beam search的概率是一個连续相乘的結果,越早遇到结束符号,所得到的概率会越大,所以更倾向于生成短文本。解决办法是对输出概率取log,然后相加,最终结果除长度求最大概率((a * b)^ 1/2  ==》 1/2*(loga + logb)相当于概率相乘然后开方)。
    • beam size过大会导致计算复杂度过高,时间复杂度为O(N*b*V),N为序列长度,b为beam size,v为词表大小
    • 语言模型通常为格式良好的文本分配高分,但较长文本的最高分往往是通用的、重复的和尴尬的。beam search的输出,与人讲话的概率分布,很不一样。

2.Stochastic Decoding

  • Sampling with temperature

解码器的输出层计算softmax时,通过改变T可以控制概率的形貌。当t大的时候,概率分布趋向平均,随机性增大(uniform sampling/pure sampling);当t小的时候,概率密度趋向于集中,即强者愈强,随机性降低(poisson distribution/greedy decoding)。
实验证明,降低t会改善生成的质量,但是会降低生成的多样性。
  • Top-k Sampling

从词表选择topk个词,使得概率之和最大,即

缺点:k的取值难以界定。k太小,会生成比较bland和generic的结果,即缺乏diversity;k太大,会退化成随机sampling(pure sampling),会陷入语义表达错误,即sample from tail distribution

  • Top-p Sampling(nucleus sampling)

丛词表选择概率之和大于给定阈值p的词,即

采样集的大小将根据每个时间步长的概率分布动态调整。对于高的阈值来说,这一个小部分的词汇,就占据了绝大多数的概率—-核。

三.Implementation

def top_k_top_p_filtering(logits, top_k=0, top_p=0.0, filter_value=-float('Inf')):
    """ Filter a distribution of logits using top-k and/or nucleus (top-p) filtering
        Args:
            logits: logits distribution shape (vocabulary size)
            top_k >0: keep only top k tokens with highest probability (top-k filtering).
            top_p >0.0: keep the top tokens with cumulative probability >= top_p (nucleus filtering).
                Nucleus filtering is described in Holtzman et al. (http://arxiv.org/abs/1904.09751)
    """
    assert logits.dim() == 1  # batch size 1 for now - could be updated for more but the code would be less clear
    top_k = min(top_k, logits.size(-1))  # Safety check
    if top_k > 0:
        # Remove all tokens with a probability less than the last token of the top-k
        indices_to_remove = logits < torch.topk(logits, top_k)[0][..., -1, None]
        logits[indices_to_remove] = filter_value

    if top_p > 0.0:
        sorted_logits, sorted_indices = torch.sort(logits, descending=True)
        cumulative_probs = torch.cumsum(F.softmax(sorted_logits, dim=-1), dim=-1)

        # Remove tokens with cumulative probability above the threshold
        sorted_indices_to_remove = cumulative_probs > top_p
        # Shift the indices to the right to keep also the first token above the threshold
        sorted_indices_to_remove[..., 1:] = sorted_indices_to_remove[..., :-1].clone()
        sorted_indices_to_remove[..., 0] = 0

        indices_to_remove = sorted_indices[sorted_indices_to_remove]
        logits[indices_to_remove] = filter_value
    return logits

# Here is how to use this function for top-p sampling
temperature = 1.0
top_k = 0
top_p = 0.9

# Get logits with a forward pass in our model (input is pre-defined)
logits = model(input)

# Keep only the last token predictions of the first batch item (batch size 1), apply a temperature coefficient and filter
logits = logits[0, -1, :] / temperature
filtered_logits = top_k_top_p_filtering(logits, top_k=top_k, top_p=top_p)

# Sample from the filtered distribution
probabilities = F.softmax(filtered_logits, dim=-1)
next_token = torch.multinomial(probabilities, 1)

四.Reference

Beam search

1.简单实现

import torch

# Beam  search
samples = []
topk = 10
log_prob, v_idx = decoder_outputs.detach().topk(topk)
for k in range(topk):
    samples.append([[v_idx[0][k].item()], log_prob[0][k], decoder_state])
for i in range(max_len):
    new_samples = []
    for sample in samples:
        v_list, score, decoder_state = sample
        if v_list[-1] == de_vocab.item2index['_EOS_']:
            new_samples.append([v_list, score, decoder_state])
            continue

        decoder_inputs = torch.LongTensor([v_list[-1]])
        decoder_outputs, new_states = decoder(decoder_inputs, encoder_output, decoder_state)
        log_prob, v_idx = decoder_outputs.data.topk(topk)

        for k in range(topk):
            new_v_list = []
            new_v_list += v_list + [v_idx[0][k].item()]
            new_samples.append([new_v_list, score + log_prob[0][k], new_states])

    new_samples = sorted(new_samples, key=lambda sample: sample[1], reverse=True)
    samples = new_samples[:topk]
    
v_list, score, states = samples[0]
for v_idx in v_list:
    pred_sent.append(de_vocab.index2item[v_idx])

2.transformers实现

Seq2Seq

一.概述

  • Seq2Seq是一个Encoder-Deocder结构的模型,输入是一个序列,输出也是一个序列。
  • Encoder将一个可变长度的输入序列变为固定长度的向量,Decoder将这个固定长度的向量解码成可变长度的输出序列。
  • 使用表示输入语句, 代表输出语句,yt代表当前输出词。所有的Seq2Seq模型都是以下目标函数,都是为了优化这个函数:
为了防止数值下溢(p连乘积趋向于0),使用log代替,即

二.改进

Seq2Seq的核心部分是其解码部分,大部分改进基于此:
    • greedy search:基础解码方法
    • beam search:对greedy search的改进
    • attention:它的引入使得解码时,每一步可以有针对地关注与当前有关的编码结果,从而减小了编码器输出表示的学习难度,也更容易学到长期的依赖关系。
    • memory network:从外部获取知识。
    • 其他方法:
      • 堆叠多层RNN的Decoder
      • 增加dropout机制
      • 与Encoder建立残差连接

三.其他以及问题

  • Attention:使得解码时,能够建立长距离依赖,更好地融入encoder的信息,使解码时每一步可以有针对地关注与当前有关的编码结果。
  • 双向RNN:单向RNN中,𝑖只包含了𝑥0𝑥𝑖的信息,𝑎𝑖𝑗丢失了𝑥𝑖后面的信息;而双向RNN中,第𝑖个输入词对应的隐状态包括了𝑖h←i,前者编码了𝑥0𝑥𝑖的信息,后者编码了𝑥𝑖及之后的信息,防止信息丢失;(捕捉上下文双向语义,)
    • 否定在后(I would like to, but I have to go school.)
    • 上文缺失,无法解码当前的位置,就可以使用下文来辅导解码
  • 如何增加多样性?

四.训练

  • Teacher forcing:根据标准答案来decode的方式(减少模型发散,加快收敛速度,但是减少生成的多样性,而且会出现矫枉过正导致不通顺
  • Autoregressive:根据上一步的输出作为下一步输入的decode方式(无法并行)
  • Exposure bias:训练Teacher forcing和测试只能Autoregressive,带来的结果来自于不同的分布,并且在测试时,如果某一步出现错误,那么错误就会一直累积(因为训练时前一个单词总是正确的),正所谓“一步错,步步错”,最终导致生成不正确的文本。
  • Scheduled Sampling
    • 模型在训练过程中的每一个steps,有 [公式] 的概率选择使用 teacher-forcing,有 [公式] 的概率选择使用 Autoregressive。
    • 模型在训练前期, [公式] 应该尽可能的大,这样能够加速收敛;而在快要结束训练的时候, [公式] 尽可能的小,让模型在 Autoregressive 的方案中尽可能的修复自身生成的错误。(这个 [公式] 概率可以随着训练的Steps or Epoch 进行衰减)

五.参考