故事是这样的。

工作上突然甩过来一个很急的需求。

几千张图。准确说,后面扩到七千多张。每张里有一块短信截图区域,要把里面的验证码抠出来,再跟 Excel 表里的字段逐条比对,看一不一样。

听起来不复杂对吧。

复杂的是时间。

需求非常急。领导的原话大概是,如果第二天大模型还跑不起来,就协调全组十几个人一起干。肉眼看。一张一张看。

而这件事,指定由我来协调。

我当时心里只有两个念头。

我不想加班。

我也不想让同事加班。

你要是经历过全组一起熬夜对图,就知道那有多磨人。七千多张图,肉眼核,不是加一晚上班的事,是加好几天,还得十几个人一起埋进去。人眼会花,标准会漂,最后还不一定比机器稳。

我不信。

不是不信领导,是不信「这么发达的 AI 时代,还得靠全组人肉刷图」这件事。

于是我开始想办法。


 

第一反应当然是 OCR。

我也是这么想的。OCR 嘛,识别文字,听起来就该快。结果一跑,脸就绿了。

一张图大概 50 秒(这个时候已经凌晨三点了,按照计划第二天必须完成)。

你算一下,几千张乘下去,整份数据跑完要十个小时量级。更要命的是准确率,不到 50%。不到一半。等于机器干完,人还得再核一遍,甚至核得比直接人看还累。

那一刻我真的有点崩溃。

不是技术不行那种抽象崩溃,是「明天全组可能要因我加班」的具象压力。

然后我就一直问 AI。怎么办。还有没有别的路。别跟我说再调调阈值、再裁裁图,我没那个时间跟传统 OCR 谈恋爱。

AI 给了一个方案。本地跑通义的多模态大模型,Qwen2-VL,先上 2B。小,能塞进消费级显卡,数据还不出本机。

我笔记本是 RTX 3050,6G 显存。听起来寒酸,但当时顾不上寒酸不寒酸了。

我就让 Claude Code(我接入的DeepSeek V4 flash) 帮我写脚本,装环境,下模型,一点点把流程跑起来。

中间当然也不是一帆风顺。小显存 Windows 上,加载参数踩过坑,进程能无声无息蒸发。这些后面细聊。

但当它真正转起来之后,效果奇好。

奇好到什么程度呢。

比我们公司专业部门那边原来那套,还要好看。

我自己都有点懵。

不是嘲讽谁。是那种「我以为要靠人海,结果一个本地小模型就把活接住了」的失重感。同组同事因此免掉了那几天可能的集体加班。以前不太准、不太稳的字段,这次也被识别到了。

所以这篇文章,不是又一篇「如何优雅部署多模态」的说明书。

是一个打工人,在deadline压顶时,怎么用 6G 显存和 Qwen2-VL-2B,把全组从人肉核图里捞出来的笔记。

我自己也还在摸索。你就当听个真实经历。说不定你也正在被类似的需求堵在门口。

图片

先说结论,免得你悬着。

能跑。

而且不是「理论上能跑」,是 Windows 小卡也能跑,后来我在 Ubuntu 的 RTX 4090 上试更大的 Qwen2.5-VL-7B,那是后话。真正救命的第一枪,是 2B。

回到本地这块。

很多人一听本地多模态,第一反应就是,我显存不够吧,我是不是得上 24G,我是不是得量化到天昏地暗。

坦率的讲,一开始我也被这种氛围带跑了。

但真正上手之后你会发现,入门门槛比想象中低一点,坑也比教程里写的脏一点。

怎么说呢。教程往往告诉你 pip install,然后写上 device_map 等于 auto,世界就和平了。

现实会给你一记闷棍。

我在 3050 上第一次加载模型的时候,日志刚打出「加载模型」,然后,没有 Python 报错,没有 Traceback,终端直接回到提示符。

进程,没了。

我当时就愣住了。

你知道最烦的是什么吗?不是报错,是「连报错都没有」。像人突然在你面前蒸发,桌上还留着一杯没喝完的水。

后来查到,是 Windows 上的 Access Violation,那种进程级崩溃。再往下追,问题就指向一个很多人随手就写的参数,device_map 设成 auto。

在某些小显存 Windows 环境里,它不稳。

解法其实朴素得有点好笑。别让它「自动拆」,先老老实实加载,再整模搬到 `cuda`。

```python

model = Qwen2VLForConditionalGeneration.from_pretrained(

    MODEL_DIR,

    torch_dtype=torch.float16,

    device_map=None,

    low_cpu_mem_usage=True,

)

model = model.to("cuda")

```

就这。

4090 那种大卡上,device_map 设成 auto 通常没事。但小卡,我建议你先稳,再骚。

这块需要注意一下。你不是在追求最酷的加载姿势,你是在追求「今晚能跑完」。

说到这个,很多人会问,那我到底该下哪个模型?

我自己的感受是,先别盯着最大的看。

Qwen2-VL-2B-Instruct,大概 4 到 6G 显存就能转起来,适合入门、批量 OCR、字段抽取。印刷体截图、结构化字段,2B 往往已经够用。

Qwen2.5-VL-7B 更强,大概十四十六 G 往上更舒服,适合更复杂的理解和核对。

再往上,32B 量化那些,能冲准确率,但部署和调参明显更重。

我始终坚信一件事。

先把 2B 跑通,再谈 7B。

否则你很容易陷入一种很窒息的状态,模型还没看见图,人已经先被环境折磨干了。

图片

环境这块,我不想写成说明书口吻。就按我实际做过的顺序聊。

显卡要是 NVIDIA,6G 及以上更稳。驱动正常,`nvidia-smi` 能看见卡。模型本身大概 4.5G,磁盘再留点余量。

conda 开个干净环境,Python 3.10 够用。

```bash

conda create -n vlm-local python=3.10 -y

conda activate vlm-local

```

PyTorch 按你的 CUDA 装。CUDA 11.8 可以这样。

```bash

pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118

```

装完先别急着下模型,先确认 GPU 真的在。

```python

import torch

print(torch.__version__)

print(torch.cuda.is_available())

print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else "no gpu")

```

如果这里都是 False,后面所有多模态故事都可以先暂停。不是模型不行,是地基没打好。

然后装推理依赖。

```bash

pip install transformers accelerate qwen-vl-utils pillow

pip install modelscope

```

模型我建议国内走 ModelScope,香。

```bash

modelscope download --model qwen/Qwen2-VL-2B-Instruct --local_dir ./Qwen2-VL-2B-Instruct

```

下完目录里会有那两块 safetensors,看着就安心。像家里囤了两袋米。

最小推理骨架,其实就一句话。

给一张图,给一句中文指令,让模型吐文本。

```python

from pathlib import Path

import torch

from transformers import Qwen2VLForConditionalGeneration, AutoProcessor

from qwen_vl_utils import process_vision_info

MODEL_DIR = "./Qwen2-VL-2B-Instruct"

IMAGE = "demo.jpg"

PROMPT = "请完整读取图片中的全部可见文字,按从上到下顺序输出,不要编造。"

model = Qwen2VLForConditionalGeneration.from_pretrained(

    MODEL_DIR,

    torch_dtype=torch.float16,

    device_map=None,

    low_cpu_mem_usage=True,

)

model = model.to("cuda")

model.eval()

processor = AutoProcessor.from_pretrained(MODEL_DIR, max_pixels=802816)

messages = [{

    "role": "user",

    "content": [

        {"type": "image", "image": str(Path(IMAGE).resolve())},

        {"type": "text", "text": PROMPT},

    ],

}]

text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)

image_inputs, video_inputs = process_vision_info(messages)

inputs = processor(

    text=[text], images=image_inputs, videos=video_inputs,

    padding=True, return_tensors="pt",

)

device = next(model.parameters()).device

inputs = inputs.to(device)

with torch.no_grad():

    out = model.generate(**inputs, max_new_tokens=512, do_sample=False)

answer = processor.batch_decode(

    out[:, inputs.input_ids.shape[1]:], skip_special_tokens=True

)[0]

print(answer.strip())

```

你看,我把 `max_pixels` 先写成了 802816。

为啥?

因为第二个大坑,叫显存爆炸。高分辨率整图会把视觉 token 顶上天。手机截图、单据特写,往往真的不需要 4K 原图。先小后大,能跑通再放开。这不是保守,这是活着。

还有个很阴的细节。如果你用了拆卡加载,`model.device` 有时会给你脸色。更稳的写法是。

```python

device = next(model.parameters()).device

inputs = inputs.to(device)

```

小坑,但能省你半小时自我怀疑。

顺着上面的,再聊聊 Prompt。

这块我以前也踩得很惨。

你会下意识觉得,模型既然能「看懂图」,那就让它像人一样随便看看呗。

结果呢?

任务越含糊,输出越漂移。

我后来给自己定了个很土的原则。任务越具体,输出越可控。

全文 OCR,就写「完整读取全部可见文字,按阅读顺序,不要编造」。

只要某个编号,就写「只输出那个编号,不要其它内容」。

抽字段,就写「找到某句式旁边的手写数字,只回答那个数字」。

你别指望 2B 拥有一个成熟打工人的默契。它更像一个很努力、但必须把需求写死的实习生。

说到实习生,就不得不提幻觉这件事。

潦草手写签名场景里,如果你逼它「一定要输出姓名」,它会很勤奋地给你编。李明,李华,张伟杰,像从某个高频姓名池里抓阄。

我第一次看到连续一串「李明」的时候,真的无语凝噎。

不是它坏,是你把「认不清」的退路堵死了,它只能表演勤奋。

更靠谱的产品形态,其实是核对式。把登记姓名作为条件,问这张签名是否像签这个名字,只回答是或否。

你以为 OCR 一定要先把字认出来,才能比对。

其实有些场景,核对比盲认更接近人的工作方式。人看到连笔签名,也经常是「对照着名字看像不像」,而不是先完美拆成三个楷书汉字。

我后来还专门拿一批样张,对比过盲认和核对。盲认那边,空结果和胡编姓名会把准确率拖得很难看。一改成核对,模型反而敢下判断了。不是它突然变聪明,是你把题出对人了。

空括号也一样。表单里括号空着,2B 有时会猜 0 或 1。这不是你 Prompt 没写好,是能力边界。难例就人工抽检,或者只把难例送云端。别跟边界死磕,死磕的通常是你的睡眠。


 

说到这里,你大概也能理解我为什么对「本地」这么执着了。

不是先有一篇部署教程,再去找业务。是业务先把刀架上来了。

传统 OCR 给我上的第一课很残酷。单张 50 秒,整包十小时,准确率不到一半。你加裁剪,加增强,加规则,纸糊的塔越堆越高,风一吹还是例外。

后来直接上本地多模态。Qwen2-VL-2B。Claude Code 帮我把脚本骨架拉起来,我负责把需求钉死,把显存坑填上,把批处理跑通。

效果奇好。好过公司专业部门原来那套。同组因此不用为七千多张图集体加班。

本地小模型做主力。听起来不炫,但能上线,还能救人。

坦率的讲,本地 VLM 的核心价值,不是处处碾压云。

是隐私,是成本,是可批量,还有一个常常被忽略的,是「能在 deadline 前把人从人海战术里救出来」。

你想想看。云端像外卖,又快又香,但每单都要付钱,而且食材要出小区。本地像自己开火,开火麻烦,锅还小,可一旦锅热了,夜里就能一直炒。更重要的是,锅在你工位旁边,领导问进度的时候,你看得见风扇在转。

当然也会有人说,那我直接用微信识图不就得了。

我非常理解这种感觉。

你不是天天做批量,你不是要对着 Excel 核几千个验证码,你只是偶尔拍一页书,微信当然香。

可一旦你面对的是成百上千张图,要固定字段,要可追溯报表,要尽量别让全组加班,问题就变了。工具没变贵,需求变重了。

大时代啊,朋友们。一边是 API 按次闪烁的账单,一边是自己电脑风扇突然开始起飞的声音。两种浪漫,都很贵。而我更想要的第三种浪漫,是同事不用熬夜。

如果你关心变现,这块卖点其实很清楚。数据不出本地,适合隐私敏感单据。闲鱼淘宝可以卖识别服务,客户发图你回文本或 Excel。也可以帮人做私有化部署。也可以做成发票合同字段、单据核验、书籍拍照转文字这类小工具。

技术文章本身也会获客。有人跑通了,就会来问,能不能帮我装到服务器上。

但我得把丑话说在前头。

一开始可能会有点笨拙。装环境、下模型、调显存,花的时间可能比你直接把图丢给云端还长。前两天你甚至会怀疑自己是不是在自找苦吃。


 

几乎所有本地部署的第一周,都有点像早年自己搭博客。你明明只是想发篇文章,结果先跟域名、报错、依赖版本纠缠了三天。可一旦跑通,那种「这东西在我机器上」的踏实,云端给不了。那种「同事不用因为我加班」的踏实,教程更给不了。

还有个小建议。别一上来就跟同事炫耀「我部署了多模态大模型」。先拿一张你自己的短信截图跑通,再拿十张相似图看看稳不稳。稳了,再谈批量。不稳,先别立 flag。愚钝如我,就是这么一点点拱出来的。

如果你也想亲自下场,我建议你别一次吃成胖子。按天来就行。

第一天,装环境,下 2B,跑通一张手机截图全文识别。

第二天,改成只抽某个字段,试不同 Prompt。

第三天,加批处理,断点续跑,导出 CSV。

第四天,压测显存,调 max_pixels,记录速度。

第五天,如果你有更大显存,再上 7B,同一批样张对比。

别跳步。跳步的人,通常死在第一步的假平静里。

写到这里,我突然想起早年那些「家用电脑也能上互联网」的故事。不是最强的机器赢了,是足够多人终于摸到了入口。多模态也一样。真正改变日常的,不一定是最大的模型,而是那个终于能在你自己桌上转起来的小模型。

6G 显存,听起来寒酸。

可寒酸有时候是门票。

屏幕前的你,如果也有一块不太体面的显卡,别先判死刑。

够你开一场很小,但很真的实验。

也够你,在某个突然砸下来的需求面前,试着把全组从加班里捞出来一次。

以上,既然看到这里了,如果觉得不错,随手点个赞、在看、转发三连吧,如果想第一时间收到推送,也可以给我个星标⭐~

谢谢你看我的文章,我们,下次再见。

另外一个风格文章:Qwen2-VL 本地部署实战:6G 显存跑多模态大模型-CSDN博客


 

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐