一、搞清楚json文件的格式1、VRSBench_train.json这是一个训练集包含了用于模型训练的对话数据。每条数据包含 ID、图像名称和对话内容对话由人类提问和 AI 回答组成。问题类型多样包括图像描述caption、目标定位refer、视觉问答vqa等。可用于训练模型理解遥感图像内容、回答相关问题以及定位图像中的目标等能力。2、VRSBench_EVAL_vqa.json这是一个评估集包含了针对遥感图像的问答对。每条数据包含图像 ID、问题、标准答案ground_truth、数据集名称、问题 ID 和问题类型如物体颜色、数量、存在性、位置等。可用于评估模型在遥感图像理解任务上的性能通过对比模型回答与标准答案来判断模型效果。二、任务描述及步骤你现在有一个包含 VQA 数据的 JSON 文件如VRSBench_EVAL_vqa.json每条 VQA 是一个单一答案问题生成VQA问题的要求特别是对于答案的要求每个问题的答案应该是一个单词或短语不超过3个单词。我们的目标是将每个 VQA 问题变成一个“多选”格式包含一个正确答案和若干错误选项干扰项调用 DeepSeek 的 API 自动生成错误选项保存为一个结构清晰的新 JSON 文件重点设计 prompt引导 DeepSeek 高质量生成干扰选项。每个VQA问题生成一个多选问题即在每个问题条目中添加一个choices字段该字段包含4个选项A、B、C、D其中一个是正确答案ground_truth另外三个是错误选项。同时我们还需要添加一个answer字段该字段为正确答案对应的字母如A。2.1 解决方案1. 读取VRSBench_EVAL_vqa.json文件加载所有问题条目。2. 对于每个问题条目1根据type字段决定如何生成三个错误选项- 如果是下面提到的预设规则类型则用预设规则生成。- 否则调用模型生成。(如果正确答案在列表中则从列表中移除正确答案然后随机选择3个如果不在则调用模型生成。)预设规则覆盖的类型 type:object quantity - 数字规则 type:object color - 颜色列表 type:object position - 位置列表 type:object direction - 方向列表 type:object existence - 存在性规则固定反义词 type:object shape - 形状列表 type:rural or urban - 场景扩展列表注意正确答案只有rural/urban干扰项用其他场景类型 调用模型生成干扰项的类型 type:object category物体类别 type:object size物体大小因为大小描述可能多样如large, small, medium等我们可以预设但为了通用性调用模型 type:scene type场景类型 type:reasoning推理2四个选项 [ground_truth] 三个错误选项3打乱四个选项的顺序使用random.shuffle4记录正确答案在打乱后的选项中的索引0,1,2,3然后映射为字母0-A, 1-B, 2-C, 3-D 在条目中添加两个字段choices: 打乱后的四个选项列表answer: 正确答案对应的字母如A3. 将修改后的数据写回到一个新的JSON文件或者覆盖原文件但建议新文件。2.2 设计prompt的预设规则注意对于存在性问题我们生成三个错误选项都是正确答案的反义词的不同表达然后四个选项包括正确答案和三个错误选项再打乱。注意对于存在性问题我们生成三个错误选项都是正确答案的反义词的不同表达然后四个选项包括正确答案和三个错误选项再打乱。 实现细节 预设规则 - object quantity: 生成三个数字 规则在正确答案的周围取三个整数避免重复和正确答案。例如正确答案为3则取2,4,5注意不要重复。 具体取 [n-1, n1, n2] 然后去重去掉n如果出现负数则用正数替代比如n0则取1,2,3n1则取0,2,3。如果生成的数字不够三个则补充随机数比如在0到10之间随机取直到凑够三个。 - object color: 预设颜色列表 [red, green, blue, yellow, white, black, gray, brown, orange, purple]去掉正确答案不区分大小写然后随机取三个。如果正确答案在列表中则从列表中移除正确答案然后随机选择3个如果不在则调用模型生成。 - object position: 预设位置列表 [top-left, top-right, bottom-left, bottom-right, middle-left, middle-right, center, top-middle, bottom-middle]去掉正确答案不区分大小写然后随机取三个。 - object direction: 预设方向列表 [north-south, east-west, north-east, south-west, north-west, south-east]去掉正确答案不区分大小写然后随机取三个。 - object existence: 如果ground_truth是Yes不区分大小写则三个错误选项为[No, Not present, Not visible] 如果ground_truth是No则三个错误选项为[Yes, Present, Visible] 注意这里我们假设ground_truth只有Yes和No且首字母可能大写。 - object shape: 由于形状的答案可能是特定词汇如圆形、矩形等我们可以预设一个形状列表然后从中选取干扰项。 预设形状列表[circle, rectangle, triangle, square, oval, polygon, irregular] 规则如果正确答案在列表中则从列表中移除正确答案然后随机选择3个如果不在则调用模型生成。 - rural or urban: 这是一个二分类问题可能的答案只有两个rural, urban。预设一个列表[suburban, industrial, residential, commercial, mountainous, coastal]。然后从中随机选择3个但要确保正确答案不在干扰项中。 - 其他类型object category, object size,scene typereasoning: 调用模型生成。 我们使用以下prompt模板 prompt f Generate three plausible but incorrect distractors for a visual reasoning question. Question: {question} Correct Answer: {correct_answer} Requirements: 1. Distractors must be: - Relevant to the image context - Factually incorrect - Short phrases (1-3 words max) 2. Avoid these prohibited elements: - Time of day (day/night/dusk/dawn) - Motion states (moving/parked/flying) - Image sources (Google Earth/aerial/satellite) - Facing directions (nose/tail of vehicles) 3. Format as JSON list: [distractor1, distractor2, distractor3] Examples: Question: What pattern do the buildings follow? Correct Answer: grid layout Distractors: [random arrangement, circular pattern, linear alignment] Question: Is the area predominantly rural? Correct Answer: Mixed Distractors: [Urban only, Purely rural, Industrial] Now generate for: Question: {question} Correct Answer: {correct_answer} 2.3 代码运行前的准备1、DeepSeek API配置申请自己的的API KEY和URL5分钟带你获取deepseek api并搭建简易问答应用_deepseek api key怎么获取-CSDN博客1、获取api首先打开deepseek接口的官网:DeepSeek点右上角“开放平台”接着点击左侧的API keys,然后点击创建API key一般需要给API key命名用来区分不同的API比如下图命名为“test” 这里需要注意的是系统生成的API key只有第一次创建时能看到并且复制此后都无法再次看到只能看到名字所以需要大家第一次就将其复制下来保存到你的文件中当然如果忘记了也影响不大重新创建一个就行。2、获取base_url和chat_model同样以deepseek为例点击2.1.1页面左下角的接口文档或者直接进入DeepSeek API文档进入文档后在“快速开始”的“首次调用API”中可以找到base_url和chat_model如下base_url https://api.deepseek.com/v1chat_modeldeepseek-chat其他平台与deepseek的获取方式差不多3、配置模型参数base_url和chat_model直接定义即可但api key是关乎着模型是否能够使用的所以尽量不要把其暴露在模型定理里面而是把他添加到环境变量里。这个方法是在安全地管理 API 密钥避免将敏感信息直接写在代码中。终端输入命令临时创建也比较麻烦而且只在当前终端内有效而创建.env文件存储api_key则不存在这种问题。首先创建.env文件然后输入以下内容记得替换成你的tokenapi_keyyour api_key同一路径下创建脚本文件然后在代码中添加以下内容import os from dotenv import load_dotenv # 加载.env文件中的环境变量 load_dotenv() # 获取特定的环境变量 api_key os.getenv(api_key) base_url https://api.deepseek.com/v1 chat_model deepseek-chat如何通过.env文件安全管理大模型 API 密钥deepseek-CSDN博客调用deep seek生成json文件代码import json import random import openai import os # 新增导入os模块用于读取环境变量 from dotenv import load_dotenv from tqdm import tqdm # 加载.env文件中的环境变量 load_dotenv() # 初始化DeepSeek客户端 - 修复API密钥获取问题 def init_deepseek_client(): # 从环境变量获取API密钥 api_key os.getenv(DEEPSEEK_API_KEY) # 如果未找到环境变量尝试直接读取.env文件 if not api_key: try: from dotenv import dotenv_values config dotenv_values(.env) api_key config.get(DEEPSEEK_API_KEY) except: pass if not api_key: raise ValueError(未找到DEEPSEEK_API_KEY。请在.env文件中设置或在环境变量中添加) return openai.OpenAI( api_keyapi_key, base_urlhttps://api.deepseek.com/v1, ) # DeepSeek API调用简化客户端初始化无需重复传参 def call_deepseek_api(prompt): try: client init_deepseek_client() # 直接使用上面的初始化函数 response client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: prompt}], temperature0.7, max_tokens200 ) return response.choices[0].message.content.strip() except Exception as e: print(fAPI调用失败: {e}) return [] # 各类型干扰项生成器带列表外检测 def generate_quantity_distractors(correct_answer): try: n int(correct_answer) candidates {str(n-1), str(n1), str(n2)} while len(candidates) 3: candidates.add(str(random.randint(max(0, n-3), n5))) return list(candidates) except ValueError: return None def generate_color_distractors(correct_answer): color_list [red, green, blue, yellow, white, black, gray, brown, orange, purple, light blue, dark green, beige, tan, silver] normalized_colors [c.strip().lower() for c in color_list] correct_normalized correct_answer.strip().lower() # 部分匹配检测如Dark green匹配dark green if any(correct_normalized in c for c in normalized_colors): available_colors [c for c in color_list if correct_normalized not in c.lower()] return random.sample(available_colors, min(3, len(available_colors))) return None def generate_position_distractors(correct_answer): position_list [top-left, top-right, bottom-left, bottom-right, middle-left, middle-right, center, top, bottom, middle-top, middle-bottom, left, right] normalized_positions [p.strip().lower() for p in position_list] correct_normalized correct_answer.strip().lower() if correct_normalized in normalized_positions: idx normalized_positions.index(correct_normalized) available_positions position_list[:idx] position_list[idx1:] return random.sample(available_positions, min(3, len(available_positions))) return None def generate_direction_distractors(correct_answer): direction_list [north-south, east-west, north-east, south-west, north-west, south-east, horizontal, vertical, diagonal, straight, curved] normalized_directions [d.strip().lower() for d in direction_list] correct_normalized correct_answer.strip().lower() if correct_normalized in normalized_directions: idx normalized_directions.index(correct_normalized) available_directions direction_list[:idx] direction_list[idx1:] return random.sample(available_directions, min(3, len(available_directions))) return None def generate_existence_distractors(correct_answer): is_yes correct_answer.lower() in [yes, y, true] base_options [No, Not present, Not visible] if is_yes else [Yes, Present, Visible] # 保持原始大小写风格 if correct_answer[0].isupper(): return [opt.capitalize() for opt in base_options] return base_options def generate_shape_distractors(correct_answer): shape_list [circle, rectangle, triangle, square, oval, polygon, irregular, round, linear, curved, narrow, wide, l-shaped, rectangular] normalized_shapes [s.strip().lower() for s in shape_list] correct_normalized correct_answer.strip().lower() if correct_normalized in normalized_shapes: idx normalized_shapes.index(correct_normalized) available_shapes shape_list[:idx] shape_list[idx1:] return random.sample(available_shapes, min(3, len(available_shapes))) return None def generate_scene_distractors(correct_answer): scene_list [residential, industrial, commercial, agricultural, transportation, recreational, educational, military, urban, rural, mixed, semi-urban, suburban] normalized_scenes [s.strip().lower() for s in scene_list] correct_normalized correct_answer.strip().lower() if correct_normalized in normalized_scenes: idx normalized_scenes.index(correct_normalized) available_scenes scene_list[:idx] scene_list[idx1:] return random.sample(available_scenes, min(3, len(available_scenes))) return None # 优化API调用函数 def generate_api_distractors(question, correct_answer): client init_deepseek_client() prompt f Generate three plausible but incorrect distractors for a visual reasoning question. Question: {question} Correct Answer: {correct_answer} Requirements: 1. Distractors must be: - Relevant to the image context - Factually incorrect - Short phrases (1-3 words max) 2. Avoid these prohibited elements: - Time of day (day/night/dusk/dawn) - Motion states (moving/parked/flying) - Image sources (Google Earth/aerial/satellite) - Facing directions (nose/tail of vehicles) 3. Format as JSON list: [distractor1, distractor2, distractor3] Examples: Question: What pattern do the buildings follow? Correct Answer: grid layout Distractors: [random arrangement, circular pattern, linear alignment] Question: Is the area predominantly rural? Correct Answer: Mixed Distractors: [Urban only, Purely rural, Industrial] Now generate for: Question: {question} Correct Answer: {correct_answer} try: response client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: prompt}], temperature0.7, max_tokens200, response_format{type: json_object} ) content response.choices[0].message.content.strip() # 处理可能的JSON格式变化 if distractors in content: return json.loads(content)[distractors][:3] elif isinstance(content, list): return content[:3] else: # 尝试直接解析为列表 try: return json.loads(content)[:3] except: # 作为最后手段分割字符串 return [s.strip([]) for s in content.split(,)][:3] except Exception as e: print(fAPI调用错误: {e}) # 返回有意义的默认选项 return [fDistractor {i1} for i in range(3)] # 主处理函数 - 移除client参数 def generate_options(item): question_type item[type].lower() correct_answer str(item[ground_truth]) # 存在性问题优先处理 if question_type object existence or \ (correct_answer.lower() in [yes, no, y, n] and any(kw in item[question].lower() for kw in [ is , are , does , do ])): return generate_existence_distractors(correct_answer) # 类型分发 generator_map { quantity: generate_quantity_distractors, color: generate_color_distractors, position: generate_position_distractors, direction: generate_direction_distractors, shape: generate_shape_distractors, scene: generate_scene_distractors, rural: generate_scene_distractors, urban: generate_scene_distractors, } # 查找匹配的生成器 for key, generator in generator_map.items(): if key in question_type: distractors generator(correct_answer) if distractors is not None: return distractors # 默认API生成 return generate_api_distractors(item[question], correct_answer) def add_multichoice_options(input_path, output_path): with open(input_path, r) as f: data json.load(f) for item in tqdm(data, desc处理问题): # 生成干扰选项 distractors generate_options(item) # 构建选项列表 choices [str(d) for d in distractors] [str(item[ground_truth])] # 去重并确保4个选项 unique_choices list(set(choices)) if len(unique_choices) 4: # 添加唯一性选项 for i in range(4 - len(unique_choices)): unique_choices.append(fOption {chr(65len(unique_choices))}) random.shuffle(unique_choices) # 记录正确答案 try: answer_index unique_choices.index(str(item[ground_truth])) answer_letter chr(65 answer_index) except ValueError: # 如果正确答案不在选项中将其添加为第一个选项 unique_choices[0] str(item[ground_truth]) answer_letter A # 添加新字段 item[choices] unique_choices item[answer] answer_letter with open(output_path, w) as f: json.dump(data, f, indent2, ensure_asciiFalse) # 执行 if __name__ __main__: # 确保.env文件存在并包含DEEPSEEK_API_KEY if not os.path.exists(.env): with open(.env, w) as f: f.write(DEEPSEEK_API_KEYyour_api_key_here) print(已创建.env文件请在其中添加您的DeepSeek API密钥) else: add_multichoice_options(VRSBench_EVAL_vqa.json, VRSBench_EVAL_multichoiceVQA.json)附录修改代码1、Import openai could not be resolved 错误通常是因为没有安装openai库导致的。解决方法如下pip install openai2、或者根据当前目录向上导航如果路径正确的话# 从当前目录向上返回3级目录 cd ../../../
