多模态大模型 LLaVA1.5 LoRA微调笔记

01 简要介绍

最近翻阅了LLaVA1.5的论文《Improved Baselines with Visual Instruction Tuning》[1],感叹多模态模型发展迅猛之余,也感觉非常的有意思,便想着自己尝试微调。论文作者贴心地在代码仓库提供了微调的脚本,但是由于微调过程会踩到很多坑(报错调了N个小时),因此记录下微调的笔记供需要的人参考。


02 前置环境准备

下载项目

git clone https://github.com/haotian-liu/LLaVA.git
cd LLaVA

因为里面有一个flash-attn库,很难安装,如果不跟着配置环境,很可能出现报错。

环境准备

conda create -n llava python=3.10 -y
conda activate llava
pip install --upgrade pip  # enable PEP 660 support
pip install -e . # 在当前工作目录下执行setup.py文件,太慢可以在后面加 -i https://pypi.tuna.tsinghua.edu.cn/simple

为训练安装额外的软件包

pip install -e ".[train]"
pip install flash-attn --no-build-isolation

03 下载预训练权重

(1)下载 llava-v1.5-7b 预训练权重

在下载 llava-v1.5-7b 的预训练权重前,最好提前预留15G以上的存储空间,7B的模型空间占用比较大。

懒人操作:可以在 LLaVA 的项目根目录中创建python文件,填入并运行下述代码,可以自动将 llava-v1.5-7b 的权重提前下载到本地的缓存文件夹(linux的话一般是在~/.cache下)。

from llava.model.builder import load_pretrained_model
from llava.mm_utils import get_model_name_from_path
from llava.eval.run_llava import eval_model

model_path = "liuhaotian/llava-v1.5-7b"

tokenizer, model, image_processor, context_len = load_pretrained_model(
    model_path=model_path,
    model_base=None,
    model_name=get_model_name_from_path(model_path)
)

(2)下载 clip-vit-large-patch14-336 预训练权重

这个是 LLaVA1.5 的视觉编码器的预训练权重,占用比较小,大概 2G。

下面也是懒人操作,填入代码运行后即可下载本地(已设置了下载的模板防止下载太多文件)。

from huggingface_hub import snapshot_download

snapshot_download(repo_id="openai/clip-vit-large-patch14-336", allow_patterns=["*.json", "model.safetensors", "vocab.txt"])

04 简单对话测试

我们用下面的图片做下简单的对话测试(记得修改成自己的显卡id+测试图片路径),

8badaa2a4b5c42f3a9af9a25b55c1d3d.png

测试图片

export CUDA_VISIBLE_DEVICES=2
python -m llava.serve.cli \
    --model-path liuhaotian/llava-v1.5-7b \
    --image-file "playground/data/test/images/image.png" \
    --load-4bit

竟然还能识别出吊带,不过无法识别出里面的人是谁,我们要微调让MLLM明白他是谁。

f026784c20fa53f7a7817e4ab9ac818e.png


05 准备微调数据

我们在 playground/data 文件夹下创建 test 文件夹,用于存放训练用的 json 文件。在新建的 test 文件夹中再创建 images 文件夹,用于存放图片,我们把下面这张图片保存到其中,命名为 image.png。

8badaa2a4b5c42f3a9af9a25b55c1d3d.png

测试图片

然后我们在 playground/data/test 中创建 test.json 并填入:

[
    {
        "id": "997bb945-628d-4724-b370-b84de974a19f",
        "image": "image.png",
        "conversations": [
            {
                "from": "human",
                "value": "<image>\nDescribe this picture briefly in one sentence."
            },
            {
                "from": "gpt",
                "value": "In the image, there is a person named \"Kun\" who is skillfully spinning a basketball on their finger."
            }
        ]
    }
]

准备妥当后,文件的目录展示如下:

ead4df9b53984e99952a7e96c5e0ea58.png

文件目录形式截图


06 开始进行LoRA微调

我们将 scripts/v1_5/finetune_task_lora.sh 修改成如下(记得修改自己的显卡id),

#!/bin/bash

export TRANSFORMERS_OFFLINE=1 # 设置为1时,启用Transformers的离线模式
### deepspeed单机多卡设置显卡,不要使用export CUDA_VISIBLE_DEVICES=2,5,改成deepspeed --include localhost:2,5
# export CUDA_VISIBLE_DEVICES=2,5
include=localhost:4 # 设置显卡id

model_name_or_path=liuhaotian/llava-v1.5-7b # 模型名称
data_path=./playground/data/test/test.json # 训练的json
image_folder=./playground/data/test/images # 训练的图像数据

deepspeed --include $include llava/train/train_mem.py \
    --lora_enable True --lora_r 8 --lora_alpha 16 --mm_projector_lr 2e-5 \
    --deepspeed ./scripts/zero3.json \
    --model_name_or_path $model_name_or_path  \
    --version v1 \
    --data_path $data_path \
    --image_folder $image_folder \
    --vision_tower openai/clip-vit-large-patch14-336 \
    --mm_projector_type mlp2x_gelu \
    --mm_vision_select_layer -2 \
    --mm_use_im_start_end False \
    --mm_use_im_patch_token False \
    --image_aspect_ratio pad \
    --group_by_modality_length False \
    --bf16 True \
    --output_dir ./checkpoints/llava-v1.5-7b-task-lora \
    --num_train_epochs 8 \
    --per_device_train_batch_size 1 \
    --per_device_eval_batch_size 1 \
    --gradient_accumulation_steps 1 \
    --evaluation_strategy "no" \
    --save_strategy "steps" \
    --save_steps 50000 \
    --save_total_limit 1 \
    --learning_rate 2e-4 \
    --weight_decay 0. \
    --warmup_ratio 0.03 \
    --lr_scheduler_type "cosine" \
    --logging_steps 1 \
    --tf32 True \
    --model_max_length 2048 \
    --gradient_checkpointing True \
    --dataloader_num_workers 4 \
    --lazy_preprocess True \
    --report_to wandb

然后运行微调脚本进行微调,

source ./scripts/v1_5/finetune_task_lora.sh

(1)报错 "ImportError: cannot import name 'EncoderDecoderCache' from 'transformers'"

b2c30939336eab546b99ed5f01984c16.png

报错信息截图

是因为 transformers 库和 peft 的版本兼容问题。如果遇到,可以打开配置文件 pyproject.toml,将 peft 修改成 peft==0.13.2,之后重新运行下载程序,

01a518776a51412281b00b8b0d3972ab.png

配置文件 pyproject.toml 的截图展示

pip install -e .

然后重新运行 sh 脚本。

source ./scripts/v1_5/finetune_task_lora.sh

(2)wandb选择

在进行LoRA微调的时候,会在命令行弹出3个选项给你选择,如果没有使用过wandb的用户,可以选择创建新的wandb账户,然后填入API key即可查看训练过程的可视化界面。


07 LoRA权重合并

记得修改 --model-base 的【占位符】为你本地存放 llava-v1.5-7b 的文件夹位置。Linux系统下,一般huggingface自动下载都在~/.cache文件夹里。运行下面的命令后,合并后的权重会保存在 ./checkpoints/llava-v1.5-7b-task-lora-merged 文件下,

python scripts/merge_lora_weights.py --model-path "checkpoints/llava-v1.5-7b-task-lora" \
       --model-base "【占位符】" \
       --save-model-path "checkpoints/llava-v1.5-7b-task-lora-merged"

08 LoRA后本地推理

现在我们微调完毕啦~来看看微调的效果如何(记得修改显卡ID为自己的显卡id),可见MLLM成功输出了我们需要的信息,

export CUDA_VISIBLE_DEVICES=2
python -m llava.serve.cli \
    --model-path ./checkpoints/llava-v1.5-7b-task-lora-merged \
    --image-file "playground/data/test/images/image.png" \
    --load-4bit
66ab58abc2e6136b5df17ae1506d2ee4.png

模型输出截图


如果您觉得这篇文章对您有帮助,请点赞支持一下~

b5ffc9dcfe3e4d66b70e2b5e768d0b5e.png

参考

  1. Liu H, Li C, Li Y, et al. Improved baselines with visual instruction tuning[C]//Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition. 2024: 26296-26306.

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未来知行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值