微调Qwen2.5-VL用于文档理解
本文将检查一个手写数字数据集、对其进行标注,并使用它来创建一个专门用于提取手写文本的微调后的Qwen 2.5 VL。

在这篇文章中,我将讨论如何对像Qwen 2.5 VL 7B这样的视觉大语言模型(通常称为vLLMs)进行微调。我将介绍一个手写数字数据集,基础版本的Qwen 2.5 VL在该数据集上表现不佳。然后我们将检查数据集、对其进行标注,并使用它来创建一个专门用于提取手写文本的微调后的Qwen 2.5 VL。
1、概述
本文的主要目标是展示如何对VLM(视觉大语言模型,通常称为vLLMs)进行微调,这是当今世界中一种重要的机器学习技术,语言模型正在改变数据科学家和机器学习工程师的工作方式和成果。我将讨论以下主题:
- 动机与目标:为什么使用VLMs进行文本提取
- VLM的优势
- 数据集
- 标注和微调
- SFT技术细节
- 结果和图表
注意:这篇文章是在Findable的工作中撰写的。我们不从中获利。这是为了突出现代视觉语言模型的技术能力,并数字化并共享一个有价值的手写物候数据集,这可能对气候研究产生重大影响。此外,本文的主题在Netlight的Data & Draft活动中进行了演讲。
你可以在此GitHub存储库中查看本文使用的全部代码,所有数据都可以在HuggingFace上找到。如果你特别感兴趣的是从挪威提取的物候数据,包括对应于数据的地理坐标信息,这些信息可以直接在此Excel文件中找到。
2、动机与目标
本文的目标是向你展示如何对像Qwen这样的VLM进行微调以优化其在特定任务上的性能。我们在这里处理的任务是从一系列图像中提取手写文本。本文的工作基于一个挪威物候数据集,你可以在此GitHub存储库的README中了解更多关于它的信息。主要一点是这些图像中包含的信息非常有价值,可以用于例如气候研究。这个主题也有明确的科学兴趣,例如,分析植物开花时间长期变化的文章,或宾夕法尼亚东部物候项目。
请注意,提取的数据是善意提供的,我不会对数据所暗示的内容做出任何声明。本文的主要目的是向您展示如何提取这些数据并提供提取的数据,供科学研究使用。

在这篇文章中,我们将使用Qwen 2.5 VL从这些类型的图像中提取文本。这些单元格是从如特色图片所示的表格中提取的,使用了将在另一篇文章中介绍的图像处理技术。图片由作者提供。
我在本文中制作的结果模型可以用于从所有图像中提取文本。然后可以将这些数据转换为表格,并像下图所示那样绘制信息:

这张图展示了从图像中提取的树线编号,并将其绘制到挪威的地图上。较冷的颜色六边形表示较低的树线,正如预期的那样,越靠近海洋,越往北走,树线就越低。较暖的颜色代表较高的树线,随着我们进入国家内部,树线预计会更高。图片由作者制作,使用了Uber的H3。
如果你只对本文中提取的数据感兴趣,您可以在这个parquet文件中查看。
3、为什么我们需要使用VLMs
在看这些图像时,你可能会认为我们应该应用传统的OCR来解决这个问题。OCR(光学字符识别)是提取图像中文本的科学,近年来,它一直被像Tesseract、DocTR和EasyOCR这样的引擎主导。
然而,这些模型往往被现代大型语言模型超越,尤其是那些结合了视觉的模型(通常称为VLMs或VLLMs)——下面的图像突出显示了为什么你想要使用VLM而不是传统的OCR引擎。第一列显示了我们数据集中的示例图像,另外两列比较了EasyOCR与我们在本文中训练的微调后的Qwen模型。

这张图突出了为什么您想使用VLMs(如Qwen2.5 VL)而不是传统的OCR引擎(如EasyOCR)。第一列显示了我们要提取文本的图像,其他两列显示了使用EasyOCR和微调后的Qwen模型提取的文本。
在第一张图像中,你可以注意到两个问题。首先,EasyOCR没有检测到“2”,它写得很模糊。其次,EasyOCR还将单元格边框误认为是“1”,这是一个关键错误。在第二张图像中,你可以看到图像中有许多点(这是由于我们进行的图像处理结果),这使得EasyOCR无法从图像中提取文本。在最后一张图像中,EasyOCR将“1”误认为是“7”,再次犯了将单元格边框误认为是数字“1”的错误。
这突显了使用VLM而不是传统OCR引擎的主要原因:当从图像中提取文本时,VLMs通常优于传统的OCR引擎。
4、VLM的优势
在从图像中提取文本时,使用VLM有几个优势。在上一节中,你看到了VLM的输出质量超过了传统OCR引擎的输出质量。另一个优势是你可以向VLM提供指令,而传统OCR引擎无法做到这一点。
因此,VLM的两大优势是:
- VLM在OCR(特别是手写文本)方面表现出色
- 可以提供指令
VLM擅长OCR是因为这是这些模型训练过程的一部分。例如,在Qwen 2.5 VL技术报告第2.2.1节预训练数据中提到过,他们将OCR数据集列为预训练数据的一部分。
5、手写文本
在过去,提取手写文本一直是一个难题,现在仍然是一个挑战。造成这种困难的原因是手写文本是非标准化的。
所谓非标准化,是指字符会因人而异,看起来差异很大。例如,标准化的字符,如果在计算机上书写,无论在哪台计算机上书写,看起来都会非常相似。例如,计算机字符“a”看起来无论在哪台计算机上都非常相似。这使得OCR引擎更容易识别字符,因为它从图像中提取的字符很可能与它在训练集中遇到的字符非常相似。
然而,手写文本正好相反。手写风格因人而异,这就是为什么有时您难以读懂他人的手写。OCR引擎也面临同样的问题。如果字符变化很大,那么它在训练集中遇到特定字符变体的可能性就更低,从而使得从图像中正确提取字符变得更加困难。
例如,您可以看看下面的图像。想象一下只看图像中的“1”(所以遮住“7”)。现在看图像,这个“1”看起来很像“7”。当然,您可以根据上下文判断这两个字符,思考得出如果“7”看起来是这样(带有水平线),那么图像中的前两个字符一定是“1”。
然而,传统的OCR引擎却没有这种能力。它们不会看整个图像,也不会根据一个字符的外观进行批判性思考,然后利用这一点来确定其他字符。当看孤立的数字时,它们只能猜测这个字符是什么。

这张图突出了区分“1”和“7”的挑战。从上下文中看这三个数字,您很容易看出前两个数字是“1”,而最后一个数字是“7”。然而,如果遮住最后一个数字,只看前两个数字,您会注意到这些数字也可能被解释为“7”。图片由作者提供
如何区分数字“1”和“7”,很好地过渡到了下一个部分,关于向VLM提供指令以提取文本。
我还想补充说,一些OCR引擎,如TrOCR,是专门用来提取手写文本的。根据我的经验,这类模型的性能无法与最先进的VLMs(如Qwen 2.5 VL)相比。
6、提供指令
使用VLM提取文本的另一个重要优势是可以向模型提供指令。这自然不可能通过传统的OCR引擎实现,因为它们提取图像中的所有文本。它们只能输入图像,而不能为提取图像中的文本提供单独的文本指令。当我们想要使用Qwen 2.5 VL提取文本时,我们会提供一个系统提示,如下所示。
SYSTEM_PROMPT = """
以下是描述任务的指令,请编写响应以适当地完成请求。
你是一位手写表格条目专家。我会给你一段表格的片段,你会读取片段中的文本并将其作为字符串返回。
文本可以包括以下内容:
1) 仅数字,数字可以有1到3位数。
2) 被普通括号包围的数字。
3) 被方括号包围的数字。
5) 字母'e'、's'或'k'
6) 百分号'%'
7) 完全空白的图像(无文本)。
指令:
**通用规则**:
- 将文本作为字符串返回。
- 如果片段中没有文本,返回:"unknown"。
- 为了将数字1与数字7分开,要知道数字7总是会在中间有一条水平线。如果没有这样的水平线,即使看起来像7,数字也是1。
- 注意,文本经常会被黑色边框包围,不要将其误认为是文本。尤其是容易将数字1与边框的一部分混淆。边框应忽略。
- 忽略边框以外的所有内容。
- 不要在响应中使用任何代码格式、反引号或markdown。只需输出原始文本。
- 仅响应字符串。不要提供解释或推理。
"""
系统提示为Qwen如何提取文本设定了框架,这给了Qwen相对于传统OCR引擎的重大优势。
主要有两点使其具有优势:
- 我们可以告诉Qwen在图像中期望看到哪些字符
- 我们可以告诉Qwen字符看起来像什么(对手写文本尤为重要)
您可以看到第一点在1) -> 7)中得到解决,其中我们告知它只能看到1-3位数字,它可以看到哪些数字和字母,等等。这是一个显著的优势,因为Qwen知道,如果它检测到超出此范围的字符,很可能是对图像的误解,或者是一个特定的挑战。它能更好地预测图像中认为的字符。
第二点对于我之前提到的分离“1”和“7”的问题尤其相关,这两个数字看起来非常相似。幸运的是,这个数据集的作者在书写“1”和“7”时保持了一致性。“1”总是斜着写,“7”总是包括水平横线,这至少从人类角度来看,清楚地将“7”与“1”区分开来。
然而,向模型提供如此详细的提示和规范只有在您真正了解您正在处理的数据集及其挑战时才可行。这就是为什么在处理机器学习问题时,您应该始终花时间手动检查数据。在下一节中,我将讨论我们正在处理的数据集。
7、数据集
我以Greg Brockman(截至撰写本文时的OpenAI总裁)的一句名言开始这一节,强调了一个重要的观点。在他的推文中,他提到了数据标注和检查不是令人羡慕的工作,但尽管如此,这是您在从事机器学习项目时可以花费时间的最重要的任务之一。
在Findable,我最初是一名数据标注员,随后管理Findable的标注团队,现在我作为一名数据科学家工作。标注工作的经验突显了手动检查和理解你正在处理的数据的重要性,并教会了我如何有效地这样做。Greg Brockman指的是这项工作并不令人羡慕,这通常是正确的,因为数据检查和标注可能很单调。然而,当你在处理机器学习问题时,应该始终花大量时间检查你的数据集。这样做将为你提供见解,例如,你可以利用这些见解来提供我在上一节中强调的详细系统提示。
我们正在处理的数据集由大约82000张图像组成,如下所示。单元格的宽度从81到93像素不等,高度从48到57像素不等,这意味着我们正在处理非常小的图像。

当我开始这个项目时,我首先花了时间查看不同的图像,以了解数据集的变化。例如,我注意到:
- “1”看起来与“7”相似
- 一些图像中有一些模糊的文本(例如,上面左下角图像中的“8”和右下角图像中的“6”)
- 从人类的角度来看,所有图像都非常易读,所以我们应该能够正确提取所有文本
然后,我继续使用Qwen 2.5 VL 7B的基础版本预测一些图像,看看模型在哪些方面存在困难。我立即注意到模型(不出所料)在分离“1”和“7”时遇到了问题。
在这个手动检查数据的过程之后,再预测一些图像来看看模型在哪里挣扎,我记下了以下数据挑战:
- “1”和“7”看起来相似
- 图像背景中有些点
- 单元格边框可能被误认为字符
- 括号和方括号有时会被混淆
- 一些图像中的文本很模糊
当我们微调模型以从图像中提取文本时,必须解决这些挑战,这将在下一节中讨论。
8、标注和微调
在充分检查数据集后,是时候进行标注和微调了。标注是为每张图像设置标签的过程,而微调是使用这些标签来提高模型的质量。
在进行标注时,主要目标是高效地创建数据集。这意味着快速生成大量标签,并确保标签的质量高。为了实现快速创建高质量数据集的目标,我将过程分为三个主要步骤:
- 预测
- 审查并纠正模型错误
- 再训练
你应该注意,当模型已经相当擅长执行任务时,这种方法效果很好。例如,在这个任务中,Qwen已经相当擅长从图像中提取文本,并且只在5-10%的情况下出错。如果你给模型一个全新的任务,这种方法的效果就不会那么好。

这张图展示了我快速创建标注数据集和微调Qwen的三步流程。第一步使用基础模型预测几百个样本。然后我查看模型预测并纠正错误。之后,我使用当前的标注样本集训练模型。接着,我使用这个微调后的模型预测新一批几百个样本,审查并纠正错误,再训练。我重复这个预测、纠正、训练的循环,直到模型性能开始收敛。这个创建数据集的过程比例如逐个查看每个图像并将图像中的文本写下来创建标注数据集要快得多。图片由作者提供。
8.1 预测
第一步是使用基础模型预测(提取文本)几百张图像。具体预测多少张图像并不重要,但您应该努力在收集足够多的标签以便训练运行可以改进模型(第三步)和考虑训练模型所需的开销之间取得平衡。
8.2 审查并纠正模型错误
在预测了几百个样本之后,是时候审查并纠正模型的错误了。您应该设置环境以便轻松显示图像和标签并修复错误。在下面的图像中,您可以看到我的审查和纠正错误的设置。在左侧,我有一个Jupyter笔记本,我可以运行单元格以显示接下来的五个样本以及对应的标签行。在右侧,所有标签都列在相应的行上。为了审查和纠正错误,我运行Jupyter笔记本单元格,确保右侧的标签与左侧的图像匹配,然后重新运行单元格以获取接下来的五个图像。我重复这个过程,直到查看完所有样本。

这张图展示了我用于审查和纠正模型错误的环境。在左侧,我有一个Jupyter笔记本,我可以运行单元格以显示接下来的五个图像,以及每个图像所属的行。在右侧,我有所有标签列在相应的行上。这个环境使我能够轻松查看所有模型预测并纠正任何错误。图片由作者提供。
8.3 再训练
现在您已经有了一些正确的样本,是时候训练模型了。在我的情况下,我使用Qwen 2.5 VL 7B并将其调整到当前的标签集。我使用Unsloth包进行微调,该包提供了这个用于微调Qwen的笔记本(笔记本是针对Qwen 2 VL的,但所有代码相同,除了更改命名,如您在下面的代码中看到的)。
训练创建了一个微调后的模型版本,我回到第一步预测几批新的样本。我重复这个预测、纠正、训练的循环,直到注意到模型性能开始收敛。
# 这是笔记本中的原始代码
model, tokenizer = FastVisionModel.from_pretrained(
"unsloth/Qwen2-VL-7B-Instruct",
load_in_4bit = False, # 这原本设置为True,但如果您的计算能力允许,我建议将其设置为False
use_gradient_checkpointing = "unsloth",
)
# 要训练Qwen 2.5 VL(而不是Qwen 2 VL),请确保使用以下代码:
model, tokenizer = FastVisionModel.from_pretrained(
"unsloth/Qwen2.5-VL-7B-Instruct",
load_in_4bit = False,
use_gradient_checkpointing = "unsloth",
)
为了确定我的模型表现如何,我还创建了一个测试集,在该测试集上测试每个微调后的模型。我从未在测试集上训练,以确保结果无偏。这个测试集是我如何确定模型性能是否收敛的方式。
9、SFT技术细节
SFT代表监督微调,这是更新模型权重以在我们提供的数据集上表现更好的过程。我们在这里处理的问题相当有趣,因为基础的Qwen 2.5 VL模型已经在OCR方面表现得相当好。这与其他我们在Findable应用VLM的任务不同,通常我们在这些任务中教导VLM完全新的任务,它本质上没有任何先前的经验。
当在新任务上微调VLM(如Qwen)时,一旦开始训练,模型性能会迅速提高。然而,我们在这里处理的任务却有所不同,因为我们只想稍微调整Qwen以更好地阅读我们特定图像的手写文本。如我所述,该模型在这个数据集上的性能约为90-95%(具体取决于我们测试的具体图像)。
这种只需要微调模型的需求使模型对微调过程参数非常敏感。为了确保我们正确地微调模型,我们采取了以下措施:
- 设置低学习率,以仅轻微更新权重
- 设置低LoRA等级,以仅更新模型权重的小部分
- 确保所有标签都是正确的(模型对少量标注错误非常敏感)
- 平衡数据集(有很多空白图像,我们过滤掉了一些)
- 微调所有层的VLM
- 进行超参数搜索
我将对其中的一些要点添加一些额外的说明:
9.1 标签正确性
标签正确性至关重要。仅仅几个标注错误就能对模型性能产生严重影响。例如,当我进行模型微调时,我发现模型开始将括号“()”误认为是方括号“[]”。这当然是一个严重的错误,所以我开始调查为什么会发生这种情况。我的第一个直觉是这可能是由于某些标注问题(即,一些实际上是括号的图像被错误地标记为方括号)。我开始检查我的标注,发现大约0.5%的标注有错误。
这帮助我做出了一个有趣的观察。我有大约1000个标注。99.5%的标注是正确的,而0.5%(5个标注!)是错误的。然而,在微调我的模型后,它实际上在测试集上的表现更差了。这突显了仅仅几个错误标签就能损害您的模型性能。

之所以这么少的错误会产生如此大的影响,是因为模型盲目信任您给它的标签。模型不会看图像并思考“嗯,为什么这个是方括号,而图像中是括号?”(就像您可能会做的)。模型盲目信任标签,并接受它是事实,即这个图像(实际上是括号)包含方括号。这极大地降低了模型性能,因为您正在提供错误信息,它现在使用这些信息来进行未来的预测。
9.2 数据平衡
微调的另一个细节是我要平衡数据集以限制空白图像的数量。大约70%的单元格包含空白图像,我不想在这些图像上花费太多微调时间(模型已经很好地忽略了这些单元格)。因此,我确保我们微调的数据中最多30%包含空白图像。
9.3 选择需要微调的层
下面的图像显示了VLM的标准架构:

这张图显示了VLM的标准架构布局。图像通过ViT(视觉变换器)传递,提取图像的视觉标记。然后这些标记通过VL(视觉-语言适配器)传递,确保图像标记与文本标记处于相同的嵌入空间中。输入到模型中的文本只是被标记化。然后文本和图像标记一起被送入解码器,生成输出文本。
在微调VLM时需要考虑的一个问题是选择哪些层进行微调。理想情况下,您希望微调所有层(在下图中标记为绿色)。这也是我在处理这个问题时所做的。然而,有时您会有计算约束,这使得微调所有层变得困难,而且您可能不需要微调所有层。一个例子是,如果您有一个非常依赖图像的任务。在Findable,例如,我们分类建筑师、土木工程师等的图纸。这自然是一个非常依赖视觉的任务,这是一个您可以潜在地只微调模型的视觉层(ViT - 视觉变换器,有时称为投影器)的例子。

这是一个建筑师的图纸示例。图纸来源于奥斯陆市,与Findable AS客户的资料无关。通过访问奥斯陆市政府的saksinnsyn(案件访问)网站,搜索Camilla Collects vei(随机选择的地址),然后点击Søk i sak(案件搜索)按钮,选择案件编号为202317562的案件,点击tegninger选项卡并选择名为plan 8 etasje的图纸。该图是在与奥斯陆市规划和建筑服务部门交谈后使用的,他们允许使用其网站上任何公开可用的图纸。图纸于2024年5月23日访问。
9.4 超参数搜索
我还进行了超参数搜索,以找到微调模型的最佳参数集。值得注意的是,超参数搜索并不总是可行的。一些大型语言模型的训练过程可能需要几天时间,在这种情况下,进行广泛的超参数搜索是不可行的,因此您必须依靠直觉来找到一组好的参数。
然而,对于这个手写文本提取的问题,我有A100 80 GB GPU的使用权。图像非常小(每个方向小于100像素),并且我使用的是7B模型。这使得训练时间在10到20分钟之间,这使得夜间超参数搜索是可行的。

这是我随意创建的一个图表,显示了提高模型准确率所需的努力量。如您在图中所见,从80%到90%的准确率所需的精力远少于从95%到99%的准确率所需的精力。图片由作者提供。
10、结果和图表
在重复训练模型、创建更多标签、重新训练等循环后,我已经创建了一个高性能的微调模型。现在是时候看看最终结果了。我创建了四个测试集,每个测试集包含278个样本。我在数据上运行EasyOCR、基础的Qwen 2.5 VL 7B模型(Qwen基础模型)和微调后的模型,您可以在下表中看到结果:

这是三个不同模型在四个测试集上的结果。您可以看到EasyOCR的表现不佳,其结果差到您无法信任它提供的数字。Qwen基础模型表现相当不错,范围在93%-99%之间。在某些场景中,这可能是可接受的性能,但它不足以满足我正在处理的数据集和我的性能期望。然而,您可以清楚地看到微调模型的效果很好,并且在所有测试集上都优于基础Qwen模型,特别是在测试集4中,两个模型表现相同。Qwen基础模型和微调后的模型基于阿里巴巴的Qwen 2.5 VL 7B。
因此,结果清楚地表明,微调按预期工作,大大提高了模型性能。
最后,我想分享一些您可以使用这些数据制作的图表。

这是从图像中提取的树线数据,并使用Uber的H3绘制到挪威地图上。您可以看到树线如何在靠近海洋和北方时变得更冷(更低),而在深入国家内部时变得更暖(更高)。图片由作者提供。
如果您想进一步研究数据,它都包含在HuggingFace上的这个parquet文件中。
11、结束语
在这篇文章中,我向您介绍了由小型图像和手写文本组成的物候数据集。本文解决的问题是如何有效从这些图像中提取手写文本。首先,我们检查了数据集,了解其外观、数据的变化以及视觉语言模型在从图像中提取文本时面临的挑战。然后我讨论了您可以用来创建标注数据集并微调模型以提高性能的三步管道。最后,我强调了一些结果,展示了微调Qwen比基础Qwen模型表现更好,并且我还展示了代表我们提取的数据的一些图表。
原文链接:Fine-Tuning vLLMs for Document Understanding
汇智网翻译整理,转载请标明出处
