尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

CLIP与LLaVA实战:从图文匹配到视觉问答的多模态大模型入门

CLIP与LLaVA实战:从图文匹配到视觉问答的多模态大模型入门 多模态视觉大模型最近不断刷屏但很多新手面对 CLIP、LLaVA 这一串名字时往往卡在“看了原理不懂代码跑了代码不懂原理”的环节。这两个模型正好构成一条从经典双塔结构到视觉语言对话模型的学习主线。本文会把底层架构拆开讲清楚再给出可以直接运行的最小代码实战包括 CLIP 的图文匹配、零样本分类以及 LLaVA 的图片问答和批量处理思路。全程不追求堆概念只讲模型怎么设计、代码怎么写、跑起来要关注什么。先说结论CLIP 是理解“图片和文本是否相关”的模型LLaVA 是在 CLIP 视觉编码器基础上接上大语言模型实现“看图回答、看图对话”的视觉语言模型。如果你刚入门深度学习与计算机视觉先跑通 CLIP再上手 LLaVA是一条比较顺的路径。文章末尾会给出常见报错和排查方法方便你对照解决。1. 核心能力速览为了让你快速判断这两个模型是否适合当前阶段先给出一张速览表。能力项说明项目类型多模态视觉大模型原理学习与代码实战核心模型OpenAI CLIP、LLaVA主要功能图文匹配、零样本图片分类、视觉问答、图片对话开源情况CLIP 源码开源LLaVA 相关权重与推理代码公开推荐硬件新手阶段建议 NVIDIA GPU显存越大越好CLIP 可尝试 CPU 推理LLaVA 较大模型需要更高显存显存占用不确定需按模型版本和推理参数实测CLIP ViT-B/32 占用较低LLaVA-7B 量化或半精度部署占用更高支持平台Linux / Windows / macOS部分依赖需适配启动方式Python 脚本、Jupyter Notebook、Flask API 服务是否支持 API可以自行封装为 HTTP 接口是否支持批量任务支持通过批量加载图片和文本实现适合场景新手入门多模态、图片标签分类、图文检索、视觉问答原型上表中的“不确定”是实际经验显存占用受模型精度、Batch Size、图片分辨率影响很大。建议在本地先跑最小例子再逐步扩大输入规模。2. 适用场景与使用边界这类模型适合谁先看适用场景刚入门深度学习、计算机视觉的开发者想理解多模态模型怎么工作。需要做“图片标签分类”或“图文匹配”的工程验证比如给图片自动打标签。想做视觉问答原型比如根据产品图片回答属性问题。想学习如何把视觉编码器和大语言模型接在一起。它不适合什么场景对识别精度要求极高的生产环境零样本分类准确率不如微调后的专用模型。高并发线上服务LLaVA 这类大模型直接部署成本高需要做量化、推理加速和并发控制。对延迟极度敏感的场景本地 CPU 推理速度较慢。使用边界必须清楚模型学到的“常识”不等于真实世界事实可能产生幻觉尤其是 LLaVA 生成文字时。图片素材、对话文本可能涉及隐私不要随意上传到第三方平台。如果使用人脸照片、版权图片、商业产品图务必确认授权并在受控的测试环境中验证。本文只做技术教学部署和商用前需要做效果复核与合规审查。3. 多模态视觉大模型基础CLIP 原理3.1 CLIP 解决什么问题CLIPContrastive Language-Image Pre-training由 OpenAI 提出核心目标是让模型学会判断“一张图片和一段文本是否匹配”。传统图像分类模型需要固定类别标签训练时标注成本高换一个任务就要重新训练。CLIP 想到的是把图片和文本同时编码到同一个向量空间然后用向量距离衡量匹配程度。这样不用固定类别输入一段文字描述就能和图片做相似度比较。3.2 双塔结构CLIP 包含两个编码器图像编码器常见有 ResNet 或 ViTVision Transformer负责把图片变成向量。文本编码器常见为 Transformer负责把文本变成向量。两个编码器各自独立所以称为“双塔结构”。训练时把成对的图片和文本分别编码然后计算它们的余弦相似度。相似度越高说明图文越匹配。在代码层面你通常不会自己实现这两个编码器而是借助 Hugging Face Transformers 加载预训练模型。比如from transformers import CLIPProcessor, CLIPModel model CLIPModel.from_pretrained(openai/clip-vit-base-patch32) processor CLIPProcessor.from_pretrained(openai/clip-vit-base-patch32)3.3 对比学习目标CLIP 的训练使用对比学习Contrastive Learning。训练时取一个 Batch 的图片-文本对模型需要把正样本对对应图片和文本的相似度拉高把负样本对不匹配的图片和文本的相似度压低。这个目标简单有效也是 CLIP 能做零样本分类的关键。为什么叫“零样本”因为训练时没有固定的分类头模型通过文本描述来指定类别。比如给图片“猫”标签文本可以是“a photo of a cat”“a picture of a cat”。模型计算图片与每个候选文本的相似度相似度最高的标签就是预测结果。3.4 为什么 CLIP 能用于零样本分类因为文本标签由自然语言构成模型在预训练阶段见过了大量图文对所以即使某个类别没有出现在训练数据中只要文本描述合理模型也能泛化。这也是 CLIP 常用于图片标签分类、图文检索的原因。当然CLIP 不是万能的抽象概念、复杂关系、细粒度类别仍可能出错。4. 从 CLIP 到 LLaVA视觉语言模型演进4.1 为什么单靠 CLIP 不够CLIP 擅长做“匹配”和“分类”但不擅长生成文本。它只能算图片和文本之间的相似度不能根据图片“说出一段话”。如果希望模型看图后回答问题、生成描述、进行多轮对话就需要一个生成式的多模态模型。LLaVALarge Language and Vision Assistant的思路非常直接把 CLIP 视觉编码器已经提取好的图片特征通过一个投影层映射到大语言模型的输入空间然后让语言模型根据图片特征和文字指令生成回答。换句话说视觉编码器负责“看懂图”大语言模型负责“组织语言”。4.2 LLaVA 的架构LLaVA 主要由三部分组成Vision Encoder通常使用 CLIP 的 ViT-L/14 视觉编码器。Projection Layer把视觉特征从视觉空间投影到语言模型的嵌入空间常用线性层或 MLP。Large Language Model负责理解指令并生成回答常见基座包括 Vicuna、Llama 等。在 Hugging Face 生态中你可以通过llava-hf/llava-1.5-7b-hf这类 checkpoint 直接加载 LLaVA 模型。底层架构对用户是透明的但理解这个结构对排查问题很有帮助。4.3 训练流程LLaVA 的训练分阶段第一阶段冻结视觉编码器和语言模型只训练投影层让视觉特征和文本嵌入对齐。第二阶段使用指令微调数据联合训练投影层和语言模型让模型学会服从指令。这种两阶段设计既降低训练成本又能保留预训练模型的泛化能力。如果你只是做推理不需要自己训练直接加载开源权重即可。4.4 底层架构全梳理一句话总结CLIP 负责“看”投影层负责“翻译”大语言模型负责“说”。整个推理流程可以拆成四步输入图片经过视觉编码器得到图像特征。图像特征通过投影层映射到语言模型能理解的向量空间。将图像特征与文本指令拼接送入大语言模型。大语言模型逐步生成回答文字。这个流程在代码里看起来就是加载模型后直接调用生成接口但理解每一步后面遇到输入格式错误、token 截断、显存不足时就能快速定位问题。5. 环境准备与前置条件建议按下面的清单准备环境这是通用流程具体版本视你的操作系统而定。项目要求操作系统Windows 10/11、Ubuntu 20.04 或更高版本Python3.9 或更高包管理pip / conda深度学习框架PyTorch 2.x加速库CUDA 11.8 或更高如果有 NVIDIA GPUHugging Face 相关库transformers、accelerate、torchvisionGPU推荐 NVIDIA GPU显存越大越好CLIP 可以用 CPU但速度慢磁盘空间至少预留 20GBLLaVA 7B 权重较大新手如果不太确定自己电脑配置可以用下面的命令查看关键信息python --version nvidia-smi如果nvidia-smi能显示显卡信息说明有 NVIDIA GPU可以走 GPU 推理如果无法显示则只能使用 CPU 或考虑云 GPU 环境。安装依赖时建议先创建虚拟环境避免和系统环境冲突python -m venv venv source venv/bin/activate # Windows 下使用 venv\Scripts\activate pip install torch torchvision transformers accelerate pillow requests如果使用清华源可以加快安装速度pip install torch torchvision transformers accelerate pillow requests -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后先用一个简单脚本验证 PyTorch 是否正常import torch print(torch.__version__) print(torch.cuda.is_available())如果输出True说明 GPU 可用如果为False后面代码也能跑但速度会慢很多。6. 代码实战搭建 CLIP 模型6.1 加载预训练模型先用 Hugging Face Transformers 加载 CLIP。第一次运行时程序会自动下载模型权重到本地缓存目录需要网络连接。from transformers import CLIPProcessor, CLIPModel model_name openai/clip-vit-base-patch32 model CLIPModel.from_pretrained(model_name) processor CLIPProcessor.from_pretrained(model_name) print(CLIP 模型加载完成)如果网络无法访问 Hugging Face可以设置镜像环境变量例如export HF_ENDPOINThttps://hf-mirror.comWindows 下使用set HF_ENDPOINThttps://hf-mirror.com。这不是唯一方案实际以你可以访问的环境为准。6.2 图片与文本匹配准备好一张本地图片以及若干候选文本让模型判断哪条文本最匹配图片。from PIL import Image import torch image Image.open(test.jpg) texts [a photo of a cat, a photo of a dog, a photo of a car] inputs processor(texttexts, imagesimage, return_tensorspt, paddingTrue) with torch.no_grad(): outputs model(**inputs) logits_per_image outputs.logits_per_image probs logits_per_image.softmax(dim1) print(匹配概率, probs)预期结果probs是一个 1x3 的矩阵每个值代表图片和对应文本的匹配概率。概率最高的文本就是模型最认可的标签。6.3 批量图像标签分类CLIP 很适合批量给图片打标签。假设你有一个images目录里面有若干图片要判断每张图属于cat还是dogimport os from PIL import Image import torch image_dir images labels [a photo of a cat, a photo of a dog] for filename in os.listdir(image_dir): if not filename.lower().endswith((.jpg, .jpeg, .png)): continue image_path os.path.join(image_dir, filename) image Image.open(image_path).convert(RGB) inputs processor(textlabels, imagesimage, return_tensorspt, paddingTrue) with torch.no_grad(): outputs model(**inputs) probs outputs.logits_per_image.softmax(dim1) pred_idx probs.argmax().item() print(f{filename}: {labels[pred_idx]}, 概率 {probs[0][pred_idx].item():.4f})这段代码会遍历目录中的图片逐张输出预测标签和概率。优点是简单直接缺点是没有批处理加速图片数量多时速度慢。后面讲解怎么用 Batch 推理。7. 代码实战搭建 LLaVA 视觉问答7.1 加载模型与处理器LLaVA 的加载方式类似 CLIP但模型更大加载时间和显存占用显著增加。下面的例子使用llava-hf/llava-1.5-7b-hf如果你的显存较小可以寻找量化版本或使用 CPU 推理但速度会慢很多。from transformers import LlavaProcessor, LlavaForConditionalGeneration model_id llava-hf/llava-1.5-7b-hf processor LlavaProcessor.from_pretrained(model_id) model LlavaForConditionalGeneration.from_pretrained( model_id, torch_dtypetorch.float16, device_mapauto )torch_dtypetorch.float16会以半精度加载模型降低显存压力。device_mapauto让 Transformers 自动分配模型到 GPU 或 CPU。7.2 图文输入推理准备一张图片和一条问句调用模型生成回答import torch from PIL import Image image Image.open(test.jpg) prompt USER: image\nWhat is in this image?\nASSISTANT: inputs processor(textprompt, imagesimage, return_tensorspt) with torch.no_grad(): output model.generate(**inputs, max_new_tokens128) answer processor.decode(output[0], skip_special_tokensTrue) print(answer)这里需要注意格式LLaVA 的输入通常要求带image占位符告诉模型图片特征插入的位置。具体格式因模型版本而异建议查看对应模型的 README 或示例代码。7.3 多轮对话LLaVA 可以支持多轮对话但多轮对话需要拼接历史。原理是把历史对话内容和新问题一起送入模型图片特征放在最前面。由于不同版本的对话模板不同这里给一个通用思路history [] while True: user_input input(你) if user_input.lower() in [exit, quit]: break history.append(fUSER: {user_input}) prompt USER: image\n \n.join(history) \nASSISTANT: inputs processor(textprompt, imagesimage, return_tensorspt) with torch.no_grad(): output model.generate(**inputs, max_new_tokens128) answer processor.decode(output[0], skip_special_tokensTrue) answer answer.split(ASSISTANT:)[-1].strip() print(f模型{answer}) history.append(fASSISTANT: {answer})多轮对话的难点在于保持上下文一致。模型输入长度有限历史太长时需要截断或摘要。实际工程中可以直接使用支持对话的推理框架不必自己拼模板。8. 接口 API 与批量任务设计很多读者关心能不能把模型封装成接口或者批量处理图片。这里给一个通用设计不绑定具体框架。8.1 用 Flask 封装 CLIP 分类接口假设你已经写好了 CLIP 推理函数下面用 Flask 暴露一个 POST 接口接收图片 URL 或 Base64 编码和标签列表返回匹配概率。from flask import Flask, request, jsonify import base64 from io import BytesIO from PIL import Image app Flask(__name__) app.route(/classify, methods[POST]) def classify(): data request.get_json() image_data data.get(image) labels data.get(labels) if image_data.startswith(http): import requests image Image.open(requests.get(image_data, streamTrue).raw) else: image_bytes base64.b64decode(image_data) image Image.open(BytesIO(image_bytes)) inputs processor(textlabels, imagesimage, return_tensorspt, paddingTrue) with torch.no_grad(): outputs model(**inputs) probs outputs.logits_per_image.softmax(dim1) result {labels[i]: round(probs[0][i].item(), 4) for i in range(len(labels))} return jsonify(result) if __name__ __main__: app.run(host0.0.0.0, port7860)这是一个最小可运行示例实际部署时还需要加入请求限流、超时控制、错误处理。8.2 批量图片处理脚本批量处理的核心是增加 Batch Size减少循环次数。CLIP 支持同时输入多张图片和多个文本但文本数量和图片数量需要匹配。下面是一个批量分类脚本模板from PIL import Image import torch image_paths [1.jpg, 2.jpg, 3.jpg] labels [a cat, a dog, a bird] images [Image.open(path).convert(RGB) for path in image_paths] # 每张图片都组合全部标签 inputs processor( text[label for _ in image_paths for label in labels], images[img for img in images for _ in labels], return_tensorspt, paddingTrue ) with torch.no_grad(): outputs model(**inputs) logits outputs.logits_per_image probs logits.softmax(dim1) for i, path in enumerate(image_paths): start i * len(labels) end (i 1) * len(labels) probs_i probs[start:end] print(path, dict(zip(labels, probs_i[0].tolist())))这里有个细节logits_per_image的维度与输入数量有关批量时代码要小心索引。更稳妥的办法是逐条推理后用线程池加速from concurrent.futures import ThreadPoolExecutor def predict_one(path): image Image.open(path).convert(RGB) inputs processor(textlabels, imagesimage, return_tensorspt, paddingTrue) with torch.no_grad(): outputs model(**inputs) probs outputs.logits_per_image.softmax(dim1) return path, labels[probs.argmax().item()] with ThreadPoolExecutor(max_workers4) as executor: results list(executor.map(predict_one, image_paths)) print(results)注意多线程不能直接共享模型输入张量但推理本身是线程安全的这里用线程池只是让多个推理并行实际上 GPU 利用率可能不高。更高效的做法是使用DataLoader实现真正的 Batch 推理。8.3 LLaVA 批量问答LLaVA 模型比较大批量处理时更关注显存和控制响应时间。可以用一个脚本循环读取图片和问题逐条生成回答然后把结果写入 CSVimport csv tasks [ {image: 1.jpg, question: What is in this image?}, {image: 2.jpg, question: What color is the car?}, ] with open(answers.csv, w, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([image, question, answer]) for task in tasks: image Image.open(task[image]) prompt fUSER: image\n{task[question]}\nASSISTANT: inputs processor(textprompt, imagesimage, return_tensorspt) with torch.no_grad(): output model.generate(**inputs, max_new_tokens128) answer processor.decode(output[0], skip_special_tokensTrue) writer.writerow([task[image], task[question], answer])如果任务量很大建议把任务列表保存为 JSON脚本读取后逐条处理并在每两条之间加入错误捕获防止某条数据异常导致整个任务中断。9. 资源占用与性能观察运行这两个模型时重点观察三个指标显存、内存、生成速度。9.1 显存占用如何观察Linux 下可以使用nvidia-smi实时查看显存watch -n 1 nvidia-smiWindows 下可以打开任务管理器的“性能”选项卡查看 GPU 专用内存。在 Python 中也可以用torch.cuda.memory_summary()查看更详细的分配情况。9.2 CPU 推理与 GPU 推理的差异CLIP 的 ViT-B/32 在 CPU 上也能运行但单张图片推理需要几百毫秒到数秒GPU 上通常几十毫秒。LLaVA 7B 模型在 CPU 上生成一段回答可能要几十秒甚至更久GPU 能明显提速。如果你的环境没有 GPU建议先跑通逻辑再考虑升级硬件或使用云服务。9.3 影响性能的因素图片分辨率CLIP 会把图片缩放到固定尺寸通常是 224x224分辨率对推理耗时影响不大但预处理会占用额外内存。Batch Size增大 Batch Size 会提高吞吐量但显存占用也会上升容易 OOM。生成长度LLaVA 回答的max_new_tokens直接影响显存和耗时。模型精度使用float16或量化可以明显降低显存但可能带来轻微精度损失。文本长度CLIP 文本编码器有最大长度限制通常截断到 77 个 token超长文本会被截断。9.4 如何降低显存占用使用torch_dtypetorch.float16。使用device_mapauto。减小 Batch Size。限制max_new_tokens。尝试量化模型例如 8bit 或 4bit 加载。关闭模型梯度model.eval()配合torch.no_grad()。9.5 进程残留与端口冲突如果用 Flask 启动 API注意关闭终端后 Python 进程可能仍然占用端口。Linux 下可以查找端口占用进程lsof -i:7860 kill -9 PIDWindows 下可以使用netstat -ano | findstr :7860 taskkill /PID PID /F把端口换成你实际使用的端口即可。10. 常见问题与排查方法下面整理一份排查表遇到问题按表走。问题现象可能原因排查方式解决方案下载模型超时网络无法访问 Hugging Face检查网络或者设置镜像设置HF_ENDPOINT镜像地址后重新运行CUDA 不可用PyTorch 与 CUDA 版本不匹配运行torch.cuda.is_available()查看安装匹配的 PyTorch 版本显存不足OOM模型过大Batch Size 过大观察nvidia-smi改用 float16、减小 Batch Size、使用量化输入格式错误图片不是 RGB 格式打印图片 mode使用convert(RGB)转换生成结果只有重复字符模型参数或提示词格式不对检查 prompt 模板参考模型文档修正提示词CLIP 分类准确率低标签描述不够清晰更换更自然的标签描述使用 “a photo of ...” 格式增加候选标签加载 LLaVA 报错transformers版本过低查看错误堆栈升级transformerspip install -U transformers多线程推理报错张量在多个线程间被修改检查推理函数避免在多线程中共享同一个处理器输出必要时加锁Flask 接口返回慢CPU 推理或大量请求同时进入查看 CPU/GPU 使用率使用队列和并发控制或改用异步服务11. 最佳实践与合规提醒从学习到工程落地有几条值得记住。第一第一次跑通之前先固定一个最小配置。CLIP 用一张图、两个标签LLaVA 用一张图、一个问题。不要一上来就批量处理几百张图否则一旦报错很难分清是代码问题还是资源问题。第二模型文件、输入图片、输出结果分目录管理。建议目录结构如下project/ ├── models/ ├── images/ ├── outputs/ ├── scripts/ └── venv/这样模型缓存和业务数据分离后期清理和备份都方便。第三批量任务一定要加日志和失败重试。不要把图片遍历和模型推理写在一个大循环里最好每条任务单独记录状态import traceback for task in tasks: try: result process(task) save_result(task, result) except Exception as e: log_error(task, traceback.format_exc())第四接口服务要限制访问范围。如果只是在本地测试启动时写127.0.0.1如果在服务器上开放必须加认证和访问控制。不要简单地把0.0.0.0暴露到公网尤其是不带任何鉴权。第五合规和版权的红线人脸照片、私人图片、版权素材、商用人声等场景必须确认授权。CLIP 和 LLaVA 是在大规模互联网数据上训练的模型可能记忆或放大训练数据中的某些偏好和偏见输出内容不一定适合直接面向公众发布。第六发布或商用前做效果复核。模型概率高不代表事实正确尤其是 LLaVA 生成的自然语句需要人工抽查。生产环境建议加一层过滤规则对不合适的输出进行拦截。12. 总结与下一步这篇内容从 CLIP 的双塔对比学习讲到了 LLaVA 的视觉编码器加投影层加大语言模型架构然后给出了加载预训练模型、图文匹配、图片标签分类、视觉问答、API 封装和批量任务的完整代码案例。整条链路适合新手从零开始理解多模态视觉大模型的核心思路也适合作为工具链的快速起步。建议你首先跑通 CLIP 最小示例因为模型小、上手快能帮你快速理解“图文匹配”和“零样本分类”这两个概念。跑通之后再切换到 LLaVA观察模型生成效果并尝试修改 prompt、调整生成参数看看回答质量和生成速度的变化。最容易踩的坑是模型下载、CUDA 版本、显存不足和 prompt 格式错误对照上面的排查表基本能解决。后续可以往几个方向扩展一是用 CLIP 做图文检索服务接入自己的图片库二是用 LLaVA 做图像描述生成配合语音合成做一个看图说话工具三是尝试在本地微调 CLIP 或 LLaVA让它更适应特定领域。每走一步都要把数据准备、评估指标和部署成本考虑清楚这样才不只是“跑通 demo”而是真正把它变成可用的能力。
返回列表