LLM的finetune 中的 attention_mask 和input_ids

部署运行你感兴趣的模型镜像

一。input_ids :

它是通过tokenizer分词器,把原来的context中的text进行进行转化,变为词元。 然后进行相应的id转化,通过查词表,记录该词在原始词表位置,即:索引位置 

【2,18,30,50,。。。】这个索引的数字就是该词在原词表中的第i位置中。 

接着就是embedding,映射成多少纬度。 

最后多个input_ids 通过np转化成matrix , 过程中我们会用一个常量来限制大小, 

if:这个len(matrix) 小于了常量,那么我们需要padding, padding的方式也是选择一个值(这个值一般是.eos的值),那么后续的decode过程中,我们不能把padding的值解码出来,这样是不遵循原始结构了,所以我们得用attention——mask进行处理。 

else if: 我们就得进行trunacation

  1. 序列太短需要padding
    • 如果序列长度小于所需长度,我们用特定值(如PAD token或EOS token)进行填充
    • 创建attention_mask,用1标记真实token,0标记padding位置
    • 解码时,通过attention_mask或设置skip_special_tokens=True来忽略这些padding token
  2. 序列太长需要截断(truncation)
    • 如果序列长度超过模型能处理的最大长度,需要截断
    • 通常会保留序列的开头或结合开头和结尾的部分,丢弃中间部分
    • 可能会保留特殊token如BOS(开始)和EOS(结束)标记

解码过程中,有几种方式处理特殊token:

  • 通过设置skip_special_tokens=True让tokenizer自动忽略如PAD、EOS等特殊token
  • 特殊token通常有预定义的ID,如BERT中PAD=0,解码时可以专门过滤掉它们
  • attention_mask本身不直接参与解码,但它在模型生成过程中确保模型不关注padding部分

所以padding和truncation是处理不同长度输入文本的两种互补方法,让批处理高效进行的同时保持模型表现。

Tokenizer自动处理padding和truncation:

inputs = tokenizer(
    ["短文本", "这是一个较长的文本需要被处理..."], 
    padding=True,  # 自动添加padding
    truncation=True,  # 自动截断过长文本
    max_length=512,  # 最大长度
    return_tensors="pt"  # 返回PyTorch张量
)
# 自动生成attention_mask
# inputs包含: input_ids, attention_mask

二.attention_mask的作用就是告诉模型哪些token是真实输入哪些只是padding 。 

attention_mask通常就是由0和1组成的序列,用于告诉模型哪些token是真实输入,哪些只是padding。

一个典型的attention_mask结构是这样的:

  • 1表示实际内容的token,模型需要关注这部分
  • 0表示padding token,模型应该忽略这部分

例如,如果我们有一个句子被编码为[101, 2054, 2003, 2026, 3793, 102],而最大长度是10,模型会进行padding:

  • input_ids: [101, 2054, 2003, 2026, 3793, 102, 0, 0, 0, 0]
  • attention_mask: [1, 1, 1, 1, 1, 1, 0, 0, 0, 0]

这个掩码告诉模型只考虑前6个token,忽略后面的padding token。这对模型非常重要,因为:

  1. 防止模型在无意义的padding token上浪费注意力计算
  2. 确保模型不会从padding token中学到错误的模式
  3. 对于BERT这样的双向模型尤其重要,防止一个词的表示被padding污染

当警告说"attention mask未设置"时,意味着模型无法区分真实输入和padding,可能导致不可预测的行为,尤其是当输入序列长度不一时。

三、LLM推理函数 

def inference(question, model, tokenizer, max_length=512, do_sample=True, temperature=0.7):
    """
    使用语言模型对输入问题进行推理并生成回答
    
    参数:
        question (str): 输入的问题文本
        model: 已加载的语言模型 (如从AutoModelForCausalLM加载的模型)
        tokenizer: 与模型匹配的分词器
        max_length (int): 生成文本的最大长度
        do_sample (bool): 是否使用采样策略生成文本
        temperature (float): 生成温度,越高越随机
        
    返回:
        str: 模型生成的回答文本
    """
    # 设置设备
    device = model.device
    
    # 编码输入文本
    inputs = tokenizer(question, return_tensors="pt").to(device)
    
    # 处理attention_mask警告
    if "attention_mask" not in inputs:
        print("The attention mask and the pad token id were not set. As a consequence, you may observe unexpected behavior.")
        # 可以在这里添加默认的attention_mask
    
    # 设置pad_token_id (如果未设置)
    if tokenizer.pad_token_id is None:
        tokenizer.pad_token_id = tokenizer.eos_token_id
        print(f"Setting 'pad_token_id' to 'eos_token_id':{tokenizer.eos_token_id} for open-end generation.")
    
    # 生成文本
    with torch.no_grad():
        output_sequences = model.generate(
            input_ids=inputs["input_ids"],
            attention_mask=inputs.get("attention_mask", None),
            max_length=max_length,
            temperature=temperature,
            do_sample=do_sample,
            pad_token_id=tokenizer.pad_token_id,
            eos_token_id=tokenizer.eos_token_id,
        )
    
    # 解码生成的文本
    generated_text = tokenizer.decode(output_sequences[0], skip_special_tokens=True)
    
    # 从生成的文本中提取回答部分 (移除输入问题)
    # 有时输出会包含输入,所以需要处理
    if question in generated_text:
        answer = generated_text[len(question):].strip()
    else:
        answer = generated_text.strip()
    
    return answer

您可能感兴趣的与本文相关的镜像

Llama Factory

Llama Factory

模型微调
LLama-Factory

LLaMA Factory 是一个简单易用且高效的大型语言模型(Large Language Model)训练与微调平台。通过 LLaMA Factory,可以在无需编写任何代码的前提下,在本地完成上百种预训练模型的微调

class Catcher(nn.Module): def __init__(self, module): super().__init__() self.module = module def forward(self, hidden_states, **kwargs): inps[:, cache["i"]:cache["i"]+1] = hidden_states cache["i"] += 1 if "attention_mask" in kwargs: cache["attention_mask"] = kwargs["attention_mask"] if "position_ids" in kwargs: cache["position_ids"] = kwargs["position_ids"] if "rotary_pos_emb" in kwargs: cache["rotary_pos_emb"] = kwargs["rotary_pos_emb"] raise ValueError layers[0] = Catcher(layers[0]) # 遍历数据加载器,收集指定数量的样本输入, 利用Catcher抛出的ValueError异常来收集数据 current_cnt = 0 with torch.no_grad(): while current_cnt < args.nsamples: try: tokens, labels, loss_mask, attention_mask, position_ids, domain_id, delimiter_pos_list, image, feature = get_batch(dataloader, zj_type=args.zj_type, is_train=False) input_ids = tokens.unsqueeze(0) if tokens.dim() == 1 else tokens.to(dev) model[0](input_ids=input_ids, attention_mask=attention_mask, position_ids=position_ids, images=image.to(torch.bfloat16), delimiter_pos=delimiter_pos_list, labels=labels) except ValueError: pass current_cnt += 1 layers[0] = layers[0].module layers[0] = layers[0].cpu() # if model.__class__.__name__ == "MiniCPMV": # model.llm.model.embed_tokens = model.llm.model.embed_tokens.cpu() # model.llm.model.norm = model.llm.model.norm.cpu() # elif &#39;qwen-7b&#39; in args.model.lower() or &#39;qwen-vl&#39; in args.model.lower(): # model.transformer.wte = model.transformer.wte.cpu() # model.transformer.ln_f = model.transformer.ln_f.cpu() # else: # model.model.embed_tokens = model.model.embed_tokens.cpu() # model.model.norm = model.model.norm.cpu() model[0].module.language_model.embedding = model[0].module.language_model.embedding.to(dev) model[0].module.language_model.decoder.final_layernorm = model[0].module.language_model.decoder.final_layernorm.to(dev) torch.cuda.empty_cache() outs = torch.zeros_like(inps) position_ids = cache.get("position_ids", None) attention_mask = cache["attention_mask"] rotary_pos_emb = cache["rotary_pos_emb"]
最新发布
08-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值