跳至主要内容

微调 Llama 3.2 Vision

学习如何使用 Unsloth 框架在 Amazon 产品数据集上微调 Meta AI 的多模态模型。
· 10分钟 阅读

使用 AI 探索

我们已经探讨了许多关于微调大型语言模型(LLM)的指南,但很少有资源涵盖微调多模态模型的流程。在本教程中,我们将介绍一款最前沿的多模态模型——Llama 3.2 Vision,并演示如何使用 Amazon 产品数据集对其进行微调。我们的目标是构建一个产品描述生成器,为 Amazon 上架的商品提供准确且简洁的图像说明。

如果您是第一次微调 LLM,请先学习Fine-tuning with Llama 3课程,熟悉常见的方法和术语。您也可以查看我们的Llama 3.2 90B 教程,其中介绍了如何使用 Streamlit 构建前端图像描述应用,使用 Llama 3.2 90B 生成描述,并以 Groq 作为 API。

微调 Llama 3.2 Vision 特色图片

图片由作者提供

了解 Llama 3.2 Vision 模型

Llama 3.2引入了多模态模型,能够处理图像和文本数据,生成自然且准确的响应。Llama 3.2 视觉模型提供 11B 和 90B 两种参数规模,专为高精度处理图像推理场景而设计。在常见行业基准上,这些模型优于许多现有的开源和闭源多模态模型。

阅读Llama 3.2 指南:工作原理、用例与更多,深入了解所有模型变量。

Llama 3.2 视觉模型擅长文档级理解、图表分析、图像描述和视觉定位等任务,其中通过自然语言描述来定位图像中的对象。

Llama 3.2 Vision 模型架构

Llama 3.2 Vision 模型构建于较早的仅文本 Llama 3.1 之上,后者是一种采用 Transformer 架构的高级语言模型。它通过有监督学习(SFT)和结合人类反馈的强化学习(RLHF)进行微调,以符合人类在有用性和安全性方面的偏好。

为支持图像识别,Llama 3.2 Vision 集成了单独训练的视觉适配器。该适配器使用交叉注意力层将图像编码器的输出融入预训练的 Llama 3.1 语言模型,使其能够高效处理基于文本与图像的任务。

Llama 3.2 Vision 的关键特性

  • 图像理解:能够轻松识别和分类图像中的对象,支持图像描述与场景解读等任务。
  • 复杂 OCR 与图表理解:Llama 3.2 的 90B 版本在从图表等复杂可视化中提取洞见方面表现突出。
  • 文档理解:支持端到端 OCR(光学字符识别),可直接从文档中提取文本与数据。
  • 视觉定位:新模型允许用户定位对象或回答有关可视数据的问题。

Llama 3.2 Vision 模型用例

Llama 3.2 Vision 在视觉问答、文档分析、图像描述、图文检索和视觉定位等用例中表现出色。

  1. 视觉问答(VQA):基于对图像内容的理解来回答问题。
  2. 文档 VQA(DocVQA):分析地图或合同等文档,结合文本与版式来回答问题。
  3. 图像描述:通过提取细节并理解场景来生成自然语言描述。
  4. 图文检索:将图像与文本描述匹配,支持高级搜索与组织。
  5. 视觉定位:基于自然语言描述在图像中精准定位对象或区域。

在 Amazon 产品数据集上微调 Llama 3.2 Vision

在本项目中,我们将使用 Kaggle 作为编码与计算环境,Unsloth 作为微调框架,以及 Amazon 产品描述数据集。与传统方法相比,Unsloth 速度快、占用 GPU 内存少、代码量更少。

如果您想为文本生成方案微调 LLM,我们有一篇非常合适的教程:Fine-tuning Llama 3.2 and Using It Locally: A Step-by-Step Guide。

1. 环境准备

创建一个新的 Kaggle 笔记本,将加速器设置为使用两块 T4 GPU。将您的 Hugging Face 令牌添加为 Kaggle 机密,以便稍后可以安全地将模型推送到您的 Hugging Face 仓库。然后使用 pip 命令安装 unsloth Python 包。

%%capture
!pip install unsloth

阅读Unsloth 指南:优化并加速 LLM 微调,进一步了解 Unsloth。

2. 加载模型

在此设置中,我们加载的是 Llama-3.2-11B-Vision-Instruct 模型,具体为 Unsloth 提供的版本,已针对高效微调与推理进行优化。模型以 4 位量化方式加载,显著降低内存占用与计算需求,使在 T4 GPU 上运行大型视觉模型成为可能。

from unsloth import FastVisionModel
import torch

model, tokenizer = FastVisionModel.from_pretrained(
    "unsloth/Llama-3.2-11B-Vision-Instruct",
    load_in_4bit = True,
    use_gradient_checkpointing = "unsloth",
)

3. 配置 LoRA

LoRA(低秩适配)是一种高效微调大型预训练模型的技术,通过在模型特定部分引入可学习的低秩矩阵来实现。该方法轻量且计算效率高,支持在不修改预训练模型核心结构的情况下进行任务特定微调。

使用 LoRA 训练模型时,我们重点选择并微调特定组件,例如视觉层、语言层、注意力模块和 MLP 模块。这使我们能够以最小的架构改动将模型适配至特定任务。

model = FastVisionModel.get_peft_model(
    model,
    finetune_vision_layers     = True, 
    finetune_language_layers   = True, 
    finetune_attention_modules = True,
    finetune_mlp_modules       = True,
    r = 16,           
    lora_alpha = 16,
    lora_dropout = 0,
    bias = "none",
    random_state = 3443,
    use_rslora = False,
    loftq_config = None,
)

4. 加载数据集

从 Hugging Face Hub 加载philschmid/amazon-product-descriptions-vlm数据集,并仅选择前 500 个样本。该数据集包含产品图片、产品描述及其他必要信息。

from datasets import load_dataset
dataset = load_dataset("philschmid/amazon-product-descriptions-vlm", 
                       split = "train[0:500]")


dataset
Dataset({
    features: ['image', 'Uniq Id', 'Product Name', 'Category', 'Selling Price', 'Model Number', 'About Product', 'Product Specification', 'Technical Details', 'Shipping Weight', 'Variants', 'Product Url', 'Is Amazon Seller', 'description'],
    num_rows: 500
})

这是其中一张产品图片。

dataset[45]["image"]

玩具车图片

以下是其描述。

dataset[45]["description"]
'Authentic Dale Earnhardt Jr. 1:24 scale diecast car. Nationwide Raw Finish.  Collectible model car for racing fans.  Perfect gift for NASCAR enthusiasts.'

5. 处理数据集

现在,我们将处理仅包含文本和图像的数据集。提示模板包含用户问题、图像和产品描述。

instruction = """
You are an expert Amazon worker who is good at writing product descriptions. 
Write the product description accurately by looking at the image.
"""


def convert_to_conversation(sample):
    conversation = [
        {
            "role": "user",
            "content": [
                {"type": "text", "text": instruction},
                {"type": "image", "image": sample["image"]},
            ],
        },
        {
            "role": "assistant",
            "content": [{"type": "text", "text": sample["description"]}],
        },
    ]
    return {"messages": conversation}


pass


converted_dataset = [convert_to_conversation(sample) for sample in dataset]

新数据集不是表格形式,而是遵循类似 OpenAI 的提示风格。

converted_dataset[45]
{'messages': [{'role': 'user',
   'content': [{'type': 'text',
     'text': '\nYou are an expert Amazon worker who is good at writing product descriptions. \nWrite the product description accurately by looking at the image.\n'},
    {'type': 'image',
     'image': <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=500x302>}]},
  {'role': 'assistant',
   'content': [{'type': 'text',
     'text': 'Authentic Dale Earnhardt Jr. 1:24 scale diecast car. Nationwide Raw Finish.  Collectible model car for racing fans.  Perfect gift for NASCAR enthusiasts.'}]}]}

6. 微调前的模型推理

我们将从数据集中选取第 46 个样本,对其进行推理,评估在未微调情况下模型生成产品描述的能力。

FastVisionModel.for_inference(model)  # Enable for inference!

image = dataset[45]["image"]

messages = [
    {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "text", "text": instruction},
        ],
    }
]
input_text = tokenizer.apply_chat_template(
    messages, add_generation_prompt=True
)
inputs = tokenizer(
    image,
    input_text,
    add_special_tokens=False,
    return_tensors="pt",
).to("cuda")

from transformers import TextStreamer

text_streamer = TextStreamer(tokenizer, skip_prompt=True)
_ = model.generate(
    **inputs,
    streamer=text_streamer,
    max_new_tokens=128,
    use_cache=True,
    temperature=1.5,
    min_p=0.1
)

生成的描述既冗长又不准确,写作风格也不一致。

The image showcases a race car featuring the well-known sponsorship branding "Nationwide," likely the primary vehicle in the Nationwide Series. The vehicle has a blue hood with the "Nationwide" logo prominently displayed and white text that reads, "on your side," on the windscreen. The car is predominantly white and grey, adorned with sponsor decals on various parts of the vehicle.

The front grille showcases the Chevrolet "Bowtie" logo, and the car is equipped with Chevrolet emblems and other sponsor decals, including:

• A white 88 logo on the front windscreen

Notably, the vehicle's wheels are equipped with "GoodYear

7. 配置微调所需的模型设置

现在我们将设置模型训练,并初始化有监督微调(SFT)训练器,结合自定义的数据整理器、数据集与训练配置,为高效微调做好准备。

from unsloth import is_bf16_supported
from unsloth.trainer import UnslothVisionDataCollator
from trl import SFTTrainer, SFTConfig

FastVisionModel.for_training(model)  # Enable for training!

trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    data_collator=UnslothVisionDataCollator(model, tokenizer),  # Must use!
    train_dataset=converted_dataset,
    args=SFTConfig(
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        warmup_steps=5,
        max_steps=30,
        learning_rate=2e-4,
        fp16=not is_bf16_supported(),
        bf16=is_bf16_supported(),
        logging_steps=5,
        optim="adamw_8bit",
        weight_decay=0.01,
        lr_scheduler_type="linear",
        seed=3407,
        output_dir="outputs",
        report_to="none",  # For Weights and Biases
        remove_unused_columns=False,
        dataset_text_field="",
        dataset_kwargs={"skip_prepare_dataset": True},
        dataset_num_proc=4,
        max_seq_length=2048,
    ),
)

8. 训练模型

运行 trainer.train() 启动训练过程。

trainer_stats = trainer.train()

模型在 16 分钟内完成了一个 epoch,训练损失逐步下降,结果不错。

模型微调训练损失。

9. 微调后的模型推理

现在我们来测试模型,以确认微调是否成功。我们将选取数据集中的同一张图片,对其进行推理。

FastVisionModel.for_inference(model)  # Enable for inference!

image = dataset[45]["image"]

messages = [
    {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "text", "text": instruction},
        ],
    }
]
input_text = tokenizer.apply_chat_template(
    messages, add_generation_prompt=True
)
inputs = tokenizer(
    image,
    input_text,
    add_special_tokens=False,
    return_tensors="pt",
).to("cuda")

from transformers import TextStreamer

text_streamer = TextStreamer(tokenizer, skip_prompt=True)
_ = model.generate(
    **inputs,
    streamer=text_streamer,
    max_new_tokens=128,
    use_cache=True,
    temperature=1.5,
    min_p=0.1
)

结果不错,但并非完全准确。话题标签没有必要。要获得最佳效果,需要在完整数据集上训练至少 3 个 epoch。

Bring the thrill of NASCAR racing to your desk or shelf with the 1/64 Die-Cast 2016 NASCAR 88 Dale Earnhardt Jr. Nationwide Chevrolet SS!  Highly detailed and precision engineered, this collectible die-cast car captures the iconic look of Earnhardt's famous No. 88 ride. Perfect for kids and adults alike, this miniature masterpiece makes a great gift. #NASCAR #DieCast #CollectibleCars #DaleEarnhardtJr #Nationwide<|eot_id|>

10. 保存模型与分词器

我们先将模型保存在本地,然后推送到 Hugging Face Hub。要将模型上传到 Hugging Face 服务器,需要使用我们的 Hugging Face 令牌登录。

通过阅读博文What is Hugging Face? The AI Community's Open-Source Oasis,探索 Hugging Face 这个面向机器学习与大型语言模型(LLM)的开源社区中心。

from huggingface_hub import login
from kaggle_secrets import UserSecretsClient
user_secrets = UserSecretsClient()

hf_token = user_secrets.get_secret("HUGGINGFACE_TOKEN")
login(hf_token)

之后,将模型与分词器保存在本地。

model.save_pretrained("llama_3.2_vision_amazon_product") # Local saving
tokenizer.save_pretrained("llama_3.2_vision_amazon_product")

然后使用 push_to_hub 将模型保存到 Hugging Face Hub。

model.push_to_hub(
    "kingabzpro/llama_3.2_vision_amazon_product"
)  # Online saving
tokenizer.push_to_hub(
    "kingabzpro/llama_3.2_vision_amazon_product"
)  # Online saving
Saved model to https://huggingface.co/kingabzpro/llama_3.2_vision_amazon_product

上述命令将创建新的模型仓库,并将所有文件推送到 Hugging Face。

已在 Hugging Face Hub 上的微调视觉模型。

来源:kingabzpro/llama_3.2_vision_amazon_product

如果您在运行上述代码时遇到问题,请参考 Kaggle 笔记本:Fine-tuning Llama 3.2 Vision on Amazon Dataset

结语

微调 Llama 3.2 Vision 模型为诸多场景打开了大门,尤其是在需要同时利用图像与文本以获得相关且准确结果的情况下。通过在自定义数据集上微调,我们可以提升性能,并将风格适配于视觉问答(VQA)、文档 VQA(DocVQA)、图像描述与图文检索等应用。

在本教程中,我们深入了解了 Llama 3.2 Vision 模型,并在 Amazon 产品描述数据集上微调了 11B 版本,构建了一个高度定制的产品描述生成器,能够采用所需风格并提供准确的产品描述。

下一步,学习如何构建 AI 应用并使用 Docker 镜像将其部署到云端,请参阅指南:How to Deploy LLM Applications Using Docker: A Step-by-Step Guide。

Abid Ali Awan

作者

Abid Ali Awan

作为一名持证的数据科学家,我热衷于利用前沿技术打造创新的机器学习应用。凭借在语音识别、数据分析与报告、MLOps、对话式人工智能以及自然语言处理方面的扎实背景,我不断打磨构建智能系统的能力,力求带来切实影响。除技术专长外,我也擅长沟通,能够将复杂概念提炼为清晰、简明的表述。因此,我成为数据科学领域备受关注的博主,与不断壮大的数据专业人士社区分享洞见与实践经验。目前,我专注于内容创作与编辑,借助大语言模型打造有力且吸引人的内容,帮助企业与个人更好地发挥数据价值。

主题