GPT-4o 目标检测微调实战:JSONL 数据集准备、模型微调与结果可视化
这篇教程根据我在 GPT-4o 视觉微调任务中的学习和项目复现经验整理,重点跑通 OpenAI JSONL 数据集检查、训练文件上传、微调任务创建、模型推理和检测结果可视化。
如果你已经有标注好的目标检测数据,并希望把它整理成多模态对话格式用于 GPT-4o 微调,这篇可以作为一份从数据到推理结果的实操模板。
本文会重点跑通以下流程:
- 安装 OpenAI、可视化和数据处理依赖
- 从数据集后台获取 OpenAI JSONL 格式数据
- 检查训练、验证和测试集 JSONL 文件
- 创建 GPT-4o 微调任务并查询状态
- 调用微调模型完成目标检测推理并可视化
如果你正在系统学习目标检测、实例分割、OCR、多目标跟踪或视觉大模型,建议收藏本文;配套 notebook、示例图片和运行环境说明后续会继续整理。如果环境配置卡住,可以在评论区说明具体报错。
📚 文章目录
- GPT-4o 目标检测微调实战:JSONL 数据集准备、模型微调与结果可视化
- ⚙️ 环境准备
- 📦 从数据集后台获取 JSONL 数据集
- 🚀 创建 GPT-4o 微调任务
- 🧪 使用微调模型推理
- 🖼️ 解析检测结果并可视化
- 📌 小结
- 📚 同系列教程汇总
⚙️ 环境准备
先检查运行环境并安装依赖。建议在 Colab 或带 NVIDIA GPU 的环境中运行,避免训练或视频推理阶段显存不足。
!pip install-q openai supervision maestro==0.2.0rc5📦 从数据集后台获取 JSONL 数据集
这里不在文章中暴露后台项目配置。实际复现时,从数据集后台导出对应格式,解压后把路径填到DATASET_DIR即可。
fromtypesimportSimpleNamespace# 从数据集后台下载 OpenAI JSONL 格式数据集后,修改 DATASET_DIR 指向解压目录。DATASET_DIR="/content/dataset"# 修改为数据集后台导出的数据集目录dataset=SimpleNamespace(location=DATASET_DIR,name="poker-cards")!wc-l{dataset.location}/_annotations.train.jsonl !wc-l{dataset.location}/_annotations.valid.jsonl !wc-l{dataset.location}/_annotations.test.jsonl!head-n1{dataset.location}/_annotations.train.jsonl!head-n200{dataset.location}/_annotations.train.jsonl>{dataset.location}/_annotations.train.200.jsonl🚀 创建 GPT-4o 微调任务
微调流程包括初始化 OpenAI 客户端、上传训练与验证文件、创建任务以及查询状态。
# @title Initiate OpenAI clientfromopenaiimportOpenAIfromgoogle.colabimportuserdata OPENAI_API_KEY=userdata.get('OPENAI_API_KEY')client=OpenAI(api_key=OPENAI_API_KEY)# @title Upload a training and validation filetraining_file_upload_response=client.files.create(file=open(f"{dataset.location}/_annotations.train.200.jsonl","rb"),purpose="fine-tune")validation_file_upload_response=client.files.create(file=open(f"{dataset.location}/_annotations.valid.jsonl","rb"),purpose="fine-tune")print("treaining file response:",training_file_upload_response)print("validation file response:",validation_file_upload_response)# @title Create a fine-tuned modelimportredefprocess_suffix(text:str)->str:"""将字符串转换为 kebab-case,用作微调任务后缀。"""returnre.sub(r'\s+','-',text.strip()).lower()fine_tuning_response=client.fine_tuning.jobs.create(training_file=training_file_upload_response.id,validation_file=validation_file_upload_response.id,suffix=process_suffix(dataset.name),model="gpt-4o-2024-08-06")fine_tuning_response# @title Check training job statusstatus_response=client.fine_tuning.jobs.retrieve(fine_tuning_response.id)status_response🧪 使用微调模型推理
训练任务成功后,使用返回的微调模型名称对测试集消息进行推理。
# @title Load test datasetimportrandomfromtorch.utils.dataimportDatasetfrommaestro.trainer.common.utils.file_systemimportread_jsonlclassJSONLDataset(Dataset):"""用于加载和管理 JSONL 数据的 PyTorch Dataset。"""@classmethoddeffrom_jsonl_file(cls,path:str):"""从 JSONL 文件加载数据,打乱后返回数据集实例。"""file_content=read_jsonl(path=path)random.shuffle(file_content)returncls(jsons=file_content)def__init__(self,jsons:list[dict])->None:"""使用 JSON 对象列表初始化数据集。"""self.jsons=jsonsdef__getitem__(self,index):"""按索引读取一条 JSON 数据。"""returnself.jsons[index]def__len__(self)->int:"""返回数据集样本数量。"""returnlen(self.jsons)defshuffle(self)->None:"""原地打乱数据顺序。"""random.shuffle(self.jsons)defextract_image_url(data):"""从消息列表中提取第一张图片 URL。"""formessageindata:ifmessage['role']=='user'andisinstance(message['content'],list):foriteminmessage['content']:ifitem.get('type')=='image_url':returnitem['image_url']['url']returnNonetest_dataset=JSONLDataset.from_jsonl_file(f"{dataset.location}/_annotations.test.jsonl")test_dataset[0]['messages']# @title Run inference using fine-tuned modelcompletion=client.chat.completions.create(model=status_response.fine_tuned_model,messages=test_dataset[0]['messages'][:-1])completion.choices[0].message🖼️ 解析检测结果并可视化
最后把模型输出解析成检测框,并叠加到原图上检查效果。
# @title Post-process inference resultimportrequestsimportsupervisionassvfromPILimportImage URL=extract_image_url(test_dataset[0]['messages'])image=Image.open(requests.get(URL,stream=True).raw)detections=sv.Detections.from_lmm(lmm=sv.LMM.PALIGEMMA,result=completion.choices[0].message.content,resolution_wh=image.size)box_annotator=sv.BoxAnnotator(color_lookup=sv.ColorLookup.INDEX)label_annotator=sv.LabelAnnotator(color_lookup=sv.ColorLookup.INDEX)annotated_image=image.copy()annotated_image=box_annotator.annotate(scene=image,detections=detections)annotated_image=label_annotator.annotate(scene=annotated_image,detections=detections)sv.plot_image(annotated_image)# @title Run inference on multiple imagesfromtqdm.notebookimporttqdm SAMPLE=9annotated_images=[]foriintqdm(range(SAMPLE)):completion=client.chat.completions.create(model=status_response.fine_tuned_model,messages=test_dataset[i]['messages'][:-1])url=extract_image_url(test_dataset[i]['messages'])image=Image.open(requests.get(url,stream=True).raw)detections=sv.Detections.from_lmm(lmm=sv.LMM.PALIGEMMA,result=completion.choices[0].message.content,resolution_wh=image.size)box_annotator=sv.BoxAnnotator(color_lookup=sv.ColorLookup.INDEX)label_annotator=sv.LabelAnnotator(color_lookup=sv.ColorLookup.INDEX)annotated_image=image.copy()annotated_image=box_annotator.annotate(scene=image,detections=detections)annotated_image=label_annotator.annotate(scene=annotated_image,detections=detections)annotated_images.append(annotated_image)sv.plot_images_grid(annotated_images,grid_size=(3,3),size=(16,16))📌 小结
这一篇的关键不在于写复杂训练循环,而在于把目标检测数据整理成 OpenAI 微调接口可接受的 JSONL 消息格式,并确保训练、验证、测试三个阶段的数据路径一致。
这一类 notebook 建议按“先环境、再数据、再单样例、最后批量推理”的顺序复现。遇到报错时,优先检查 GPU、依赖版本、数据集目录和模型权重路径。
后续我会继续按源项目顺序整理同系列中的目标检测、实例分割、OCR、多目标跟踪和视觉大模型教程。
📚 同系列教程汇总
Google Gemini 3.5 Flash 零样本目标检测教程:从提示词到可视化结果
GLM-OCR 文档识别实战教程:从验证码、公式到车牌 OCR
RF-DETR + ByteTrack 多目标跟踪实战教程:从命令行到 Python 视频轨迹可视化
SAM 3 图像分割实战教程:文本、框和点提示的多种分割方式
SAM 3 视频分割实战教程:用文本提示分割并跟踪视频中的目标
Google Gemini 2.5 零样本检测与分割实战:从 JSON 结果到可视化-本文