论文信息
标题: Search-based Testing of Vision Language Models for In-Car Scene Understanding
会议: ECCV 2026
作者: Chen Yang (TU Munich), Ken E. Friedl (BMW), Andrea Stocco (TU Munich/fortiss)
链接: https://arxiv.org/html/2607.02300
核心创新: 首次提出基于搜索的VLM测试框架,在工业级原型上实现10倍故障发现率
研究背景 VLM在座舱场景理解中的应用 场景理解系统(ISU)定义:
接收2D座舱图像,生成结构化/非结构化文本描述的系统
两种输出模式:
模式
输入
输出
应用场景
VQA(视觉问答)
图像+结构化问题
JSON键值对
DMS状态检测、安全带识别
VC(视觉描述)
图像+自由提示
自然语言描述
场景理解、异常检测
示例:
1 2 3 4 5 6 7 8 9 { "gender" : "female" , "seat_belt" : "off" , "baby_on_board" : "true" } "The car shows a smiling female driver sitting next to a baby, holding a phone in her hand."
测试挑战 传统测试方法局限:
方法
问题
真实数据采集
成本高、难以覆盖极端场景、隐私争议
静态数据集
缺乏可控性、可能已用于训练、无法生成新场景
随机场景生成
故障发现率低、缺乏针对性
论文核心问题:
如何系统化地生成多样化座舱场景,并高效发现VLM的故障?
ISU-Test框架 整体架构 graph TB
A[场景定义] --> B[场景采样]
B --> C[场景生成]
C --> D[VLM执行]
D --> E[评估与Oracle]
E --> F{失败?}
F -->|是| G[记录故障]
F -->|否| H[优化算法]
H --> B
style A fill:#f9f,stroke:#333,stroke-width:2px
style G fill:#f96,stroke:#333,stroke-width:2px
style H fill:#9cf,stroke:#333,stroke-width:2px
1. 场景定义与表示 场景特征分类:
类别
特征示例
数据类型
驾驶员特征
情绪、姿态、性别、交互对象
离散/连续
静态对象
行李、水瓶、儿童座椅
离散
自适应对象
安全带(需适配人体)
连续
环境参数
光照强度、外部场景
连续
场景向量表示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 scene_vector = { 'driver_gender' : 'female' , 'driver_emotion' : 'smiling' , 'driver_pose' : 'normal' , 'driver_weight' : 65.0 , 'seatbelt_attached' : False , 'baby_present' : True , 'luggage_color' : 'yellow' , 'illumination' : 'medium' , 'external_scene' : 'highway' }
2. 场景生成 SMPL-X人体模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import numpy as npclass SMPLXGenerator : """ SMPL-X参数化人体模型生成器 参数: - 身高、体重、BMI - 姿态(关节角度) - 情绪(面部表情) """ def __init__ (self ): self .body_shape_params = ['height' , 'weight' , 'bmi' ] self .pose_params = ['head_pitch' , 'head_yaw' , 'head_roll' , 'shoulder_left' , 'shoulder_right' , 'elbow_left' , 'elbow_right' ] self .emotion_params = ['smile' , 'frown' , 'surprise' ] def generate (self, params ): """ 生成SMPL-X人体模型 Args: params: { 'height': 175, # cm 'weight': 70, # kg 'pose': {'head_pitch': 10, ...}, 'emotion': 'smiling' } Returns: human_model: SMPL-X模型对象 """ shape = self .map_body_shape(params['height' ], params['weight' ]) pose = self .map_pose(params['pose' ]) expression = self .map_emotion(params['emotion' ]) human_model = self .create_smplx(shape, pose, expression) return human_model def map_body_shape (self, height, weight ): """ 将身高体重映射为SMPL-X形状参数 """ shape_vector = np.zeros(10 ) shape_vector[0 ] = (height - 170 ) / 10 shape_vector[1 ] = (weight - 70 ) / 15 shape_vector[2 ] = (weight / (height/100 )**2 - 24 ) / 5 return shape_vector
自适应对象生成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class AdaptiveSeatbelt : """ 自适应安全带生成器 根据人体形状自动调整安全带路径 """ def __init__ (self ): self .attachment_points = { 'shoulder' : 'upper_anchor' , 'hip' : 'lower_anchor' } def generate (self, human_model, attached=True ): """ 生成安全带3D模型 Args: human_model: SMPL-X人体模型 attached: 是否佩戴 Returns: seatbelt_mesh: 安全带网格模型 """ if not attached: return self .generate_loose_belt(human_model) shoulder = human_model.get_keypoint('left_shoulder' ) hip = human_model.get_keypoint('left_hip' ) path = self .generate_bezier_path(shoulder, hip) seatbelt_mesh = self .extrude_along_path(path, width=0.05 ) return seatbelt_mesh def generate_loose_belt (self, human_model ): """ 生成未佩戴的安全带(松弛状态) """ return self .generate_draped_belt()
环境参数生成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class EnvironmentGenerator : """ 环境参数生成器 包括:光照、外部场景 """ def __init__ (self ): self .lighting_presets = { 'low' : {'intensity' : 0.3 , 'color' : (255 , 200 , 150 )}, 'medium' : {'intensity' : 0.6 , 'color' : (255 , 255 , 255 )}, 'high' : {'intensity' : 1.0 , 'color' : (255 , 255 , 240 )} } self .external_scenes = [ 'highway' , 'city' , 'parking' , 'tunnel' , 'night' ] def setup_scene (self, illumination, external_scene, panoramic_photo ): """ 设置场景环境 Args: illumination: 'low' | 'medium' | 'high' external_scene: 场景类型 panoramic_photo: 外部全景照片(HDR) """ light_config = self .lighting_presets[illumination] self .setup_lighting(light_config) self .setup_external_view(panoramic_photo)
3. 搜索算法 问题形式化:
定义: ISU搜索测试问题 $P = (ISU, D, F, O)$
$ISU$:座舱场景理解系统(被测系统)
$D \subseteq \mathbb{R}^n$:搜索空间
$F$:适应度函数
$O$:Oracle函数
适应度函数设计:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class FitnessFunction : """ 适应度函数 评估生成的场景是否暴露VLM故障 """ def __init__ (self, vlm_model ): self .vlm = vlm_model def evaluate (self, scene_vector, scene_image ): """ 计算适应度值 Returns: fitness_values: (f1, f2, ..., fm) """ vlm_output = self .vlm.predict(scene_image) expected_output = self .get_expected_output(scene_vector) fitness_values = [] for feature in scene_vector: if feature in expected_output and feature in vlm_output: diff = self .compute_difference( expected_output[feature], vlm_output[feature] ) fitness_values.append(diff) return fitness_values def compute_difference (self, expected, actual ): """ 计算预期值与实际值的差异 """ if isinstance (expected, str ): return 0.0 if expected == actual else 1.0 elif isinstance (expected, (int , float )): return abs (expected - actual) / (abs (expected) + 1e-6 )
Oracle函数设计:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class OracleFunction : """ Oracle函数 判断是否发现故障 """ def __init__ (self, threshold=0.5 ): self .threshold = threshold def is_failure (self, fitness_values ): """ 判断是否为故障场景 Args: fitness_values: 适应度值向量 Returns: is_failure: True if failure detected """ if max (fitness_values) > self .threshold: return True if np.mean(fitness_values) > self .threshold * 0.8 : return True return False
优化算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 import randomfrom typing import List , Tuple class SearchOptimizer : """ 基于搜索的优化器 使用遗传算法搜索故障场景 """ def __init__ (self, population_size=50 , mutation_rate=0.1 ): self .population_size = population_size self .mutation_rate = mutation_rate def search (self, fitness_func, oracle, n_generations=100 ): """ 搜索故障场景 Args: fitness_func: 适应度函数 oracle: Oracle函数 n_generations: 迭代代数 Returns: failures: 发现的故障场景列表 """ population = self .initialize_population() failures = [] for gen in range (n_generations): fitness_values = [] for individual in population: f = fitness_func.evaluate(individual) fitness_values.append(f) if oracle.is_failure(f): failures.append(individual) selected = self .selection(population, fitness_values) offspring = self .crossover(selected) population = self .mutation(offspring) return failures def initialize_population (self ): """ 随机初始化种群 """ population = [] for _ in range (self .population_size): individual = self .random_scene_vector() population.append(individual) return population def selection (self, population, fitness_values ): """ 轮盘赌选择 """ selected = [] for i, (ind, f) in enumerate (zip (population, fitness_values)): if max (f) > 0.5 : selected.append(ind) while len (selected) < self .population_size // 2 : selected.append(random.choice(population)) return selected def crossover (self, population ): """ 单点交叉 """ offspring = [] for i in range (0 , len (population) - 1 , 2 ): parent1 = population[i] parent2 = population[i + 1 ] cross_point = random.randint(1 , len (parent1) - 1 ) child1 = {**parent1} child2 = {**parent2} keys = list (parent1.keys()) for key in keys[cross_point:]: child1[key] = parent2[key] child2[key] = parent1[key] offspring.extend([child1, child2]) return offspring def mutation (self, population ): """ 随机变异 """ for individual in population: if random.random() < self .mutation_rate: key = random.choice(list (individual.keys())) individual[key] = self .random_value(key) return population
4. 完整测试流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 class ISUTest : """ ISU-Test完整测试框架 """ def __init__ (self, vlm_model, renderer ): self .vlm = vlm_model self .renderer = renderer self .generator = SMPLXGenerator() self .optimizer = SearchOptimizer() def run (self, n_generations=100 ): """ 运行测试 """ fitness_func = FitnessFunction(self .vlm) oracle = OracleFunction(threshold=0.5 ) failures = self .optimizer.search( fitness_func, oracle, n_generations ) return failures def generate_scene (self, scene_vector ): """ 根据场景向量生成渲染图像 """ human = self .generator.generate({ 'height' : scene_vector['driver_height' ], 'weight' : scene_vector['driver_weight' ], 'pose' : scene_vector['driver_pose' ], 'emotion' : scene_vector['driver_emotion' ] }) seatbelt = AdaptiveSeatbelt().generate( human, scene_vector['seatbelt_attached' ] ) EnvironmentGenerator().setup_scene( scene_vector['illumination' ], scene_vector['external_scene' ], scene_vector['panoramic_photo' ] ) image = self .renderer.render() return imageif __name__ == "__main__" : vlm = VLMModel.load("gpt-4-vision" ) renderer = BlenderRenderer() isu_test = ISUTest(vlm, renderer) failures = isu_test.run(n_generations=100 ) print (f"发现故障场景: {len (failures)} " ) analyze_failures(failures)
实验结果 性能对比
方法
故障发现率
覆盖率
故障多样性
随机生成
12%
35%
低
ISU-Test
120% (10倍)
126% (3.6倍)
高
关键发现:
VQA模式: 结构化输出易于评估,故障发现率更高
VC模式: 开放式描述更难评估,但发现的问题更丰富
工业原型: 在BMW原型系统上验证有效性
故障类型分析
故障类型
VQA模式
VC模式
安全带误检
高频
中频
婴儿漏检
高频
低频
物体幻觉
低频
高频
性别误判
中频
中频
典型故障场景 场景1:低光照+安全带误检
1 2 3 4 5 6 7 8 9 10 failure_scene_1 = { 'illumination' : 'low' , 'seatbelt_attached' : True , 'driver_emotion' : 'neutral' , 'vlm_output' : { 'seat_belt' : 'off' } }
场景2:婴儿+行李混淆
1 2 3 4 5 6 7 8 9 10 11 failure_scene_2 = { 'baby_present' : True , 'luggage_color' : 'yellow' , 'luggage_location' : 'rear_left' , 'vlm_output' : { 'baby_on_board' : 'false' , 'objects' : ['yellow luggage' ] } }
IMS应用启示 1. VLM测试流水线 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class IMSVLMTestPipeline : """ IMS VLM测试流水线 """ def __init__ (self ): self .scenarios = self .load_euro_ncap_scenarios() self .isu_test = ISUTest(VLMModel.load(), Renderer()) def run_tests (self ): """ 运行Euro NCAP相关测试 """ results = { 'dms' : self .test_dms(), 'seatbelt' : self .test_seatbelt(), 'cpd' : self .test_cpd(), 'occupant' : self .test_occupant() } return results def test_seatbelt (self ): """ 安全带检测测试 """ seatbelt_scenarios = [ {'illumination' : 'low' , 'attached' : True }, {'illumination' : 'high' , 'attached' : False }, {'driver_pose' : 'leaning' , 'attached' : True } ] failures = [] for scenario in seatbelt_scenarios: if self .isu_test.test_scenario(scenario): failures.append(scenario) return { 'total' : len (seatbelt_scenarios), 'failures' : len (failures), 'failure_rate' : len (failures) / len (seatbelt_scenarios) }
2. 持续集成测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class CIIntegration : """ 持续集成测试 """ def __init__ (self ): self .test_pipeline = IMSVLMTestPipeline() def run_on_commit (self ): """ 每次提交后运行测试 """ results = self .test_pipeline.run_tests() if self .check_pass(results): print ("✅ 测试通过" ) else : print ("❌ 测试失败" ) self .report_failures(results) def check_pass (self, results ): """ 检查是否通过 """ for module, result in results.items(): if result['failure_rate' ] > 0.1 : return False return True
3. 合成数据生成 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class SyntheticDataGenerator : """ 基于ISU-Test的合成数据生成 """ def __init__ (self, n_samples=1000 ): self .n_samples = n_samples self .isu_test = ISUTest(VLMModel.load(), Renderer()) def generate_dataset (self ): """ 生成合成数据集 """ dataset = [] for i in range (self .n_samples): scene_vector = self .random_scene_vector() image = self .isu_test.generate_scene(scene_vector) dataset.append({ 'image' : image, 'label' : scene_vector, 'id' : f'synthetic_{i} ' }) return dataset def random_scene_vector (self ): """ 随机场景向量 """ return { 'driver_gender' : random.choice(['male' , 'female' ]), 'driver_emotion' : random.choice(['smiling' , 'neutral' , 'frown' ]), 'seatbelt_attached' : random.choice([True , False ]), 'baby_present' : random.choice([True , False ]), 'illumination' : random.choice(['low' , 'medium' , 'high' ]) }
4. 开发优先级
测试模块
场景数量
自动化程度
优先级
安全带检测
50
高
🔴 高
DMS状态
100
高
🔴 高
CPD检测
30
中
🟡 中
乘员分类
40
中
🟡 中
物体检测
60
低
🟢 低
总结 ISU-Test首次将基于搜索的测试 应用于VLM座舱场景理解 ,在工业级原型上实现10倍故障发现率 提升。核心贡献:
框架: 模块化测试框架(场景定义→生成→执行→优化)
技术: 新颖的适应度函数和Oracle定义
评估: 工业级原型+开源VLM验证
IMS开发启示:
集成ISU-Test到CI/CD流水线
使用合成数据补充训练集
重点关注低光照、遮挡、复杂背景场景
参考论文: Search-based Testing of Vision Language Models for In-Car Scene Understanding, ECCV 2026