大模型学习笔记十:多模态大模型

本文详细介绍了多模态大模型的概念,包括跨模态、单模态和多模态模型。重点讨论了图-文多模态模型的发展,如CLIP、Chinese-CLIP以及GPT4v和Gemini。通过代码示例展示了如何使用这些模型,并探讨了它们在图文对话系统和多模态任务中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、多模态大预言模型(MLLM)的定义

1)跨模态模型

(1)以视觉、文本、音频三种模态为例(艺术人对话):
①Real3D-Portrait
在这里插入图片描述
②SadTalker
在这里插入图片描述
③Audio2Photoreal
在这里插入图片描述
(2)suno:文本\歌词->音乐生成
在这里插入图片描述

在这里插入图片描述

(3)音色克隆、语音发言:GPT-SoVITS
在这里插入图片描述

2)单模态大模型

1)视觉大模型
在这里插入图片描述

2)语言大模型
在这里插入图片描述

3)多模态模型

在这里插入图片描述

二、(图-文)多模态模型的发展历程

1)发展历程

①vision transformer(ViT)模型:图片模型
在这里插入图片描述
②基于transformer架构的图像-文本联合建模
以VisualBert为例子
在这里插入图片描述
③大规模 图-文 Token对其模型 CLIP(开放域下的图像分类-目标检测-图像分割)
在这里插入图片描述
文本和图片的特征提取出来
更加深入理解:(图片分类CLIP->物体检测GLIP->像素级别检测MaskCLIP)
在这里插入图片描述

2)CLIP代码举例展示

  • 代码目的:文生图或图生文
#1、加载模块
from transformers import CLIPProcessor, CLIPModel
model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
#加载数据处理的模块
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32") 


#2、加载图片,输入要模型识别的模块
from PIL import Image
image = Image.open("data_examples/truck.jpg")
cls_list = ["dog", "woman", "man", "car", "truck",
            "a black truck", "a white truck", "cat"]
input = processor(text=cls_list, images=image,
                  return_tensors="pt", padding=True)
outputs = model(**input)
print(outputs.keys()) 

这里返回的结果是六个参数:
CLIP 模型反馈的结果包含[‘logits_per_image’, ‘logits_per_text’, ‘text_embeds’, ‘image_embeds’, ‘text_model_output’, ‘vision_model_output’] 这六组结果,分别对应:

logits_per_image: 每个图像于 cls_list 中所有文本标签的相似度;[1x7]
logits_per_text: logits_per_image 的矩阵转置 logits_per_text = logits_per_image.t()
text_embeds: 每个文本标签对应的特征矩阵
image_embeds: 每个图像对应的特征矩阵
text_model_output: 文本模型(未经过)特征映射的输出
vision_model_output: 图像模型(未经过)特征映射的输出

继续打印

logits_per_image = outputs.logits_per_image
probs = logits_per_image.softmax(dim=1)

for i in range(len(cls_list)):
    print(f"{cls_list[i]}: {probs[0][i]}")

结果(可信度)

dog: 4.405536310514435e-05
woman: 3.664955875137821e-05
man: 0.0002588978677522391
car: 0.013573568314313889
truck: 0.06473302841186523
a black truck: 0.02343929372727871
a white truck: 0.8979105353355408
cat: 3.939394446206279e-06

3)国内对应库:Chinese-CLIP

Chinese-CLIP

  • 安装
pip install cn_clip
  • 代码加载模型
import torch
import cn_clip.clip as clip
from PIL import Image
from cn_clip.clip import load_from_name, available_models
device = "cuda" if torch.cuda.is_available() else "cpu"
print("Available models:", available_models())
# Available models: ['ViT-B-16', 'ViT-L-14', 'ViT-L-14-336', 'ViT-H-14', 'RN50']

B 代表 Big,L代表 Large, H代表 Huge; B L H 后面紧跟的数字代表图像 patch 化时,每个 patch 的分辨率大小,14 代表图像是按照 14x14 的分辨率被划分成相互没有 overlap 的图像块。 -336 表示,输入图像被 resize 到 336x336 分辨率后进行的处理;默认是 224x224 的分辨率。 RN50 表示 ResNet50

  • 选择标签
model, preprocess = load_from_name(
    "ViT-B-16", device=device, download_root='./')
model.eval()

image = preprocess(Image.open("data_examples/truck.jpg")
                   ).unsqueeze(0).to(device)
cls_list = ["狗", "汽车", "白色皮卡", "火车", "皮卡"]
text = clip.tokenize(cls_list).to(device)

import torch

with torch.no_grad():
    image_features = model.encode_image(image)
    text_features = model.encode_text(text)
    # 对特征进行归一化,请使用归一化后的图文特征用于下游任务
    image_features /= image_features.norm(dim=-1, keepdim=True)
    text_features /= text_features.norm(dim=-1, keepdim=True)

    logits_per_image, logits_per_text = model.get_similarity(image, text)
    probs = logits_per_image.softmax(dim=-1).cpu().numpy()

from IPython.display import Image, display
display(Image(filename="data_examples/truck.jpg"))
for i in range(len(cls_list)):
    print(f"{cls_list[i]}: {probs[0][i]}")

在这里插入图片描述

  • 标签打印
: 1.3424560165731236e-06
汽车: 0.0012602715287357569
白色皮卡: 0.7032643556594849
火车: 2.633531403262168e-05
皮卡: 0.2954477369785309

4)多模态大语言模型GPT4-with Vision(GPT4v)的出现

在这里插入图片描述

  • 输入输出
    输入:支持图片和文本
    输出:输出自然语言文本
  • 使用举例
    ①遵循文字提示
    在这里插入图片描述
    ②理解视觉指向和参考
    在这里插入图片描述

③支持图片和文本联合提示
在这里插入图片描述
④少量样本学习
在这里插入图片描述
⑤强大视觉认识能力
在这里插入图片描述

5)Google:Gemini也是GPT4v的类似产品(原生多模态:不需要agent实现多模态功能)

在这里插入图片描述

6)Geimini代码示例

三、GPT4v以及Gemini-Pro实战

四、图文对话系统的搭建

五、Beyond VL:支持多模态输入的大预言模型

六、使用多模态大预言模型完成更多任务

七、图文多模态大模型(评测、训练和部署)

1)模型评测->MME评测集(目前比较权威的评测集)

在这里插入图片描述

2)模型评测->评测集分类(一半都是选择题为主,缺少逻辑分析)

①Perception 视觉认知的评测

1)	Coarse-Grained Tasks 粗粒度:比如辨认动物种类、计算数量、辨认位置或颜色
2)  Fine-Grained Tasks 细粒度:辨认明星、辨认不同地点的名胜古迹、辨认绘画风格
3)  OCR Tasks OCR任务:辨认电话号码、辨认字符

②Cognition 推理认知的评测

1) Commensense Reasoning 常识推理
红灯是否能行、辨认前面有几只猫(有一只露出了尾巴)
2)Numerical Calculation 术语计算
数字计算、公式推理
3)文本翻译
4)代码解释
  • 开源模型一览(比较偏向视觉模型)
    在这里插入图片描述

3)多模态大预言模型训练过程的原理(以LLaVA举例)

  • 注意
    ①LLaVA不建议微调,容易过度拟合
    ②LLaVA适合自己的数据和原本数据集全量去训练一个模型
    ③LLaVA微调后的大预言模型效果不是很好

  • 图示
    在这里插入图片描述

  • 解释
    ①比普通的transformer多了视觉编码器和特征矩阵映射(其他不变)

1)视觉编码器:把图片切分成一块块的patch并转化成token
2)特征映射模块:CLIP虽然一定程度上有图文对其的能力,但是对其的文本模型和大预言的文本不是同一个特征空间里面·
  • 训练过程
    1)步骤一:特征对其的预训练,只更新特征映射矩阵
    实际原理:把图片形成的token转化成大预言模型能认知的矩阵里面
    目的:做图片的文本描述
    2)步骤二:端到端微调。特征投影矩阵和LLM都进行更新
    目的:微调

  • 图像数据准备(数据来源)

(1)图文对其数据(步骤一训练)
1)LAION Dataset
2)Conceptual Captions Dataset
3)SBU Cpations Dataset
总共558K
(2)图文指令数据(步骤二训练,图文问答数据集)
1)coco:118287
2)gpa:148854 
3)ocr_vqa:207572
4)textvqa:25119
5)VG_100K:64346
6)VG_100K_2:43903
总共608081

或是用GPT生成一些精细的文本描述
在这里插入图片描述

①生成图像精细描述
②生成对话
③生成复杂推理

步骤一:特征对其的预训练,只更新特征映射矩阵
  • 步骤
1)图像解析实战
①任务一:抽取出图像包含的所有物体
②任务二:根据抽取出来的物体列表,获取其在图像中的位置
2)生成LLaVA所需训练数据
①生成图像描述
②生成对话类数据
③生成复杂推理类问题
  • 任务一:抽取出图像包含的所有物体
    方法:使用 RAM 完成上述任务。与 CLIP 不同,RAM 默认提供了可识别的物体类别列表,详见
import argparse
import numpy as np
import random
import os
import torch

from PIL import Image
from ram.models import ram_plus, ram
from ram import inference_ram as inference
from ram import get_transform

#1、加载模型
image_size = 384  # 一般来说,图像分辨率越大,可识别的图像内容精细程度越高。但是随之可能带来的风险是提升识别错误的概率。
transform = get_transform(image_size=image_size)
# model = ram(pretrained="models/ram_swin_large_14m.pth",
#                             image_size=image_size,
#                             vit='swin_l')
model = ram_plus(pretrained="models/ram_plus_swin_large_14m.pth",
                 image_size=image_size,
                 vit='swin_l')
model.eval()
model = model.to(device)

#2、打印图片抽取的标签
from IPython.display import display
from PIL import Image
image_path = "data_examples/test.jpg"
image_pil = Image.open(image_path)
image = transform(image_pil).unsqueeze(0).to(device)
recog_res = inference(image, model)


display(image_pil)
print("Image Tags: ", recog_res[0])
print("图像标签: ", recog_res[1])

在这里插入图片描述

Image Tags:  bicycle | man | passenger train | railroad | ride | rural | track | train | train track
图像标签:  自行车  | 男人 | 旅客列车  | 铁道 | 骑/搭乘 | 农村的 | 跑道 | 火车  | 火车轨道
  • 任务二:根据抽取出来的物体列表,获取其在图像中的位置信息
1)安装(使用 GroundingDINO 完成上述任务)
!pip uninstall groundingdino -y
!pip install -e ./GroundingDINO
from groundingdino.util.inference import load_model, load_image, predict, annotate, Model
import cv2

CONFIG_PATH = "GroundingDINO/groundingdino/config/GroundingDINO_SwinT_OGC.py"
CHECKPOINT_PATH = "models/groundingdino_swint_ogc.pth"
model = load_model(CONFIG_PATH, CHECKPOINT_PATH)
image_path = "data_examples/test.jpg"
image_source, image = load_image(image_path)
# "bicycle. man. passenger train. railroad. ride. rural. track. train. train track"
TEXT_PROMPT = recog_res[0].replace(" | ", ". ")
BOX_TRESHOLD = 0.25
TEXT_TRESHOLD = 0.25
boxes, logits, phrases = predict(
    model=model,
    image=image,
    caption=TEXT_PROMPT,
    box_threshold=BOX_TRESHOLD,
    text_threshold=TEXT_TRESHOLD,
    device=device,
)
annotated_frame = annotate(image_source=image_source,
                           boxes=boxes, logits=logits, phrases=phrases)
annotated_frame = cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB)
annotated_frame = Image.fromarray(annotated_frame)
print(TEXT_PROMPT)        #打印标签
print(boxes, logits, phrases) #打印位置信息
bicycle. man. passenger train. railroad. ride. rural. track. train. train track
tensor([[0.5825, 0.7033, 0.2177, 0.3277],
        [0.4994, 0.4557, 0.9942, 0.3211],
        [0.6033, 0.7750, 0.1764, 0.2441],
        [0.4996, 0.8716, 0.9920, 0.2515],
        [0.5004, 0.4999, 0.9906, 0.9869]]) tensor([0.8379, 0.5691, 0.8021, 0.3149, 0.3078]) ['man', 'passenger train train', 'bicycle', 'track', 'rural']
#真正调用代码
from PIL import Image
from IPython.display import display

display(annotated_frame)
def convertDINO2GPT(boxes, phrases):
    return ", ".join(f"{phrases[i]}: {boxes[i].numpy()}" for i in range(len(phrases)))


bbox_query = convertDINO2GPT(boxes, phrases)
print(bbox_query)

在这里插入图片描述
打印出来的位置信息

man: [0.58250546 0.70334786 0.2176611  0.32774457], passenger train train: [0.4994392  0.45572934 0.9941685  0.32106024], bicycle: [0.60330147 0.7749733  0.17639382 0.24406381], track: [0.49963006 0.8715638  0.9920128  0.25146163], rural: [0.50035655 0.49993825 0.9905996  0.9868902 ]
步骤二:端到端微调。特征投影矩阵和LLM都进行更新
  • 生成LLaVA所需训练数据
    1)query_gpt4_vision: 调用 gpt-4v 接口,生成详细图像描述;
    2)query_gpt4_text: 调用 gpt4 文本模型接口,生成对话语料以及复杂逻辑推理问题。

  • 代码示例

from openai import OpenAI
import io
import base64
import os

# 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(messages, api_key=os.getenv('OPENAI_API_KEY')):
    client = OpenAI(api_key=api_key)

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        max_tokens=4096,
    )
    return response.choices[0].message.content

# Function to query GPT-4 Vision


def query_gpt4_text(messages, api_key=os.getenv('OPENAI_API_KEY')):
    client = OpenAI(api_key=api_key)

    response = client.chat.completions.create(
        model="gpt-4",
        messages=messages,
        max_tokens=2048,
    )
    return response.choices[0].message.content

①数据类型一:生成图像描述
在这里插入图片描述

from IPython.display import display
from PIL import Image
system_message_description = f"""你是一个功能强大的中文图像描述器。请创建详细的描述,阐述给定图片的内容。包括物体的类型和颜色、计算物体的数量、物体的动作、物体的精确位置、图片中的文字、核对物体之间的相对位置等。不要描述虚构的内容,只描述从图片中可以确定的内容。在描述内容时,不要以清单形式逐项列出。尽可能最小化审美描述。"""

image_path = "data_examples/test.jpg"
image = Image.open(image_path)
base64_image = encode_image_to_base64(image)
messages = [{"role": "system", "content": system_message_description}, {"role": "user", "content": [
    {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}}]}]
gpt4v_description = query_gpt4_vision(messages)

display(image)

print(gpt4v_description)

在这里插入图片描述

这张照片展示了一位骑自行车的男子,他在一个铁路道口附近。男子穿着深色上衣和浅色裤子,正骑着一辆黑色自行车,位于图片的前景中偏右。背景中可以看到一列行驶中的红色和白色相间的列车,铁轨上方有许多电线和支架。铁路的左侧有一个绿色的柱子和一些铁架结构。前景中右侧有一个圆形标志牌,标志牌的具体内容不可辨认。旁边还可见到一些灌木丛和较低的植被,整体环境显得相对安静

②数据类型二:生成对话类数据

system_message_conversation = f"""你是一个AI视觉助手,你正在观看一张图片。你看到的可能是描述一副图片的若干句子,它们描述了你正在看的同一张图片。回答所有问题时,你要像正在观看图片一样回答。设计一段你和询问这张照片的人之间的对话。回答应该以视觉AI助手正在观看图片并回答问题的语气来进行。提出各种问题并给出相应的答案。包括询问图片中的视觉内容,包括物体类型、计算物体数量、物体动作、物体位置、物体之间的相对位置等。只包括有明确答案的问题:
(1) 可以在图片中看到问题所询问的内容,并能给出自信地回答;
(2) 可以明确在图像中看不到的内容。不要提出任何无法自信回答的问题。

还要包括与图片内容相关的复杂问题,例如询问图片中物体的背景知识,讨论图片中正在发生的事件等。同样,不要询问不确定的细节。在回答复杂问题时提供详细答案。例如,给出详细的例子或推理步骤,使内容更有说服力和组织性。如果必要,可以包括多个段落。"""

fewshot_samples = [{
    "context": "这是一家电影院,放映时间显示在门上方。一个红色的消防栓深埋在雪中。消防栓位于一条最近刚刚清扫过的人行道旁的雪地里。这个城市经历了一个雪量非常大的严冬。在冬天的雪中有一家狗狗的酒店。",
    "response": f"""问题:
图片中的消防栓是什么颜色?
===
答案:
图片中的消防栓是红色的。
===
问题:
消防栓是否被雪完全覆盖还是部分可见?
===
答案:
消防栓部分可见,其大部分被深雪覆盖。
===
问题:
消防栓附近的人行道状况如何?
===
答案:
消防栓附近的人行道最近刚刚清扫过,与周围地区相比,相对没有那么多雪。
===
问题:
这张图片对这个城市的冬季有何暗示?
===
答案:
这张图片暗示这个城市的冬季非常严酷和具有挑战性。图片中可见的大量积雪表明这个城市经历了大量降雪,这可能会给居民生活带来各种困难和中断。
例如,消防栓被深雪覆盖可能会妨碍紧急情况下的可及性,这就引发了安全问题。最近清扫过的人行道表明城市维护人员一直在积极工作,以保持人行道的清洁和安全,但大量降雪可能使持续的除雪工作变得困难。
此外,这种极端的冬季条件可能影响交通,导致交通问题、公共交通延误以及由于道路湿滑而增加的事故风险。这也可能给商业和学校带来问题,因为人们上班或上课的通勤可能会面临挑战。此外,大量积雪还可能对基础设施造成额外压力,如屋顶和电线,增加了结构损坏或停电的可能性。
总之,深埋在雪中的红色消防栓和最近刚刚清扫过的人行道的图片表明这个城市经历了一个特别严酷的冬季,大量降雪可能已经给居民和基础设施带来了各种挑战和中断。"""
},
    {"context": "一名男子正在开阔的雪地山丘上滑雪。一名滑雪者正滑入雪地。滑雪者位于一座巨大山脉的山麓。一名滑雪者站在小径标志旁边,望着山脉。一名独自滑雪者滑过一片灌木丛生的区域。",
     "response": f"""问题:
这个滑雪者在做什么?
===
答案:
这个滑雪者正在雪覆盖的山丘上滑雪,他穿越雪地,享受着美丽的山景。他们还站在一块指示他们在山上位置的小路标识牌旁边。
===
问题:
图片中有其他人或滑雪者可见吗?
===
答案:
不,图片中只有一个人在滑雪,他们被许多灌木丛所包围。
===
问题:
这个人在做什么类型的滑雪?越野滑雪还是高山滑雪?
===
答案:
根据我在照片中看到的,无法明确确定这个滑雪者是在做越野滑雪还是高山滑雪。但是,考虑到存在小路标识牌,以及他们在山丘上滑雪的事实,更有可能是这个滑雪者在进行越野滑雪。高山滑雪通常发生在更陡峭的斜坡上,并涉及使用滑雪缆车,而越野滑雪通常发生在相对平坦的地形上,并有标记的小路。
===
问题:
你能更详细地解释一下越野滑雪和高山滑雪吗?
===
答案:
越野滑雪和高山滑雪是两种不同类型的滑雪,每种都有自己的技术、装备和地形偏好。
1. 越野滑雪:
也称为北欧滑雪,越野滑雪是利用滑雪板和滑雪杖在相对平坦的地形或缓坡上滑行。它是一项受欢迎的娱乐和竞技运动,注重耐力、平衡和有氧健身。越野滑雪者依靠自身运动在雪覆盖的地形上移动,而不是依靠滑雪缆车或其他辅助方式。
越野滑雪有两种主要技术:
- 古典式:这种技术涉及在平行的轨道上滑行,使用前后滑动的动作,保持滑雪板互相平行。滑雪者使用滑雪杖推动自己向前滑行。
- 滑行式滑雪:这种技术类似于溜冰,滑雪者在一个滑雪板上以角度用力踢出并在另一侧滑行。它需要平滑的小路表面,通常比古典式技术更快。
越野滑雪装备包括轻便滑雪板、靴子、绑脚器和滑雪杖。鞋子比高山滑雪的鞋子更灵活,使踝关节更容易移动和控制。
2. 高山滑雪:
也称为滑降滑雪,高山滑雪是利用滑雪板和滑雪杖以高速下滑斜坡来平衡和控制。这项运动更注重速度、技术和在富有挑战性的地形上滑降,包括陡坡、障碍和甚至跳跃。
高山滑雪可以进一步分为几个项目,例如回转滑雪、大回转、超级大回转、速降滑雪等。每个项目都有一套自己的规则、赛道和滑雪设备。
高山滑雪装备包括比越野滑雪使用的滑雪板、靴子、绑脚器和滑雪杖更重、更硬。鞋子更硬以在高速下降和急转弯时提供更好的支撑和控制。
总的来说,越野滑雪是一项基于耐力的运动,涉及在平坦或缓坡地形上旅行,而高山滑雪则集中在速度和技术上,滑雪者在陡坡和富有挑战性的地形上滑降。两种运动都需要专业的装备和技术,但它们给参与者带来不同的体验和挑战。"""}]

messages = [{"role": "system", "content": system_message_conversation}]
for sample in fewshot_samples:
    messages.append({"role": "user", "content": sample['context']})
    messages.append({"role": "assistant", "content": sample['response']})
messages.append({"role": "user", "content": '\n'.join(gpt4v_description)})

from IPython.display import display
from PIL import Image
gpt4t_conversation = query_gpt4_text(messages)

display(image)

print(gpt4t_conversation)

在这里插入图片描述

问题:
图片中的男子穿着什么颜色的衣服?
===
答案:
照片中的男子穿着深色的上衣和浅色的裤子。
===
问题:
男子正在骑什么颜色的自行车?
===
答案:
男子正在骑一辆黑色的自行车。
===
问题:
列车的颜色是什么?
===
答案:
列车的颜色是红色和白色相间的。
===
问题:
男子在哪个位置?
===
答案:
男子在图片的前景中偏右。
===
问题:
在铁路的那一侧有一个绿色的柱子?
===
答案:
在铁路的左侧有一个绿色的柱子。
===
问题:
图片右侧的标志牌上写了什么?
===
答案:
我无法确定图片右侧的标志牌上写了什么,因为标志牌的具体内容不可辨认。
===
问题:
系统可以推测这个男子可能是在做什么?
===
答案:
从我作为AI视觉助手对这张图片的识别来看,这个男子可能正在进行日常的骑自行车活动。考虑到他位于图像的前景中且在铁路道口附近,他可能正在经过这个地方,也许是前往他的目的地或者只是为了骑车而骑车。然而,必须注意的是,我不能确定他是否正在等待列车通过,因为尽管列车在行驶,但我不能确定列车的准确位置或者道口的状态。我也无法确定他是否注意到了列车或者是正在赞美这个安静的环境。然而,可以根据这个场景推理,男子很可能在骑行中并因此类似的活动提供了有趣的背景视觉。

③数据类型三:生成复杂推理类问题
这里需要结束图像解析过程最终得到的物体在图像上的坐标信息bbox_query,来辅助构建一些复杂推理类问题。

import json
system_message_reasoning = f"""你是一个可以分析单张图片的AI视觉助手。你收到了若干句子,每个句子都描述了你正在观察的同一幅图片。此外,还给出了图片内特定物体的位置,以及详细的坐标。这些坐标以边界框的形式表示,用四个浮点数(x1, y1, x2, y2)范围从0到1表示。这些值对应于左上角的x、左上角的y、右下角的x和右下角的y。

任务是利用提供的标题和边界框信息,创建一个关于图片的合理问题,并详细提供答案。

创建超出描述场景的复杂问题。要回答这样的问题,首先需要理解视觉内容,然后根据背景知识或推理,解释为什么会发生这种情况,或者针对用户的请求提供指导和帮助。通过在问题中不包含视觉内容细节来使问题具有挑战性,这样用户需要首先对此进行推理。

在描述场景时,不要直接提及边界框坐标,而是利用这些数据用自然语言解释场景。包括物体的数量、物体的位置、物体之间的相对位置等细节。

在使用标题和坐标的信息时,直接解释场景,不要提及信息来源是标题或边界框。始终回答得好像你是直接在看这幅图片。

要求‘问题’和‘答案’交替输出,中间用单独一行‘===’隔开
"""

fewshot_samples = [{
    "context": f"""一个戴着多根领带的男人做鬼脸。
一个穿着白衬衫戴着很多领带的男人。
一个戴着领带的男人摆姿势照相。
一个脖子上戴着多根领带的男人。
一个年轻男子戴着几条领带微笑着。

tie: [0.574, 0.298, 0.752, 0.704]
tie: [0.464, 0.339, 0.639, 0.789]
tie: [0.349, 0.363, 0.563, 0.732]
tie: [0.259, 0.255, 0.668, 0.805]
person: [0.019, 0.065, 0.962, 0.988]
person: [0.0, 0.24, 0.214, 1.0]
tie: [0.316, 0.778, 0.443, 0.867]
tie: [0.386, 0.707, 0.496, 0.801]
tie: [0.251, 0.354, 0.402, 0.747]
tie: [0.44, 0.318, 0.63, 0.397]
tie: [0.566, 0.33, 0.655, 0.543]
tie: [0.25, 0.409, 0.359, 0.556]",""",
    "response": f"""问题:
这张照片有什么不寻常之处?
===
答案:
在照片中,这个男人脖子上戴了多条领带。这被认为是不寻常的,因为通常情况下,一个人只会戴一条领带。这个男人傻笑的表情也增加了这张照片的非同寻常和幽默性质。"""
},
    {
        "context": f"""一群人站在一辆黑色车辆外面,带着各种行李。
行李散落在地下停车场的一辆车周围。
人们试图把所有的行李都塞进一辆SUV中。
这辆运动型多用途车停在公共车库里,正在为一次旅行做准备。
一些人带着行李靠近一辆用于运输的货车。

person: [0.681, 0.242, 0.774, 0.694]
person: [0.63, 0.222, 0.686, 0.516]
person: [0.444, 0.233, 0.487, 0.34]
backpack: [0.384, 0.696, 0.485, 0.914]
backpack: [0.755, 0.413, 0.846, 0.692]
suitcase: [0.758, 0.413, 0.845, 0.69]
suitcase: [0.1, 0.497, 0.173, 0.579]
bicycle: [0.282, 0.363, 0.327, 0.442]
car: [0.786, 0.25, 0.848, 0.322]
car: [0.783, 0.27, 0.827, 0.335]
car: [0.86, 0.254, 0.891, 0.3]
car: [0.261, 0.101, 0.787, 0.626]""",
    "response": f"""问题:
这些人面临着什么挑战?
===
答案:
在这张图片中,一群人站在一个停车区域外面,周围散落着各种行李,包括手提箱和背包。他们面临的挑战是要把所有的行李都塞进这辆黑色SUV中。有多个手提箱和背包需要装载,这表明这个团队有相当多的物品需要安排。他们可能需要制定策略,高效地安排行李,以确保一切都能够正确地放入车内。此外,他们还需要考虑乘客的舒适度和驾驶过程中的可见性,因此行李的放置不能妨碍驾驶员的视线,也不能让乘客在旅途中感到不舒服。"""
}]

messages = [{"role": "system", "content": system_message_reasoning}]
for sample in fewshot_samples:
    messages.append({"role": "user", "content": sample['context']})
    messages.append({"role": "assistant", "content": sample['response']})
messages.append({"role": "user", "content": '\n'.join(
    [gpt4v_description, bbox_query])})

print(json.dumps(messages, indent=2, ensure_ascii=False))
  • 回复
[
  {
    "role": "system",
    "content": "你是一个可以分析单张图片的AI视觉助手。你收到了若干句子,每个句子都描述了你正在观察的同一幅图片。此外,还给出了图片内特定物体的位置,以及详细的坐标。这些坐标以边界框的形式表示,用四个浮点数(x1, y1, x2, y2)范围从0到1表示。这些值对应于左上角的x、左上角的y、右下角的x和右下角的y。\n\n任务是利用提供的标题和边界框信息,创建一个关于图片的合理问题,并详细提供答案。\n\n创建超出描述场景的复杂问题。要回答这样的问题,首先需要理解视觉内容,然后根据背景知识或推理,解释为什么会发生这种情况,或者针对用户的请求提供指导和帮助。通过在问题中不包含视觉内容细节来使问题具有挑战性,这样用户需要首先对此进行推理。\n\n在描述场景时,不要直接提及边界框坐标,而是利用这些数据用自然语言解释场景。包括物体的数量、物体的位置、物体之间的相对位置等细节。\n\n在使用标题和坐标的信息时,直接解释场景,不要提及信息来源是标题或边界框。始终回答得好像你是直接在看这幅图片。\n\n要求‘问题’和‘答案’交替输出,中间用单独一行‘===’隔开\n"
  },
  {
    "role": "user",
    "content": "一个戴着多根领带的男人做鬼脸。\n一个穿着白衬衫戴着很多领带的男人。\n一个戴着领带的男人摆姿势照相。\n一个脖子上戴着多根领带的男人。\n一个年轻男子戴着几条领带微笑着。\n\ntie: [0.574, 0.298, 0.752, 0.704]\ntie: [0.464, 0.339, 0.639, 0.789]\ntie: [0.349, 0.363, 0.563, 0.732]\ntie: [0.259, 0.255, 0.668, 0.805]\nperson: [0.019, 0.065, 0.962, 0.988]\nperson: [0.0, 0.24, 0.214, 1.0]\ntie: [0.316, 0.778, 0.443, 0.867]\ntie: [0.386, 0.707, 0.496, 0.801]\ntie: [0.251, 0.354, 0.402, 0.747]\ntie: [0.44, 0.318, 0.63, 0.397]\ntie: [0.566, 0.33, 0.655, 0.543]\ntie: [0.25, 0.409, 0.359, 0.556]\","
  },
  {
    "role": "assistant",
    "content": "问题:\n这张照片有什么不寻常之处?\n===\n答案:\n在照片中,这个男人脖子上戴了多条领带。这被认为是不寻常的,因为通常情况下,一个人只会戴一条领带。这个男人傻笑的表情也增加了这张照片的非同寻常和幽默性质。"
  },
  {
    "role": "user",
    "content": "一群人站在一辆黑色车辆外面,带着各种行李。\n行李散落在地下停车场的一辆车周围。\n人们试图把所有的行李都塞进一辆SUV中。\n这辆运动型多用途车停在公共车库里,正在为一次旅行做准备。\n一些人带着行李靠近一辆用于运输的货车。\n\nperson: [0.681, 0.242, 0.774, 0.694]\nperson: [0.63, 0.222, 0.686, 0.516]\nperson: [0.444, 0.233, 0.487, 0.34]\nbackpack: [0.384, 0.696, 0.485, 0.914]\nbackpack: [0.755, 0.413, 0.846, 0.692]\nsuitcase: [0.758, 0.413, 0.845, 0.69]\nsuitcase: [0.1, 0.497, 0.173, 0.579]\nbicycle: [0.282, 0.363, 0.327, 0.442]\ncar: [0.786, 0.25, 0.848, 0.322]\ncar: [0.783, 0.27, 0.827, 0.335]\ncar: [0.86, 0.254, 0.891, 0.3]\ncar: [0.261, 0.101, 0.787, 0.626]"
  },
  {
    "role": "assistant",
    "content": "问题:\n这些人面临着什么挑战?\n===\n答案:\n在这张图片中,一群人站在一个停车区域外面,周围散落着各种行李,包括手提箱和背包。他们面临的挑战是要把所有的行李都塞进这辆黑色SUV中。有多个手提箱和背包需要装载,这表明这个团队有相当多的物品需要安排。他们可能需要制定策略,高效地安排行李,以确保一切都能够正确地放入车内。此外,他们还需要考虑乘客的舒适度和驾驶过程中的可见性,因此行李的放置不能妨碍驾驶员的视线,也不能让乘客在旅途中感到不舒服。"
  },
  {
    "role": "user",
    "content": "这张照片展示了一位骑自行车的男子,他在一个铁路道口附近。男子穿着深色上衣和浅色裤子,正骑着一辆黑色自行车,位于图片的前景中偏右。背景中可以看到一列行驶中的红色和白色相间的列车,铁轨上方有许多电线和支架。铁路的左侧有一个绿色的柱子和一些铁架结构。前景中右侧有一个圆形标志牌,标志牌的具体内容不可辨认。旁边还可见到一些灌木丛和较低的植被,整体环境显得相对安静。\nman: [0.58250546 0.70334786 0.2176611  0.32774457], passenger train train: [0.4994392  0.45572934 0.9941685  0.32106024], bicycle: [0.60330147 0.7749733  0.17639382 0.24406381], track: [0.49963006 0.8715638  0.9920128  0.25146163], rural: [0.50035655 0.49993825 0.9905996  0.9868902 ]"
  }
]
  • 单个问题询问
from IPython.display import display
from PIL import Image
gpt4t_reasoning = query_gpt4_text(messages)

display(image)

print(gpt4t_reasoning)

在这里插入图片描述

问题:
骑自行车的男子离行驶中的列车有多近?
===
答案:
尽管这个男子正在靠近一个铁路道口骑自行车,但他与行驶中的列车之间仍有足够的距离。这可能是由于他知道队列车的存在,并且在保持一定的安全距离以防止任何意外。因此,尽管他在铁路道口骑自行车,他并未站在靠近列车的轨道上,他是在安全的地方。然而,尽管他保持了安全的距离,但他应始终保持警惕,并遵守相关的安全规定,以防止任何不测。
  • 多轮问题询问


import re
def parser_gpt4_return(input_string, first_block=True):
    # Split the input string into blocks based on the question and answer pattern
    blocks = re.split(r"===\n", input_string.strip())
    
    # Create a list to hold conversation elements
    conversations = []
    
    # Process each block to extract questions and answers
    for block in blocks:
        lines = block.split("\n")
        if lines[-1] == "":
            lines = lines[:-1]
        if lines:
            if lines[0][:3] == "问题:":
                if first_block:
                    conversations.append({"from": "human", "value": "<image>\n" + "\n".join(lines[1:])})
                    first_block = False
                else:
                    conversations.append({"from": "human", "value": "\n".join(lines[1:])})
            elif lines[0][:3] == "答案:":
                conversations.append({"from": "gpt", "value": "\n".join(lines[1:])})
            else:
                raise ValueError(f"lines[0] should be Answer: or Question. Unexpected: -{lines[0]}-")
    
    return conversations

parsed_json = parser_gpt4_return(gpt4t_conversation)
parsed_json += parser_gpt4_return(gpt4t_reasoning, first_block=False)
print(json.dumps(parsed_json, indent=2, ensure_ascii=False))
  • 回复
[
  {
    "from": "human",
    "value": "<image>\n图片中的男子穿着什么颜色的衣服?"
  },
  {
    "from": "gpt",
    "value": "照片中的男子穿着深色的上衣和浅色的裤子。"
  },
  {
    "from": "human",
    "value": "男子正在骑什么颜色的自行车?"
  },
  {
    "from": "gpt",
    "value": "男子正在骑一辆黑色的自行车。"
  },
  {
    "from": "human",
    "value": "列车的颜色是什么?"
  },
  {
    "from": "gpt",
    "value": "列车的颜色是红色和白色相间的。"
  },
  {
    "from": "human",
    "value": "男子在哪个位置?"
  },
  {
    "from": "gpt",
    "value": "男子在图片的前景中偏右。"
  },
  {
    "from": "human",
    "value": "在铁路的那一侧有一个绿色的柱子?"
  },
  {
    "from": "gpt",
    "value": "在铁路的左侧有一个绿色的柱子。"
  },
  {
    "from": "human",
    "value": "图片右侧的标志牌上写了什么?"
  },
  {
    "from": "gpt",
    "value": "我无法确定图片右侧的标志牌上写了什么,因为标志牌的具体内容不可辨认。"
  },
  {
    "from": "human",
    "value": "系统可以推测这个男子可能是在做什么?"
  },
  {
    "from": "gpt",
    "value": "从我作为AI视觉助手对这张图片的识别来看,这个男子可能正在进行日常的骑自行车活动。考虑到他位于图像的前景中且在铁路道口附近,他可能正在经过这个地方,也许是前往他的目的地或者只是为了骑车而骑车。然而,必须注意的是,我不能确定他是否正在等待列车通过,因为尽管列车在行驶,但我不能确定列车的准确位置或者道口的状态。我也无法确定他是否注意到了列车或者是正在赞美这个安静的环境。然而,可以根据这个场景推理,男子很可能在骑行中并因此类似的活动提供了有趣的背景视觉。"
  },
  {
    "from": "human",
    "value": "骑自行车的男子离行驶中的列车有多近?"
  },
  {
    "from": "gpt",
    "value": "尽管这个男子正在靠近一个铁路道口骑自行车,但他与行驶中的列车之间仍有足够的距离。这可能是由于他知道队列车的存在,并且在保持一定的安全距离以防止任何意外。因此,尽管他在铁路道口骑自行车,他并未站在靠近列车的轨道上,他是在安全的地方。然而,尽管他保持了安全的距离,但他应始终保持警惕,并遵守相关的安全规定,以防止任何不测。"
  }
]

4)实际训练步骤

(1)阶段一:图文特征提取与对齐预训练
①基本数据格式

{
    "id": "任意一个非重复id,例如 0888888",
    "image": ",
    "conversations": [
      {
        "from": "human",
        "value": "请简要描述这幅图像.\n<image>"
      },
      {
        "from": "gpt",
        "value": "这张图片中显示了一名男子骑自行车和一列正在行驶的火车。前台的男子穿着深色上衣和裤子,看起来有亚洲面孔,他正骑着一辆深色自行车,从左向右穿过画面,并且与镜头形成了接近正面的视角。他的表情专注,似乎正在前往某个目的地。

在他的后方,可以看到一列红色和白色相间的高速火车,火车车身上有几个窗户,火车上方有电网。火车左边的树木使得场景给人一种自然的氛围。在图片的左上角部分,还有一个路牌,上面有日文和英文的混合文本,但具体内容不清晰。整个场景是在室外拍摄的,光线来自自然光,可能是在傍晚或清晨,因为阳光有点斜射到场景中。

整体上,这张照片创造了一种行驶中的火车与骑自行车的人共同构成的动态场面,可能在日本的城市郊外或者乡村地区拍摄。。"
      }
    ]
},

②下载LLaVA预训练集
传送门
③开始训练

  • 8x A100 (80GB) 耗时 5.5h
  • 基于 DeepSpeed ZeRO2
  • 输入图像分辨率 336 px
  • 训练参数:特征映射层结构(2 层全连接层)
    预训练脚本pretrain.sh
#!/bin/bash

deepspeed llava/train/train_mem.py \
    --deepspeed ./scripts/zero2.json \
    --model_name_or_path lmsys/vicuna-13b-v1.5 \  #表示使用的语言模型
    --version plain \      #表示进行阶段一的训练,更新特征映射矩阵
    --data_path ./playground/data/LLaVA-Pretrain/blip_laion_cc_sbu_558k.json \ #数据集
    --image_folder ./playground/data/LLaVA-Pretrain/images \  #表示图像文件夹
    --vision_tower openai/clip-vit-large-patch14-336 \  #视觉编码器是clip ,patch是14x14
    --mm_projector_type mlp2x_gelu \  #表示特征映射层是2层,mlp3x是3层,gelu是激活函数
    --tune_mm_mlp_adapter True \
    --mm_vision_select_layer -2 \ #用来选择模型中的特定层 比如为-2的时候,可能就是加载输出层的前一层(视觉解码器的特征层数)
    --mm_use_im_start_end False \
    --mm_use_im_patch_token False \
    --bf16 True \  #混合精度打开
    --output_dir ./checkpoints/llava-v1.5-13b-pretrain \  #输出模型位置
    --num_train_epochs 1 \ #只需要训练一轮,多次微调容易过度拟合
    --per_device_train_batch_size 32 \
    --per_device_eval_batch_size 4 \
    --gradient_accumulation_steps 1 \
    --evaluation_strategy "no" \
    --save_strategy "steps" \
    --save_steps 24000 \
    --save_total_limit 1 \
    --learning_rate 1e-3 \
    --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

(2)阶段二:图-文指令微调训练
①基本数据格式

  {
    "id": "任意一个非重复id,例如 0999999",
    "image": "图像文件路径,例如:my_data/hongyadong.jpg ",
    "conversations": [
      {
        "from": "human",
        "value": "<im图中的男子正在做什么?拍摄于哪里?"
      },
      {
        "from": "gpt",
        "value": "图中的男子正在骑自行车,他的视线专注,看起来他正在前往某个目的地。市洪崖洞景区的照片."
      },
      {
        "from": "human",
        "value": "图中有什么可以识别的文字内容?"
      },
      {
        "from": "gpt",
        "value": "图片右下角墙体上写着\”洪崖洞\“三个字."
      }]
  },

②下载LLaVA训练所需文本数据集:
llava_v1_5_mix665k.json
③下载LLaVA训练所需图像数据集:

④训练参数

  • 8x A100 (80GB) 耗 20h
  • 基于 DeepSpeed ZeR3
  • 输入图像分辨率 336 px
  • 训练参数:特征映射层结构(2 层全连接层以及 LLM
    训练脚本: finetune.sh
    LoRA 训练脚本: finetune_lora.sh
#!/bin/bash

deepspeed llava/train/train_mem.py \
    --deepspeed ./scripts/zero3.json \
    --model_name_or_path lmsys/vicuna-13b-v1.5 \
    --version v1 \
    --data_path ./playground/data/llava_v1_5_mix665k.json \
    --image_folder ./playground/data \
    --vision_tower openai/clip-vit-large-patch14-336 \
    --pretrain_mm_mlp_adapter ./checkpoints/llava-v1.5-13b-pretrain/mm_projector.bin \
    --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 True \
    --bf16 True \
    --output_dir ./checkpoints/llava-v1.5-13b \
    --num_train_epochs 1 \
    --per_device_train_batch_size 16 \
    --per_device_eval_batch_size 4 \
    --gradient_accumulation_steps 1 \
    --evaluation_strategy "no" \
    --save_strategy "steps" \
    --save_steps 50000 \
    --save_total_limit 1 \
    --learning_rate 2e-5 \
    --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

5)实际部署步骤

  • 整体模型示意图
    在这里插入图片描述
    ①前端UI Server是Gradio
    ②API服务器作为中转的controller
    ③Model Worker服务器是作为不同端口不同模型下的服务器

  • 启动步骤

①启动API Sever

python -m llava.serve.controller --host 0.0.0.0  --port 10000

②启动WebUI(链接llava-v1.5-7b)

python -m llava.serve.model_server  
	--host 0.0.0.0  
	--controller http://localhost:10000  
	--port 40000  
	--worker http://localhost:40000
	--model_path liuhaotian/llava-1.5-13b

③启动woker

python -m llava.serve.model_worker --host 0.0.0.0
	-controller http://localhost:10000  
	--port <different from 40000 ,say 400001>
	-worker http://localhost:<change accordingly ,i.e. 40001>
	-model_path  <ckpt2>
	--load-4bit #加载4比特

6)llava模型评测

在这里插入图片描述+ 总结
GPT-4基于30张图片的对话、详细描述、推理来进行与LLaVA结果比对打本,大体上两者有85%的相似

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值