• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

GenerationMixin类

武飞扬头像
LawsonAbs
帮助1

1. GenerationMixin

这个类的源码中给了这么一个博客链接: https://huggingface.co/blog/how-to-generate 。对生成的理解大有帮助。我总结一下这个博客的内容如下:

  • 自回归的假设是:整条句子的概率其实就是条件概率的乘积
  • 生成的句子的长度其实是动态决定的。
  • 文中列出了几种解码策略:Greedy Search Beam Search Top-K sampling top-p sampling
    在贪心策略和束搜索中,会导致一个重复生成的问题。也就是下面这样:

Output:
I enjoy walking with my cute dog, but I’m not sure if I’ll ever be able to walk with my dog. I’m not sure if I’ll ever be able to walk with my dog.
I’m not sure if I’ll…

解决这个重复生成的问题,就是采用n-grams 的策略。就是让生成的文本中,限制ngrams 重复出现的次数。
beam search 不适合开放域生成。这个文章讲的也是比较浅显,但是易懂~

学新通
今天在用Bart做生成的时候,发现model.generate() 方法,发现原来是PreTrainedModel 这个基类继承了GenerationMixin,而这个类则是用于生成方法的基类。下面看看源码的执行步骤:
学新通
学新通
其中这里的 inputs 就是平常我们tokenizer之后的 input_ids,其shape大小是 [bsz,hidden_dim]。bos_token_id = 0

学新通
看一下 attention_mask 的属性
学新通
这个 attention_mask 是给encoder使用的。上面这个流程会判断:如果模型是encoder_decoder 架构,那么就要事先把encoder的结果算出来。也就是如下这行代码:

 if self.config.is_encoder_decoder and "encoder_outputs" not in model_kwargs:
      #if model is encoder decoder encoder_outputs are created
      # and added to `model_kwargs`
      model_kwargs = self._prepare_encoder_decoder_kwargs_for_generation(
          inputs_tensor, model_kwargs, model_input_name
      )

其中的这个 _prepare_encoder_decoder_kwargs_for_generation()函数如下:
学新通
将encoder的结果写到 model_kwargs 中。下面就紧接着准备 decoder_input_ids ,这是给生成做的。主要是调用 _prepare_decoder_input_ids_for_generation()这个函数
学新通

学新通
看下这个具体的函数逻辑:

  • 如果decdoer_input_ids 在模型中,那么就直接返回这个decoder_input_ids,
  • 否则创建一个shape 为 (batch_size,1)的 tensor,其中的值为1*decoder_start_token_id

计算完这个之后,就可以得到 input_ids_seq_length,也就是输入到decoder的decoder_input_ids的第二个维度的值。在这里就是1。
学新通
调整完生成的文档的长度之后,需要再判断目前用什么模式生成文本。
学新通
接着,定义一个logits的处理器,用于在计算得到logits之后,再做一些修改。
学新通
然后定义一个生成结束的条件
学新通

最后就进入到生成的核心模块了,因为我这里选用的是beam search 作为最后的生成方法。
学新通

== 那么这里面的 BeamSearchScorer 是干嘛的?==

学新通
上面这个 _expand_inputs_for_generation()我也不是很清楚原因。

但造成的结果是 input_ids 和 model_kwargs 中的attention_mask, encoder_outputs 都从之前的[bsz,…] 变成了 [bsz*num_beams,…] 维度。最后就是执行 beam_search 的过程了。
学新通

进入到beam_search之后,主要的是下面这个while循环
学新通
学新通
outputs.logits.size (bsznum_beams,1,|V|) => (bsznum_beam,|V|)

然后对生成的结果做一个 softmax 操作:
学新通

得到得到了softmax之后的分数还不算完,还需要是用 LogitProcessor 进行处理。
学新通
上面这行代码会对应执行下面几个类的处理:
学新通
紧接着调用下面这个 LogitsProcessor
学新通
学新通

在对scores处理之后,需要加上beam_score?这又是为啥?
beam_scores[:,None] 便从 bsz * num_beam 变成了 [bsz*num_beams,1]

学新通
这里的topk操作结合了下面这几个参数:

  • largest表示的是是否返回最大值,如果为false,就代表返回最小值
  • 2*num_beams 代表的就是k的值

得到的next_token_scores 就是一个 维度大小为[bsz,2*num_beams] 的一个值。(为啥是 2*num_beams 不清楚)。

学新通
torch_int_div 是一个整除的方法,可能不同的torch版本,实现的方法有些不同,所以这里搞成了 torch_int_div 的方式来实现。【但是不清楚为啥要得到 next_indices】
学新通
这个process方法就会调用 BeamSearchScorer 类的 process 方法。
学新通

学新通
学新通
学新通

下面看看这个 prepare_inputs_for_generation

讲一下 cache 生成的细节,涉及到的代码主要是在 BartDecoder的forward方法中,主要由下面这几行构成
学新通
decoder_layer() 方法中的 hidden_states 就是decoder_input_ids 映射得到的embedding。

再进入到 BartDecoderLayer 的forward方法,可以看到其实past_key_value 包括了两个部分的key_value,分别是self attention 和 cross_attention 中的。
学新通
这存的是K 和 V的值,K和V的值是通过hidden_states 经过一个线性矩阵映射过来的。

为什么要有这个cache?
什么时候用?
怎么用的?

再看下面这张图:
学新通
这里cross_attention 的key_states, value_states 其实始终如一。这个很好理解,因为 cross_attention 对于每层decoder都是同一个K,V。但是对于不同层的decoder的 self-attention 的 key,value 都是不同的。所以这里都是先计算一下当前的这个 key_states 和 value_states,然后再拼接回去。这也就说明,在decoder的self-attention中,每次的hidden_states 都是一个单词的hidden states?

再看下:greedy_search() 这个函数
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhiagikh
系列文章
更多 icon
同类精品
更多 icon
继续加载