把结果导出成JSON格式,方便后续业务调用
本文是一篇聚焦工程落地的实践类技术博客,专为已初步运行“万物识别-中文-通用领域”模型的开发者而写。你可能已经成功执行了推理.py,看到了终端里几行中文识别结果;但当真正接入业务系统时,你会发现:控制台打印的文本无法被程序自动解析,人工复制易出错,多图批量处理无从下手,API对接缺少结构化响应——这些都不是模型能力的问题,而是输出形态的瓶颈。
本文不重复讲解环境搭建或基础推理流程,而是直击真实工程场景中的关键一环:如何将模型识别结果稳定、规范、可编程地导出为标准JSON格式。我们将从修改脚本、统一数据结构、支持多图批量、适配业务字段四个层面,手把手带你完成一次轻量但完整的工程化改造。所有代码均可直接复用,无需额外依赖,5分钟内即可让识别结果变成下游服务可直接消费的结构化数据。
1. 为什么必须导出JSON?——来自真实业务的三个痛点
在电商商品审核、智能相册归类、内容安全巡检等实际项目中,我们反复遇到以下问题:
- 前端无法解析纯文本:Vue/React应用需要
{label: "动物", score: 0.967}这样的对象,而不是识别结果: 动物 (置信度: 0.967)这样的字符串 - 批量任务丢失上下文:一次处理100张图片,如果每张都打印6行,日志里根本找不到某张图对应的结果
- 与现有系统对接困难:公司内部已有统一的数据网关,只接受
{"code":0,"data":[...]}格式的响应,而当前输出完全不兼容
这些问题的本质,是模型输出停留在“演示友好”阶段,尚未进入“生产就绪”状态。JSON不是技术炫技,而是现代软件协作的通用语言——它明确字段含义、定义数据类型、支持嵌套结构、天然兼容HTTP协议,是连接AI能力与业务逻辑最可靠的一座桥。
本文目标:让你的
python 推理.py命令,不再只输出几行文字,而是生成一个结构清晰、字段完整、可直接用于API返回或数据库写入的标准JSON文件。
2. 修改推理脚本:从打印到生成JSON对象
原始推理.py使用print()逐行输出,我们需要将其重构为构建字典结构,再序列化为JSON。这不是重写,而是精准替换——仅改动核心输出部分,保留全部预处理与推理逻辑。
2.1 定义标准输出结构
我们采用行业通用的识别结果Schema,兼顾可读性与扩展性:
{ "image_path": "/root/workspace/mydog.jpg", "timestamp": "2024-06-12T14:32:18+08:00", "results": [ { "label": "动物", "score": 0.967, "rank": 1 }, { "label": "人物", "score": 0.021, "rank": 2 } ], "top_label": "动物", "max_score": 0.967 }该结构包含:
image_path:记录原始输入路径,便于溯源timestamp:ISO 8601时间戳,满足审计与排序需求results:按置信度降序排列的完整结果列表top_label与max_score:高频访问字段,避免每次遍历数组
2.2 替换原输出逻辑(完整可运行代码)
打开/root/workspace/推理.py,定位到原print()循环位置(通常在topk(5)之后),将其整体替换为以下代码:
# -*- coding: utf-8 -*- import torch import json from datetime import datetime from PIL import Image from transformers import AutoModel, AutoProcessor # 加载模型与处理器(保持不变) model_name = "bailian/wwts-visual-recognition-base" processor = AutoProcessor.from_pretrained(model_name) model = AutoModel.from_pretrained(model_name) device = "cuda" if torch.cuda.is_available() else "cpu" model.to(device) # 加载图像(保持不变) image_path = "/root/workspace/mydog.jpg" # ← 请按需修改 image = Image.open(image_path).convert("RGB") # 图像预处理 + 文本提示(保持不变) inputs = processor( images=image, text=["动物", "人物", "交通工具", "食物", "建筑", "植物"], return_tensors="pt", padding=True ).to(device) # 模型推理(保持不变) with torch.no_grad(): outputs = model(**inputs) logits_per_image = outputs.logits_per_image probs = logits_per_image.softmax(dim=1) top_probs, top_labels = probs[0].topk(5) # === 关键修改区:构建JSON结构 === class_names = ["动物", "人物", "交通工具", "食物", "建筑", "植物"] # 构建results数组 results = [] for i in range(top_labels.shape[0]): label_idx = top_labels[i].item() results.append({ "label": class_names[label_idx], "score": round(top_probs[i].item(), 3), "rank": i + 1 }) # 构建完整输出字典 output_data = { "image_path": image_path, "timestamp": datetime.now().isoformat(), "results": results, "top_label": results[0]["label"], "max_score": results[0]["score"] } # 将结果写入JSON文件(推荐方式) output_file = image_path.rsplit(".", 1)[0] + "_result.json" with open(output_file, "w", encoding="utf-8") as f: json.dump(output_data, f, ensure_ascii=False, indent=2) print(f" 识别结果已保存至:{output_file}") print(f" 内容预览:{json.dumps(output_data, ensure_ascii=False, separators=(',', ':'))[:120]}...")2.3 运行验证
执行命令:
cd /root/workspace python 推理.py预期输出:
识别结果已保存至:/root/workspace/mydog_result.json 内容预览:{"image_path":"/root/workspace/mydog.jpg","timestamp":"2024-06-12T14:32:18.123456","results":[{"label":"动物","score":0.967,"rank":1}...同时,在文件浏览器中可看到新生成的mydog_result.json文件,双击即可查看格式化内容。
3. 支持多图批量处理:一次调用,多个JSON
单图处理只是起点。真实业务中,你往往需要处理一个目录下的数十张商品图、上百张用户上传照片。我们只需增加一个简单的循环,就能实现批量能力。
3.1 创建批量处理脚本batch_inference.py
在/root/workspace下新建文件batch_inference.py,内容如下:
# -*- coding: utf-8 -*- import os import json import torch from datetime import datetime from PIL import Image from transformers import AutoModel, AutoProcessor # 复用模型加载逻辑(与推理.py一致) model_name = "bailian/wwts-visual-recognition-base" processor = AutoProcessor.from_pretrained(model_name) model = AutoModel.from_pretrained(model_name) device = "cuda" if torch.cuda.is_available() else "cpu" model.to(device) # 配置参数 IMAGE_DIR = "/root/workspace/images" # 存放待识别图片的目录 SUPPORTED_EXT = {".png", ".jpg", ".jpeg"} # 确保目录存在 os.makedirs(IMAGE_DIR, exist_ok=True) # 获取所有图片文件 image_files = [ os.path.join(IMAGE_DIR, f) for f in os.listdir(IMAGE_DIR) if os.path.splitext(f)[1].lower() in SUPPORTED_EXT ] if not image_files: print(" 目录中未找到图片文件,请先上传PNG/JPG格式图片到 /root/workspace/images") exit(1) print(f" 发现 {len(image_files)} 张图片,开始批量识别...") # 批量处理 all_results = [] for idx, image_path in enumerate(image_files, 1): try: print(f" [{idx}/{len(image_files)}] 正在处理:{os.path.basename(image_path)}") # 加载并预处理 image = Image.open(image_path).convert("RGB") inputs = processor( images=image, text=["动物", "人物", "交通工具", "食物", "建筑", "植物"], return_tensors="pt", padding=True ).to(device) # 推理 with torch.no_grad(): outputs = model(**inputs) probs = outputs.logits_per_image.softmax(dim=1) top_probs, top_labels = probs[0].topk(5) # 构建单图结果 class_names = ["动物", "人物", "交通工具", "食物", "建筑", "植物"] results = [] for i in range(top_labels.shape[0]): label_idx = top_labels[i].item() results.append({ "label": class_names[label_idx], "score": round(top_probs[i].item(), 3), "rank": i + 1 }) # 记录到总结果 all_results.append({ "image_path": image_path, "timestamp": datetime.now().isoformat(), "results": results, "top_label": results[0]["label"], "max_score": results[0]["score"] }) except Exception as e: print(f" ❌ 处理失败:{os.path.basename(image_path)} — {str(e)}") all_results.append({ "image_path": image_path, "error": str(e), "timestamp": datetime.now().isoformat() }) # 保存汇总JSON summary_file = "/root/workspace/batch_result.json" with open(summary_file, "w", encoding="utf-8") as f: json.dump({ "summary": { "total_images": len(image_files), "successful": len([r for r in all_results if "error" not in r]), "failed": len([r for r in all_results if "error" in r]), "generated_at": datetime.now().isoformat() }, "details": all_results }, f, ensure_ascii=False, indent=2) print(f" 批量处理完成!汇总结果已保存至:{summary_file}")3.2 使用方法
- 在左侧文件浏览器中,进入
/root/workspace,新建文件夹images - 将多张测试图片(如
product1.jpg,product2.png)上传至该文件夹 - 终端执行:
cd /root/workspace python batch_inference.py - 查看生成的
batch_result.json,其中details数组即为每张图的独立识别结果
提示:该脚本具备错误隔离能力——单张图片处理失败不会中断整个流程,错误信息会以
"error"字段记录,便于后续排查。
4. 适配业务系统:自定义字段与灵活提示词
不同业务对识别结果的要求不同。电商关注“是否含违禁品”,教育APP需要“是否出现人脸”,内容平台则要“是否含敏感场景”。我们通过两个小改造,让JSON输出真正贴合你的业务语义。
4.1 添加业务标识字段
在推理.py的output_data字典中,插入业务相关字段:
# 在构建 output_data 字典时,加入以下字段 output_data = { "image_path": image_path, "timestamp": datetime.now().isoformat(), "business_id": "ecommerce_v2", # ← 业务系统唯一标识 "task_type": "content_moderation", # ← 任务类型 "results": results, "top_label": results[0]["label"], "max_score": results[0]["score"] }这样,下游服务可通过business_id路由到对应处理逻辑,无需二次解析图片路径。
4.2 动态提示词配置
将固定text列表改为从外部读取,支持按场景切换:
# 在脚本开头添加配置区 BUSINESS_CONFIG = { "ecommerce_v2": ["服装", "鞋帽", "箱包", "饰品", "违禁品", "品牌Logo"], "edu_app": ["人脸", "书本", "黑板", "实验器材", "危险物品"], "news_platform": ["旗帜", "集会", "武器", "血腥", "政治人物", "正常场景"] } # 使用时 business_id = "ecommerce_v2" text_list = BUSINESS_CONFIG.get(business_id, ["动物", "人物", "交通工具"]) inputs = processor( images=image, text=text_list, # ← 动态提示词 return_tensors="pt", padding=True ).to(device)4.3 输出字段映射(可选增强)
若业务方要求字段名与现有系统完全一致(如"label"需改为"category","score"需改为"confidence"),只需在构建results时做字段重命名:
results.append({ "category": class_names[label_idx], # 原 label → category "confidence": round(top_probs[i].item(), 3), # 原 score → confidence "rank": i + 1 })这种零侵入式适配,让模型能力无缝融入任何遗留系统。
5. 总结:从“能跑通”到“可交付”的关键跨越
把识别结果导出为JSON,看似只是一个小小的格式转换,实则是AI模型从实验室走向生产线的分水岭。本文没有引入复杂框架,也没有增加运维负担,而是通过四步务实改造,帮你完成了这次关键跨越:
- 第一步:定义清晰、通用、可扩展的JSON Schema,让数据有据可依
- 第二步:重构输出逻辑,用
json.dump()替代print(),确保结果可存储、可追溯 - 第三步:封装批量处理能力,支持目录级操作,满足真实业务吞吐需求
- 第四步:开放业务字段与提示词配置,让同一模型适配多场景,拒绝硬编码
你现在拥有的,不再是一个只能在终端里“看看效果”的Demo,而是一个可集成、可监控、可维护的AI能力模块。下一步,你可以轻松将其封装为FastAPI接口:
@app.post("/recognize") def recognize_image(file: UploadFile = File(...)): # 保存上传文件 → 调用上述逻辑 → 返回JSON响应 return JSONResponse(content=output_data)或者接入Airflow定时任务,每天凌晨自动扫描新图片并入库。真正的工程价值,就藏在这些看似微小、却直指业务本质的细节之中。
--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。