当前位置: 首页 > article >正文

Chapter5.3 Decoding strategies to control randomness

文章目录

  • 5 Pretraining on Unlabeled Data
    • 5.3 Decoding strategies to control randomness
      • 5.3.1 Temperature scaling
      • 5.3.2 Top-k sampling
      • 5.3.3 Modifying the text generation function

5 Pretraining on Unlabeled Data

5.3 Decoding strategies to control randomness

  • 以下是重新组织并精简后的内容:

    在本节中,我们将介绍文本生成策略(也称为解码策略)以生成更具原创性的文本。首先,简要回顾前一章的 generate_text_simple 函数,该函数之前用于 generate_and_print_sample 中。接着,介绍两种改进该函数的技术:

    1. 温度调节(temperature scaling)
    2. top-k 采样(top-k sampling).

  • 我们首先将模型从 GPU 转移回 CPU,因为对于相对较小的模型来说,推理(inference)不需要 GPU。此外,在训练结束后,我们将模型设置为评估模式(evaluation mode),以关闭随机组件,例如 dropout。接下来,我们将 GPTModel 实例(模型)插入到generate_text_simple函数中,该函数使用 LLM 一次生成一个token:

    model.to("cpu")
    model.eval()
    
    tokenizer = tiktoken.get_encoding("gpt2")
    
    token_ids = generate_text_simple(
        model=model,
        idx=text_to_token_ids("Every effort moves you", tokenizer),
        max_new_tokens=25,
        context_size=GPT_CONFIG_124M["context_length"]
    )
    
    print("Output text:\n", token_ids_to_text(token_ids, tokenizer))
    
    """输出"""
    Output text:
     Every effort moves you?"
    
    "Yes--quite insensible to the irony. She wanted him vindicated--and by me!"
    

    我们已知,在每个生成步骤中选择生成的标记,对应于词汇表中所有标记中的最大概率分数。这意味着即使我们在同一台计算机上多次运行上面的 generate_text_simple 函数,大语言模型(LLM)也将始终生成相同的输出。 因此,后续两个小节介绍的两个概念,用于控制生成文本的随机性和多样性:温度调节(temperature scaling)和 top-k 采样(top-k sampling)。

5.3.1 Temperature scaling

  • 此前,在generate_text_simple函数中,我们总是使用torch.argmax采样概率最高的token作为下一个token,这种方式也被称为greedy decoding。为了生成更多样化的文本,我们可以将argmax替换为一个从概率分布中采样的函数torch.multinomial(probs, num_samples=1)(这里的概率分布是指LLM在每一步token生成时为词汇表中每个条目生成的概率分数)。

    为了通过具体示例说明概率采样,我们简要讨论下一个标记生成过程,并使用一个非常小的词汇表进行说明

    vocab = { 
        "closer": 0,
        "every": 1, 
        "effort": 2, 
        "forward": 3,
        "inches": 4,
        "moves": 5, 
        "pizza": 6,
        "toward": 7,
        "you": 8,
    } 
    
    inverse_vocab = {v: k for k, v in vocab.items()}
    
    # 假设 LLM 被赋予起始上下文“every effort moves you”,并生成以下下一个令牌逻辑
    next_token_logits = torch.tensor(
        [4.51, 0.89, -1.90, 6.75, 1.63, -1.62, -1.89, 6.28, 1.79]
    )
    
    probas = torch.softmax(next_token_logits, dim=0)
    next_token_id = torch.argmax(probas).item()
    
    # The next generated token is then as follows:
    print(inverse_vocab[next_token_id])
    
    """输出"""
    forward
    

    由于最大的 logit 值以及相应的最大的 softmax 概率得分位于第四个位置(索引位置 3,因为 Python 使用 0 索引),因此生成的单词是“forward”。

    为了实现概率采样过程,我们现在可以替换argmax 与 PyTorch 中的multinomial函数:

    torch.manual_seed(123)
    next_token_id = torch.multinomial(probas, num_samples=1).item()
    print(inverse_vocab[next_token_id])
    
    """输出"""
    toward
    

    我们使用torch.multinomial(probas, num_samples=1)从softmax分布中采样确定最可能的token,而非直接使用torch.argmax。为便于说明,观察使用原始softmax概率对下一个token进行1,000次采样的结果

    def print_sampled_tokens(probas):
        torch.manual_seed(123) # Manual seed for reproducibility
        sample = [torch.multinomial(probas, num_samples=1).item() for i in range(1_000)]
        sampled_ids = torch.bincount(torch.tensor(sample))
        for i, freq in enumerate(sampled_ids):
            print(f"{inverse_vocab[i]}\t x \t {freq}")
    
    print_sampled_tokens(probas)
    
    """输出"""
    closer	 x 	 71
    every	 x 	 2
    effort	 x 	 0
    forward	 x 	 544
    inches	 x 	 2
    moves	 x 	 1
    pizza	 x 	 0
    toward	 x 	 376
    you	 x 	 4
    

    从输出中可以看出,单词“forward”被采样的次数最多(1000次中有544次),但是其他token如closer,toward偶尔也会被采样。这意味着,如果我们在generate_and_print_sample函数中用multinomial函数替换argmax函数,LLM有时会生成诸如“every effort moves you toward”“every effort moves you inches”和“every effort moves you closer”的文本,而不仅仅是“every effort moves you forward”。

  • 我们可以通过一种称为“temperature scaling”的概念进一步控制分布和选择过程,其中“temperature scaling”只是一个花哨的描述,指的是将logits除以一个大于0的数:

    def softmax_with_temperature(logits, temperature):
        scaled_logits = logits / temperature
        return torch.softmax(scaled_logits, dim=0)
    
    # Temperature values
    temperatures = [1, 0.1, 5]  # Original, higher confidence, and lower confidence
    
    # Calculate scaled probabilities
    scaled_probas = [softmax_with_temperature(next_token_logits, T) for T in temperatures]
    
    # Plotting
    x = torch.arange(len(vocab))
    bar_width = 0.15
    
    fig, ax = plt.subplots(figsize=(5, 3))
    for i, T in enumerate(temperatures):
        rects = ax.bar(x + i * bar_width, scaled_probas[i], bar_width, label=f'Temperature = {T}')
    
    ax.set_ylabel('Probability')
    ax.set_xticks(x)
    ax.set_xticklabels(vocab.keys(), rotation=90)
    ax.legend()
    
    plt.tight_layout()
    plt.savefig("temperature-plot.pdf")
    plt.show()
    

    温度值大于1会导致token概率分布更加均匀,而温度值小于1则会导致分布更加集中(更尖锐或更突出)我们通过绘制原始概率与不同温度值缩放后的概率来直观说明这一点:

    image-20250104221727704

    我们可以看到

    1. 温度值为1时等同于无缩放,token选择概率与原始softmax一致;

      print_sampled_tokens(scaled_probas[0]) # temperature=1
      
      """输出"""
      closer	 x 	 71
      every	 x 	 2
      effort	 x 	 0
      forward	 x 	 544
      inches	 x 	 2
      moves	 x 	 1
      pizza	 x 	 0
      toward	 x 	 376
      you	     x 	 4
      
    2. 温度值小于1(如0.1)时分布更尖锐,接近torch.argmax的效果,几乎总是选择最可能的token;

      print_sampled_tokens(scaled_probas[1]) # temperature=0.1
      
      """输出"""
      closer	 x 	 0
      every	 x 	 0
      effort	 x 	 0
      forward	 x 	 992
      inches	 x 	 0
      moves	 x 	 0
      pizza	 x 	 0
      toward	 x 	 8
      
    3. 温度值大于1(如5)时分布更均匀,增加文本多样性但可能导致无意义内容,如

      every effort moves you pizza(pizza出现了43次,概率为4.3%)

      print_sampled_tokens(scaled_probas[2]) # temperature=5
      
      """输出"""
      closer	 x 	 153
      every	 x 	 68
      effort	 x 	 55
      forward	 x 	 223
      inches	 x 	 102
      moves	 x 	 50
      pizza	 x 	 43
      toward	 x 	 218
      you	     x 	 88
      

5.3.2 Top-k sampling

  • 在上一节中,我们通过结合温度缩放的概率采样方法增加了输出多样性,较高温度值使token分布更均匀,减少重复选择最可能token的情况,从而探索更具创造性的路径,但这种方法有时会导致语法错误或完全无意义的输出(如“every effort moves you pizza”)。

    为了能够使用较高的温度值来增加输出多样性并减少无意义句子的概率,我们可以将采样的token限制在top-k最可能的token中:

    使用 k=3 的 top-k 采样,我们关注与最高 logits 相关的 3 个标记,并在应用 softmax 函数之前屏蔽掉所有其他具有负无穷大 (-inf) 的标记。这会导致概率分布的概率值为 0 分配给所有非前 k 个标记。

  • 在代码中实现上图中概述的 top-k 过程

    首先选择具有最大 logit 值的标记:

    top_k = 3
    top_logits, top_pos = torch.topk(next_token_logits, top_k)
    
    print("Top logits:", top_logits)
    print("Top positions:", top_pos)
    
    """输出"""
    Top logits: tensor([6.7500, 6.2800, 4.5100])
    Top positions: tensor([3, 7, 0])
    

    随后,我们应用 PyTorch 的 where 函数将低于 top-3 选择中最低 logit 值的标记的 logit 值设置为负无穷大 (-inf)

    new_logits = torch.where(
        condition=next_token_logits < top_logits[-1],
        input=torch.tensor(float("-inf")), 
        other=next_token_logits
    )
    # 或者
    # new_logits = torch.full_like( # 创建一个包含-inf值的张量  
    #    next_token_logits, -torch.inf  
    # )   
    # new_logits[top_pos] = next_token_logits[top_pos] # 将top k值复制到-inf张量中  
    
    print(new_logits)
    
    
    """输出"""
    tensor([4.5100, -inf, -inf, 6.7500, -inf, -inf, -inf, 6.2800, -inf])
    

    最后,让我们应用 softmax 函数将它们转换为下一个标记的概率:

    topk_probas = torch.softmax(new_logits, dim=0)
    print(topk_probas)
    
    """输出"""
    tensor([0.0615, 0.00, 0.00, 0.5775, 0.00, 0.00, 0.00, 0.3610, 0.00])
    

5.3.3 Modifying the text generation function

  • 前两小节介绍了温度采样(temperature sampling)和top-k采样(top-k sampling),我们将利用这两个概念修改之前用于通过LLM生成文本的generate_simple函数,创建一个新的generate函数。

    def generate(model, idx, max_new_tokens, context_size, temperature=0.0, top_k=None, eos_id=None):
    
        # For-loop is the same as before: Get logits, and only focus on last time step
        for _ in range(max_new_tokens):
            idx_cond = idx[:, -context_size:]
            with torch.no_grad():
                logits = model(idx_cond)
            logits = logits[:, -1, :]
    
            # New: Filter logits with top_k sampling
            if top_k is not None:
                # Keep only top_k values
                top_logits, _ = torch.topk(logits, top_k)
                min_val = top_logits[:, -1]
                logits = torch.where(logits < min_val, torch.tensor(float("-inf")).to(logits.device), logits)
    
            # New: Apply temperature scaling
            if temperature > 0.0:
                logits = logits / temperature
    
                # Apply softmax to get probabilities
                probs = torch.softmax(logits, dim=-1)  # (batch_size, context_len)
    
                # Sample from the distribution
                idx_next = torch.multinomial(probs, num_samples=1)  # (batch_size, 1)
    
            # Otherwise same as before: get idx of the vocab entry with the highest logits value
            else:
                idx_next = torch.argmax(logits, dim=-1, keepdim=True)  # (batch_size, 1)
    
            if idx_next == eos_id:  # Stop generating early if end-of-sequence token is encountered and eos_id is specified
                break
    
            # Same as before: append sampled index to the running sequence
            idx = torch.cat((idx, idx_next), dim=1)  # (batch_size, num_tokens+1)
    
        return idx
    

    更改完成后,看看这个新生成函数的实际效果

    torch.manual_seed(123)
    
    token_ids = generate(
        model=model,
        idx=text_to_token_ids("Every effort moves you", tokenizer),
        max_new_tokens=15,
        context_size=GPT_CONFIG_124M["context_length"],
        top_k=25,
        temperature=1.4
    )
    
    print("Output text:\n", token_ids_to_text(token_ids, tokenizer))
    
    """输出"""
    Output text:
     Every effort moves you know began to my surprise, poor StI was such a good; and
    

    下面的是我们先前生成的output

     Every effort moves you?"
    
    "Yes--quite insensible to the irony. She wanted him vindicated--and by me!"
    

    可以对比一下,已经有很大的不同了。



http://www.kler.cn/a/505414.html

相关文章:

  • ubuntu支持中文的字体
  • css实现响应式详解
  • C++算法第十五天
  • Flink 应用
  • 《零基础Go语言算法实战》【题目 2-30】并发安全问题
  • w160社区智慧养老监护管理平台设计与实现
  • 论文阅读:Searching for Fast Demosaicking Algorithms
  • 从语音识别到语音合成:一步步构建智能语音交互系统
  • (12)springMVC文件的上传
  • pytorch快速入门--数据的基本操作
  • GPU算力平台|在GPU算力平台部署智能媒体生成助手LivePortrait的应用教程
  • uni-app黑马商场项目-4封装$myrequest方法并挂载到全局
  • 44.ComboBox的数据绑定 C#例子 WPF例子
  • APP推荐:全新TV端来了,8K原画电视版
  • iOS - 底层实现中涉及的类型
  • 计算机网络之---SSL/TLS协议
  • 人工智能任务20-利用LSTM和Attention机制相结合模型在交通流量预测中的应用
  • Excel 技巧09 - 通过IF筛选数据,并给对象单元格赋值背景色 (★)
  • maven 安装jar到本地仓库和上传至远程仓库
  • Java开发防止SQL注入攻击
  • 深度学习的超参数
  • dockerfile实现lnmp
  • 深度学习-卷积神经网络实战文档注释
  • 【精选】基于EfficientViT优化YOLOv8的智能车辆识别系统设计 车辆颜色分类与车牌检测、深度学习目标检测系统开发
  • MySQL(高级特性篇) 07 章——InnoDB数据存储结构
  • 在一个地方待多久才会改变ip属地