1. 为什么全网都在聊LLaVA-1.5:我的最初印象与价值判断
先交代一下背景。2023年下半年,大模型赛道几乎被纯文本对话占满了,GPT-4V虽然展示了多模态能力,但不开源。开源社区里能用的多模态方案,要么像Flamingo那样动辄几百亿参数,要么像BLIP-2那样引入一个复杂的Q-Former结构,普通实验室想微调一下都费劲。所以当LLaVA-1.5的论文和权重放出来的时候,我第一反应是:又来一个刷榜的?但认真看完架构图和训练策略之后,发现事情没那么简单。
LLaVA-1.5的全称是Large Language and Vision Assistant,1.5版本对应的论文叫《Improved Baselines with Visual Instruction Tuning》。它做的事情一句话就能讲清楚:把一张图片和一段文字问题同时丢给模型,让模型输出自然语言答案。听起来很朴素,但它在当年的多个多模态基准上直接把SOTA拉高了一大截,VQAv2准确率冲到了80.6%,MMBench拿到67.7%,MM-Vet超过58%,而且用的方法极其“朴素”——架构上就是一个现成的CLIP视觉编码器加上一个现成的大语言模型,中间用一个两层MLP做投影。没有复杂的交叉注意力,没有额外的Q-Former,没有让人看不懂的预训练任务,一切都是一条直线。
这恰恰就是它最大的价值。对于做应用和做研究的人来说,LLaVA-1.5提供了一个“最小可复现单元”:你不需要几百张显卡,不需要企业级数据清洗流水线,只要有一张显存足够的GPU,甚至用LoRA这种参数高效微调手段,就能在自己想要的数据集上跑出一个效果相当不错的多模态问答模型。这也是为什么后来涌现了一大批基于LLaVA架构改进的工作,它成了社区里的一个基座。
这篇文章我会从架构原理、训练策略、完整复现步骤、踩坑经验、部署优化这几个维度展开。目标读者是两类人:一类是想把LLaVA-1.5部署到自己业务里的工程师,另一类是打算入门多模态大模型研究、想彻底搞懂一个开源基线代码的研究者。读完你应该能独立完成从环境搭建、数据准备、模型训练到推理部署的全流程,并且对中间每一步“为什么这样做”有清晰的理解。
2. 从图像到答案:LLaVA-1.5架构逐层拆解
2.1 输入预处理:图像如何变成模型能读的token
先看一张图片进入LLaVA-1.5之后发生了什么。视觉编码器用的是OpenAI开源的CLIP ViT-L/14-336,也就是patch size为14、输入分辨率336x336的ViT-Large模型。336这个数字不是随便定的,CLIP系列在训练时用了224、336、384等多档分辨率,336是官方提供的权重中性价比比较高的一个档位,再往上到384虽然精度略有提升,但计算量涨得很快。
输入图像首先会被resize到336x336,然后切成一个个14x14大小的patch。336除以14等于24,所以一张图会得到24x24=576个patch,每一个patch经过线性嵌入之后变成一个视觉token。加上CLIP的class token,视觉编码器实际输出的序列长度是577。但LLaVA-1.5在代码实现里做了个细节处理:它取的是CLIP最后一层的所有patch token特征,而不是把class token单独拎出来,这576个token随后会被送入投影层。
这一步有一个容易忽略的地方:CLIP模型本身有一个图像归一化过程,均值和方差要用CLIP官方的那组数值(mean=[0.48145466, 0.4578275, 0.40821073],std=[0.26862954, 0.26130258, 0.27577711]),而不是ImageNet的标准归一化。我见过不少人在自定义数据加载器时偷懒直接用了torchvision的默认归一化,结果模型输出完全崩掉,找半天找不到原因,其实就是这里。
2.2 视觉塔:CLIP ViT-L/14-336的职责边界
CLIP在LLaVA-1.5里不是用来做图文匹配的,它只负责一件事:把图像转换成高层次的视觉特征。具体来说,CLIP ViT-L/14-336的隐藏层维度是1024,所以576个patch经过视觉编码器后会得到一个形状为(576, 1024)的特征矩阵。这个矩阵保留了图像的空间信息,每一个token对应原图上的一块局部区域,这跟文本里一个词对应一个token是类似的逻辑。
为什么选CLIP而不是别的视觉模型?原因主要有两点。第一,CLIP的视觉特征是在海量图文对数据上训练出来的,它对语义的理解比单纯在ImageNet上分类训练的ResNet强很多,尤其当遇到开放词汇的场景时,CLIP特征能更好地和文本语义对齐。第二,CLIP本身就有一个对应的文本编码器,视觉特征空间和文本特征空间天然有对齐的先验,虽然LLaVA-1.5的投影层是用训练数据硬学出来的对齐,但这个先验还是让初始训练更容易收敛。后来有一些工作尝试用DINOv2或者SigLIP替换CLIP,效果各有千秋,但CLIP到今天依然是多模态LLM最主流的视觉骨干。
一个值得注意的细节是:LLaVA-1.5的视觉编码器在整个训练过程中是被冻结的,不是端到端联合训练的。这个设计在当时看起来有点“保守”,但后来大量实验证明,冻结视觉编码器可以大幅降低训练成本,同时模型的最终效果并没有明显下降。这背后的原因大概是CLIP的特征表达已经足够丰富,语言模型通过投影层和微调已经能够学会如何“解读”这些视觉特征,强行反向传播更新视觉塔反而可能破坏CLIP原有的语义空间。
2.3 投影层:从线性层到两层MLP的升级
视觉特征不能直接拼到大语言模型的输入里,因为CLIP的输出维度是1024,而Vicuna-7B的隐藏层维度是4096,两者不在一个空间。需要一个投影层把(576, 1024)映射成(576, 4096)。LLaVA-1.0用的是最简单的线性层,就是算一个矩阵乘法加偏置。LLaVA-1.5则改成了两层MLP,中间加了一个GELU激活函数。
这个改动看起来不起眼,但对最终效果的影响很大。论文里的消融实验显示,两层MLP替换线性层之后,MMBench分数提升了将近10个百分点。为什么一个简单的非线性层能带来这么大的收益?因为视觉特征和文本特征之间的映射本来就是高度非线性的,一层线性变换只能做旋转和缩放,不足以把CLIP的语义空间完全“翻译”到大语言模型的空间里。而两层MLP引入的非线性给了模型更强的表达能力,让视觉token和文本token能在语义上更精确地对齐。
投影层的参数量并不大。CLIP输出1024维,Vicuna隐藏层4096维,两层MLP实际上是一个1024->4096的线性层加上一个4096->4096的线性层,再加上GELU,参数量大概在2000万级别。相比70亿参数的语言模型,这个比例可以忽略不计。但就是这个小小的模块,在训练阶段一是唯一被更新的部分,承担了整个视觉语言对齐任务,所以它的设计直接决定了模型理解图像的上限。
2.4 语言模型基座:Vicuna-7B/13B的输入拼接与生成逻辑
语言模型部分用的是Vicuna-7B和13B的v1.5版本。Vicuna本身是基于LLaMA微调的对话模型,指令跟随能力已经经过了一轮强化。LLaVA-1.5没有改语言模型的内部结构,只是在输入层做拼接操作。
具体来说,模型会在文本token序列里插入两个特殊token:<im_start>和<im_end>,用来标记图像内容的边界。图像经过视觉编码器和投影层之后形成的576个视觉token,会被放置在用户输入中<image>这个占位符的位置。所以最终送入语言模型的输入序列大致是这样的:
<im_start>User: <image> What is the color of the car in the picture?<im_end> <im_start>Assistant:其中<image>占位符在embedding阶段会被替换成576个视觉token对应的embedding序列。这样语言模型看到的就是一个“混合序列”,既有文本token的embedding,又有视觉token的embedding,但它完全不需要分辨哪些来自文本哪些来自图像,只需要在这个序列上做自回归预测下一个token。
这里有一个概念需要区分:视觉token的数量直接影响语言模型的计算量。576个视觉token相当于在原有文本序列上额外增加了576个位置,自回归生成时每一个新token都要对这576个视觉token做注意力计算,这也是为什么多模态模型比纯文本模型推理更慢的一个主要原因。后面讲部署优化的时候还会提到,VILA等后续工作尝试压缩视觉token数量,目的就是降低这部分开销。
3. 两阶段训练:LLaVA-1.5的核心竞争力到底在哪
3.1 阶段一:先让视觉特征“学会说话”
LLaVA-1.5的训练分两个阶段,这个设计思路非常值得学习。阶段一叫特征对齐预训练,目标只有一个:让投影层学会把CLIP的视觉特征映射到语言模型的embedding空间里。这个阶段的训练数据不需要多复杂,就是大量的图片加上一句简单的描述文本,类似“一张猫坐在沙发上的照片”这种。
训练时,视觉编码器和语言模型都是冻结的,只有投影层可更新。损失函数就是最标准的自回归语言模型损失——输入图像特征和描述文本的前半段,让模型预测后半段。本质上是在做条件文本生成。论文里这个阶段训练了大约60k步,batch size是128,用的是CC3M的一个子集,学习率设为1e-3,采用cosine decay。
为什么阶段一不直接让语言模型也参与训练?因为如果一开始就解开所有参数,视觉特征和文本特征之间的初始错位太大了,语言模型很容易陷入局部最优,甚至出现灾难性遗忘,丢掉它原本掌握的通用知识。先把投影层对齐好,相当于给语言模型一个“眼睛已经睁开”的状态,第二阶段微调自然就顺了。这个由粗到细、从局部到整体的训练思路,在后续很多多模态模型里都有体现。
3.2 阶段二:端到端指令微调,解锁真正的对话能力
阶段二是整个模型最重要的部分。此时视觉编码器依然冻结,但投影层和语言模型全部解冻,开始端到端联合训练。用的数据不再只是简单的图文描述,而是混合了多种来源的高质量指令数据。
LLaVA-1.5使用的数据组合大致包括:LLaVA-Instruct-150K(由GPT-4生成的视觉对话数据,覆盖了对话、详细描述和复杂推理三种任务)、VQAv2训练集、GQA训练集、OKVQA训练集、TextVQA训练集以及OCR-VQA等。论文里把除LLaVA-Instruct以外的数据合称为“学术任务数据”,加起来大概是655K个样本。两种数据按1:1的比例混合组成最终的训练集。
训练参数上,batch size设为128,学习率2e-5,训练一个epoch,warmup比例0.03,同样用了cosine学习率调度。单卡A100-80G全参数微调Vicuna-7B大约需要12个小时左右,如果只用LoRA会更快。这里的2e-5学习率是经验值,比纯文本指令微调常用的1e-5稍微大一点点,可能是因为视觉token的引入让模型需要更大幅度地调整参数才能适应新的输入分布。
3.3 数据配比背后藏着什么逻辑
我自己在复现的时候,对数据配比这事做了几组对照实验,结论跟论文里基本一致:学术任务数据和指令数据缺一不可。
只用LLaVA-Instruct-150K训练出来的模型,对话流畅度不错,但是在VQAv2这种需要“精确回答问题”的基准上会明显偏弱。因为GPT-4生成的数据偏开放性,答案往往很长、很多样,模型学到了“怎么聊”,但不一定学到了“怎么答对”。而VQAv2、GQA这些数据集的答案是确定的、短的,模型在这些数据上学习会强化它从图像中提取精确信息的能力。两者的配合关系有点像一个人既练了口语表达,又做了大量阅读理解题,缺哪个都考不了高分。
还有一个细节是TextVQA和OCR-VQA的加入。这两类数据主要针对图像中的文字识别问题,比如路牌、菜单、截图里的文字。纯CLIP+LLM的架构在文字识别上其实不占优势,但加入这些数据后模型至少学会了“当图像里有文字时,要把注意力放在文字区域”。LLaVA-1.5的OCR能力谈不上顶尖,但应付日常场景足够了。
另外,训练时所有数据都会被转成统一的对话格式,每条样本由一条用户消息和一条助手消息组成,中间用特殊token分隔。数据的格式一致性非常重要,混用多种格式训练会严重收敛稳定性,这也是我踩过的坑之一,后面会细说。
4. 把LLaVA-1.5跑起来:完整复现步骤与参数解析
4.1 环境准备与依赖版本建议
LLaVA官方仓库基于Python和PyTorch,建议直接用官方推荐的依赖组合,而不是自己配一套。我自己用的环境是:Ubuntu 22.04、Python 3.10、CUDA 11.8、PyTorch 2.1.2、transformers 4.36.2、deepspeed 0.12.6、flash-attention 2.3.2。这几个版本搭配起来经过了很多人的验证,比较省心。
clone仓库之后,建议用conda创建虚拟环境,然后按下面步骤安装:
git clone https://github.com/haotian-liu/LLaVA.git cd LLaVA conda create -n llava python=3.10 conda activate llava pip install -e . pip install flash-attn --no-build-isolationflash-attention是可选依赖,但强烈建议装。它能把注意力计算的速度提升两到三倍,同时减少显存占用。如果你在训练或推理时总报CUDA out of memory,装上flash-attention大概率能缓解。
4.2 模型权重准备:CLIP和Vicuna缺一不可
模型权重分两部分。视觉塔用CLIP ViT-L/14-336,可以直接从HuggingFace拉取。语言模型基座用Vicuna-7B-v1.5或Vicuna-13B-v1.5。需要注意,Vicuna是基于LLaMA微调的,所以如果你拿不到Vicuna的权重,也可以用Meta官方LLaMA-2-7B替代,效果会略差但流程能走通。我测试过直接用LLaMA-2-7B替换Vicuna,最终分数大概会掉3到5个点,主要差距集中在对话流畅性和指令跟随能力上。
一个常见问题是transformers库升级后,旧版本Vicuna权重的加载方式可能会有变化。建议保持transformers版本不低于4.36,这个版本对LLaMA架构的支持已经非常稳定。加载权重时LLaVA会自动识别CLIP的config并加载对应参数,如果出现key mismatch的警告,多半是版本问题,优先检查transformers版本。
4.3 数据下载与目录组织
官方训练数据分两部分:图片数据和对话标注数据。LLaVA-Instruct-150K的标注文件在HuggingFace上直接下载,学术任务数据则散落在各自数据集的官网或者第三方镜像。图片数据的存放目录需要和标注文件里的图片路径字段保持完全一致,否则训练时会直接抛FileNotFoundError。
建议按照官方README里约定好的目录结构来组织:
LLaVA └── data ├── llava_instruct_150k.json # 指令数据标注 ├── vqav2_train2015.json # VQAv2标注 ├── gqa_train.json # GQA标注 ├── okvqa_train.json # OKVQA标注 ├── textvqa_train.json # TextVQA标注 ├── ocr_vqa_train.json # OCR-VQA标注 └── images ├── coco ├── gqa ├── ocr_vqa ├── textvqa └── vqav2下载数据的时候建议用多线程工具,COCO的train2017图片包大概18GB,GQA图片也有几十GB,一次性下载可能需要几个小时。下载完成后可以写一个小脚本快速校验图片数量,防止下载过程中文件损坏。
4.4 训练命令与关键参数解读
数据准备好之后,训练命令其实很简单。以单机8卡A100-80G全参数微调7B模型为例:
torchrun --nproc_per_node=8 train.py \ --model_name_or_path lmsys/vicuna-7b-v1.5 \ --version v1 \ --data_path ./data/llava_instruct_150k.json \ --image_folder ./data/images \ --vision_tower openai/clip-vit-large-patch14-336 \ --pretrain_mm_mlp_adapter ./checkpoints/llava-v1.5-mlp2x-336px-pretrain/mm_projector.bin \ --mm_vision_select_layer -2 \ --mm_use_im_start_end True \ --bf16 True \ --output_dir ./checkpoints/llava-v1.5-7b \ --num_train_epochs 1 \ --per_device_train_batch_size 16 \ --gradient_accumulation_steps 1 \ --learning_rate 2e-5 \ --evaluation_strategy no \ --save_strategy steps \ --save_steps 1000 \ --save_total_limit 1 \ --logging_steps 10 \ --lr_scheduler_type cosine \ --warmup_ratio 0.03 \ --lazy_preprocess True \ --report_to wandb几个容易踩坑的地方我重点说一下。
--pretrain_mm_mlp_adapter指向的是阶段一训练完保存的投影层权重,这个参数不加的话,阶段二会从随机初始化的投影层开始训,模型基本学不出什么效果。所以必须先跑阶段一,拿到mm_projector.bin,再回来跑阶段二。
--mm_vision_select_layer -2表示取CLIP倒数第二层的特征。为什么不是最后一层?因为CLIP最后一层特征更偏向全局的图文匹配信息,倒数第二层保留了更多局部空间细节,对视觉问答更友好。这个细节论文里没有详细讲,但代码里默认就是这个值。
--lazy_preprocess True是一个省内存的优化开关。开启后,训练过程中不会一次性把图片都加载到内存里,而是按需加载。这能大幅降低内存占用,代价是每个step的数据预处理时间会边长,相当于用时间换空间。
4.5 阶段一训练命令差异
阶段一的命令和阶段二很相似,核心区别在于:第一步要加载语言模型和视觉塔,但只有投影层可训练,语言模型权重整体冻结。代码层面通过--model_max_length参数控制输入序列长度,以及一个--freeze_backbone True的开关实现。阶段一的训练数据用的是一个纯文本描述的caption数据集,学习率提到1e-3,训练步数约60k。跑完阶段一之后,输出目录里会多出一个mm_projector.bin文件,这个文件就是投影层的权重。
如果训练资源紧张,阶段一也可以跳过,直接用LLaVA官方发布在HuggingFace上的llava-v1.5-7b权重里的投影层文件,路径在llava_projector目录下。我自己第二次复现时就是这么干的,省掉了阶段一的训练时间,效果没有明显差异。
5. 复现与调优中我最真实的踩坑记录
5.1 图片路径不一致导致的训练中断
第一次跑LLaVA-1.5训练时,我以为数据准备已经万无一失,结果训练进行到1000步之后开始频繁报错。一开始是FileNotFoundError,检查后发现是COCO的图片文件名是带COCO_train2014_前缀的,而标注文件里引用的是不带前缀的裸文件名。这类问题其实通过一个小脚本批量检查能解决,但更常见的情况是:标注文件里的图片路径字段和--image_folder拼接后的结果与实际文件路径对不上。我后来写了个自动校验脚本,遍历标注文件里所有图片路径,确认在磁盘上真实存在才启动训练,这轮扫描花不了几分钟,但能帮你省下几小时排查时间。
5.2 消融实验发现:数据格式混用的影响比想象中大
第一次做消融实验时,我在LLaVA-Instruct-150K的基础上加了自定义的问答数据,但自定义数据的格式和官方的不完全一致。我图省事,简单把两条数据拼成了一个JSON列表就丢进去训练了。结果模型在验证集上的BLEU分数全面下跌。后来一条条对比才发现,官方的每条指令数据里的conversations字段有严格的角色标签和换行格式,比如用户消息必须以"from": "human"、助手消息必须以"from": "gpt"这样标记,且消息内部以\n换行分隔。我的自定义数据用的是别的分隔符,导致模型输出格式全乱了。所以如果你要在官方数据上追加自己的数据,先把一条官方样本打印出来,逐字段对齐格式,再批量转换。
5.3 显存OOM的解决方案
全参数微调7B模型,在8卡A100-80G的配置下能勉强跑起来。但如果只有4张A100或者更小的显卡,就不得不做取舍。我的建议是优先考虑LoRA微调而不是去买更多显卡。LLaVA官方仓库其实已经支持了--lora_enable参数,我测试过用LoRA(rank=128)训练Vicuna-7B,最终效果和全参数微调只差了1到2个百分点,但显存占用直接降了将近一半。单卡A100-80G甚至可以跑起来。
如果你的场景是领域数据微调,比如让模型学会识别某种特定型号的工业零件,完全没必要全参数微调。视觉编码器继续保持冻结,LoRA加在语言模型的q_proj、v_proj这些注意力层上就够了。我自己在汽车零部件识别项目上用的就是这套方案,标注数据只有5000条,效果已经能满足内部工具的需求。
5.4 推理时<image>占位符丢失导致结果异常
推理阶段的坑往往不在模型本身,而在数据预处理。LLaVA的推理脚本要求输入文本里必须包含<image>占位符,否则模型不知道把视觉token插在哪里。我刚开始封装API时,在模板里漏掉了占位符,模型输出的内容跟图片完全无关,变成了一个纯文本对话模型。排查了很久才发现是模板拼接的问题。另外,如果输入图片不是正方形,cv2.resize和transforms.Resize的默认行为会有细微差异,建议统一用Pillow配合torchvision.transforms.Resize处理,避免不同图像缩放库之间的边界像素差异。
5.5 关于评测的一个建议
复现完模型之后,别急着用官方脚本跑全部基准,先在COCO的val2014图片上手动测几张。随便挑一张复杂的街景图,问模型“图片里一共有几辆车”,如果模型回答得吞吞吐吐甚至胡说八道,大概率是训练环节有问题。如果单图问答表现正常,再跑完整benchmark。这样做的好处是能快速定位问题,不用等评测一晚上跑完才发现训练出了偏差。
6. 部署到业务场景:推理优化与实用建议
6.1 官方推理脚本的正确打开方式
LLaVA仓库自带了一个命令行推理脚本,llava/eval/run_llava.py。基本的调用方式是这样:
python -m llava.eval.run_llava \ --model-path liuhaotian/llava-v1.5-7b \ --image-file "./images/test.jpg" \ --query "What is the content of this image?"脚本会输出模型生成的文本答案。这个脚本适合快速验证效果,但如果要做成服务,建议直接用transformers的pipeline或者自己写一个简单的FastAPI接口。需要注意,每次推理都要加载完整的7B模型,显存占用大概在16GB左右(fp16精度),如果模型放在CPU上,加载时间可能要两分钟以上。
6.2 推理速度优化:vLLM与量化方案
真实业务对推理延迟有要求,这时候就要上推理加速框架。LLaVA-1.5官方支持的vLLM集成了多模态推理能力,部署步骤很简单:
from llava.llava import LLava model = LLava.from_pretrained("liuhaotian/llava-v1.5-7b") output = model.generate( image="./images/test.jpg", prompt="请描述这张图片的内容。", max_new_tokens=512, temperature=0.2 )vLLM的核心优势是PagedAttention,能显著降低KV Cache的显存占用,同时用continuous batching提高吞吐量。实测在A10G显卡上,7B模型并发8个请求时,单个请求的延迟能控制在3秒以内。
如果显存还是不够,可以考虑4bit量化。用bitsandbytes的load_in_4bit=True参数可以直接加载量化权重,模型大小从约14GB压缩到约4GB。代价是生成质量会略有下降,对一些需要精确视觉理解的场景影响比较明显。我个人的经验是:对话类场景可以接受4bit的精度损失,但视觉问答和图像描述不建议用4bit,最好用8bit或者保持fp16。
6.3 落地场景选择与数据闭环
根据我用LLaVA-1.5做了几个落地项目的经验,它最擅长的场景有三个:开放域图像描述、图片基础问答、图片中的文字提取。开放域图像描述不用多说,就是输入图片输出一段流畅的文字描述。图片基础问答可以拿来做线上客服的辅助工具,用户拍一张商品照片,模型帮忙识别商品属性。图片文字提取适合做OCR的前置过滤,比如从一张票据照片里先定位文字区域,再交给专门的OCR引擎做文字识别。
有一个常见的误区是,很多人会拿LLaVA-1.5直接做细粒度目标检测或者像素级分割,这完全不是它的设计目标。它的视觉特征是全局性的,虽然576个patch token保留了一定的空间位置信息,但远没有达到目标检测所需的定位精度。如果业务里需要“告诉我图片里猫的具体坐标”,还是老老实实接一个检测头,不要指望LLM能给你输出准确的bounding box。
另外,不管用哪个场景,我都建议把用户对模型输出的反馈数据保存下来,定期拿来增量微调。LLaVA-1.5的架构决定了它非常适合增量学习,投影层和语言模型都能快速适应新数据分布,一个周末就能完成一轮小规模微调并重新上线。
6.4 中文场景的几个问题
LLaVA-1.5的基座是Vicuna,中文能力虽然还行,但如果你的业务面向中文用户,我建议用中文能力更强的LLM替换基座。社区里有不少基于Qwen或Yi的LLaVA变体,比如llava-zh系列。原理和官方实现完全一致,只是把--model_name_or_path换成了中文基座模型。我做过一次对比实验:用Qwen-7B替换Vicuna-7B后,模型在中文指令跟随和中文视觉问答上的表现提升非常明显,而英文表现略有下降但不多。
替换基座时需要注意,投影层的维度要跟新基座的隐藏层维度对齐。Vicuna-7B的隐藏层是4096,Qwen-7B是4096,LLaMA-2-13B是5120。如果不匹配,投影层的权重就无法直接加载,要么重新训练阶段一的对齐层,要么做一个很小的线性适配层把维度变换过去。前者更干净,后者也有可行性。
7. 我对LLaVA-1.5未来演进的一些判断
LLaVA-1.5已经是2023年底的模型了,后续社区出现了很多改进版本,比如LLaVA-NeXT把输入分辨率提高到672甚至1024,LLaVA-1.6优化了视觉编码器和训练数据,还有各种基于MOE的变体。但即使到了今天,LLaVA-1.5依然是很多人入门多模态的第一个模型,原因就在于它的简洁和可复现性。
我在实际使用中发现,理解LLaVA-1.5的训练范式和数据配比,是理解绝大多数后续多模态工作的一把钥匙。不管是SFT还是DPO,不管是全参数微调还是LoRA,底层的架构逻辑都是“视觉塔+投影层+语言塔”的三段式组合,LLaVA-1.5只是把这个框架用最简单的方式跑通了。
如果你正准备入手多模态方向,我强烈建议先把LLaVA-1.5的代码从数据加载、模型构建到训练循环完整读一遍,再跑通一次训练和推理。这个流程走下来,你对多模态大模型的理解会有一个质的提升。如果你想快速验证自己的业务场景,直接从官方HuggingFace权重开始,用LoRA微调自己的小数据集,也是一个投入产出比非常高的路径。