一。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
- 序列太短需要padding
- 如果序列长度小于所需长度,我们用特定值(如PAD token或EOS token)进行填充
- 创建attention_mask,用1标记真实token,0标记padding位置
- 解码时,通过attention_mask或设置skip_special_tokens=True来忽略这些padding token
- 序列太长需要截断(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。这对模型非常重要,因为:
- 防止模型在无意义的padding token上浪费注意力计算
- 确保模型不会从padding token中学到错误的模式
- 对于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