环境准备
# Python 3.11+,CUDA 12+ pip install byaldi pdf2image pillow # macOS / Ubuntu 系统级依赖:pdf2image 需要 poppler brew install poppler # macOS sudo apt install poppler-utils # Ubuntu
显存需求
ColPali v1.2 推理需要 ≈ 8GB 显存(bfloat16)。ColQwen2-2B ≈ 6GB。没有独立 GPU 也能用 MPS(Apple Silicon M2+)——慢但能跑。后面讲量化后可以压到 4GB。
ColPali v1.2 推理需要 ≈ 8GB 显存(bfloat16)。ColQwen2-2B ≈ 6GB。没有独立 GPU 也能用 MPS(Apple Silicon M2+)——慢但能跑。后面讲量化后可以压到 4GB。
索引一个 PDF 文件夹
from byaldi import RAGMultiModalModel # 1. 加载模型(首次下载 ~6GB,之后走本地缓存) model = RAGMultiModalModel.from_pretrained("vidore/colpali-v1.2") # 2. 把文件夹下所有 PDF 都索引 model.index( input_path="./pdfs/", index_name="annual-reports", store_collection_with_index=True, # 保存页面图像,方便后续看原图 overwrite=True, ) # 3. 查询 results = model.search("2024 年营收同比增长多少?", k=5) for r in results: print(f"{r.doc_id} 第 {r.page_num} 页,分数 {r.score:.2f}")
这 10 行代码的背后,byaldi 做了:
- 用
pdf2image把每页 PDF 渲染成 PIL Image(默认 DPI=150) - 批量送入 ColPali,每页产出 1024×128 张量
- 向量和原图都存到本地磁盘(
.byaldi/annual-reports/) - 查询时对 query 做同样编码,对所有页面算 MaxSim,topK 返回
不用 byaldi:裸调 transformers
byaldi 封装得太多,理解原理还得看裸版本:
import torch from transformers import ColPaliForRetrieval, ColPaliProcessor from pdf2image import convert_from_path device = "cuda" if torch.cuda.is_available() else "cpu" model = ColPaliForRetrieval.from_pretrained( "vidore/colpali-v1.2", torch_dtype=torch.bfloat16, device_map=device, ).eval() processor = ColPaliProcessor.from_pretrained("vidore/colpali-v1.2") # 1. 编码所有页 pages = convert_from_path("report.pdf", dpi=150) batch = processor.process_images(pages).to(device) with torch.no_grad(): page_vecs = model(**batch).embeddings # (N_pages, 1024, 128) # 2. 编码 query queries = ["revenue growth in 2024"] q_batch = processor.process_queries(queries).to(device) with torch.no_grad(): q_vecs = model(**q_batch).embeddings # (1, n_tok, 128) # 3. MaxSim 打分 scores = processor.score_multi_vector(q_vecs, page_vecs) # (1, N_pages) top_pages = scores.squeeze().topk(5).indices for i in top_pages: print(f"第 {i+1} 页,得分 {scores[0, i]:.3f}")
加速:批处理
from torch.utils.data import DataLoader def collate(batch): return processor.process_images(batch) loader = DataLoader(pages, batch_size=8, collate_fn=collate) all_vecs = [] with torch.no_grad(): for batch in loader: batch = { k: v.to(device) for k, v in batch.items() } all_vecs.append(model(**batch).embeddings) page_vecs = torch.cat(all_vecs, dim=0)
A100 40GB 上 batch=16 大概 40 张 / 秒,一本 500 页的年报 12 秒索引完。
DPI 与图片尺寸
DPI 是质量关键
- DPI 72:字号 8pt 的脚注可能读不清——不推荐
- DPI 150(byaldi 默认):日常文档的甜点
- DPI 200+:财报密集表格可考虑,但单页推理慢 2x
- 图片长边超过 1500 像素:模型内部会 resize 到 448×448,无意义
第一个实战:查一本真实财报
queries = [
"哪一页展示 2024 年各业务线营收饼图?",
"管理层讨论里提到的三大风险是什么",
"ESG 报告里说温室气体排放降多少",
]
for q in queries:
r = model.search(q, k=3)
print(f"\n【{q}】")
for hit in r:
print(f" p.{hit.page_num} score={hit.score:.2f}")
对 Apple 2024 Annual Report 测试,三条查询都在 top-1 命中正确页。对照 OCR + BGE 方案的 top-3 命中率约 60%——差距明显。
常见错误 & 排查
CUDA OOM
把 batch_size 调到 4,或换 ColSmolVLM-500M 小模型。还可以用
torch.autocast + fp16 再省一半。pdf2image 在 macOS 报 "Unable to get page count"
brew install poppler 然后重启终端。仍不行给 poppler_path 参数显式指定。第一次加载模型极慢
HuggingFace 下载 6GB,设置
HF_ENDPOINT=https://hf-mirror.com 用镜像或提前手动下载。搜索结果都是同一页
检查是不是同一张图被索引多次(脚本 bug)。删掉
.byaldi/ 重建。本章小结
- byaldi 10 行代码跑通 ColPali:加载 → 索引文件夹 → search
- 裸 transformers 写法:
process_images+process_queries+score_multi_vector - DPI 150 是质量甜点,批处理提升吞吐
- 500 页年报 A100 上 ~12 秒索引完
- 常见坑:OOM、poppler、模型下载——都有标准解法