ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Transformers-Tutorials 中的 UDOP 实战指南:融合 OCR 的生成式文档 AI 模型

Transformers-Tutorials 中的 UDOP 实战指南:融合 OCR 的生成式文档 AI 模型 示例工程【免费下载链接】Transformers-TutorialsThis repository contains demos I made with the Transformers library by HuggingFace.项目地址https://gitcode.com/GitHub_Trending/tr/Transformers-Tutorials点击查看免费下载本文以 Transformers-Tutorials 仓库中 UDOP 系列教程为核心系统讲解 Microsoft Research 的 UDOPUnified Document Processing模型它的编码器-解码器架构、与 OCR 引擎的协作方式以及如何在本仓库提供的 5 个 Notebook 中完成推理、JSON 抽取微调、文档分类微调、布局分析与仅编码器微调。读完本文你将掌握 UDOP 的完整使用链路包括UdopProcessor的数据预处理、UdopForConditionalGeneration的自回归生成以及面向 CORD、RVL-CDIP、FUNSD 等数据集的实际训练与推理方案。UDOP 是什么一个会写答案的文档 AIUDOP 是 Microsoft Research 推出的文档 AI 模型与 LayoutLM、LiLT 等只做读取编码的模型不同UDOP 采用编码器-解码器encoder-decoder架构因此本质上是一个生成式generative模型——它会像语言模型一样逐 token 地写出输出序列。从架构上看UDOP 非常接近 Donut、Pix2Struct 这类图像进、文本出的模型由视觉编码器vision encoder 基于 GPT 的文本解码器text decoder组成。但关键区别在于UDOP 额外依赖一个 OCR 引擎如 LayoutLMv3 所用的方案让模型在生成文本时有准确的词与坐标可依Donut、Pix2Struct 只向编码器输入pixel_values纯视觉UDOP 则向编码器同时输入pixel_values、input_ids和bbox图像 OCR 文本 文本坐标。更直观的理解方式是把 UDOP 看作一个 T5 模型不过它的编码器换成了 LayoutLMv3 风格的编码器并搭配 T5 文本解码器同时加入了一系列针对 2D 布局数据的精巧设计如布局感知的注意力、位置编码等。由于解码器是生成式的只要给定文档图像就能训练它生成任意想要的序列。正如 UDOP/README.md 所述我们可以训练它生成文档关键字段的JSON结构化信息抽取生成文档的类别标签文档分类生成问题的答案文档问答 DocVQA。这赋予了 UDOP 在文档解析、表单理解、票据结构化等场景中一模型多任务的灵活性。官方文档与检查点信息见 UDOP/README.md模型文档与microsoft/udop-*系列检查点集合。仓库还提供了更强的检查点基于更高分辨率512×512 而非 224×224与更长的预训练代价是更大的显存需求。环境准备Transformers SentencePiece TesseractUDOP 的所有 Notebook 都围绕三个核心依赖展开参考 Inference_with_UDOP, a generative document AI model.ipynb 与 Fine_tune_UDOP_on_a_custom_dataset_(JSON_extraction).ipynb.ipynb) Transformers提供UdopProcessor、UdopForConditionalGeneration、UdopEncoderModel等实现。Notebook 写作时模型较新因此采用从源码安装的方式!pip install -q githttps://github.com/huggingface/transformers.gitSentencePieceTokenizer 依赖的底层分词实现!pip install -q sentencepieceTesseract开源 OCR 引擎及其 Python 绑定pytesseractUdopProcessor默认用它从文档图像中抽取词与坐标!sudo apt install tesseract-ocr !pip install -q pytesseract安装后可验证版本!tesseract --version。微调类 Notebook 还会额外安装datasets加载数据集、bitsandbytes8-bit 优化器以降低显存、seqeval序列标注评测与accelerate。例如 Fine_tune_UDOP_on_a_custom_dataset_(toy_RVL_CDIP_dataset).ipynb.ipynb) 中的安装命令为!pip install -q datasets sentencepiece bitsandbytes仅编码器微调 Notebook 则使用!pip install -q datasets seqeval sentencepiece accelerate。模型与 Processor 加载UdopProcessor本质上是一个包装器内部包含两部分图像处理器image processor负责对文档图像做 resize、rescale、normalize得到pixel_values默认还会调用 Tesseract 对图像做 OCR抽出词列表及对应坐标TokenizerUdopTokenizer负责把 OCR 得到的词与坐标转为 token 级的input_ids、attention_mask和bbox。因此一个 processor 调用即可产出模型所需的全部输入。推理与微调 Notebook 的加载方式一致from transformers import UdopProcessor, UdopForConditionalGeneration repo_id microsoft/udop-large processor UdopProcessor.from_pretrained(repo_id) model UdopForConditionalGeneration.from_pretrained(repo_id)布局分析 Notebook 则使用 512 分辨率的检查点microsoft/udop-large-512见 Layout_analysis_with_UDOP.ipynb。也可以借助 Auto APIAutoProcessor.from_pretrained(microsoft/udop-large, apply_ocrFalse)——当数据已经自带 OCR 结果例如 FUNSD 数据集中已有 words 和 boxes时用apply_ocrFalse跳过 OCR直接把词与框喂给 processor这与 LayoutLMv2/LayoutLMv3 的 Processor 用法完全一致见 Fine_tune_UDOPEncoderModel_on_FUNSD_(HuggingFace_Trainer).ipynb.ipynb)。如果希望使用 Azure Read API 等更强的 OCR 引擎也可以先自行 OCR再以apply_ocrFalse方式手动传入词与框。推理实战用提示词做文档问答Inference_with_UDOP, a generative document AI model.ipynb 展示了一条最简推理链路。首先加载一张示例文档图像来自hf-internal-testing/fixtures_docvqa数据集from huggingface_hub import hf_hub_download from PIL import Image filepath hf_hub_download( repo_idhf-internal-testing/fixtures_docvqa, filenamedocument_2.png, repo_typedataset ) image Image.open(filepath).convert(RGB)关键一步是用文本提示词prompt对 UDOP 进行条件生成。提示词承担任务指令的作用例如prompt Question answering. What is the title of the presentation? encoding processor(imagesimage, textprompt, return_tensorspt) for k, v in encoding.items(): print(k, v.shape)可以看到 encoding 中同时出现input_ids、attention_mask、bbox与pixel_values四个键——这正是 UDOP 与 Donut/Pix2Struct 的输入差异点。可以用processor.batch_decode(encoding.input_ids)直观看到喂给模型的内容OCR 词 坐标 token 提示词。随后用generate自回归补全提示词outputs model.generate(**encoding, max_new_tokens20) generated_text processor.batch_decode(outputs, skip_special_tokensTrue)[0] print(generated_text)Notebook 中默认使用贪心解码greedy decoding如需 beam search、采样等更丰富的解码策略可参考 Transformers 官方的文本生成指南。将提示词换成document classification.或Question answering. In which year is the report made?同一模型即可切换任务类型——这正是生成式文档 AI 的核心能力。微调一在 CORD 上做 JSON 抽取票据文档结构化key-value 抽取是最有代表性的 UDOP 微调场景。Fine_tune_UDOP_on_a_custom_dataset_(JSON_extraction).ipynb.ipynb) 使用CORD 数据集naver-clova-ix/cord-v2由 Donut 作者预处理、托管于 Hub 的人工标注票据集合from datasets import load_dataset dataset load_dataset(naver-clova-ix/cord-v2)数据集包含 train/validation/test 三个划分每个样本由图像与ground_truth解析结果组成。ground_truth以字符串形式存储 JSON 解析结果需要用ast.literal_eval还原为字典查看如gt_parse。用 processor 构造输入与目标输入侧直接调用 processorprocessor UdopProcessor.from_pretrained(microsoft/udop-large) encoding processor(imagesimage, return_tensorspt) for k, v in encoding.items(): print(k, v.shape)这里处理器默认用 Tesseract 做 OCR——票据图像较模糊时 OCR 质量会受影响此时可以考虑换用更强的 OCR 引擎。目标侧则需要先把 ground truth 转成模型可学的 token 序列Notebook 采用 Donut 作者风格的json2token转换函数将 JSON 结构编码为带特殊 token 的线性序列# 字典被展开为 s_keyvalue/s_key 的序列 # 列表用 sep/ 连接 # 训练集上会把新的 s_k//s_k 加入 tokenizer 并 resize 解码器词嵌入对应的 PyTorchDataset实现要点如下源码见 Fine_tune_UDOP_on_a_custom_dataset_(JSON_extraction).ipynb.ipynb)在__init__中遍历ground_truth解析出gt_parse或gt_parses列表如 DocVQA逐条执行json2tokenjson2token对 dict 按键递归展开sort_json_key可控制键排序update_special_tokens_for_json_key控制训练时是否注册新特殊 token对 list 用sep/拼接对普通值直接转为字符串若该值已注册为分类特殊 token 则使用值/形式add_tokens调用processor.tokenizer.add_tokens并通过model.resize_token_embeddings扩展解码器词嵌入__getitem__中用processor(imagesimage, truncationTrue, paddingmax_length, max_length100)构造输入Colab T4 上受显存限制编码长度设为 100用processor.tokenizer(text_targettarget_sequence, ..., max_length128)构造labels解码目标同样受显存限制设为 128。训练循环训练采用原生 PyTorch 循环 bitsandbytes 的 8-bit Adam 优化器以降低显存占用将torch.optim.AdamW换成bnb.optim.Adam8bit(model.parameters(), lr5e-5)batch size 设为 1每步打印 lossoptimizer bnb.optim.Adam8bit(model.parameters(), lr5e-5) device cuda if torch.cuda.is_available() else cpu model.to(device) model.train() for epoch in range(10): for batch in train_dataloader: batch {k: v.to(device) for k, v in batch.items()} outputs model( input_idsbatch[input_ids], attention_maskbatch[attention_mask], bboxbatch[bbox], pixel_valuesbatch[pixel_values], labelsbatch[labels], ) loss outputs.loss loss.backward() optimizer.step() optimizer.zero_grad() print(Loss:, loss.item())Notebook 作者明确指出该循环纯为演示、未做任何优化epoch 数、学习率调度、梯度累积、梯度检查点等均可自行补充追求单卡训练效率建议阅读 Transformers 官方的单 GPU 高效训练指南。推理训练结束后对测试集图像做自回归生成即可输出 JSON 文本inputs processor(test_image.convert(RGB), return_tensorspt).to(device) model.eval() generated_ids model.generate(**inputs, max_new_tokens128) generated_text processor.batch_decode(generated_ids, skip_special_tokensTrue)[0] print(generated_text)微调二在 RVL-CDIP 子集上做文档分类生成式模型同样能输出类别。Fine_tune_UDOP_on_a_custom_dataset_(toy_RVL_CDIP_dataset).ipynb.ipynb) 使用 RVL-CDIP 的玩具子集nielsr/rvl_cdip_10_examples_per_class_donut每类 10 个样本演示分类微调。首先从 Hub 加载标签映射from huggingface_hub import hf_hub_download import json repo_id huggingface/label-files filename rvlcdip-id2label.json id2label json.load(open(hf_hub_download(repo_id, filename, repo_typedataset), r)) id2label {int(k): v for k, v in id2label.items()}分类任务的目标序列构造非常简洁——把任务描述与类别拼接成一个字符串作为解码目标label id2label[sample[label]] target_sequence fdocument image classification. {label} encoding[labels] self.processor( text_targettarget_sequence, paddingmax_length, max_length10, truncationTrue, return_tensorspt ).input_ids.squeeze()训练循环与 JSON 抽取 Notebook 高度相似同样使用bnb.optim.Adam8bit、batch size 1但作者额外加入了一个很实用的技巧每 2 个 epoch 在训练 batch 上跑一次自回归生成用processor.batch_decode(predictions, skip_special_tokensTrue)打印预测结果肉眼确认模型确实在学会输出类别。推理时用model.generate(**inputs, max_new_tokens10)将生成文本与id2label[test_example[label]]对照即可验证效果。布局分析让模型输出坐标UDOP 还能做文档布局分析。Layout_analysis_with_UDOP.ipynb 使用 PubLayNet 样例图从nielsr/dit-document-layout-analysisspace 下载并加载microsoft/udop-large-512检查点512 分辨率。任务提示词采用Layout analysis. Element形式Element可替换为 PubLayNet 标签如 Table、Title、Paragraph 等prompt Layout analysis. Table encoding processor(imagesimage.convert(RGB), textprompt, return_tensorspt)生成时注意不要跳过特殊 token因为布局分析的输出包含特殊的位置locationtokenoutputs model.generate(**encoding) output_text processor.batch_decode(outputs, skip_special_tokensFalse)[0] print(output_text)把位置 token 还原成坐标框UDOP 的布局输出是一组归一化坐标。Notebook 提供了完整的解码工具函数import re def extract_coordinates(string): numbers re.findall(r\d, string) numbers list(map(int, numbers)) if len(numbers) ! 4: numbers numbers[-4:] x1, y1, x2, y2 numbers return [x1, y1, x2, y2] # UDOP 使用 501 个特殊 loclocationtoken LAYOUT_VOCAB_SIZE 501 def unnormalize_box(box, image_width, image_height): x1 box[0] / LAYOUT_VOCAB_SIZE * image_width y1 box[1] / LAYOUT_VOCAB_SIZE * image_height x2 box[2] / LAYOUT_VOCAB_SIZE * image_width y2 box[3] / LAYOUT_VOCAB_SIZE * image_height return [x1, y1, x2, y2] coordinates extract_coordinates(output_text) coordinates unnormalize_box(coordinates, unnormalized_image.width, unnormalized_image.height)随后用 PIL 的ImageDraw把框画在反归一化的图像上即可可视化from PIL import ImageDraw draw ImageDraw.Draw(unnormalized_image) draw.rectangle(coordinates, outlinered)反归一化图像时需要用processor.image_processor.image_mean/image_std恢复像素值范围(pixel_values * std) mean再乘以 255 转回 uint8。Notebook 作者还提示Tesseract 效果有限微软作者预训练时很可能使用 Azure Read API换用更强 OCR 可能得到更好结果社区也有人反馈提示词Layout analysis on PubLayNet. Text效果更佳。仅编码器微调FUNSD 上的 token 分类并非所有任务都需要生成能力。Fine_tune_UDOPEncoderModel_on_FUNSD_(HuggingFace_Trainer).ipynb.ipynb) 展示了另一种范式只取 UDOP 的编码器部分在顶部加一个线性分类头像训练 BERT/LayoutLMv3 一样做 token 级分类——例如 FUNSD 表单上的命名实体识别question/answer/header 等标签。数据集为nielsr/funsd-layoutlmv3含 train/test 两个划分每个样本有tokens词列表、bboxes框、ner_tags标注与image。预处理与自定义模型头因为数据自带 OCR 结果processor 用apply_ocrFalseprocessor AutoProcessor.from_pretrained(microsoft/udop-large, apply_ocrFalse) def prepare_examples(examples): encoding processor( examples[image], examples[tokens], boxesexamples[bboxes], word_labelsexamples[ner_tags], truncationTrue, paddingmax_length ) return encoding随后定义标签映射、用dataset.map(..., batchedTrue)批量预处理并显式声明Featurespixel_values为 (3,224,224) 的 Array3D、bbox为 (512,4) 的 Array2D 等保证set_format(torch)正常运作。自定义分类模型继承UdopPreTrainedModel内部加载UdopEncoderModel.from_pretrained(microsoft/udop-large)并加Dropout(0.5)Linear(config.hidden_size, config.num_labels)class UdopForTokenClassification(UdopPreTrainedModel): def __init__(self, config): super().__init__(config) self.udop UdopEncoderModel.from_pretrained(microsoft/udop-large) self.num_labels config.num_labels self.dropout nn.Dropout(0.5) self.classifier nn.Linear(config.hidden_size, config.num_labels) def forward(self, input_ids, bbox, attention_mask, pixel_values, labels): outputs self.udop(input_idsinput_ids, bboxbbox, attention_maskattention_mask, pixel_valuespixel_values) seq_length input_ids.shape[1] # 只取文本部分的输出表征 sequence_output outputs[0][:, :seq_length] sequence_output self.dropout(sequence_output) logits self.classifier(sequence_output) loss None if labels is not None: loss nn.CrossEntropyLoss()(logits.view(-1, self.num_labels), labels.view(-1)) return TokenClassifierOutput(lossloss, logitslogits, ...)这里UdopEncoderModel输出的序列表示同时包含视觉与文本部分因此前向时用[:, :seq_length]切出与input_ids等长的文本表示再分类。Trainer 训练与评估训练参数Fine_tune_UDOPEncoderModel_on_FUNSD_(HuggingFace_Trainer).ipynb.ipynb) 中完整给出兼顾了 UDOP 较大的显存开销training_args TrainingArguments( output_dirtest, max_steps3000, warmup_ratio0.1, per_device_train_batch_size1, per_device_eval_batch_size1, gradient_accumulation_steps8, eval_accumulation_steps8, learning_rate5e-5, evaluation_strategysteps, eval_steps100, load_best_model_at_endTrue, metric_for_best_modelf1, )compute_metrics用seqeval计算整体 precision/recall/F1/accuracy并忽略 -100 位置。Notebook 展示了作者的一次典型运行FUNSD 上 F1 可达约 90%前 1000 步内从约 0.82 逐步升至约 0.86并附上了 LayoutLMv3 的对照日志。不过作者特别提醒该分数不能直接与 LayoutLM/LayoutLMv2 对比因为 LayoutLMv3 使用了分段位置嵌入segment position embeddings受 StructuralLM 启发——同一片段如一个地址内的多个 token 共享相同 bbox 与 2D 位置嵌入而 UDOP 论文采用 word-level 布局位置论文也明确指出了这一差异。推理与可视化加载训练好的 checkpoint 后AutoModelForTokenClassification.from_pretrained(/content/test/checkpoint-1000)对单样本前向得到(batch_size, seq_len, num_labels)的 logits用argmax(-1)得到每个 token 的预测标签。将 token 级bbox除以 1000 再乘以图像宽高反归一化后用 PIL 按标签着色绘制彩色框question 蓝色、answer 绿色、header 橙色、other 紫色即可直观对照预测与 ground truth。真实推理场景没有labels可用此时无法依赖 -100 判断词首 token需要改用 tokenizer 返回的offset_mapping定位每个词的边界LayoutLMv2 的真推理Notebook 有等价实现可参考仓库 LayoutLMv2/FUNSD 目录。实战要点总结综合 UDOP 系列 5 个 Notebook几条关键经验值得沉淀输入四元组UDOP 的输入永远是pixel_valuesinput_idsattention_maskbbox一切都由UdopProcessor一站式产出这也是它与 Donut/Pix2Struct 的本质差异。OCR 是双刃剑默认 Tesseract 免费易用但模糊图像上效果有限需要更高精度时用apply_ocrFalse自行接入 Azure Read API 等更强引擎。任务 提示词 目标序列问答用Question answering. ...分类用document image classification. label布局分析用Layout analysis. ElementJSON 抽取则用json2token把结构化目标线性化并在训练时向 tokenizer 注册新特殊 token 并 resize 解码器词嵌入。显存敏感large 模型在 Colab T4 上 batch size 只能取 1建议结合 8-bit Adambitsandbytes、梯度累积、梯度检查点需要更强效果可换 512 分辨率检查点显存开销更高。生成式 vs 判别式默认UdopForConditionalGeneration走自回归生成若任务只需编码表示如 token 分类可复用UdopEncoderModel 自定义分类头按 BERT/LayoutLMv3 的方式用 Trainer 微调。如果你想继续深挖仓库中的完整可运行代码分别在 Inference_with_UDOP, a generative document AI model.ipynb、Fine_tune_UDOP_on_a_custom_dataset_(JSON_extraction).ipynb.ipynb)、Fine_tune_UDOP_on_a_custom_dataset_(toy_RVL_CDIP_dataset).ipynb.ipynb)、Layout_analysis_with_UDOP.ipynb 与 Fine_tune_UDOPEncoderModel_on_FUNSD_(HuggingFace_Trainer).ipynb.ipynb) 中每一份都可以直接在 Colab 中运行并复现本文描述的流程。赞分享示例工程【免费下载链接】Transformers-TutorialsThis repository contains demos I made with the Transformers library by HuggingFace.项目地址https://gitcode.com/GitHub_Trending/tr/Transformers-Tutorials点击查看免费下载相关推荐文档问答系统Transformers-Tutorials中DocVQA数据集的模型微调实战文档问答系统Transformers Tutorials中DocVQA数据集的模型微调实战 在当今数字化时代处理和理解大量文档信息已成为一项重要需求。文档问示例工程Hugging Face Transformers 中的 Donut 文档理解模型免 OCR 的端到端视觉文档理解实战Hugging Face Transformers 中的 Donut 文档理解模型免 OCR 的端到端视觉文档理解实战 DonutDocument Unde人工智能大模型深度学习NLP预训练微调模型推理服务深入解析 Transformers 中的 CodeGen 模型对话式程序合成与代码生成实战指南深入解析 Transformers 中的 CodeGen 模型对话式程序合成与代码生成实战指南 CodeGen 是由 Salesforce 提出的自回归程序合人工智能大模型深度学习NLP预训练微调模型推理服务上一篇Practical Python异步编程asyncio入门到实战指南下一篇Pixi-Spine打造流畅2D骨骼动画的完整解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表