多模态大模型LLaVA技术原理与训练方法

LLaVALarge Language and Vision Assistant-大语言模型与视觉助手

网站地址:https://llava-vl.github.io

LLaVAv1论文:Visual Instruction Tuning 地址:https://arxiv.org/pdf/2304.08485

LLaVAv1.5 论文:Improved Baselines with Visual Instruction Tuning 地址:

https://arxiv.org/pdf/2310.03744

原理讲解:

视觉指令调整

LLaVA一个端到训练的大型模态模型,连接视觉编码器和LLM,以实现通用的视觉和语使(LLM)力。LLaVA使用纯语GPT-4-LLaVA视觉-视觉LLaVA以下: 

1、多视角使ChatGPT/GPT-4-

2、过连CLIP视觉Vicuna(LLM)了一个(LMM)视觉-使用生成数据LMMGPT-4问答最先进

3、lava-bench两个

4、以下:

相关工作:

1、专于为个任一个视觉

2、视觉视觉数效

GPT

ChatGPT/GPT-4广

GPT-4ChatGPT()视觉为了视觉GPT使:(i)从不视觉;(ii)14了一个

LLM使COCO images一个14设计一些一人上下GPT-4

158K独特-58K23K77kChatGPTGPT-4使GPT-4

视觉

1、架构

LLM视觉架构1Vicuna

LLMfϕ(·)ϕ有最

XvCLIP视觉ViT-L/14视觉Zv=g(Xv)Transformer使一个线层将了一个WZvHv:

一个视觉Hv这里代以为中

2、训练

Xv(X1,X1,···,XT,XT)T组织一个t-th的指令

下面2LLM

token

L以下Xa:

θXinstruct,<iXa,<i分别token xitoken2(3)Xv基于图像一事且为了Xsystem-message<STOP><STOP>LLaVA一个两

1:为了,对CC3M595k-为了(2)构建输Xinstruct于一个Xv一个Xq一个真实Xa描述视觉LLM使θ=W()(3)Hv以与LLM为为LLM一个视觉

2:视觉继续LLaVALLM;(3)θ={W,ϕ}两个

1、上面的158K-了一个他两

2、科学问题。在科学问答一个上下(2)组织上下XinstructXa

实验

两个主LLaVA视觉:科学问答8×a100VicunaCC-595K1epoch2e-3128LLaVA-Instruct-158K3epoch2e-532

结论

上面论证视觉了一个-LLaVA一个视觉科学问答它实最先进的视觉一个视觉

基于视觉指令微调的改进

1、简介

近期的工作进一步通过分别扩大预训练数据、指令跟随数据、视觉编码器或语言模型来展示性能的提升。LLaVA架构被应用于不同的下游任务和领域,包括区域级和像素级的理解、生物医学助手、图像生成、对抗性研究。

首次系统地研究了在受控设置中LMMs的设计选择。研究起源于LLaVA,并通过从输入、模型和数据的角度仔细做出有效贡献来构建路线图。

首先,揭示了LLaVA中全连接的视觉语言连接器具有惊人的强大和数据高效性,并在LLaVA框架上建立了更强大和更可行的基线。有两个简单的改进,即MLP跨模态连接器和整合学术任务相关数据如VQA,与LLaVA的框架正交,当与LLaVA一起使用时,导致更好的多模态理解能力。LLaVALMMs使用了最简单的架构设计,并且仅需要在一个简单的全连接投影层上训练60万个图像-文本对。最终模型可以在单个8-A100机器上在约1天内完成训练,并在广泛的基准测试中达到最先进的结果。此外,与Qwen-VL在训练中包含内部数据不同,LLaVA仅使用公开可用数据。

2、相关工作

指令跟随大型多模态模型(LMMs)。常见的架构包括一个预训练的视觉骨干来编码视觉特征,一个预训练的大型语言模型(LLM)来理解用户指令并生成响应,以及一个视觉-语言跨模态连接器来将视觉编码器的输出对齐到语言模型。如图1所示,LLaVA可能是LMMs最简单的架构。可选地,视觉重采样器(例如Qformer)用于减少视觉块的数量。训练一个指令跟随LMM通常遵循一个两阶段协议。首先,视觉-语言对齐预训练阶段利用图像-文本对来将视觉特征与语言模型的词嵌入空间对齐。早期的工作使用相对较少的图像-文本对(例如∼600K或∼6M),而一些最近的工作在大量图像-文本对(例如129M和1.4B)上预训练视觉-语言连接器,以最大化LMM的性能。第二,视觉指令调优阶段在视觉指令上微调模型,以使模型能够遵循用户在涉及视觉内容的指令上的多样化请求。处理更高分辨率的LMM在网格中的研究在同时进行的工作中进行。

多模态指令跟随数据。在自然语言处理(NLP)中,研究表明指令跟随数据的质量在很大程度上影响着最终指令跟随模型的能力。考虑调查多模态模型中无法在自然对话和学术任务之间取得平衡的根本原因。

3、方法

3.1 准备工作

LLaVA 使用单个线性层将视觉特征投影到语言空间,并对整个大型语言模型(LLM)进行视觉指令调优。然而,LLaVA 在需要简短回答(例如单个词)的学术基准测试中表现不佳,并且在缺乏此类训练数据的情况下,倾向于对是非问题回答“是”。

3.2 . 响应格式提示

为了使 LLaVA 能够更好地处理简短答案,建议使用一个明确指示输出格式的单一响应格式提示。在需要促进简短回答时,将其附加在 VQA 问题的末尾:使用单个单词或短语回答问题。发现,当使用这样的提示对 LLM 进行微调时,LLaVA 能够根据用户的指令适当调整输出格式(见表 1b),并且不需要使用 ChatGPT VQA 答案进行额外处理,这进一步使其能够扩展到各种数据源。如表 2 所示,仅仅在训练中包含 VQAv2LLaVA 在 MME 上的性能就有了显著提高(1323.8 对 809.6),

扩展数据和模型

MLP 视觉语言连接器:受到将线性投影改为多层感知机(MLP)后在自监督学习中性能提升的启发,发现使用两层MLP来提高视觉语言连接器的表示能力,相较于原始的线性投影,可以增强LLaVA的多模态能力。

学术任务导向数据:进一步为 VQA、OCR 和区域级感知等任务纳入了更多的学术任务导向的 VQA 数据集,如表 2 所示,以多种方式增强模型的能力。

额外的扩展:进一步将输入图像分辨率提升到 336×336,通过将视觉编码器替换为 CLIP - ViT - L - 336px(CLIP 可用的最高分辨率),以使 LLM 能够清晰地“看到”图像的细节。此外,添加 GQA 数据集作为额外的视觉知识源。还纳入了 ShareGPT 数据,并将 LLM 扩展到 130 亿参数。在 MM- Vet 上的结果表明,将 LLM 扩展到 130 亿参数时,改进最为显著,这表明基础 LLM 的能力对于视觉对话的重要性。

LLaVA - 1.5:将具有所有这些修改的最终模型表示为 LLaVA - 1.5(表 2 的最后两行),它取得了令人印象深刻的性能,显著优于原始的 LLaVA

计算成本:对于 LLaVA - 1.5,使用相同的预训练数据集,并在指令调优方面保持与 LLaVA 大致相同的训练迭代次数和批处理大小。由于将图像输入分辨率提高到 336×336,LLaVA - 1.5 的训练时间约为 LLaVA 的 2 倍:预训练约 6 小时,视觉指令调优约 20 小时,使用 8 块 A100 显卡。

将图像的分辨率提升到更高的水平

通过将图像分割成视觉编码器原本训练的分辨率的较小图像块,并对它们进行独立编码来克服这个问题。在获得各个图像块的特征图后,将它们合并成目标分辨率的单个大特征图,并将其输入到 LLM 中。为了为 LLM 提供全局上下文并减少分割-编码-合并操作的伪影,还将下采样图像的特征连接到合并的特征图上。这能够将输入扩展到任意分辨率,并保持 LLaVA - 1.5 的数据效率。将这个得到的模型称为 LLaVA - 1.5 - HD

4、实证评估

结果

LLaVA - 1.5 使用的预训练和指令调优数据量要小得多,但它在12个基准测试中实现了最佳的总体性能。LLaVA - 1.5在所有针对指令跟随LMMs的基准测试中都显著优于LLaVA

当使用LLaVA - 1.5 - HD将图像分辨率继续提升到448×448时,它在所有基准测试中的整体性能进一步提高,特别是在需要感知图像细节的任务上(例如MM - Vet中的OCR,LLaVA - Bench - in - the - Wild中的详细描述)。

此外,发现添加全局上下文可以有效地使模型从分割和合并的伪影中恢复,并引导模型更容易从高分辨率特征中定位相关区域。

令人鼓舞的是,LLaVA - 1.5以最简单的架构、学术计算和公共数据集实现了最佳性能,并为未来的研究提供了一个完全可重现且经济实惠的基线。结果还表明,视觉指令调优在提高LMM的能力方面发挥着重要作用,并对LMM需要大量视觉语言对齐预训练的普遍观点提出了质疑。

新兴属性

首先,它在格式指令泛化方面表现出色;

其次,它具有多语言多模态能力,尽管没有针对多语言多模态指令进行微调,但能跟随多语言指令。这部分归功于 ShareGPT 中的多语言指令,模型从该数据集中学习到了根据用户请求自适应响应语言的行为。

最后,在MMBench-CN上的定量评估中,LLaVA-1.5在中文任务上的表现优于经过中文多模态指令微调的Qwen-VL-Chat

LLM 选择上的消融研究

基础模型的重要性:基于 LLaMA-2 的模型在多模态任务上表现优于基于 LLaMA-1 的模型,表明基础语言模型的能力对最终模型的性能有显著影响。

指令微调的影响:语言指令微调在特定任务上至关重要,尤其是在需要处理多语言或多模态数据时。

数据多样性的影响:数据的多样性和噪声处理能力对模型的泛化能力和鲁棒性有重要影响。

通过这些发现,可以更好地理解不同 LLM 在多模态任务上的表现,并为未来的模型设计和优化提供指导。

5、多模态模型的开放问题

利用 LLaVA-1.5 的模型设计和数据混合,对多模态模型(LMMs)中的开放问题进行了进一步研究。

5.1 数据效率

LLaVA-1.5 在数据效率方面表现出色,但与 LLaVA 相比,LLaVA-1.5 的训练数据量仍然翻倍。

5.2 多模态幻觉的思考

LMMs 可能对训练数据中的少量错误具有鲁棒性。然而,当输入分辨率不足以让模型辨别训练数据中的所有细节,并且超出模型处理能力的数据量变得足够大时,模型就会学会产生幻觉。这进一步表明,在提高数据注释的详细程度和模型处理这些细粒度信息的能力之间需要保持平衡。希望这一发现能为未来处理幻觉问题以及模型和数据的扩展提供参考。

5.3 组合能力

LLaVA-1.5 在独立训练的一组任务上进行了训练,能够泛化到需要这些能力组合的任务,而无需显式的联合训练。以下是一些发现:

通过全面包含所有任务组合,多模态模型的组合能力可以被利用来提高模型的性能,而无需显著增加数据量。

6、结论

模型设计:提出了一个简单、有效且数据高效的基础模型 LLaVA-1.5,用于大型多模态模型。

开放问题:探讨了视觉指令调优中的开放问题,并展示了模型幻觉和多模态模型组合能力方面的一些有趣发现。

未来研究:希望这些改进且易于复现的基线以及新的发现,能为未来开源多模态模型的研究提供参考。

局限性:LLaVA-1.5 仍存在一些局限性,包括高分辨率图像的长时间训练、缺乏多图像理解能力、在某些领域的有限问题解决能力。在关键应用中应谨慎使用。

下面介绍基于LLaVA源码进行训练的方法步骤(Linux系统):

1、获取代码,安装环境

git clone GitHub - haotian-liu/LLaVA: [NeurIPS'23 Oral] Visual Instruction Tuning (LLaVA) built towards GPT-4V level capabilities and beyond.

cd LLaVA

pip install --upgrade pip  # enable PEP 660 support

pip install -e .

pip install -e ".[train]"

pip install flash-attn --no-build-isolation

2、训练

下面为LLaVA v1.5的配置

一个8 A100 GPUs  80GB 内存。如果要在更小配置的GPUs上训练, 需要减少per_device_train_batch_size与增加gradient_accumulation_steps

预训练(特征对齐)超参数如下:

模型名:LLaVA-v1.5-13B

Global Batch Size:256

Learning rate:1e-3

Epochs:1

Max length:2048

Weight decay:0

微调(视觉指令调整)超参数如下:

模型名:LLaVA-v1.5-13B

Global Batch Size:128

Learning rate:2e-5

Epochs:1

Max length:2048

Weight decay:0

执行下面训练脚本,会自动下载预训练模型

预训练(特征对齐):

在Pycharm中或命令行运行脚本llava//scripts/v1_5/pretrain.sh,用DeepSpeed ZeRO-2进行训练

微调(视觉指令调整):

数据准备:

llava_v1_5_mix665k.json下载:https://huggingface.co/datasets/liuhaotian/LLaVA-Instruct-150K/blob/main/llava_v1_5_mix665k.json

COCO: train2017http://images.cocodataset.org/zips/train2017.zip

GQA: images下载:https://downloads.cs.stanford.edu/nlp/data/gqa/images.zip

OCR-VQA: download script,下载:https://drive.google.com/drive/folders/1_GYPY5UkUy7HIcR0zq3ZCFgeZN7BAfm_?usp=sharing, 执行文件后下载的图片文件保存为.jpg格式

TextVQA: train_val_images下载:https://dl.fbaipublicfiles.com/textvqa/images/train_val_images.zip

VisualGenome: part1, part2下载:https://cs.stanford.edu/people/rak248/VG_100K_2/images.zip

https://cs.stanford.edu/people/rak248/VG_100K_2/images2.zip

所有数据下载后,保存在./playground/data位置

训练:

由于分辨率提高到336px,8x A100(80G)上的LLaVA-v1.5-13B的视觉指令调整大约需要20个小时。在8x A100(40G)上,LLaVA-v1.5-7B大约需要10个小时。

在Pycharm中或命令行运行脚本llava//scripts/v1_5/finetune.sh,用DeepSpeed ZeRO-3进行训练

如果你没有足够的GPU内存,可以用LoRA训练脚本: finetune_lora.sh。可以适合13B在8-A100-40G/8-A6000和7B在8-RTX3090.上训练。  确保per_device_train_batch_size*gradient_acumulation_steps与提供的脚本相同,以获得最佳再现性。

如果你要用自己的数据进行视觉指令调整训练,可以用如下方法生成训练集:

pip install gradio==3.50

pip install -q -U google-generativeai

pip install anthropic openai

创建一个.py文件,代码如下:

import os

googleapi_key = os.getenv('GOOGLE_API_KEY')

#claude_key = os.getenv('CLAUDE_API_KEY')

claude_key = ""

#print(googleapi_key)

import gradio as gr

from openai import OpenAI

import base64

from PIL import Image

import io

import os

import google.generativeai as genai

import anthropic, openai

# Function to encode the image to base64

def encode_image_to_base64(image):

    buffered = io.BytesIO()

    image.save(buffered, format="JPEG")

    return base64.b64encode(buffered.getvalue()).decode('utf-8')

# Function to query GPT-4 Vision

def query_gpt4_vision(text, image1, image2, image3):

    client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))

    messages = [{"role": "user", "content": [{"type": "text", "text": text}]}]

    images = [image1, image2, image3]

for image in images:

if image is not None:

            base64_image = encode_image_to_base64(image)

            image_message = {

                "type": "image_url",

                "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}

            }

            messages[0]["content"].append(image_message)

response = client.chat.completions.create(

        #model="gpt-4-vision-preview",

        model="gpt-4-turbo",

        messages=messages,

        max_tokens=1024,

    )

return response.choices[0].message.content

def query_gpt4o_vision(text, image1, image2, image3):

    client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))

    messages = [{"role": "user", "content": [{"type": "text", "text": text}]}]

    images = [image1, image2, image3]

    for image in images:

        if image is not None:

            base64_image = encode_image_to_base64(image)

            image_message = {

                "type": "image_url",

                "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}

            }

            messages[0]["content"].append(image_message)

    response = client.chat.completions.create(

        model="gpt-4o",

        #model=model_type,

        messages=messages,

        max_tokens=1024,

    )

return response.choices[0].message.content

def query_gpt4o_mini_vision(text, image1, image2, image3):

    client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))

    messages = [{"role": "user", "content": [{"type": "text", "text": text}]}]

    images = [image1, image2, image3]

    for image in images:

        if image is not None:

            base64_image = encode_image_to_base64(image)

            image_message = {

                "type": "image_url",

                "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}

            }

            messages[0]["content"].append(image_message)

    response = client.chat.completions.create(

        model="gpt-4o-mini",

        #model=model_type,

        messages=messages,

        max_tokens=1024,

    )

return response.choices[0].message.content

def query_claude_vision(text, image1, image2, image3):

    claude_key = ""

    modelConfig ={

        "claude_S": "claude-3-haiku-20240307",

        "claude_M": "claude-3-sonnet-20240229",

        "claude_B": "claude-3-opus-20240229",

    }

    client = anthropic.Anthropic(api_key=claude_key)

    messages = [{"role": "user", "content": [{"type": "text", "text": text}]}]

    images = [image1, image2, image3]

    for image in images:

        if image is not None:

            base64_image = encode_image_to_base64(image)

            image_message = {

                "type": "image",

                "source": {

                    "type": "base64",

                    "media_type": "image/jpeg",

                    "data": base64_image,

                }

            }

            messages[0]["content"].append(image_message)

    #print(messages)

    response = client.messages.create(

        #model="gpt-4-vision-preview",

        model=modelConfig["claude_M"],

        messages=messages,

        max_tokens=1024,

    )

return response.content[0].text

def query_gemini_vision(text, image1, image2, image3):

    # Or use `os.getenv('GOOGLE_API_KEY')` to fetch an environment variable.

    # GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')

    GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')

    genai.configure(api_key=GOOGLE_API_KEY)

    model = genai.GenerativeModel('gemini-1.5-flash')

    images = [image1, image2, image3]

    query = [text]

    for image in images:

        if image is not None:

            query.append(image)

    response = model.generate_content(query, stream=False)

    response.resolve()

return response.text

def main():

    with gr.Blocks() as demo:

        gr.Markdown("### 输入文本")

        input_text = gr.Textbox(lines=2, label="输入文本")

        input_images = [

            gr.Image(type="pil", label="Upload Image", tool="editor") for i in range(3)]

        output_gpt4 = gr.Textbox(label="GPT-4v-Turbo 输出")

        output_gemini = gr.Textbox(label="Gemini-Pro 输出")

        output_claude3 = gr.Textbox(label="Claude3 sonnet 输出")

        output_gpt4o = gr.Textbox(label="GPT-4o 输出")

        output_gpt4o_mini = gr.Textbox(label="GPT-4o-mini 输出")

        btn_gpt4 = gr.Button("调用GPT-4")

        btn_gemini = gr.Button("调用Gemini-Pro")

        btn_claude = gr.Button("调用Claude-3-sonnet")

        btn_gpt4o = gr.Button("调用GPT-4o")

        btn_gpt4o_mini = gr.Button("调用GPT-4o-mini")

        btn_gpt4.click(fn=query_gpt4_vision, inputs=[

                       input_text] + input_images, outputs=output_gpt4)

        btn_gemini.click(fn=query_gemini_vision, inputs=[

                            input_text] + input_images, outputs=output_gemini)

        btn_claude.click(fn=query_claude_vision, inputs=[

                       input_text] + input_images, outputs=output_claude3)

        btn_gpt4o.click(fn=query_gpt4o_vision, inputs=[

                       input_text] + input_images, outputs=output_gpt4o)

        btn_gpt4o_mini.click(fn=query_gpt4o_mini_vision, inputs=[

                       input_text] + input_images, outputs=output_gpt4o_mini)

demo.launch(share=True)

if __name__ == "__main__":

    main()

3、评估

可以用自己的数据转换成LLaVA的 jsonl 格式,评估用llava/model_vqa.py

4、CLI推理

多模态在命令行用图片与LLaVA 进行聊天,支持多个 GPUs, 4-bit a8-bit 量化接口。  4-bit 量化, 对于LLaVA-1.5-7B, 在一个 GPU上只需要少于8GB内存,命令如下:

python -m llava.serve.cli \

    --model-path liuhaotian/llava-v1.5-7b \

    --image-file "https://llava-vl.github.io/static/images/view.jpg" \

    --load-4bit

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值