1. 从标注数据到可运行检测模型:object_detection_api 训练预测全流程拆解
object_detection_api 是 TensorFlow 官方提供的一套目标检测工具箱,它把 Faster R-CNN、SSD、CenterNet 等主流检测网络封装成统一的配置驱动流程。你只要准备好标注数据、写一份 pipeline 配置文件,就能用同一套命令完成训练、评估和导出推理图。它适合谁?适合手里已经有 VOC 或 COCO 格式标注、想在自己机器上跑通一次完整训练并验证推理结果的开发者,而不是只想调个在线接口的人。
我见过太多人卡在中间环节:数据转 tfrecord 报编码错、config 里路径没改全、训练跑起来 loss 不动、导出 pb 后预测框全错。这些问题的根源往往不是模型本身,而是数据格式和配置文件的细节没对齐。这篇就按“数据准备 → 配置 → 训练 → 评估 → 导出 → 预测”的顺序,把每一步的可复制命令和踩坑点写清楚。
整个流程可以拆成六个阶段,每个阶段都有明确的输入和输出:
| 阶段 | 输入 | 输出 | 关键文件 |
|---|---|---|---|
| 数据准备 | 标注 XML + 原图 | tfrecord | create_xx_tf_record.py |
| 配置 | 预训练模型 config | 自定义 pipeline.config | faster_rcnn_resnet101_xx.config |
| 训练 | tfrecord + config | ckpt 检查点 | train.py |
| 评估 | ckpt + val.record | mAP 指标 | eval.py |
| 导出 | ckpt + config | frozen_inference_graph.pb | export_inference_graph.py |
| 预测 | pb + label_map | 可视化结果 | demo_xx.py |
如果你只是想在本地快速验证一个检测模型能不能跑通,这套流程完全够用。下面从环境前置开始,一步步来。
2. TaoToken 前置准备:模型下载与 API Key 配置
object_detection_api 本身是本地训练框架,但预训练模型权重、部分依赖包的下载,以及后续如果你想用大模型辅助生成标注或调试代码,会涉及网络访问。这里我用 TaoToken 来做统一的模型与 API 接入层,它的官网是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 端点是 https://taotoken.net/api 。
先说清楚它在这里的角色:TaoToken 不是替代 TensorFlow 的框架,而是帮你管理模型访问凭证和调用入口。比如你在调试阶段想让大模型帮你检查 config 文件里的字段是否写错,或者根据报错日志给出修复建议,就可以通过它的 API 来调用。对于长期做检测项目的人来说,把 API Key 和 Base URL 统一配置好,后面切换模型或做批量推理会省很多事。
配置方式很简单,在项目根目录建一个环境变量文件,或者在终端里 export:
export TAOTOKEN_API_KEY="你的API Key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"如果你用的是 Python 脚本调用,可以这样读:
import os import requests api_key = os.environ.get("TAOTOKEN_API_KEY") base_url = os.environ.get("TAOTOKEN_BASE_URL") headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } payload = { "model": "claude-3-5-sonnet", "messages": [ {"role": "user", "content": "帮我检查这段 pipeline config 的 num_classes 和 label_map 是否一致"} ] } resp = requests.post(f"{base_url}/v1/messages", headers=headers, json=payload, timeout=60) print(resp.json())API Key 的获取入口在 https://taotoken.net/api-keys ,进去后创建一个新 Key,复制出来填到上面的环境变量里。注意不要把 Key 硬编码进提交到 Git 的脚本里,用 .env 或者系统环境变量管理。
模型对话的调试入口在 https://taotoken.net/models ,你可以在这里先测试一下模型能不能正常返回,确认 Key 和 Base URL 没问题,再去写自动化脚本。对于检测项目来说,这个环节主要用在两个地方:一是生成数据转换脚本的模板代码,二是根据训练日志里的报错定位问题。比如你遇到DataLossError: Unable to open table file,可以把完整报错贴给模型,让它给出排查方向,比翻 issue 快很多。
如果你后面要做长期的编码和 Agent 任务,比如自动生成标注转换脚本、批量跑推理,可以考虑 Coding Plan,入口在 https://taotoken.net/coding-plan 。它的定位是给需要持续调用模型的开发场景用的,不是一次性问答。
3. 可复制配置:pipeline.config 与数据转换脚本
这一节是整篇的核心,所有内容都可以直接复制到你的项目里改路径就能用。先看数据存放结构,我按 VOC 格式来组织:
data/ ├── label_map.pbtxt └── VOC2007/ ├── Annotations/ │ ├── 000001.xml │ └── ... ├── ImageSets/ │ └── Main/ │ ├── train.txt │ └── val.txt └── JPEGImages/ ├── 000001.jpg └── ...label_map.pbtxt 的内容按类别写,id 从 1 开始,0 留给背景:
item { id: 1 name: "cat" } item { id: 2 name: "dog" }数据转换脚本基于官方的 create_pascal_tf_record.py 改,核心改动是路径和字段。把脚本放到 data 同级目录,命名为 create_xx_tf_record.py,然后改这几处:
# 主函数里的路径 data_dir = './data' label_map_path = './data/label_map.pbtxt' output_path = './data/xx_train.tfrecord' examples_path = os.path.join(data_dir, 'VOC2007', 'ImageSets', 'Main', 'train.txt') # 如果 XML 里没有 width/height,改成从图片读 width, height = image.size # 注释掉不需要的字段 # difficult_obj.append(int(difficult)) # truncated.append(int(obj['truncated'])) # poses.append(obj['pose'].encode('utf8'))运行转换命令:
python create_xx_tf_record.py \ --data_dir=./data \ --year=VOC2007 \ --set=train \ --label_map_path=./data/label_map.pbtxt \ --output_path=./data/xx_train.tfrecord验证 tfrecord 是否生成成功,可以用一段小脚本读一条出来看:
import tensorflow as tf raw_dataset = tf.data.TFRecordDataset('./data/xx_train.tfrecord') for raw_record in raw_dataset.take(1): example = tf.train.Example() example.ParseFromString(raw_record.numpy()) print(example.features.feature['image/object/class/text'].bytes_list.value)接下来是 pipeline.config。从 detection_model_zoo 下载 faster_rcnn_resnet101_coco 的 config,复制一份改名为 faster_rcnn_resnet101_xx.config,然后改这几个字段:
model { faster_rcnn { num_classes: 2 image_resizer { keep_aspect_ratio_resizer { min_dimension: 600 max_dimension: 1024 } } } } train_config { batch_size: 1 fine_tune_checkpoint: "./demo_xx/model.ckpt" fine_tune_checkpoint_type: "detection" num_steps: 50000 data_augmentation_options { random_horizontal_flip { } } } train_input_reader { label_map_path: "./data/label_map.pbtxt" tf_record_input_reader { input_path: "./data/xx_train.tfrecord" } } eval_config { num_examples: 100 metrics_set: "pascal_voc_detection_metrics" } eval_input_reader { label_map_path: "./data/label_map.pbtxt" shuffle: false num_readers: 1 tf_record_input_reader { input_path: "./data/xx_val.tfrecord" } }注意 num_classes 必须和 label_map 里的类别数一致,fine_tune_checkpoint 指向预训练模型的 ckpt 前缀(不带 .index 或 .data 后缀)。如果你下载的预训练模型是三个文件 model.ckpt.data-00000-of-00001、model.ckpt.index、model.ckpt.meta,那 fine_tune_checkpoint 就写./demo_xx/model.ckpt。
4. 训练启动与推理验证:从 train.py 到 frozen_inference_graph.pb
配置写好后,训练命令本身很简单,但路径和参数要对齐:
python object_detection/train.py \ --logtostderr \ --pipeline_config_path=./demo_xx/faster_rcnn_resnet101_xx.config \ --train_dir=./demo_xx/train训练启动后,终端会打印每一步的 loss。正常情况下 loss 会从几降到零点几,如果一直不动或者报 NaN,先检查学习率和 batch_size。faster_rcnn 在单卡上 batch_size 设 1 是常态,显存不够就再降 image_resizer 的 min_dimension。
评估命令:
python object_detection/eval.py \ --logtostderr \ --pipeline_config_path=./demo_xx/faster_rcnn_resnet101_xx.config \ --checkpoint_dir=./demo_xx/train \ --eval_dir=./demo_xx/eval评估结果会写进 eval_dir,用 tensorboard 看:
tensorboard --logdir=./demo_xx/eval重点看 Pascal VOC mAP 这个指标,如果 mAP 在 0.5 以上,说明模型基本可用。如果低于 0.2,大概率是 label_map 的 id 和 XML 里的类别对不上,或者 tfrecord 里的图片和标注错位了。
训练到满意程度后,导出推理图:
python object_detection/export_inference_graph.py \ --input_type image_tensor \ --pipeline_config_path ./demo_xx/faster_rcnn_resnet101_xx.config \ --trained_checkpoint_prefix ./demo_xx/train/model.ckpt-50000 \ --output_directory ./demo_xx/output这里的 model.ckpt-50000 要换成你 train_dir 里实际存在的最大步数检查点。导出成功后,output 目录下会有 frozen_inference_graph.pb。
预测脚本基于官方 notebook 改写,核心是加载 pb 和 label_map:
import numpy as np import tensorflow as tf from PIL import Image from object_detection.utils import label_map_util from object_detection.utils import visualization_utils as vis_util PATH_TO_CKPT = './demo_xx/output/frozen_inference_graph.pb' PATH_TO_LABELS = './data/label_map.pbtxt' NUM_CLASSES = 2 detection_graph = tf.Graph() with detection_graph.as_default(): od_graph_def = tf.GraphDef() with tf.gfile.GFile(PATH_TO_CKPT, 'rb') as fid: serialized_graph = fid.read() od_graph_def.ParseFromString(serialized_graph) tf.import_graph_def(od_graph_def, name='') label_map = label_map_util.load_labelmap(PATH_TO_LABELS) categories = label_map_util.convert_label_map_to_categories( label_map, max_num_classes=NUM_CLASSES, use_display_name=True) category_index = label_map_util.create_category_index(categories) with detection_graph.as_default(): with tf.Session(graph=detection_graph) as sess: image_tensor = detection_graph.get_tensor_by_name('image_tensor:0') boxes = detection_graph.get_tensor_by_name('detection_boxes:0') scores = detection_graph.get_tensor_by_name('detection_scores:0') classes = detection_graph.get_tensor_by_name('detection_classes:0') num_detections = detection_graph.get_tensor_by_name('num_detections:0') image = Image.open('./test_images/000001.jpg') image_np = np.array(image) image_np_expanded = np.expand_dims(image_np, axis=0) (boxes_out, scores_out, classes_out, num_out) = sess.run( [boxes, scores, classes, num_detections], feed_dict={image_tensor: image_np_expanded}) vis_util.visualize_boxes_and_labels_on_image_array( image_np, np.squeeze(boxes_out), np.squeeze(classes_out).astype(np.int32), np.squeeze(scores_out), category_index, use_normalized_coordinates=True, line_thickness=4) Image.fromarray(image_np).save('./test_images/result_000001.jpg')跑完后打开 result_000001.jpg,看框的位置和类别是否正确。如果框全在左上角或者类别全错,先检查 label_map 的 id 顺序和训练时是否一致,再检查输入图片的通道顺序。
5. 常见报错排查:401、DataLossError、pycocotools 与 OAuth 问题
这一节按真实报错来对照,每个都给出定位方法和修复动作。
401 Unauthorized / invalid api key:如果你在调用 TaoToken API 时遇到 401,先确认环境变量里的 Key 没有多余空格,再确认 Base URL 是 https://taotoken.net/api 而不是带 UTM 的官网地址。API 端点和官网是两个不同的入口,混用会报 401。修复方式:
echo $TAOTOKEN_API_KEY curl -H "Authorization: Bearer $TAOTOKEN_API_KEY" https://taotoken.net/api/v1/models如果 curl 返回 200,说明 Key 没问题,问题在代码里的读取逻辑。
DataLossError: Unable to open table file:这个报错通常出现在 fine_tune_checkpoint 路径写错的时候。新版 TensorFlow 的 ckpt 是三个文件,fine_tune_checkpoint 要写前缀,比如./demo_xx/model.ckpt,而不是./demo_xx/model.ckpt.index。另外确认 ckpt 文件和 config 在同一台机器上,路径不要用 Windows 的反斜杠。
No module named 'pycocotools':COCO API 在 Windows 上安装容易失败。从源码编译:
git clone https://github.com/philferriere/cocoapi.git cd cocoapi/PythonAPI python setup.py build_ext --inplace python setup.py build_ext install如果 build_ext 报缺少 Visual C++ 编译环境,装一个 Build Tools 再重试。装完后import pycocotools不报错即可。
local proxy failed / connection refused:这类报错一般出现在调用外部 API 时。先确认网络能通,再检查代码里有没有硬编码的代理地址。如果你在 config 或脚本里写了 proxy 相关配置,删掉,直接用系统默认网络。
OAuth token expired:如果你用 OAuth 方式接入模型服务,token 过期后会报这个。重新走一遍授权流程,或者改用 API Key 方式。TaoToken 的 API Key 方式不需要 OAuth,直接在 https://taotoken.net/api-keys 生成即可。
reading choices / shape mismatch:这个报错出现在预测阶段,通常是 num_classes 和 label_map 的类别数不一致。比如 label_map 里有 3 个类别,config 里 num_classes 写了 2,导出 pb 后预测就会 shape mismatch。修复方式是统一改成实际类别数,重新导出。
CC Switch / Cline MCP / Codex auth.json 三件套:如果你在检测项目里用这些工具做辅助编码,配置时要写全三件套——Base URL、Key、Model ID。以 auth.json 为例:
{ "base_url": "https://taotoken.net/api", "api_key": "你的Key", "model": "claude-3-5-sonnet" }缺任何一个都会导致调用失败。Model ID 要和 https://taotoken.net/models 里列出的名称一致,不要自己拼。
6. 语义一致 CTA:把训练流程接到你的实际项目里
走到这一步,你已经有了一个能跑通训练和预测的检测模型。接下来最实际的动作是把这套流程接到你自己的数据上。先换 label_map,再换 tfrecord,然后改 config 里的 num_classes 和路径,重新跑一遍 train.py。如果 mAP 不达标,优先加数据而不是调模型,检测任务里数据质量和标注一致性比网络结构影响大得多。
如果你在调试过程中需要快速定位报错,或者想让模型帮你生成数据转换脚本的变体,可以用 TaoToken 的模型对话入口 https://taotoken.net/models 先测一下调用是否正常。API Key 在 https://taotoken.net/api-keys 生成,接入文档在 https://taotoken.net/doc 有完整的请求示例。对于需要长期跑编码和 Agent 任务的场景,Coding Plan 的入口在 https://taotoken.net/coding-plan ,适合把模型调用固化到你的开发流程里。
最后给一个实用技巧:训练前先用 100 张图跑 500 步,确认 loss 能降、eval 能出 mAP,再上全量数据。这样能把数据格式问题在早期暴露出来,比跑了一天发现 tfrecord 错位要省时间。导出 pb 后,先用训练集里的图做预测,确认框的位置和训练时可视化的一致,再去测新图。这一步能帮你区分是模型没学好还是导出环节出了问题。