使用create_coco_tf_record脚本转换COCO标签JSON为TFRecord时遇序列化错误
解决TFRecord写入错误:‘tuple’对象没有‘SerializeToString’属性
这个错误我之前在处理COCO转TFRecord时遇到过,核心问题非常清晰——你传给TFRecordWriter.write()方法的是一个元组(tuple),但TFRecord只接受能调用SerializeToString()的Protobuf对象,比如tf.train.Example或者tf.train.SequenceExample。结合你用create_coco_tf_record类脚本的场景,我来拆解具体原因和解决办法:
可能的错误原因
- 构造TFExample时返回了元组而非Protobuf对象:你可能在处理图片特征、标注信息时,把多个数据打包成了tuple(比如
return (img_feature, bbox_feature)),然后直接把这个tuple传给了writer.write(),而没有封装成标准的tf.train.Example。 - 未关联COCO的标注数据:你的代码只遍历了
label_info["images"],但COCO的标注存在annotations字段里,如果没按image_id匹配标注,后续构造Example时可能生成错误的数据结构(比如tuple)。 - 代码片段遗漏部分出错:你提供的代码到
image["fi..."]中断了,大概率是这里处理图片路径/数据时返回了tuple,导致后续传给writer的不是合法的Example对象。
具体解决方法
1. 确保传给writer的是tf.train.Example实例
必须把图片数据、标注信息(bbox、类别ID、面积等)全部封装成tf.train.Features结构,再构建成tf.train.Example,最后调用它的SerializeToString()方法写入。示例代码如下:
import tensorflow as tf from collections import defaultdict def create_coco_tf_example(image_data, image_info, annotations): # 提取图片基础信息 height = image_info["height"] width = image_info["width"] # 整理标注数据 xmins = [] xmaxs = [] ymins = [] ymaxs = [] class_ids = [] for ann in annotations: # COCO的bbox格式是[x, y, width, height],转成xmin/xmax/ymin/ymax x, y, w, h = ann["bbox"] xmins.append(x / width) xmaxs.append((x + w) / width) ymins.append(y / height) ymaxs.append((y + h) / height) class_ids.append(ann["category_id"]) # 构建Feature字典 feature_dict = { "image/encoded": tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_data])), "image/height": tf.train.Feature(int64_list=tf.train.Int64List(value=[height])), "image/width": tf.train.Feature(int64_list=tf.train.Int64List(value=[width])), "image/object/bbox/xmin": tf.train.Feature(float_list=tf.train.FloatList(value=xmins)), "image/object/bbox/xmax": tf.train.Feature(float_list=tf.train.FloatList(value=xmaxs)), "image/object/bbox/ymin": tf.train.Feature(float_list=tf.train.FloatList(value=ymins)), "image/object/bbox/ymax": tf.train.Feature(float_list=tf.train.FloatList(value=ymaxs)), "image/object/class/label": tf.train.Feature(int64_list=tf.train.Int64List(value=class_ids)), } # 返回tf.train.Example对象 return tf.train.Example(features=tf.train.Features(feature=feature_dict)) # 主流程修改 with open('coco_labels.json') as json_data: label_info = json.load(json_data) # 先把标注按image_id分组,方便后续匹配 annotations_by_image = defaultdict(list) for ann in label_info["annotations"]: annotations_by_image[ann["image_id"]].append(ann) IMAGE_FOLDER = "coco_images" with tf.python_io.TFRecordWriter("training.record") as writer: for i, image in enumerate(label_info["images"]): # 获取对应图片的标注 image_id = image["id"] image_annotations = annotations_by_image.get(image_id, []) # 读取图片数据(这里建议本地读取,而非requests.get,避免网络问题) # 如果你的file_name是URL才用requests,否则用本地路径 img_data = requests.get(image["file_name"]).content # 或者本地读取:img_data = open(os.path.join(IMAGE_FOLDER, image["file_name"]), 'rb').read() # 生成TFExample并写入 tf_example = create_coco_tf_example(img_data, image, image_annotations) writer.write(tf_example.SerializeToString())
2. 检查所有返回值类型
如果你用了自定义函数处理数据,一定要确认函数返回的是tf.train.Example,而不是tuple或其他类型。比如不要写出return (img_data, annotations)这种代码,必须把这些数据封装成Protobuf对象后返回。
3. 修复图片数据读取逻辑
如果你的image["file_name"]是本地路径,建议用open()本地读取而非requests.get(),避免网络请求返回异常数据(比如tuple)。如果是URL,也要确保requests.get(image["file_name"]).content返回的是字节流,而非其他结构。
内容的提问来源于stack exchange,提问作者Oblomov
相关产品推荐
相关产品推荐

