flyfish
在 vLLM 的代码中,logprobs
是一个控制生成过程中返回对数概率信息的参数。它决定了模型在生成每个 token 时,会返回多少个候选 token 的概率分布信息。以下是详细解释:
logprobs
参数的作用在 SamplingParams
中设置 logprobs=k
时:
k
个候选 token 的 ID、文本和对数概率。k+1
(包含选中的 token 本身)。sampling_params = SamplingParams(
logprobs=5, # 返回选中 token 和 top-4 候选的对数概率
# 其他参数...
)
代码
```py
from transformers import AutoProcessor
from vllm import LLM, SamplingParams
from qwen_vl_utils import process_vision_info
import os
MODEL_PATH = "Qwen/Qwen2.5-VL-7B-Instruct"
# 本地图像路径,请替换为实际图像路径
image_path = "path_to_your_image.jpg"
llm = LLM(
model=MODEL_PATH,
limit_mm_per_prompt={"image": 10, "video": 10},
)
# 启用logprobs功能,设置为5表示返回选中token和top4候选token的对数概率
sampling_params = SamplingParams(
temperature=0.7,
top_p=0.9,
n=1, # 只生成1个序列,专注于logprobs分析
max_tokens=256,
logprobs=5, # 返回每个token的对数概率及top4候选
repetition_penalty=1.05,
)
if not os.path.exists(image_path):
raise FileNotFoundError(f"图像文件不存在: {image_path}")
image_messages = [
{"role": "system", "content": "You are a helpful assistant."},
{
"role": "user",
"content": [
{
"type": "image",
"image": image_path,
"min_pixels": 224 * 224,
"max_pixels": 1280 * 1280,
},
{"type": "text", "text": "What is in this image?"},
],
},
]
messages = image_messages
processor = AutoProcessor.from_pretrained(MODEL_PATH)
prompt = processor.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
)
image_inputs, video_inputs = process_vision_info(messages)
mm_data = {}
if image_inputs is not None:
mm_data["image"] = image_inputs
if video_inputs is not None:
mm_data["video"] = video_inputs
llm_inputs = {
"prompt": prompt,
"multi_modal_data": mm_data,
}
# 生成结果
outputs = llm.generate([llm_inputs], sampling_params=sampling_params)
# 获取第一个生成序列的logprobs信息
output = outputs[0].outputs[0]
print("生成的文本:")
print(output.text.strip())
# 解析并打印token_ids和logprobs信息
if output.logprobs is not None:
print("\n=== Token IDs 和 Logprobs 详细信息 ===")
# 确保token_ids和logprobs长度匹配
token_count = min(len(output.token_ids), len(output.logprobs))
for i in range(token_count):
token_id = output.token_ids[i]
token_text = processor.tokenizer.decode([token_id])
logprob_info = output.logprobs[i]
print(f"\nToken {i+1}:")
print(f" Token ID: {token_id}")
print(f" Token 文本: {token_text}")
# 打印原始logprobs字典结构(用于调试)
print(" Logprobs 原始数据:")
print(logprob_info)
else:
print("\n警告: 未获取到logprobs信息,请确认模型和vllm版本支持此功能")
生成的文本:
The image depicts a vintage green truck parked on a dirt path surrounded by a lush, forested area with tall trees and mountains in the background. On top of the truck, there is a praying mantis perched on the hood. The scene has a serene, nature-inspired atmosphere, and there are red seals with Chinese characters in the top right corner, adding an artistic or cultural element to the illustration.
=== Token IDs 和 Logprobs 详细信息 ===
Token 1:
Token ID: 785
Token 文本: The
Logprobs 原始数据:
{785: Logprob(logprob=-0.20143340528011322, rank=1, decoded_token='The'), 1986:
Logprob(logprob=-1.7014334201812744, rank=2, decoded_token='This'), 641:
Logprob(logprob=-10.826433181762695, rank=3, decoded_token='In'), 2132:
Logprob(logprob=-16.201433181762695, rank=4, decoded_token='It'), 8420:
Logprob(logprob=-17.701433181762695, rank=5, decoded_token='Here')}
Token 2:
Token ID: 2168
Token 文本: image
Logprobs 原始数据:
{2168: Logprob(logprob=0.0, rank=1, decoded_token='Ġimage'), 6802:
Logprob(logprob=-17.125, rank=2, decoded_token='Ġpicture'), 107553:
Logprob(logprob=-18.625, rank=3, decoded_token='åĽ¾åĥı'), 4654:
Logprob(logprob=-18.625, rank=4, decoded_token='ĠImage'), 1805:
Logprob(logprob=-19.375, rank=5, decoded_token='image')}
Token 3:
Token ID: 61891
Token 文本: depicts
Logprobs 原始数据:
{61891: Logprob(logprob=-0.055077165365219116, rank=1, decoded_token='Ġdepicts'), 374:
Logprob(logprob=-3.055077075958252, rank=2, decoded_token='Ġis'), 4933:
Logprob(logprob=-5.680077075958252, rank=3, decoded_token='Ġshows'), 4419:
Logprob(logprob=-6.305077075958252, rank=4, decoded_token='Ġfeatures'), 7952:
Logprob(logprob=-7.305077075958252, rank=5, decoded_token='Ġappears')}
Token 4:
Token ID: 264
Token 文本: a
Logprobs 原始数据:
{264: Logprob(logprob=-0.06197008118033409, rank=1, decoded_token='Ġa'), 458:
Logprob(logprob=-2.8119699954986572, rank=2, decoded_token='Ġan'), 1378:
Logprob(logprob=-13.436969757080078, rank=3, decoded_token='Ġtwo'), 279:
Logprob(logprob=-14.811969757080078, rank=4, decoded_token='Ġthe'), 23790:
Logprob(logprob=-16.311969757080078, rank=5, decoded_token='Ġvintage')}
Token 5:
Token ID: 23790
Token 文本: vintage
Logprobs 原始数据:
{23790: Logprob(logprob=-0.960280179977417, rank=1, decoded_token='Ġvintage'), 6176:
Logprob(logprob=-1.710280179977417, rank=2, decoded_token='Ġgreen'), 94763:
Logprob(logprob=-1.835280179977417, rank=3, decoded_token='Ġserene'), 32976:
Logprob(logprob=-2.585280179977417, rank=4, decoded_token='Ġvibrant'), 69105:
Logprob(logprob=-3.335280179977417, rank=5, decoded_token='Ġwhims')}
。。。。。。
每个token的输出包含以下核心信息:
Token 1:
Token ID: 785 # 模型实际选择的token在词汇表中的唯一ID
Token 文本: The # 该ID对应的文本内容
这是一个字典,键为token ID,值为该token的详细概率信息:
{
785: Logprob(logprob=-0.20143340528011322, rank=1, decoded_token='The'),
1986: Logprob(logprob=-1.7014334201812744, rank=2, decoded_token='This'),
...
}
logprob
:对数概率(log probability),值越小表示概率越低。例如:
-0.2014
对应的概率约为 exp(-0.2014) ≈ 0.818
(即81.8%)-1.7014
对应的概率约为 exp(-1.7014) ≈ 0.183
(即18.3%)rank
:该token在概率分布中的排名(1表示最可能)decoded_token
:token ID对应的文本表示观察选中token的对数概率:
-0.2
)表示模型非常确定-10
)表示模型对该选择信心很低例如,Token 1中:
The
的 logprob=-0.2014
(高概率,模型很确定)This
的 logprob=-1.7014
(低概率)查看排名靠前的其他候选token,可以了解模型在生成时的"犹豫程度":
image
(ID:2168)和 picture
(ID:6802)之间选择,两者的logprob差距较大(0 vs -17.125),说明模型对 image
的选择非常确定。注意概率分布中的异常token,例如:
åĽ¾åĥı
(ID:107553)是乱码,不知道是不是词汇表中的特殊符号或未正确解码的字符,没关系这种低概率的异常token通常可以忽略。评估生成质量:
优化提示工程:
后处理过滤:
The
This
的概率为18.3%The
明显更可能image
(概率接近100%)在自然语言中,句子的第一个词前面没有空格,因此分词器不会为其添加 Ġ
(空格标记)。
The
,作为句首词,其前没有空格,因此分词器直接输出 The
。image
,其前有空格(文本为 The image
),因此分词器用 Ġimage
表示“空格+image”。Ġ
的作用范围Ġ
仅用于表示 词与词之间的空格(即词首空格),不用于句首。"The image"
会被分词为 ["The", "Ġimage"]
(句首词无 Ġ
,后续词有 Ġ
)。" image"
(开头有空格)会被分词为 ["Ġimage"]
。# Token 1(句首词)
decoded_token='The' # 无前缀空格,正常
# Token 2(后续词)
decoded_token='Ġimage' # 表示前有空格,对应文本中的 " image"
The image
,其中 The
是句首词,image
前有空格,因此分词器分别处理为 The
和 Ġimage
。Ġ
假设生成的文本是 The image
,其分词过程如下:
"The" + " " + "image"
"The"
→ 直接编码为 token ID 785
(无 Ġ
,因是句首)。" image"
→ 空格转换为 Ġ
,与 image
合并为 Ġimage
,编码为 token ID 2168
。Ġ
是分词器的内部表示,在最终解码的文本中会被自动转换为真实空格。Ġ
的出现场景 | 分词结果示例 | 说明 |
---|---|---|
句首词 | The |
无 Ġ ,因前方无空格 |
非句首词(有前置空格) | Ġimage |
Ġ 表示前方有空格 |
连续空格 | ĠĠhello |
多个 Ġ 表示连续空格 |
在概率论中,对数概率(log probability)是指对概率值取自然对数(即以 e 为底的对数,记为 ln)。例如:
p = 0.5
对应的对数概率为 ln(0.5) ≈ -0.693
p = 0.1
对应的对数概率为 ln(0.1) ≈ -2.303
为什么用对数概率?
[0, 1]
之间,而对数概率可以将其映射到整个实数轴 (-∞, 0]
,便于数值计算和比较。如果已知对数概率 log_p
,可以通过 自然指数函数 exp()
还原原始概率 p
:
p = exp(log_p)
其中 exp(x)
表示 e 的 x 次幂(e ≈ 2.71828
)。
import math
log_p = -0.2014
p = math.exp(log_p) # 计算 e^(-0.2014)
print(f"概率: {p:.4f} ({p:.2%})")
e^(-0.2014) ≈ 0.8177
(四舍五入为 0.818
,即 81.8%)。log_p = -1.7014
p = math.exp(log_p)
print(f"概率: {p:.4f} ({p:.2%})")
e^(-1.7014) ≈ 0.1826
(四舍五入为 0.183
,即 18.3%)。对数概率 (log_p) | 原始概率 (p = exp(log_p)) | 解释 |
---|---|---|
0 | exp(0) = 1.0 | 确定性事件(概率100%) |
-0.5 | exp(-0.5) ≈ 0.607 | 约60.7%的概率 |
-1.0 | exp(-1.0) ≈ 0.368 | 约36.8%的概率 |
-2.0 | exp(-2.0) ≈ 0.135 | 约13.5%的概率 |
-10.0 | exp(-10.0) ≈ 0.000045 | 极小概率(约0.0045%) |
在模型生成的 logprobs 数据中:
logprob=-0.2014
表示模型对该 token 的置信度很高(约 81.8% 的概率)。logprob=-1.7014
表示其他候选 token 的概率较低(约 18.3%)。from transformers import AutoProcessor
from vllm import LLM, SamplingParams
from qwen_vl_utils import process_vision_info
import os
import math
MODEL_PATH = "Qwen/Qwen2.5-VL-7B-Instruct"
# 本地图像路径,请替换为实际图像路径
image_path = "path_to_your_image.jpg"
llm = LLM(
model=MODEL_PATH,
limit_mm_per_prompt={"image": 10, "video": 10},
)
# 启用logprobs功能,设置为5表示返回选中token和top4候选token的对数概率
sampling_params = SamplingParams(
temperature=0.7,
top_p=0.9,
n=1, # 只生成1个序列,专注于logprobs分析
max_tokens=256,
logprobs=5, # 返回每个token的对数概率及top4候选
repetition_penalty=1.05,
)
if not os.path.exists(image_path):
raise FileNotFoundError(f"图像文件不存在: {image_path}")
image_messages = [
{"role": "system", "content": "You are a helpful assistant."},
{
"role": "user",
"content": [
{
"type": "image",
"image": image_path,
"min_pixels": 224 * 224,
"max_pixels": 1280 * 1280,
},
{"type": "text", "text": "What is in this image?"},
],
},
]
messages = image_messages
processor = AutoProcessor.from_pretrained(MODEL_PATH)
prompt = processor.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
)
image_inputs, video_inputs = process_vision_info(messages)
mm_data = {}
if image_inputs is not None:
mm_data["image"] = image_inputs
if video_inputs is not None:
mm_data["video"] = video_inputs
llm_inputs = {
"prompt": prompt,
"multi_modal_data": mm_data,
}
# 生成结果
outputs = llm.generate([llm_inputs], sampling_params=sampling_params)
# 获取第一个生成序列的logprobs信息
output = outputs[0].outputs[0]
print("生成的文本:")
print(output.text.strip())
if output.logprobs is not None:
print("\n=== Token IDs 和 Logprobs 详细信息 ===")
token_count = min(len(output.token_ids), len(output.logprobs))
for i in range(token_count):
token_id = output.token_ids[i]
token_text = processor.tokenizer.decode([token_id])
logprob_info = output.logprobs[i]
print(f"\nToken {i+1}:")
print(f" Token ID: {token_id}")
print(f" Token 文本: {token_text}")
# 解析选中token的概率
selected_logprob = None
selected_prob = None
if token_id in logprob_info:
selected_logprob = logprob_info[token_id].logprob
selected_prob = math.exp(selected_logprob)
print(f" 选中概率: {selected_prob:.4%}")
# 解析top-k候选
print(" Top-k候选:")
sorted_candidates = sorted(
logprob_info.items(),
key=lambda x: x[1].rank if hasattr(x[1], 'rank') else 0
)
for j, (candidate_id, candidate_info) in enumerate(sorted_candidates[:5]):
candidate_text = processor.tokenizer.decode([candidate_id])
candidate_logprob = candidate_info.logprob
candidate_prob = math.exp(candidate_logprob)
is_selected = candidate_id == token_id
print(f" {j+1}. {'*' if is_selected else ''} Token ID: {candidate_id}, 文本: {candidate_text}, 对数概率: {candidate_logprob:.4f}, 概率: {candidate_prob:.4%}")
输出
生成的文本:
The image depicts a vintage green truck parked on a dirt path in a lush, forested area with mountains in the background. The truck has a classic design with a large front grille and round headlights. On top of the truck, there is a praying mantis perched. The scene is serene and natural, with trees, rocks, and wildflowers surrounding the vehicle. There is also a red stamp with Chinese characters in the upper right corner of the image.
=== Token IDs 和 Logprobs 详细信息 ===
Token 1:
Token ID: 785
Token 文本: The
选中概率: 81.7558%
Top-k候选:
1. * Token ID: 785, 文本: The, 对数概率: -0.2014, 概率: 81.7558%
2. Token ID: 1986, 文本: This, 对数概率: -1.7014, 概率: 18.2422%
3. Token ID: 641, 文本: In, 对数概率: -10.8264, 概率: 0.0020%
4. Token ID: 2132, 文本: It, 对数概率: -16.2014, 概率: 0.0000%
5. Token ID: 8420, 文本: Here, 对数概率: -17.7014, 概率: 0.0000%
Token 2:
Token ID: 2168
Token 文本: image
选中概率: 100.0000%
Top-k候选:
1. * Token ID: 2168, 文本: image, 对数概率: 0.0000, 概率: 100.0000%
2. Token ID: 6802, 文本: picture, 对数概率: -17.1250, 概率: 0.0000%
3. Token ID: 107553, 文本: 图像, 对数概率: -18.6250, 概率: 0.0000%
4. Token ID: 4654, 文本: Image, 对数概率: -18.6250, 概率: 0.0000%
5. Token ID: 1805, 文本: image, 对数概率: -19.3750, 概率: 0.0000%
Token 3:
Token ID: 61891
Token 文本: depicts
选中概率: 94.6412%
Top-k候选:
1. * Token ID: 61891, 文本: depicts, 对数概率: -0.0551, 概率: 94.6412%
2. Token ID: 374, 文本: is, 对数概率: -3.0551, 概率: 4.7119%
3. Token ID: 4933, 文本: shows, 对数概率: -5.6801, 概率: 0.3413%
4. Token ID: 4419, 文本: features, 对数概率: -6.3051, 概率: 0.1827%
5. Token ID: 7952, 文本: appears, 对数概率: -7.3051, 概率: 0.0672%