本文记录分享Qwen3-VL使用Lora完成监督微调后,进行8bit量化的过程;
- 首先使用LLaMA Factory,对Qwen3-VL-4b进行Lora监督微调,得到微调后的lora权重;
- 然后合并 基础Qwen3-VL-4b权重 + lora权重 = 完整微调权重
- 最后对"完整微调权重"进行8bit量化,进行模型推理,提供实践案例。
目录
[一、对Qwen3-VL进行Lora 监督微调](#一、对Qwen3-VL进行Lora 监督微调)
一、对Qwen3-VL进行Lora 监督微调
下面是LLaMA Factory 的微调训练配置,用于Qwen3-VL-4B-Instruct 多模态模型 的有监督微调:
| 项 | 配置值 | 作用 & 分析 |
|---|---|---|
| 模型 | Qwen3-VL-4B-Instruct(HuggingFace 源) | 选择了 4B 参量的多模态(图文)模型,适合轻量化多模态任务微调 |
| 微调方法 | LoRA | 低参数量微调(只训练适配器权重),显存占用低、训练速度快 |
| 量化策略 | 8bit(QLoRA)+ bnb 量化 | 进一步压缩显存(4bit 加载模型),结合 LoRA 可在普通消费级显卡(如 16G 显存)上训练 |
| 训练阶段 | Supervised Fine-Tuning (SFT,有监督微调) | 基于标注数据集训练模型生成符合要求的输出 |
微调界面:

核心超参数配置(仅供参考,需要根据自己的模型调整的)
| 项 | 配置值 | 作用 & 分析 |
|---|---|---|
| 学习率 | 3e-5 | LoRA 微调的常用学习率(比全量微调高 1-2 个数量级) |
| 训练轮数 | 3.0 | 训练轮次较少,适合快速收敛或小数据集(避免过拟合) |
| 批处理 / 梯度累积 | 批大小 2 + 梯度累积 2 → 等效批大小 4 | 小批量 + 梯度累积平衡显存占用与训练稳定性 |
| 截断长度 | 2048 | 匹配 Qwen3-VL 的上下文长度上限,适配长文本 / 多模态输入 |
| 学习率调节器 | cosine(余弦退火) | 训练后期平滑降低学习率,帮助模型稳定收敛 |
| 计算类型 | bf16 | 半精度计算(需显卡支持 Ampere 及以上架构),进一步节省显存并加速训练 |
微调完整后,得到lora权重,默认保存在LLaMA Factory目录下的./saves/Qwen3-VL-4B-Instruct/lora/xxxxxx
二、合并权重
这里的思路:基础Qwen3-VL-4b权重 + lora权重 = 完整微调权重
我们只需确定:基础权重的路径model_name_or_path、lora微调权重路径adapter_name_or_path
然后执行下面命令,进行合并:
bash
llamafactory-cli export \
--model_name_or_path "/home/user/.cache/huggingface/hub/models--Qwen--Qwen3-VL-4B-Instruct/snapshots/ebb281ec70b05090aa6165b016eac8ec08e71b17/" \
--adapter_name_or_path ./saves/Qwen3-VL-4B-Instruct/lora/train_2025-11-13-13-37/ \
--export_dir ./qwen3-vl-4b-merged-20251113-fp16-lora\
--template qwen3_vl_nothink
等待合并完成~
bash
[2025-11-15 08:49:02,636] [INFO] [real_accelerator.py:254:get_accelerator] Setting ds_accelerator to cuda (auto detect)
[INFO|2025-11-15 15:36:02] llamafactory.model.model_utils.kv_cache:143 >> KV cache is enabled for faster generation.
[INFO|2025-11-15 15:36:02] llamafactory.model.model_utils.attention:143 >> Using torch SDPA for faster training and inference.
INFO ENV: Auto setting PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' for memory saving.
INFO ENV: Auto setting CUDA_DEVICE_ORDER=PCI_BUS_ID for correctness.
[INFO|2025-11-15 15:36:02] llamafactory.model.adapter:143 >> Merged 1 adapter(s).
[INFO|2025-11-15 15:36:02] llamafactory.model.adapter:143 >> Loaded adapter(s): ./saves/Qwen3-VL-4B-Instruct/lora/train_2025-11-13-13-37
[INFO|2025-11-15 15:36:02] llamafactory.model.loader:143 >> all params: 4,437,815,808
[INFO|2025-11-15 15:36:02] llamafactory.train.tuner:143 >> Convert model dtype to: torch.bfloat16.
[INFO|2025-11-15 15:36:02] llamafactory.train.tuner:143 >> Ollama modelfile saved in ./model_path/qwen3-vl-4b-merged-20251113-fp16-lora/Modelfile
合并后的权重大小:
8.3G model_path/qwen3-vl-4b-merged
三、使用bnb进行8bit量化
通过**BitsAndBytes工具** 对 Qwen3-VL 模型进行8 位量化,以降低模型显存占用,
同时保存量化后的模型、分词器(tokenizer)和处理器(processor),便于后续部署使用。
- 使用
transformers库中的模型加载类(Qwen3VLForConditionalGeneration、AutoModel)、量化配置(BitsAndBytesConfig) - 依赖
torch进行张量计算和设备管理。
模型量化的实力代码,如下所示:
bash
from transformers import Qwen3VLForConditionalGeneration, AutoModel, BitsAndBytesConfig, AutoTokenizer, AutoProcessor
import torch
input_merged_model = "./model_path/qwen3-vl-4b-merged-20251113-8bit-lora"
output_merged_model = "./model_path/qwen3-vl-4b-bnb-quantized-8bit-merged-20251113-int8"
'''
BitsAndBytes 仅支持:
位量化: quant_type="fp4" 或 "nf4"(配合 load_in_4bit=True)
位量化:必须用 quant_type="int8"(实际是 8 位整数,不是浮点)。
fp8 是 NVIDIA 的 8 位浮点格式,不在 Hugging Face BitsAndBytes 支持范围内。
'''
def quantize_model():
# 配置8位bnb量化
quantization_config = BitsAndBytesConfig(
load_in_8bit=True, # 8位量化(必须)
bnb_8bit_compute_dtype=torch.float16, # 计算用float16
bnb_8bit_use_double_quant=True, # 双量化(压缩高效,可选)
bnb_8bit_quant_type="int8" # ✅ 修正:必须为 "int8"(8位整数量化)
)
try:
# 尝试使用特定模型类
print("尝试使用 Qwen3VLForConditionalGeneration 加载模型...")
model = Qwen3VLForConditionalGeneration.from_pretrained(
input_merged_model,
quantization_config=quantization_config,
device_map="auto",
trust_remote_code=True
)
except Exception as e:
print(f"使用特定类失败: {e}")
print("尝试使用 AutoModel 加载模型...")
# 回退到 AutoModel
model = AutoModel.from_pretrained(
input_merged_model,
quantization_config=quantization_config,
device_map="auto",
trust_remote_code=True
)
# 加载并保存tokenizer和processor
tokenizer = AutoTokenizer.from_pretrained(input_merged_model, trust_remote_code=True)
processor = AutoProcessor.from_pretrained(input_merged_model, trust_remote_code=True)
# 保存量化后的模型和相关组件
model.save_pretrained(output_merged_model)
tokenizer.save_pretrained(output_merged_model)
processor.save_pretrained(output_merged_model)
print("模型8位量化并保存完成!")
if __name__ == "__main__":
quantize_model()
明确 8 位量化的关键参数:
load_in_8bit=True:启用 8 位量化bnb_8bit_quant_type="int8":指定量化类型为 8 位整数(符合 BitsAndBytes 对 8 位量化的要求)bnb_8bit_compute_dtype=torch.float16:量化过程中使用 float16 进行计算,平衡精度与性能bnb_8bit_use_double_quant=True:启用双量化(可选优化,进一步压缩模型大小,减少内存占用)
量化后的权重大小:
4.6G model_path/qwen3-vl-4b-bnb-quantized-8bit-merged-20251113-int8
四、量化后的模型推理(实践案例1)
这个实践案例,基于 Qwen3-VL 量化模型的单张图像描述
- 模型加载:使用
AutoModelForImageTextToText加载多模态模型,适配 Qwen3-VL 的图文生成能力。 - 核心参数:
device_map="auto"自动分配模型到 CPU/GPU,trust_remote_code=True允许加载模型自定义代码。 - 处理器配套:
AutoProcessor用于统一处理文本提示和图像输入,确保格式符合模型要求。
特点:
- 输入处理:用
apply_chat_template格式化对话(用户 + 图像 + 文本提示),processor将文本和图像转为模型可识别的张量,并移至对应设备。 - 生成配置:
max_new_tokens=512限制描述长度,do_sample=False+num_beams=1采用确定性生成,保证结果稳定。 - 结果提取:裁剪模型输出中冗余的输入部分,解码后去除特殊 token,得到纯净描述文本。
推理代码:
python
import os
from PIL import Image
import torch
from transformers import AutoProcessor, AutoModelForImageTextToText
# 模型路径配置
QUANTIZED_MODEL_PATH = "./model_path/qwen3-vl-4b-bnb-quantized-8bit-merged-20251113-int8"
# 输入图片路径
input_image = "dataset/test_pic/350012.jpg"
# 初始化模型和处理器
print(f"正在加载模型:{QUANTIZED_MODEL_PATH}...")
model = AutoModelForImageTextToText.from_pretrained(
QUANTIZED_MODEL_PATH,
device_map="auto",
trust_remote_code=True
)
processor = AutoProcessor.from_pretrained(QUANTIZED_MODEL_PATH)
print("模型和处理器加载成功!")
def describe_image(image_path):
"""生成图像的详细描述"""
try:
# 加载图像
image = Image.open(image_path).convert("RGB")
# 构建提示词(专注于图像整体描述)
messages = [
{
"role": "user",
"content": [
{"type": "image"},
{"type": "text", "text": "请详细描述这张图片的内容,包括场景、物体、颜色、布局等信息。"}
]
}
]
# 处理输入
text = processor.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
inputs = processor(
text=text,
images=image,
return_tensors="pt",
padding=True
).to(model.device)
# 生成描述
with torch.no_grad():
generated_ids = model.generate(
**inputs,
max_new_tokens=512,
do_sample=False,
num_beams=1
)
# 提取并返回生成的描述
generated_ids_trimmed = generated_ids[:, inputs.input_ids.shape[1]:]
description = processor.batch_decode(
generated_ids_trimmed,
skip_special_tokens=True,
clean_up_tokenization_spaces=False
)[0]
return description
except Exception as e:
print(f"图像描述失败: {str(e)}")
return ""
def process_single_image(image_path):
"""处理单张图像并打印描述"""
if not os.path.exists(image_path):
print(f"图像文件不存在: {image_path}")
return
print(f"\n--- 处理图像: {os.path.basename(image_path)} ---")
description = describe_image(image_path)
if description:
print("\n图像描述:")
print(description)
print(f"\n--- 处理完成 ---")
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='图像描述工具')
parser.add_argument('--image', type=str, default=input_image, help='需要描述的图像路径')
args = parser.parse_args()
process_single_image(args.image)
输入图片:

运行信息:
python
正在加载模型:./model_path/qwen3-vl-4b-bnb-quantized-8bit-merged-20251113-int8...
模型和处理器加载成功!
--- 处理图像: 350012.jpg ---
The following generation flags are not valid and may be ignored: ['temperature', 'top_p', 'top_k']. Set `TRANSFORMERS_VERBOSITY=info` for more details.
图像描述:
这张图片展示了一个布置温馨、光线柔和的现代客厅。整个空间以中性色调为主,搭配暖色装饰,营造出舒适宜人的氛围。
**场景与布局:**
客厅布局清晰,以一张米色布艺沙发为中心,沙发靠墙放置,旁边是深色木质边桌。前方是一个深棕色木质咖啡桌,桌下铺着一块色彩丰富的几何图案地毯,地毯以蓝色、红色和米色为主,为整个空间增添活力。左侧是壁炉区域,右侧是边桌和台灯,墙上挂有艺术画作,整体布局平衡且富有层次感。
**主要物体与细节:**
1. **沙发:**
- 一张米色布艺沙发,靠背和坐垫厚实,显得柔软舒适。
- 沙发上摆放着多个靠垫,颜色丰富:深紫色、橙色、红色和橄榄绿,形成视觉焦点。
- 沙发右侧有一个深色木质边桌,上面放着一盏白色台灯和一个酒杯。
2. **咖啡桌:**
- 深棕色木质咖啡桌,带有开放式下层置物架。
- 桌面上摆放着一个白色陶瓷花瓶,瓶身呈优雅的鹅颈状,旁边是一个透明玻璃花瓶,内有干花枝。
- 一个小型绿色盆栽植物放在花瓶旁,增添自然气息。
- 一个透明玻璃杯和一个酒杯也放在桌上。
3. **壁炉与镜子:**
- 左侧是一个深色砖砌壁炉,壁炉上方悬挂着一个大尺寸的木框镜子,镜中反射出楼梯的一部分,暗示房屋结构。
- 壁炉上方的架子上摆放着几个玻璃烛台和装饰品。
4. **墙面装饰:**
- 墙上挂着一幅大型抽象画,画中描绘了城市景观,色调以暖橙、赭石和米白为主,与沙发靠垫颜色相呼应。
- 墙角处有一扇白色窗框的小窗,透入自然光。
5. **灯光与家具:**
- 墙角的台灯和壁炉旁的台灯都采用白色灯罩,与整体色调协调。
- 墙边有一个白色书架,上面摆放着书籍和装饰品。
**颜色与氛围:**
整个空间以米
--- 处理完成 ---
五、量化后的模型推理(实践案例2)
这个模型推理示例,是 Qwen3-VL 量化模型的特定类别物体检测与可视化,
核心用于批量处理图像 、提取目标物体多维度信息并生成可视化结果。
核心功能:
- 支持指定任意类别的物体(table、cup、bottle 等),输出类别、边界框、颜色、形状、外观 5 类信息。
- 支持批量读取图像目录,自动按自然排序处理文件。
- 生成带边界框和类别的可视化图像,同时打印详细物体描述。
- 包含异常处理和格式容错,确保流程稳定性。
推理代码:
python
import os
import json
import glob
import re
import torch
import numpy as np
from PIL import Image
import cv2
import time
from transformers import AutoProcessor, AutoModelForImageTextToText
QUANTIZED_MODEL_PATH = "./model_path/qwen3-vl-4b-bnb-quantized-8bit-merged-20251113-int8" # lora微调后的8-bit量化模型
input_dir = "./dataset_label/01_waitingroom/"
output_dir = "./Output_DATA/01_waitingroom"
# 指定检测的物体类别,可以指定任意物体名称或在物体描述
NODE_SPACE = ['table', 'cup', 'bottle', 'chair', 'robot', 'garbage can', 'shelf', 'tissue box', 'potted plant']
# 全局初始化模型和处理器
print(f"正在加载8-bit量化后的Qwen3-VL-4B模型:{QUANTIZED_MODEL_PATH}...")
model = AutoModelForImageTextToText.from_pretrained(
QUANTIZED_MODEL_PATH,
device_map="auto",
trust_remote_code=True
)
processor = AutoProcessor.from_pretrained(QUANTIZED_MODEL_PATH)
print("修复后的量化Qwen3-VL-4B模型和处理器加载成功!")
def call_vlm(image_path, prompt):
"""安全的VLM调用函数"""
try:
# >>>>> 修改点1:直接使用 PIL 加载图像 <<<<<
# 假设模型能处理任意大小的有效图像,不再强制调整尺寸
image = Image.open(image_path).convert("RGB") # 确保是 RGB 模式
messages = [
{
"role": "user",
"content": [
{"type": "image"},
{"type": "text", "text": prompt}
]
}
]
text = processor.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
inputs = processor(
text=text,
images=image,
return_tensors="pt",
padding=True
).to(model.device)
# 生成参数
with torch.no_grad():
generated_ids = model.generate(
**inputs,
max_new_tokens=512,
do_sample=False,
num_beams=1,
early_stopping=False
)
generated_ids_trimmed = generated_ids[:, inputs.input_ids.shape[1]:]
output_text = processor.batch_decode(
generated_ids_trimmed,
skip_special_tokens=True,
clean_up_tokenization_spaces=False
)[0]
return output_text
except Exception as e:
print(f"VLM调用失败: {str(e)}")
return ""
def detect_and_describe_objects(image_path):
"""检测图像中的物体,获取其描述并反归一化bbox"""
# 构建提示词
prompt = f"""
请严格检测图像中属于以下类别的所有物体:{NODE_SPACE}。
对于每个检测到的物体,请提供:
1. 类别 (category)
2. 紧贴边缘的边界框 (bbox),格式为 [x1,y1,x2,y2](整数像素坐标)
3. 颜色 (color)
4. 形状 (shape)
5. 外观描述 (appearance)
输出要求:
- 仅识别列表中的类别。
- bbox必须精确且紧密贴合物体边缘。
- 描述信息需与bbox内的区域一致。
- 严格以 JSON 数组形式返回,不要包含任何额外的文本或代码块标记。
输出示例(格式参考):
[
{{
"category": "cup",
"bbox": [97, 203, 176, 282],
"color": "白色",
"shape": "圆柱形",
"appearance": "带把手陶瓷杯"
}},
{{
"category": "table",
"bbox": [10, 318, 639, 474],
"color": "原木色",
"shape": "长方形",
"appearance": "四腿木质桌面"
}}
]
"""
try:
# >>>>> 修改点2:直接使用 PIL 获取图像尺寸 <<<<<
# 加载图像以获取尺寸用于坐标反归一化
with Image.open(image_path) as img_pil:
w_img, h_img = img_pil.convert("RGB").size # 确保获取到尺寸
print("开始调用VLM进行物体检测...")
time_start = time.time()
response = call_vlm(image_path, prompt)
time_end = time.time()
print(f'VLM推理时间:{time_end - time_start:.2f}s')
if not response:
print("VLM返回空响应")
return []
# 解析JSON响应
try:
objects_data = json.loads(response.strip())
except json.JSONDecodeError:
# 尝试清理常见的格式问题
cleaned_response = response.strip()
if cleaned_response.startswith('```json'):
cleaned_response = cleaned_response[7:]
if cleaned_response.startswith('```'):
cleaned_response = cleaned_response[3:]
if cleaned_response.endswith('```'):
cleaned_response = cleaned_response[:-3]
cleaned_response = cleaned_response.strip()
try:
objects_data = json.loads(cleaned_response)
except json.JSONDecodeError as e:
print(f"JSON解析失败: {e}")
print(f"原始响应内容: {response}")
return []
if not isinstance(objects_data, list):
print(f"响应不是列表格式: {objects_data}")
return []
# 处理并验证每个检测到的物体
valid_objects = []
for i, obj in enumerate(objects_data):
# 验证基本结构
if not (isinstance(obj, dict) and
obj.get('category') in NODE_SPACE and
len(obj.get('bbox', [])) == 4):
print(f"警告:跳过无效的检测结果 #{i+1}: {obj}")
continue
# 提取并转换bbox坐标
try:
coords = list(map(float, obj['bbox']))
x1_norm, y1_norm, x2_norm, y2_norm = coords
except (ValueError, TypeError) as e:
print(f"警告:跳过坐标格式错误的物体 #{i+1}: {e}")
continue
# 反归一化 (假设模型输出的是0-1000范围的坐标)
x1 = int(round(x1_norm / 1000 * w_img))
y1 = int(round(y1_norm / 1000 * h_img))
x2 = int(round(x2_norm / 1000 * w_img))
y2 = int(round(y2_norm / 1000 * h_img))
# 确保坐标在图像范围内
x1 = max(0, min(x1, w_img - 1))
y1 = max(0, min(y1, h_img - 1))
x2 = max(x1 + 1, min(x2, w_img - 1))
y2 = max(y1 + 1, min(y2, h_img - 1))
# 更新对象字典
obj['bbox'] = [x1, y1, x2, y2]
valid_objects.append(obj)
print(f"共检测并验证了 {len(valid_objects)} 个物体。")
return valid_objects
except Exception as e:
print(f"物体检测过程失败: {str(e)}")
return []
def visualize_detections(image_path, detected_objects, output_path):
"""可视化检测结果:绘制bbox和标签"""
try:
# 读取图像
image_bgr = cv2.imread(image_path)
if image_bgr is None:
print(f"无法读取图像: {image_path}")
return
h_img, w_img = image_bgr.shape[:2] # 获取OpenCV图像的尺寸
# 绘制每个检测到的物体
for i, obj in enumerate(detected_objects):
bbox = obj.get('bbox', [0, 0, 0, 0])
category = obj.get('category', 'Unknown')
# 确保坐标在有效范围内 (基于OpenCV图像尺寸)
x1, y1, x2, y2 = bbox
x1 = max(0, min(x1, w_img - 1))
y1 = max(0, min(y1, h_img - 1))
x2 = max(x1 + 1, min(x2, w_img - 1))
y2 = max(y1 + 1, min(y2, h_img - 1))
# 绘制边界框
cv2.rectangle(image_bgr, (x1, y1), (x2, y2), (0, 255, 0), 2)
# 准备标签文本
label_parts = [category]
label = " ".join(label_parts)
# 计算标签位置(在框上方)
(text_width, text_height), baseline = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
y_label = y1 - 10 if y1 - 10 > 10 else y1 + 10 + text_height
# 绘制标签背景矩形
cv2.rectangle(image_bgr, (x1, y_label - text_height - baseline),
(x1 + text_width, y_label + baseline), (0, 255, 0), -1)
# 绘制标签文字
cv2.putText(image_bgr, label, (x1, y_label),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)
# 保存可视化图像
cv2.imwrite(output_path, image_bgr)
print(f"检测结果可视化已保存至: {output_path}")
except Exception as e:
print(f"可视化检测结果失败: {str(e)}")
def print_object_descriptions(detected_objects):
"""打印每个检测到的物体的详细描述信息"""
if not detected_objects:
print("未检测到任何物体。")
return
print("\n--- 检测到的物体描述 ---")
for i, obj in enumerate(detected_objects):
print(f"物体 #{i+1}:")
print(f" 类别 (Category): {obj.get('category', 'N/A')}")
print(f" 边界框 (Bbox): {obj.get('bbox', 'N/A')}")
print(f" 颜色 (Color): {obj.get('color', 'N/A')}")
print(f" 形状 (Shape): {obj.get('shape', 'N/A')}")
print(f" 外观 (Appearance): {obj.get('appearance', 'N/A')}")
print("-" * 20)
print("--- 描述结束 ---\n")
def natural_sort_key(filename):
"""自然排序含数字的文件名"""
return [int(t) if t.isdigit() else t.lower()
for t in re.split(r'(\d+)', os.path.basename(filename))]
def process_images_simple(input_dir, output_dir):
"""批量处理图像目录,执行简化任务"""
try:
os.makedirs(output_dir, exist_ok=True)
viz_output_dir = os.path.join(output_dir, "visualizations_simple")
os.makedirs(viz_output_dir, exist_ok=True)
image_extensions = ['*.jpg', '*.jpeg', '*.png', '*.bmp', '*.gif']
image_files = []
for ext in image_extensions:
image_files.extend(glob.glob(os.path.join(input_dir, ext)))
image_files = sorted(image_files, key=natural_sort_key)
if not image_files:
print(f"在目录 {input_dir} 中未找到图像文件")
return
for image_path in image_files:
image_name = os.path.basename(image_path)
print(f"\n---------- 处理图像: {image_name} ----------")
# 1. 检测物体并获取描述
detected_objects = detect_and_describe_objects(image_path)
# 2. 打印物体描述
print_object_descriptions(detected_objects)
# 3. 可视化检测框
viz_filename = os.path.splitext(image_name)[0] + "_simple_viz.jpg"
viz_path = os.path.join(viz_output_dir, viz_filename)
visualize_detections(image_path, detected_objects, viz_path)
print(f"---------- 完成处理: {image_name} ----------\n")
print("\n所有图像处理完成")
except Exception as e:
print(f"处理图像目录失败: {str(e)}")
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='简化版Qwen3-VL物体检测与可视化工具')
parser.add_argument('--input_dir', type=str, default=input_dir, help='包含图像的输入目录')
parser.add_argument('--output_dir', type=str, default=output_dir, help='输出结果的目录')
args = parser.parse_args()
process_images_simple(args.input_dir, args.output_dir)
初始化模型→2. 批量读取图像→3. 单图处理(检测物体→解析结果→打印描述→绘制可视化)→4. 输出所有结果。
核心逻辑是利用多模态模型实现特定类别物体的检测与描述,并通过可视化和文本输出直观呈现结果
运行效果:

打印信息:
---------- 处理图像: be158920.jpg ----------
开始调用VLM进行物体检测...
VLM推理时间:17.25s
共检测并验证了 2 个物体。
--- 检测到的物体描述 ---
物体 #1:
类别 (Category): table
边界框 (Bbox): [162, 304, 315, 401]
颜色 (Color): 原木色
形状 (Shape): 长方形
外观 (Appearance): 木质桌面,表面有纹理
物体 #2:
类别 (Category): potted plant
边界框 (Bbox): [402, 148, 495, 256]
颜色 (Color): 绿色
形状 (Shape): 灌木状
外观 (Appearance): 高大的盆栽植物,叶片茂密
--- 描述结束 ---
检测结果可视化已保存至: ./Output_DATA/01_waitingroom/visualizations_simple/be158920_simple_viz.jpg
---------- 完成处理: be158920.jpg ----------
其他案例:


能看到通过8-bit量化的Qwen3-VL-4b模型,还是能准确把物体检测出来,而且物体的框比较贴合
后面部署到NVIDIA Orin板子中,看看效果~
分享完成~