SiameseUIE模型训练数据准备:YOLOv8标注转换技巧

张开发
2026/4/12 6:14:11 15 分钟阅读

分享文章

SiameseUIE模型训练数据准备:YOLOv8标注转换技巧
SiameseUIE模型训练数据准备YOLOv8标注转换技巧如果你之前用过YOLOv8训练过自己的数据集现在想试试SiameseUIE这个信息抽取模型可能会遇到一个头疼的问题手里的数据格式对不上。YOLOv8的标注文件是一堆坐标框而SiameseUIE需要的是文本和对应的实体标签这俩看起来八竿子打不着。别急这篇文章就是来帮你解决这个问题的。我会手把手带你把YOLOv8的视觉标注数据转换成SiameseUIE能用的文本标注格式。我们不止讲转换还会聊聊怎么在这个过程中利用图片里的文字信息开发一个半自动化的标注工具让你手里的数据“活”起来实现视觉和文本数据的协同利用。1. 理解数据YOLOv8和SiameseUIE的差异在动手转换之前我们得先搞清楚这两者到底要什么。这就像你要把一份英文菜谱翻译成中文总得先看懂两边分别写了啥。1.1 YOLOv8的数据长什么样YOLOv8处理的是图片它的标注文件通常是.txt格式非常简单直接。每一行代表图片中的一个物体包含了以下信息类别编号 中心点x坐标 中心点y坐标 宽度 高度这里的坐标和尺寸都是相对于图片宽度和高度的比例值0到1之间。比如一个0 0.5 0.5 0.2 0.1的标注意思是类别0的物体中心点在图片正中央宽度占图片的20%高度占10%。这种格式只关心“哪里有什么东西”至于这个东西具体叫什么名字、有什么属性它是不管的。你的数据集可能是一堆标注了“商品”、“logo”、“文本区域”的图片。1.2 SiameseUIE需要什么样的数据SiameseUIE是一个信息抽取模型它处理的是文本。它的目标是从一段话里找出我们关心的特定信息比如人名、地点、时间、组织机构等等。它需要的训练数据通常是这样的格式以JSON为例{ text: 阿里巴巴集团于1999年在杭州由马云创立。, entities: [ { start_idx: 0, end_idx: 4, label: 组织机构 }, { start_idx: 10, end_idx: 14, label: 时间 }, { start_idx: 15, end_idx: 17, label: 地点 }, { start_idx: 20, end_idx: 22, label: 人物 } ] }看到了吗核心是text原始文本和entities实体列表每个实体有在文本中的起止位置和类别标签。它完全不涉及任何图片坐标。1.3 我们的核心任务建立桥梁现在矛盾很清楚了我们有一堆知道“文字在哪里”的图片YOLOv8标注但我们需要的是“文字是什么以及它属于哪一类”的文本数据SiameseUIE标注。转换的关键在于光学字符识别OCR。我们需要利用YOLOv8的标注框从图片中裁剪出包含文字的区域。对这些区域使用OCR技术识别出里面的文字内容。根据YOLOv8框的类别比如“人名”、“公司名”为识别出的文字打上对应的SiameseUIE实体标签。将同一张图片或同一上下文中的所有文字片段组合成连贯的文本并记录每个实体在组合后文本中的位置。听起来有点复杂别担心我们一步步来。2. 从YOLO标注到文本基础转换流程我们先搭建一个最基础的、能跑通的转换流程。这个流程虽然半自动化程度不高但能让你彻底理解每一个环节。2.1 第一步准备你的YOLOv8数据集假设你的数据集结构是这样的这是YOLOv8的标准格式your_yolo_dataset/ ├── images/ │ ├── train/ │ │ ├── image1.jpg │ │ └── image2.jpg │ └── val/ │ └── image3.jpg └── labels/ ├── train/ │ ├── image1.txt │ └── image2.txt └── val/ └── image3.txt每个imageX.txt里的内容就是我们前面说的class_id x_center y_center width height。你还需要一个data.yaml文件里面定义了类别名称。比如names: 0: 人名 1: 组织机构 2: 地点 3: 时间这个names的映射关系至关重要它将是连接YOLO类别和SiameseUIE实体标签的桥梁。2.2 第二步用OCR提取框内文字我们需要一个OCR引擎。这里用Python中比较流行的paddleocr库来演示它识别中文的效果不错。首先安装如果你环境里没有的话pip install paddlepaddle paddleocr然后写一个脚本来遍历你的数据集对每个标注框进行裁剪和识别import os from PIL import Image import paddleocr import yaml # 初始化PaddleOCR使用中文模型 ocr paddleocr.PaddleOCR(use_angle_clsTrue, langch) # 加载类别映射 with open(path/to/your/data.yaml, r, encodingutf-8) as f: data_yaml yaml.safe_load(f) class_names data_yaml[names] def extract_text_from_yolo_label(img_path, label_path, img_output_base_dirNone): 读取一张图片及其YOLO标签提取每个标注框内的文字。 Args: img_path: 图片路径 label_path: 标签文件路径 img_output_base_dir: 可选用于保存裁剪框图片的目录调试用 Returns: list: 每个元素是一个字典包含text(识别文字), label(类别名), confidence(置信度)等 results [] img Image.open(img_path) img_width, img_height img.size with open(label_path, r, encodingutf-8) as f: lines f.readlines() for line in lines: parts line.strip().split() if len(parts) ! 5: continue class_id int(parts[0]) x_center, y_center, width, height map(float, parts[1:5]) # 将YOLO归一化坐标转换为像素坐标 x_center_abs x_center * img_width y_center_abs y_center * img_height width_abs width * img_width height_abs height * img_height # 计算边框左上角和右下角 x1 int(x_center_abs - width_abs / 2) y1 int(y_center_abs - height_abs / 2) x2 int(x_center_abs width_abs / 2) y2 int(y_center_abs height_abs / 2) # 确保坐标在图片范围内 x1, y1 max(0, x1), max(0, y1) x2, y2 min(img_width - 1, x2), min(img_height - 1, y2) # 裁剪出框内的图片区域 cropped_img img.crop((x1, y1, x2, y2)) # 可选保存裁剪图用于调试 if img_output_base_dir: os.makedirs(img_output_base_dir, exist_okTrue) base_name os.path.splitext(os.path.basename(img_path))[0] cropped_img.save(os.path.join(img_output_base_dir, f{base_name}_crop_{len(results)}.jpg)) # 使用OCR识别裁剪区域 # 将PIL图像转换为OpenCV格式PaddleOCR需要 import cv2 import numpy as np cropped_cv_img cv2.cvtColor(np.array(cropped_img), cv2.COLOR_RGB2BGR) ocr_result ocr.ocr(cropped_cv_img, clsTrue) recognized_text confidence 0.0 if ocr_result and ocr_result[0]: # 取识别结果中置信度最高的那一行文本 # ocr_result结构: [[[[坐标], (文本, 置信度)]], ...] texts [line[1][0] for line in ocr_result[0]] confidences [line[1][1] for line in ocr_result[0]] if texts: # 简单拼接多行文本可根据需要调整比如加空格或换行 recognized_text .join(texts) confidence sum(confidences) / len(confidences) label_name class_names.get(class_id, f未知类别_{class_id}) results.append({ text: recognized_text, label: label_name, confidence: confidence, bbox_pixels: (x1, y1, x2, y2), # 原始图片上的坐标后续可能有用 bbox_yolo: (x_center, y_center, width, height) # 原始YOLO坐标 }) return results # 示例处理一张图片 img_path your_yolo_dataset/images/train/image1.jpg label_path your_yolo_dataset/labels/train/image1.txt detections extract_text_from_yolo_label(img_path, label_path, img_output_base_dirdebug_crops) for det in detections: print(f识别文字: {det[text]}, 标签: {det[label]}, 置信度: {det[confidence]:.2f})运行这个脚本你就能看到对于每一个YOLO标注框我们识别出了什么文字以及它应该对应什么实体标签。2.3 第三步组装成SiameseUIE格式单张图片里可能有多个文本框。我们需要把它们合理地组合成一段文本并计算出每个实体在这段文本中的起止位置。这里有一个简单的策略按照文本框在图片中的位置比如从上到下从左到右进行排序和拼接。这符合大多数文档或海报的阅读顺序。def assemble_siameseuie_sample(detections, img_width, img_height): 将一张图片上的多个检测框结果组装成一个SiameseUIE训练样本。 这里采用简单的按Y坐标从上到下排序后拼接的策略。 if not detections: return None # 1. 按文本框顶部Y坐标排序从上到下 sorted_detections sorted(detections, keylambda d: d[bbox_pixels][1]) # 2. 拼接文本并记录每个片段在最终文本中的位置 full_text_parts [] current_index 0 entities [] for det in sorted_detections: text_segment det[text].strip() if not text_segment: # 跳过未识别出文字的框 continue label det[label] # 记录实体位置 start_idx current_index end_idx current_index len(text_segment) entities.append({ start_idx: start_idx, end_idx: end_idx, label: label }) # 添加到完整文本 full_text_parts.append(text_segment) current_index end_idx 1 # 1 是留给分隔符如空格 if not full_text_parts: return None # 用空格连接各个文本片段 full_text .join(full_text_parts) # 重要由于我们插入了空格需要调整实体结束索引 # 因为空格不算在实体文本内 for entity in entities: # 实体结束索引之前有多少个插入的空格 # 简单的调整实体在parts中的索引决定了前面有多少个空格 # 这里简化处理更严谨的做法是在拼接时记录映射关系 pass # 为了清晰这里省略复杂的索引重映射代码。实际使用时需要仔细处理。 # 简化版假设我们不用空格或者索引计算已考虑分隔符 # 我们换一种更清晰的拼接方式直接拼接不加额外分隔符 full_text .join(full_text_parts) # 重新计算实体位置因为去掉了空格 current_idx 0 entities.clear() for i, det in enumerate(sorted_detections): text_segment det[text].strip() if not text_segment: continue start_idx current_idx end_idx current_idx len(text_segment) entities.append({ start_idx: start_idx, end_idx: end_idx, label: det[label] }) current_idx end_idx siamese_sample { text: full_text, entities: entities } return siamese_sample # 接续前面的例子 sample assemble_siameseuie_sample(detections, img_width, img_height) if sample: print(组装后的文本, sample[text]) print(实体列表, sample[entities])2.4 第四步批量处理与格式保存现在我们把针对单张图片的操作扩展到整个数据集训练集、验证集。import json from tqdm import tqdm # 用于显示进度条安装pip install tqdm def convert_yolo_dataset_to_siamese(yolo_image_dir, yolo_label_dir, output_json_path, class_names_map): 批量转换整个YOLO格式的数据集目录。 siamese_data [] # 获取所有图片文件 image_extensions [.jpg, .jpeg, .png, .bmp] image_files [] for ext in image_extensions: image_files.extend([f for f in os.listdir(yolo_image_dir) if f.lower().endswith(ext)]) for img_file in tqdm(image_files, desc处理图片): img_path os.path.join(yolo_image_dir, img_file) base_name os.path.splitext(img_file)[0] label_path os.path.join(yolo_label_dir, base_name .txt) if not os.path.exists(label_path): print(f警告{label_path} 标签文件不存在跳过 {img_file}) continue # 提取单张图片信息 img Image.open(img_path) img_width, img_height img.size detections extract_text_from_yolo_label(img_path, label_path) # 组装成SiameseUIE样本 sample assemble_siameseuie_sample(detections, img_width, img_height) if sample: # 可以附加一些元信息如图片路径方便回溯 sample[source_image] img_file siamese_data.append(sample) else: print(f警告{img_file} 未能生成有效样本可能无文字识别结果。) # 保存为JSON文件 with open(output_json_path, w, encodingutf-8) as f: json.dump(siamese_data, f, ensure_asciiFalse, indent2) print(f转换完成共处理 {len(image_files)} 张图片生成 {len(siamese_data)} 个有效样本。) print(f结果已保存至{output_json_path}) # 使用示例 class_names_map {0: 人名, 1: 组织机构, 2: 地点, 3: 时间} # 与你的data.yaml对应 convert_yolo_dataset_to_siamese( yolo_image_diryour_yolo_dataset/images/train, yolo_label_diryour_yolo_dataset/labels/train, output_json_pathsiamese_train_data.json, class_names_mapclass_names_map )运行完这个批量转换脚本你就会得到一个siamese_train_data.json文件它的格式就是SiameseUIE模型可以直接用来训练的了。对验证集val也执行同样的操作。3. 进阶技巧打造半自动化标注工具基础流程能跑通但效率可能不高尤其是OCR识别可能出错或者文本框排序逻辑不符合复杂版面。我们可以把这个流程升级成一个带界面的半自动化工具让人工来校对和调整从而高效地生产高质量数据。3.1 工具设计思路我们将构建一个简单的桌面应用它能够自动加载与展示加载图片和对应的YOLO标注框并自动运行OCR在框内识别文字。人工校对与编辑在界面中高亮显示每个框并展示OCR识别结果。用户可以修改识别错误的文字。调整实体的类别如果YOLO类别映射不对。删除无效的框可能是误检。调整文本框的拼接顺序通过拖拽或指定顺序。实时导出用户校对完一张图片后可以立即生成或更新SiameseUIE格式的标注文件。批量处理提供“上一张/下一张”导航快速处理整个数据集。3.2 使用Gradio快速搭建界面Gradio是一个非常适合快速构建机器学习演示界面的Python库。我们用它来搭建这个工具的雏形。pip install gradioimport gradio as gr import cv2 import json from pathlib import Path # 假设我们有之前写好的函数 extract_text_from_yolo_label 和 assemble_siameseuie_sample # 这里我们重新组织一下使其更适合交互 current_index 0 image_files_list [] label_files_list [] current_annotations [] # 存储当前图片所有框的详细信息 output_data [] # 存储所有已处理的SiameseUIE数据 def load_image_and_annotations(img_path, label_path): 加载图片解析YOLO标签运行OCR返回用于显示和编辑的数据 global current_annotations detections extract_text_from_yolo_label(img_path, label_path) img_cv cv2.imread(img_path) img_height, img_width img_cv.shape[:2] # 为每个检测框生成显示信息 boxes_for_display [] current_annotations.clear() for i, det in enumerate(detections): x1, y1, x2, y2 det[bbox_pixels] # 格式化为Gradio AnnotatedImage组件需要的格式 boxes_for_display.append(((x1, y1, x2, y2), f{det[label]}: {det[text]})) # 存储详细信息用于后续编辑 current_annotations.append({ id: i, bbox: det[bbox_pixels], text: det[text], label: det[label], confidence: det[confidence] }) # 组装当前文本预览 sample assemble_siameseuie_sample(detections, img_width, img_height) preview_text sample[text] if sample else 未能组装文本 preview_entities json.dumps(sample[entities], ensure_asciiFalse, indent2) if sample else [] return img_cv, boxes_for_display, preview_text, preview_entities def update_display(index): 根据索引更新界面显示 if not image_files_list: return None, [], , [] img_path image_files_list[index] label_path label_files_list[index] return load_image_and_annotations(img_path, label_path) def save_current_annotation(): 将当前图片的标注经过人工修改后的current_annotations保存到output_data global output_data, current_annotations if not current_annotations: return 当前没有可保存的标注。 # 假设我们有一个函数将current_annotations转换成SiameseUIE样本 # 这里需要根据你的排序逻辑来写为了演示我们假设顺序就是current_annotations的顺序 full_text_parts [ann[text] for ann in current_annotations if ann[text].strip()] full_text .join(full_text_parts) entities [] current_idx 0 for ann in current_annotations: text ann[text].strip() if not text: continue start_idx current_idx end_idx current_idx len(text) entities.append({ start_idx: start_idx, end_idx: end_idx, label: ann[label] }) current_idx end_idx sample { text: full_text, entities: entities, source_image: Path(image_files_list[current_index]).name } # 查找或替换output_data中当前图片的条目 img_name Path(image_files_list[current_index]).name existing_idx next((i for i, item in enumerate(output_data) if item.get(source_image) img_name), -1) if existing_idx 0: output_data[existing_idx] sample else: output_data.append(sample) return f已保存对 {img_name} 的标注。 def export_all_annotations(): 导出所有已保存的标注为JSON文件 global output_data if not output_data: return 暂无数据可导出。 output_path siamese_final_annotations.json with open(output_path, w, encodingutf-8) as f: json.dump(output_data, f, ensure_asciiFalse, indent2) return f已导出 {len(output_data)} 个样本到 {output_path} # 构建Gradio界面 with gr.Blocks(titleYOLO to SiameseUIE 标注转换工具) as demo: gr.Markdown(## YOLOv8标注转SiameseUIE训练数据工具) gr.Markdown(加载图片和YOLO标签自动OCR识别框内文字请校对和调整后保存。) with gr.Row(): with gr.Column(scale1): img_index gr.Number(value0, label当前图片索引, precision0) img_name_display gr.Textbox(label当前图片, interactiveFalse) with gr.Row(): prev_btn gr.Button(上一张) next_btn gr.Button(下一张) load_dir_btn gr.Button(加载数据集目录) with gr.Column(scale3): # 图像显示区域支持框标注 annotated_image gr.AnnotatedImage(label图片与标注框) # 当前图片的文本预览 text_preview gr.Textbox(label组装文本预览, lines3, interactiveFalse) entities_preview gr.Code(label实体结构预览, languagejson, interactiveFalse) with gr.Row(): # 这里可以扩展一个可编辑的表格用于修改每个框的text和label # 为了简化演示我们用一个大的文本框让用户编辑整个current_annotations的JSON annotation_editor gr.Code(label编辑标注详情 (JSON格式), languagejson, lines10, valuejson.dumps([], indent2)) with gr.Row(): save_btn gr.Button(保存当前标注) export_btn gr.Button(导出全部标注) status gr.Textbox(label状态, interactiveFalse) # 交互逻辑 def on_load_dir(dataset_root): global image_files_list, label_files_list, current_index # 这里需要实现扫描目录填充image_files_list和label_files_list # 示例逻辑需要根据你的实际目录结构调整 img_dir Path(dataset_root) / images / train label_dir Path(dataset_root) / labels / train image_files list(img_dir.glob(*.jpg)) list(img_dir.glob(*.png)) image_files_list [str(f) for f in sorted(image_files)] label_files_list [str(label_dir / (f.stem .txt)) for f in image_files] if image_files_list: current_index 0 img, boxes, text, entities update_display(current_index) return (image_files_list[current_index], img, boxes, text, entities, current_index, json.dumps(current_annotations, indent2)) else: return (未找到图片, None, [], , [], 0, []) load_dir_btn.click( fnon_load_dir, inputs[gr.Textbox(label数据集根目录路径, placeholder请输入your_yolo_dataset的路径)], outputs[img_name_display, annotated_image, annotated_image, text_preview, entities_preview, img_index, annotation_editor] ) def on_nav_button(change): global current_index current_index change current_index max(0, min(current_index, len(image_files_list) - 1)) img, boxes, text, entities update_display(current_index) return (image_files_list[current_index], img, boxes, text, entities, current_index, json.dumps(current_annotations, indent2)) prev_btn.click(fnlambda: on_nav_button(-1), outputs[img_name_display, annotated_image, annotated_image, text_preview, entities_preview, img_index, annotation_editor]) next_btn.click(fnlambda: on_nav_button(1), outputs[img_name_display, annotated_image, annotated_image, text_preview, entities_preview, img_index, annotation_editor]) def on_save(): # 首先用编辑器的内容更新current_annotations try: edited_anns json.loads(annotation_editor.value) # 这里应该做一些验证... global current_annotations current_annotations edited_anns except json.JSONDecodeError: return JSON格式错误保存失败。 msg save_current_annotation() return msg save_btn.click(fnon_save, outputs[status]) export_btn.click(fnexport_all_annotations, outputs[status]) # 启动界面 demo.launch(shareFalse) # 设置shareTrue可以生成一个公网链接这个Gradio应用提供了一个基础的交互界面。在实际使用中你可能需要进一步优化比如添加一个可编辑的表格来修改每个框的文字和标签比直接编辑JSON更友好。实现框的拖动排序功能。集成更强大的OCR引擎选项。添加快捷键支持。但它的核心价值已经体现将枯燥的格式转换和容易出错的OCR校验变成了一个可视化、可交互的校对过程能极大提升数据准备的效率和质量。4. 总结从YOLOv8的视觉标注转换到SiameseUIE的文本标注核心思路就是“视觉定位”“文字识别”“标签映射”。我们首先通过基础脚本实现了全自动的转换流程这适用于标注质量高、版面规整的场景。但对于更复杂、要求更高的项目半自动化的标注工具才是生产力的关键。它尊重了人在环路Human-in-the-loop的价值让算法处理重复性工作OCR而让人来负责质量把控和复杂决策校对、调整顺序。这样产出的数据质量更有保障也能更好地训练出强大的SiameseUIE模型。希望这篇教程和工具开发的思路能帮你盘活手中的视觉数据集顺利踏入信息抽取模型训练的大门。在实际操作中你可能会遇到更具体的挑战比如倾斜文本、复杂背景、嵌套实体等那时可以再基于这个框架进行针对性的优化。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。

更多文章