两种路线
1.纯视觉大模型
2.yolo+语言大模型

Qwen-VL(阿里)大模型的架构与训练

InternVL的核心思路

GPT-4V核心架构


第11讲:多模态理解的新高度——Qwen-VL、InternVL、GPT-4V

一、从"考试排名"开始

1.1 怎么判断一个VLM好不好?

你买了新手机,怎么判断摄像头好不好?
  - 看参数?(像素高不一定好)
  - 看品牌?(可能溢价)
  - 最好的办法:拍几张照片对比!

VLM也一样:
  - 看参数量?(大不一定强)
  - 看训练数据量?(可能过拟合)
  - 最好的办法:做同一套题,看分数!

基准测试(Benchmark) = VLM的"高考"


1.2 为什么需要专门的视觉基准?

传统NLP基准(如GLUE):
  测的是纯文本能力
  
VLM需要测什么?
  ┌─────────────────────────────────────────┐
  │ 1. 看图说话(Image Captioning)           │
  │    "描述这张图" → 描述准不准?             │
  └─────────────────────────────────────────┘
  
  ┌─────────────────────────────────────────┐
  │ 2. 视觉问答(VQA)                       │
  │    "图中有几个人?" → 数对不对?           │
  └─────────────────────────────────────────┘
  
  ┌─────────────────────────────────────────┐
  │ 3. 光学字符识别(OCR)                    │
  │    "图中招牌写了什么?" → 字认不认得?      │
  └─────────────────────────────────────────┘
  
  ┌─────────────────────────────────────────┐
  │ 4. 图表理解(Chart Understanding)        │
  │    "根据柱状图,2023年增长了多少?"         │
  │    → 能不能读图、做计算、给答案?          │
  └─────────────────────────────────────────┘
  
  ┌─────────────────────────────────────────┐
  │ 5. 视觉推理(Visual Reasoning)           │
  │    "如果把红球换成蓝球,结果会怎样?"       │
  │    → 能不能理解因果关系、做逻辑推理?       │
  └─────────────────────────────────────────┘
  
  ┌─────────────────────────────────────────┐
  │ 6. 多图理解(Multi-image)                │
  │    "这两张图有什么相同和不同?"             │
  │    → 能不能跨图比较、找关联?               │
  └─────────────────────────────────────────┘

二、评估基准详解:VLM的"高考科目"

2.1 MME(Multimodal Model Evaluation)

出题人:腾讯优图实验室

特点:全面但简洁
  - 14个子任务,每个任务几十道题
  - 覆盖:存在性判断、计数、位置、颜色、OCR、海报理解等

题型示例(存在性判断):
  图片:一只狗在草地上
  问题:图中有没有猫?
  答案:否
  
  模型答"有" → 错!(幻觉)

评分:准确率

2.2 MMBench

出题人:上海AI Lab / 商汤

特点:选择题形式,自动评分
  避免了"生成文本难评判"的问题

题型:
  图片:一张餐厅菜单
  问题:最贵的菜多少钱?
  选项:A. ¥28  B. ¥58  C. ¥88  D. ¥128
  
  模型选C → 对/错,一目了然

覆盖:20+能力维度
  细粒度感知、推理、知识、OCR、科学、数学...

2.3 MMMU(Massive Multi-discipline Multimodal Understanding)

出题人:多个高校联合

特点:大学水平的多学科问题
  - 来自真实大学考试题
  - 需要专业知识 + 视觉理解

题型示例(物理):
  图片:一个电路图,有电阻、电容、电源
  问题:当开关S闭合后,电容C两端的电压随时间如何变化?
  选项:A. 线性上升 B. 指数上升 C. 指数衰减 D. 保持不变
  
  需要:看懂电路图 + 回忆物理知识 + 推理计算

难度:⭐⭐⭐⭐⭐(GPT-4V也只有55-60%准确率)

2.4 TextVQA

出题人:Facebook AI

特点:图中文字理解 + 问答
  图片中有文字(招牌、菜单、路牌、屏幕截图)
  问题需要读图上的文字才能回答

题型示例:
  图片:一个路牌,写着"南京路 1200号"
  问题:这条路叫什么名字?
  答案:南京路
  
  需要:OCR + 语义理解

三、国产VLM的力量:Qwen-VL与InternVL

3.1 Qwen-VL(阿里)

定位:通义千问的多模态版本

架构特点:
  ┌─────────────────────────────────────────┐
  │ 视觉编码器:ViT-Transformer              │
  │   支持448×448高分辨率                   │
  │   支持任意长宽比(Not just square)      │
  └─────────────────────────────────────────┘
              ↓
  ┌─────────────────────────────────────────┐
  │ 位置编码:2D-aware + 分辨率自适应         │
  │   能处理不同尺寸的图                     │
  └─────────────────────────────────────────┘
              ↓
  ┌─────────────────────────────────────────┐
  │ 连接器:Cross-Attention + FFN            │
  │   把视觉token对齐到LLM空间               │
  └─────────────────────────────────────────┘
              ↓
  ┌─────────────────────────────────────────┐
  │ LLM:Qwen-7B / Qwen-14B                │
  │   阿里自研大语言模型                     │
  └─────────────────────────────────────────┘

训练数据:
  - 图像-文本对:22亿(比LLaVA多得多)
  - 多轮对话数据:35万
  - 中文数据占比高(优势!)

特色能力:
  ✅ 中文OCR强(招牌、菜单、票据)
  ✅ 文档理解(PDF、表格、发票)
  ✅ 细粒度定位("指出图中的红色按钮")

3.2 InternVL(商汤/清华)

定位:开源GPT-4V的国产替代

架构特点:
  ┌─────────────────────────────────────────┐
  │ 视觉编码器:InternViT-6B                │
  │   超大视觉编码器(60亿参数!)             │
  │   独立预训练,视觉能力极强                │
  └─────────────────────────────────────────┘
              ↓
  ┌─────────────────────────────────────────┐
  │ 动态分辨率:AnyRes                       │
  │   把大图切成多个336×336块               │
  │   支持最高4K分辨率!                     │
  └─────────────────────────────────────────┘
              ↓
  ┌─────────────────────────────────────────┐
  │ 连接器:MLP Projector                   │
  └─────────────────────────────────────────┘
              ↓
  ┌─────────────────────────────────────────┐
  │ LLM:InternLM-20B / Qwen-7B / Vicuna   │
  │   可插拔设计,适配多种LLM                 │
  └─────────────────────────────────────────┘

核心创新:
  1. 视觉编码器独立做大(6B参数)
     → 视觉理解能力接近GPT-4V
     
  2. 像素级对齐
     不是整图一个特征,而是每个patch有特征
     → 支持"指出图中位置"的细粒度任务
     
  3. 多阶段训练
     阶段1:视觉预训练(对比学习)
     阶段2:图文对齐(像CLIP)
     阶段3:指令微调(像LLaVA)
     阶段4:对话微调(多轮对话)

性能:
  - MMMU:接近GPT-4V(差距5-10%)
  - 中文场景:部分超越GPT-4V

四、GPT-4V的能力边界

4.1 GPT-4V强在哪里?

能力1:通用视觉理解
  "这张图讲了什么故事?"
  → 能描述场景、情感、隐含意义

能力2:多模态推理
  "根据图表,如果Q3增长趋势持续,Q4预计多少?"
  → 读图 + 趋势外推 + 计算

能力3:OCR + 理解
  手写笔记、模糊照片、多语言混合
  → 几乎都能识别

能力4:多图对话
  "对比这两张设计图,哪个更节省空间?"
  → 跨图比较、分析优劣

能力5:代码生成(从UI图)
  "根据这个网页截图,写出HTML代码"
  → 视觉→代码的转换

4.2 GPT-4V弱在哪里?

弱点1:空间精度
  "指出图中第3个人的左手"
  → 经常指错位置!

  原因:视觉编码分辨率有限(可能512×512)
        手指级别的细节丢失

弱点2:计数(大数量)
  "图中有多少颗草莓?"
  → 超过20个就容易数错

  原因:自注意力的"数"能力有限
        没有显式的计数机制

弱点3:幻觉(仍然存在)
  尤其在描述细节时,会编造不存在的东西

弱点4:实时性/成本
  API调用贵、有速率限制
  不能本地部署(闭源)

五、动手实验:实战对比不同VLM

5.1 环境准备

# 安装必要库
pip install transformers accelerate bitsandbytes
pip install qwen-vl-utils  # Qwen-VL的工具

# 如果需要GPT-4V,需要OpenAI API Key
# export OPENAI_API_KEY="your-key"

5.2 实验1:加载Qwen-VL做推理

import torch
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np

print("=" * 60)
print("【实验1】Qwen-VL图文推理")
print("=" * 60)

# 尝试加载Qwen-VL
try:
    from transformers import Qwen2VLForConditionalGeneration, AutoProcessor
    from qwen_vl_utils import process_vision_info
    
    QWEN_AVAILABLE = True
except ImportError:
    QWEN_AVAILABLE = False
    print("Qwen-VL未安装,展示代码框架...")

if QWEN_AVAILABLE:
    # 加载模型(需要较大显存,建议GPU)
    model_name = "Qwen/Qwen2-VL-7B-Instruct"
    
    print(f"正在加载 {model_name}...")
    print("(需要约16GB显存,可用4-bit量化减少)")
    
    # 4-bit量化加载(节省显存)
    model = Qwen2VLForConditionalGeneration.from_pretrained(
        model_name,
        torch_dtype=torch.bfloat16,
        device_map="auto",  # 自动分配层到GPU/CPU
    )
    
    processor = AutoProcessor.from_pretrained(model_name)
    
    print("✅ Qwen-VL加载完成!")
    
    # 准备测试图片(模拟或真实)
    # 创建模拟测试图
    np.random.seed(42)
    test_image = Image.new('RGB', (448, 448), color=(200, 180, 160))
    
    # 在图上画一些几何形状模拟"图表"
    import random
    pixels = test_image.load()
    for i in range(100, 350, 50):
        for j in range(100, 350):
            pixels[i, j] = (50, 100, 200)  # 蓝色柱状
    
    for i in range(200, 220):
        for j in range(100, 300):
            pixels[i, j] = (200, 50, 50)  # 红色柱状
    
    # 保存测试图
    test_image.save('/mnt/agents/output/test_chart.png')
    
    # 构造对话
    messages = [
        {
            "role": "user",
            "content": [
                {"type": "image", "image": "/mnt/agents/output/test_chart.png"},
                {"type": "text", "text": "描述这张图,并告诉我图中有什么形状。"},
            ],
        }
    ]
    
    # 处理输入
    text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
    image_inputs, video_inputs = process_vision_info(messages)
    inputs = processor(
        text=[text],
        images=image_inputs,
        videos=video_inputs,
        padding=True,
        return_tensors="pt",
    )
    inputs = inputs.to(model.device)
    
    # 生成
    with torch.no_grad():
        generated_ids = model.generate(**inputs, max_new_tokens=128)
    
    # 解码
    generated_ids_trimmed = [
        out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generated_ids)
    ]
    response = processor.batch_decode(
        generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False
    )[0]
    
    print(f"\n用户问题: 描述这张图,并告诉我图中有什么形状。")
    print(f"Qwen-VL回答:\n{response}")
    
    # 可视化
    fig, axes = plt.subplots(1, 2, figsize=(12, 5))
    
    axes[0].imshow(test_image)
    axes[0].set_title('Input Image')
    axes[0].axis('off')
    
    axes[1].text(0.5, 0.5, response, ha='center', va='center',
                fontsize=10, wrap=True,
                bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.8))
    axes[1].set_title('Qwen-VL Response')
    axes[1].axis('off')
    
    plt.tight_layout()
    plt.savefig('/mnt/agents/output/qwen_vl_response.png', dpi=150)
    plt.show()

else:
    # 展示代码框架
    print("""
Qwen-VL使用代码框架:

from transformers import Qwen2VLForConditionalGeneration, AutoProcessor
from qwen_vl_utils import process_vision_info

# 1. 加载模型(4-bit量化节省显存)
model = Qwen2VLForConditionalGeneration.from_pretrained(
    "Qwen/Qwen2-VL-7B-Instruct",
    torch_dtype=torch.bfloat16,
    device_map="auto",
)
processor = AutoProcessor.from_pretrained("Qwen/Qwen2-VL-7B-Instruct")

# 2. 构造多模态消息
messages = [
    {
        "role": "user",
        "content": [
            {"type": "image", "image": "path/to/image.jpg"},
            {"type": "text", "text": "描述这张图"},
        ],
    }
]

# 3. 处理并生成
text = processor.apply_chat_template(messages, tokenize=False)
image_inputs, video_inputs = process_vision_info(messages)
inputs = processor(text=[text], images=image_inputs, padding=True, return_tensors="pt")
inputs = inputs.to(model.device)

generated_ids = model.generate(**inputs, max_new_tokens=128)
response = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]

print(response)
    """)

print("\n" + "=" * 60)

5.3 实验2:构造视觉推理测试题

print("\n" + "=" * 60)
print("【实验2】构造视觉推理测试集")
print("=" * 60)

# 创建多道测试题,模拟MMBench/MMMU风格

test_questions = [
    {
        "name": "存在性判断",
        "image_type": "scene",
        "question": "图中有没有红色的物体?",
        "options": ["A. 有", "B. 没有"],
        "answer": "A",
        "difficulty": "简单",
        "skills": ["颜色识别", "存在性判断"]
    },
    {
        "name": "计数",
        "image_type": "objects",
        "question": "图中有几个圆形物体?",
        "options": ["A. 2个", "B. 3个", "C. 4个", "D. 5个"],
        "answer": "B",
        "difficulty": "中等",
        "skills": ["计数", "形状识别"]
    },
    {
        "name": "空间关系",
        "image_type": "scene",
        "question": "蓝色的物体在红色物体的哪一边?",
        "options": ["A. 左边", "B. 右边", "C. 上边", "D. 下边"],
        "answer": "A",
        "difficulty": "中等",
        "skills": ["空间关系", "颜色识别"]
    },
    {
        "name": "OCR理解",
        "image_type": "text_image",
        "question": "图中招牌上的电话号码是多少?",
        "options": ["A. 138-0000-0000", "B. 139-1234-5678", "C. 400-800-8888", "D. 无法识别"],
        "answer": "C",
        "difficulty": "中等",
        "skills": ["OCR", "信息提取"]
    },
    {
        "name": "图表推理",
        "image_type": "chart",
        "question": "根据柱状图,2023年销售额比2022年增长了多少百分比?",
        "options": ["A. 10%", "B. 20%", "C. 25%", "D. 50%"],
        "answer": "C",
        "difficulty": "困难",
        "skills": ["图表理解", "数学计算", "推理"]
    },
    {
        "name": "物理推理",
        "image_type": "physics_diagram",
        "question": "如果移除支撑物B,物体会向哪个方向倾倒?",
        "options": ["A. 向左", "B. 向右", "C. 保持平衡", "D. 无法判断"],
        "answer": "A",
        "difficulty": "困难",
        "skills": ["物理知识", "因果推理", "空间想象"]
    },
    {
        "name": "多图比较",
        "image_type": "multi_image",
        "question": "两张图中,哪张的桌子面积更大?",
        "options": ["A. 图1", "B. 图2", "C. 一样大", "D. 无法比较"],
        "answer": "B",
        "difficulty": "困难",
        "skills": ["跨图比较", "尺度判断", "面积估算"]
    }
]

# 打印测试集
print(f"构造了 {len(test_questions)} 道测试题:\n")
for i, q in enumerate(test_questions, 1):
    print(f"题{i}: {q['name']} [{q['difficulty']}]")
    print(f"  问题: {q['question']}")
    print(f"  选项: {', '.join(q['options'])}")
    print(f"  答案: {q['answer']}")
    print(f"  考察能力: {', '.join(q['skills'])}")
    print()

# 可视化难度分布
difficulties = [q['difficulty'] for q in test_questions]
difficulty_counts = {'简单': 0, '中等': 0, '困难': 0}
for d in difficulties:
    difficulty_counts[d] += 1

plt.figure(figsize=(8, 5))
colors = {'简单': 'green', '中等': 'orange', '困难': 'red'}
bars = plt.bar(difficulty_counts.keys(), difficulty_counts.values(),
               color=[colors[k] for k in difficulty_counts.keys()],
               alpha=0.7, edgecolor='black')
plt.title('Test Question Difficulty Distribution', fontsize=14)
plt.ylabel('Number of Questions')
plt.xlabel('Difficulty Level')

for bar in bars:
    height = bar.get_height()
    plt.text(bar.get_x() + bar.get_width()/2., height,
             f'{int(height)}', ha='center', va='bottom', fontsize=12)

plt.tight_layout()
plt.savefig('/mnt/agents/output/vlm_test_difficulty.png', dpi=150)
plt.show()

# 技能覆盖分析
all_skills = []
for q in test_questions:
    all_skills.extend(q['skills'])

skill_counts = {}
for skill in all_skills:
    skill_counts[skill] = skill_counts.get(skill, 0) + 1

plt.figure(figsize=(10, 6))
skills = list(skill_counts.keys())
counts = list(skill_counts.values())
colors_list = plt.cm.Set3(np.linspace(0, 1, len(skills)))

bars = plt.barh(skills, counts, color=colors_list, edgecolor='black')
plt.title('Skills Covered in Test Set', fontsize=14)
plt.xlabel('Number of Questions')

for i, bar in enumerate(bars):
    width = bar.get_width()
    plt.text(width, bar.get_y() + bar.get_height()/2.,
             f' {int(width)}', ha='left', va='center', fontsize=10)

plt.tight_layout()
plt.savefig('/mnt/agents/output/vlm_test_skills.png', dpi=150)
plt.show()

print("\n📊 测试集分析图已保存!")
print("=" * 60)

5.4 实验3:模拟模型对比评估

print("\n" + "=" * 60)
print("【实验3】模拟多模型对比评估")
print("=" * 60)

# 模拟不同模型在同一测试集上的表现
# (实际应用时,用真实模型跑测试集)

np.random.seed(42)

models = {
    'Qwen-VL-7B': {'base_acc': 0.65, 'ocr_bonus': 0.15, 'reasoning_penalty': -0.05},
    'InternVL-Chat-V1-5': {'base_acc': 0.70, 'ocr_bonus': 0.10, 'reasoning_penalty': -0.03},
    'LLaVA-1.5-13B': {'base_acc': 0.60, 'ocr_bonus': 0.05, 'reasoning_penalty': -0.08},
    'GPT-4V': {'base_acc': 0.85, 'ocr_bonus': 0.05, 'reasoning_penalty': 0.00},
}

# 为每道题、每个模型生成模拟结果
results = {model: [] for model in models}

for q in test_questions:
    for model_name, profile in models.items():
        # 基础准确率
        base = profile['base_acc']
        
        # 根据题目类型调整
        if 'OCR' in q['skills']:
            base += profile['ocr_bonus']
        if '推理' in q['skills'] or '因果' in str(q['skills']):
            base += profile['reasoning_penalty']
        
        # 根据难度调整
        if q['difficulty'] == '简单':
            base += 0.1
        elif q['difficulty'] == '困难':
            base -= 0.1
        
        # 加入随机性
        prob = np.clip(base + np.random.normal(0, 0.05), 0, 1)
        
        # 生成是否正确
        correct = np.random.random() < prob
        results[model_name].append({
            'correct': correct,
            'prob': prob,
            'question': q['name'],
            'difficulty': q['difficulty']
        })

# 计算总体指标
print("模型性能对比:\n")
print(f"{'模型':<20} {'总体准确率':<12} {'简单题':<10} {'中等题':<10} {'困难题':<10}")
print("-" * 65)

summary = {}
for model_name, res in results.items():
    total_correct = sum(1 for r in res if r['correct'])
    total = len(res)
    
    simple_correct = sum(1 for r in res if r['correct'] and r['difficulty'] == '简单')
    simple_total = sum(1 for r in res if r['difficulty'] == '简单')
    
    medium_correct = sum(1 for r in res if r['correct'] and r['difficulty'] == '中等')
    medium_total = sum(1 for r in res if r['difficulty'] == '中等')
    
    hard_correct = sum(1 for r in res if r['correct'] and r['difficulty'] == '困难')
    hard_total = sum(1 for r in res if r['difficulty'] == '困难')
    
    total_acc = total_correct / total
    simple_acc = simple_correct / simple_total if simple_total > 0 else 0
    medium_acc = medium_correct / medium_total if medium_total > 0 else 0
    hard_acc = hard_correct / hard_total if hard_total > 0 else 0
    
    summary[model_name] = {
        'total': total_acc,
        'simple': simple_acc,
        'medium': medium_acc,
        'hard': hard_acc
    }
    
    print(f"{model_name:<20} {total_acc:<12.1%} {simple_acc:<10.1%} {medium_acc:<10.1%} {hard_acc:<10.1%}")

# 可视化对比
fig, axes = plt.subplots(1, 2, figsize=(14, 6))

# 总体准确率对比
ax = axes[0]
model_names = list(summary.keys())
total_accs = [summary[m]['total'] for m in model_names]
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4']

bars = ax.bar(model_names, total_accs, color=colors, edgecolor='black', alpha=0.8)
ax.set_ylim(0, 1)
ax.set_ylabel('Accuracy')
ax.set_title('Overall Accuracy Comparison', fontsize=14)
ax.grid(True, alpha=0.3, axis='y')

for bar, acc in zip(bars, total_accs):
    height = bar.get_height()
    ax.text(bar.get_x() + bar.get_width()/2., height + 0.02,
            f'{acc:.1%}', ha='center', va='bottom', fontsize=11, weight='bold')

# 按难度分解
ax = axes[1]
x = np.arange(len(model_names))
width = 0.25

simple_accs = [summary[m]['simple'] for m in model_names]
medium_accs = [summary[m]['medium'] for m in model_names]
hard_accs = [summary[m]['hard'] for m in model_names]

bars1 = ax.bar(x - width, simple_accs, width, label='Simple', color='green', alpha=0.7)
bars2 = ax.bar(x, medium_accs, width, label='Medium', color='orange', alpha=0.7)
bars3 = ax.bar(x + width, hard_accs, width, label='Hard', color='red', alpha=0.7)

ax.set_ylabel('Accuracy')
ax.set_title('Accuracy by Difficulty Level', fontsize=14)
ax.set_xticks(x)
ax.set_xticklabels(model_names, rotation=15, ha='right')
ax.legend()
ax.grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.savefig('/mnt/agents/output/vlm_model_comparison.png', dpi=150)
plt.show()

# 雷达图:多维度能力对比
from math import pi

categories = ['存在性', '计数', '空间', 'OCR', '图表', '推理', '多图']
N = len(categories)

# 模拟各模型在各维度的表现
model_dims = {
    'Qwen-VL-7B': [0.85, 0.70, 0.75, 0.90, 0.65, 0.60, 0.55],
    'InternVL-Chat': [0.90, 0.75, 0.80, 0.85, 0.70, 0.65, 0.60],
    'LLaVA-1.5-13B': [0.80, 0.65, 0.70, 0.70, 0.60, 0.55, 0.50],
    'GPT-4V': [0.95, 0.85, 0.90, 0.95, 0.85, 0.80, 0.75],
}

fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True))

angles = [n / float(N) * 2 * pi for n in range(N)]
angles += angles[:1]

colors_radar = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4']
linestyles = ['-', '--', '-.', ':']

for i, (model_name, values) in enumerate(model_dims.items()):
    values += values[:1]
    ax.plot(angles, values, 'o-', linewidth=2, label=model_name,
            color=colors_radar[i], linestyle=linestyles[i])
    ax.fill(angles, values, alpha=0.1, color=colors_radar[i])

ax.set_xticks(angles[:-1])
ax.set_xticklabels(categories, fontsize=11)
ax.set_ylim(0, 1)
ax.set_title('VLM Capability Radar Chart', fontsize=14, pad=20)
ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1.0))

plt.tight_layout()
plt.savefig('/mnt/agents/output/vlm_radar_chart.png', dpi=150)
plt.show()

print("\n📊 模型对比图已保存!")
print("""
解读:
  GPT-4V:全面领先,但差距在缩小
  InternVL:接近GPT-4V,尤其在中文场景
  Qwen-VL:OCR和中文强,推理稍弱
  LLaVA:开源基础,适合二次开发
""")

print("\n" + "=" * 60)

5.5 实验4:工业应用场景演示

print("\n" + "=" * 60)
print("【实验4】工业应用:质检报告生成")
print("=" * 60)

# 模拟工业质检场景
def generate_inspection_report(image_path, defect_type, model_name="Qwen-VL"):
    """
    模拟VLM生成工业质检报告
    """
    # 实际应用时,用真实VLM推理
    # 这里是模拟输出
    
    templates = {
        "划痕": {
            "description": "产品表面发现线性划痕缺陷,长度约15mm,深度较浅,未贯穿涂层。",
            "cause": "可能原因:运输过程中与硬物摩擦,或装配工具接触。",
            "severity": "严重程度:中等。不影响功能,但影响外观。",
            "suggestion": "建议:1) 加强包装防护;2) 检查装配线工具;3) 对轻微划痕可抛光处理。"
        },
        "凹陷": {
            "description": "产品边缘发现局部凹陷,直径约8mm,深度约2mm。",
            "cause": "可能原因:注塑压力不足,或脱模时受力不均。",
            "severity": "严重程度:高。可能影响结构强度。",
            "suggestion": "建议:1) 调整注塑参数;2) 检查模具磨损;3) 该批次需全检。"
        },
        "色差": {
            "description": "产品与标准色板对比,存在明显色差(ΔE>3)。",
            "cause": "可能原因:颜料配比偏差,或烘烤温度不均。",
            "severity": "严重程度:中等。客户可能拒收。",
            "suggestion": "建议:1) 重新校准配色;2) 检查烘道温度分布;3) 隔离该批次。"
        }
    }
    
    info = templates.get(defect_type, templates["划痕"])
    
    report = f"""
========================================
工业视觉质检报告
========================================
检测模型: {model_name}
检测时间: 2024-01-15 14:32:08
产品型号: XYZ-2024-A
批次号:   BT-20240115-003

【缺陷识别】
{info['description']}

【根因分析】
{info['cause']}

【严重程度评估】
{info['severity']}

【处理建议】
{info['suggestion']}

【置信度】
模型置信度: 92.5%
人工复核: 待确认

========================================
"""
    return report

# 演示
defect_types = ["划痕", "凹陷", "色差"]

for defect in defect_types:
    print(f"\n{'='*50}")
    print(f"缺陷类型: {defect}")
    print(f"{'='*50}")
    
    report = generate_inspection_report("dummy.jpg", defect, "Qwen-VL-7B")
    print(report)

# 可视化:VLM在工业场景的工作流
print("\n" + "=" * 60)
print("VLM工业质检工作流")
print("=" * 60)

workflow = """
┌─────────────────────────────────────────────────────────┐
│  步骤1:图像采集                                          │
│  工业相机拍摄产品图像(高分辨率、多角度)                    │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  步骤2:VLM预处理                                         │
│  图像resize → 归一化 → 输入VLM                           │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  步骤3:VLM推理                                           │
│  Prompt: "分析这张产品图,识别缺陷类型、位置、严重程度,      │
│          并给出处理建议"                                   │
│                                                          │
│  VLM输出:结构化报告(缺陷描述 + 根因 + 建议)              │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  步骤4:人工复核                                          │
│  质检员查看VLM报告 + 原图,确认或修正                       │
│  修正数据回流,微调VLM(持续学习)                          │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  步骤5:决策执行                                           │
│  合格 → 流入下一工序                                       │
│  不合格 → 按建议处理(返工/报废/隔离)                      │
└─────────────────────────────────────────────────────────┘

优势:
  ✅ 减少人工目检疲劳和漏检
  ✅ 生成结构化报告,便于追溯
  ✅ 24小时不间断检测
  ✅ 持续学习,越用越准

挑战:
  ⚠️ 需要大量领域数据微调
  ⚠️ 实时性要求(需边缘部署)
  ⚠️ 小缺陷检测精度有限
  ⚠️ 幻觉问题(需人工复核)
"""

print(workflow)

# 可视化工作流
fig, ax = plt.subplots(figsize=(12, 10))
ax.set_xlim(0, 10)
ax.set_ylim(0, 12)

# 步骤框
steps = [
    (5, 11, "1. 图像采集", "#E8F5E9"),
    (5, 9, "2. VLM预处理", "#E3F2FD"),
    (5, 7, "3. VLM推理\n(缺陷识别+分析)", "#FFF3E0"),
    (5, 5, "4. 人工复核\n(确认+修正)", "#FCE4EC"),
    (5, 3, "5. 决策执行\n(合格/返工/报废)", "#F3E5F5"),
]

for x, y, text, color in steps:
    rect = plt.Rectangle((x-2, y-0.4), 4, 0.8, 
                        facecolor=color, edgecolor='black', linewidth=2)
    ax.add_patch(rect)
    ax.text(x, y, text, ha='center', va='center', 
           fontsize=11, weight='bold')

# 箭头
for y in [10.2, 8.2, 6.2, 4.2]:
    ax.annotate('', xy=(5, y-0.2), xytext=(5, y+0.2),
               arrowprops=dict(arrowstyle='->', lw=2, color='black'))

# 优势/挑战框
rect1 = plt.Rectangle((0.5, 0.5), 4, 1.5, 
                     facecolor='#C8E6C9', edgecolor='green', linewidth=2)
ax.add_patch(rect1)
ax.text(2.5, 1.5, '优势', ha='center', va='center', 
       fontsize=11, weight='bold', color='green')
ax.text(2.5, 1.0, '减少疲劳|结构化报告\n24h检测|持续学习', 
       ha='center', va='center', fontsize=9)

rect2 = plt.Rectangle((5.5, 0.5), 4, 1.5, 
                     facecolor='#FFCDD2', edgecolor='red', linewidth=2)
ax.add_patch(rect2)
ax.text(7.5, 1.5, '挑战', ha='center', va='center', 
       fontsize=11, weight='bold', color='red')
ax.text(7.5, 1.0, '领域微调|实时性\n小缺陷精度|幻觉复核', 
       ha='center', va='center', fontsize=9)

ax.set_title('VLM Industrial Quality Inspection Workflow', fontsize=14, weight='bold')
ax.axis('off')

plt.tight_layout()
plt.savefig('/mnt/agents/output/vlm_industrial_workflow.png', dpi=150)
plt.show()

print("\n📊 工业质检工作流图已保存!")
print("=" * 60)

六、核心总结

概念 一句话解释
MME 全面视觉能力评估,14个子任务
MMBench 选择题形式,20+维度自动评分
MMMU 大学水平多学科问题,难度最高
TextVQA 图中文字识别+问答
Qwen-VL 阿里出品,中文OCR和文档理解强
InternVL 商汤/清华,超大视觉编码器,接近GPT-4V
GPT-4V 全面领先但闭源,有空间精度和计数弱点
幻觉 VLM编造视觉信息,需RLHF和事实核查缓解

七、面试高频题

Q1:怎么科学评估一个VLM的好坏?

:不能只看总体分数,要分解到具体能力维度:1)基础感知(颜色、形状、计数);2)OCR(印刷体、手写体、多语言);3)推理(因果、数学、物理);4)多图(比较、时序、跨图关联)。用MMBench等自动评分基准,结合人工抽查,关注模型在目标应用场景的特定能力。

Q2:国产VLM和GPT-4V的差距在哪里?

:差距在缩小,但仍有:1)通用推理能力(MMMU差距5-10%);2)多语言混合场景;3)极端复杂图表;4)创意性视觉任务。国产优势:1)中文场景(OCR、文化理解);2)开源可定制;3)成本可控;4)数据隐私(可本地部署)。

Q3:VLM在工业部署的关键挑战?

:1)实时性:工业检测需要毫秒级响应,VLM推理慢,需模型压缩(量化、剪枝)或边缘计算;2)精度:小缺陷、低对比度场景,VLM可能不如专用检测模型;3)幻觉:质检报告不能出错,需人工复核机制;4)数据:工业数据隐私敏感,需联邦学习或本地微调。


八、课后作业

作业1:设计你的评估基准

# 为你的应用场景(如医疗、教育、零售)设计10道测试题
# 覆盖:存在性、计数、OCR、推理、多图
# 用真实VLM跑分,找出最适合你场景的模型

作业2:分析幻觉案例

# 收集VLM的10个错误回答
# 分类错误类型:幻觉、理解错、推理错、OCR错
# 分析哪种错误最多,针对性优化Prompt

作业3:思考VLM的终极形态

问题:未来的VLM应该是什么样子?

提示:
  1. 实时视频理解(流式输入)?
  2. 3D空间理解(点云、深度图)?
  3. 与机器人/AR结合(视觉→动作)?
  4. 多模态生成(看图→生成视频/3D模型)?

九、下讲预告

第12讲:多模态生成——从文生图到图生视频

我们将:

  • 理解Diffusion Model的核心机制
  • 探索Stable Diffusion、DALL-E 3、Midjourney
  • 动手用Diffusers库做文生图 + ControlNet
  • 了解Sora的视频生成原理
Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐