在英特尔加速器上微调 Meta Llama 3.2-Vision-Instruct 多模态大型语言模型
在本文中,我将通过代码向您展示如何在英特尔® Gaudi® 2 AI 处理器上,使用图像-字幕数据集微调多模态大型语言模型 (MLLM) Meta Llama-3.2 11B Vision Instruct。是的,Llama 3.3 最近发布了!但 Vision Instruct 版本尚未发布。尽管意义重大,但我不会在本文中花费时间介绍如何从 PDF 文档中提取图像和字幕;相反,我将重点关注实际的微调过程,以及如何使用英特尔® Gaudi® 2 AI 处理器加速该过程。为了高效训练,我使用了低秩适应 (LoRA)。我准备了一个 Docker 容器,并将分享我的策略和代码,以便您也可以微调 Llama-3.2 模型或 Hugging Face 上的其他多模态模型。
概述:
- 什么是多模态大型语言模型?
- Llama 模型 - 在 Hugging Face 上获取 Meta Llama 模型访问权限。
- Docker – 设置环境以构建 Docker 镜像并运行 Docker 容器。
- 数据集 - 使用 Hugging Face 上的图像-字幕数据集。
- 微调 - 微调 Llama-3.2 11B Vision Instruct 模型。
- 推理 - 在微调前后测试模型。
- 亲自动手尝试 - 在 Intel Tiber AI Cloud 上尝试最新的英特尔 AI 加速器。
什么是多模态大型语言模型?
多模态大型语言模型 (MLLM) 是大型语言模型 (LLM) 的扩展,例如 OpenAI GPT-4 和 Llama 3,以融合文本以外的其他媒体。MLLM 将 LLM 的推理能力扩展到包含图像、音频和视频输入和输出。就本文的微调而言,我专注于 MLLM 的一个特定子类别,称为视觉语言模型,简称 VLM。VLM 从图像和文本中学习,并生成描述图像内容或基于图像和文本输入回答问题的文本输出。这里感兴趣的 VLM 是 Llama-3.2 11B Vision Instruct,它经过专门训练以回答有关图像的问题。例如,可以向 VLM 提示“描述图像中正在描绘的过程。”
Llama 模型
要使用 Meta Llama 模型,您首先需要在 Hugging Face 上请求访问权限。您可以按照 Meta 在其 Hugging Face 组织卡片上的说明进行操作:https://huggingface.co/meta-llama 以获取对其模型的访问权限。然后,从您的 Hugging Face 个人资料设置中生成访问令牌。选择屏幕右上角的个人资料头像,然后选择“访问令牌”。点击“+ 创建新令牌”,然后选择“读取您可访问的所有公共受限仓库的内容”。我建议将生成的令牌保存在隐藏文件中。
Docker
接下来,让我们了解环境和 Docker 设置。我正在使用 Ubuntu 22.04 的 Linux 环境中运行,并拥有 8 块 Intel Gaudi 2 显卡。类似于 NVIDIA GPU 的 nvidia-smi
,我可以运行 hl-smi
来查看 8 块 Intel Gaudi 显卡的状态。输出应类似于
+-----------------------------------------------------------------------------+
| HL-SMI Version: hl-1.18.0-fw-53.1.1.1 |
| Driver Version: 1.18.0-ee698fb |
|-------------------------------+----------------------+----------------------+
| AIP Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | AIP-Util Compute M. |
|===============================+======================+======================|
| 0 HL-225 N/A | 0000:cc:00.0 N/A | 0 |
| N/A 26C N/A 90W / 600W | 768MiB / 98304MiB | 0% N/A |
|-------------------------------+----------------------+----------------------+
| 1 HL-225 N/A | 0000:44:00.0 N/A | 0 |
| N/A 24C N/A 88W / 600W | 768MiB / 98304MiB | 0% N/A |
|-------------------------------+----------------------+----------------------+
| 2 HL-225 N/A | 0000:1a:00.0 N/A | 0 |
| N/A 28C N/A 89W / 600W | 768MiB / 98304MiB | 0% N/A |
|-------------------------------+----------------------+----------------------+
| 3 HL-225 N/A | 0000:b4:00.0 N/A | 0 |
| N/A 27C N/A 85W / 600W | 768MiB / 98304MiB | 0% N/A |
|-------------------------------+----------------------+----------------------+
| 4 HL-225 N/A | 0000:19:00.0 N/A | 0 |
| N/A 24C N/A 66W / 600W | 768MiB / 98304MiB | 0% N/A |
|-------------------------------+----------------------+----------------------+
| 5 HL-225 N/A | 0000:b3:00.0 N/A | 0 |
| N/A 25C N/A 87W / 600W | 768MiB / 98304MiB | 0% N/A |
|-------------------------------+----------------------+----------------------+
| 6 HL-225 N/A | 0000:43:00.0 N/A | 26 |
| N/A 29C N/A 278W / 600W | 98304MiB / 98304MiB | 41% N/A |
|-------------------------------+----------------------+----------------------+
| 7 HL-225 N/A | 0000:cd:00.0 N/A | 0 |
| N/A 25C N/A 95W / 600W | 768MiB / 98304MiB | 0% N/A |
|-------------------------------+----------------------+----------------------+
| Compute Processes: AIP Memory |
| AIP PID Type Process name Usage |
|=============================================================================|
| 0 N/A N/A N/A N/A |
| 1 N/A N/A N/A N/A |
| 2 N/A N/A N/A N/A |
| 3 N/A N/A N/A N/A |
| 4 N/A N/A N/A N/A |
| 5 N/A N/A N/A N/A |
| 6 N/A N/A N/A N/A |
| 7 N/A N/A N/A N/A |
+=============================================================================+
创建一个包含必要 Python 包的 requirements.txt
文件
huggingface_hub[cli]==0.27.0
optimum-habana==1.15.0
peft==0.14.0
Levenshtein==0.26.1
sentencepiece!=0.1.92
git+https://github.com/HabanaAI/DeepSpeed.git@1.19.0
我假设您已经在 Linux 系统上安装了 Docker。如果没有,您可以按照 Docker 文档 中的步骤进行操作。参考英特尔 Gaudi 文档中的 指南,我创建了一个 Dockerfile
,这样我就可以轻松复制我的工作并在容器中运行微调。请注意,您可能需要更新 Dockerfile
中的版本号。我首先创建镜像,然后交互式地进入 Docker 容器以试验我正在运行的脚本。如果您愿意,您可以让 Docker 容器为您运行所有脚本,但我想在设置环境后手动与其交互。
# Get the Gaudi Docker image for Ubuntu 22.04
FROM vault.habana.ai/gaudi-docker/1.19.0/ubuntu22.04/habanalabs/pytorch-installer-2.5.1:latest
# Set environment variables
ENV HABANA_VISIBLE_DEVICES=all
ENV OMPI_MCA_btl_vader_single_copy_mechanism=none
# Set working directory in container
WORKDIR /app/home
# Copy the current directory into the container at /app/home. This ensures we copy requirements.txt to be able to install packages later.
COPY . .
# Specify a mount point in the container
VOLUME ["/app/home"]
# Clone optimum-habana to easily run some of the scripts
RUN git clone https://github.com/huggingface/optimum-habana
# Install python packages
RUN pip install -r requirements.txt
现在,我们已准备好创建 Docker 镜像,然后运行并基于该镜像创建一个 Docker 容器。要创建 Docker 镜像,您可以运行
docker build -t llama32-visioninstruct-image .
然后,要交互式地创建和运行容器,您可以运行
docker run -it --runtime=habana llama32-visioninstruct-image
这是一个简短的剪辑,展示了如何在命令行启动 Docker 以及 8 个可用的 Gaudi 卡。
现在,您应该在 Docker 容器中有一个命令行提示符。您现在可以输入 Hugging Face 令牌以获取 Llama 模型的访问权限。由于 Hugging Face CLI 是从 requirements.txt
文件安装的,请运行以下登录命令
huggingface-cli login
然后复制粘贴您的 Hugging Face 令牌,您应该可以访问 Llama 模型了。
数据集
用于微调 Llama-3.2 11B Vision Instruct 模型的数据集来自 nielsr/docvqa_1200_examples 的图像-字幕对。训练集中共有 1000 对图像-字幕对,测试集中有 200 对图像-字幕对。描述数据集的最佳方式是展示一个图像-字幕对的示例。这是训练集中的一个示例(train_1125),其下方是相应的字幕
微调
为了通过无需从头开始重新训练整个架构来提高微调效率,我使用了 低秩适应 (LoRA)
[LoRA] 冻结预训练模型权重,并将可训练的秩分解矩阵注入到 Transformer 架构的每一层中,从而大大减少了下游任务的可训练参数数量。
运行该示例的 Python 代码直接取自 Optimum for Intel® Gaudi® AI Accelerator 图像到文本示例。我在 Docker 容器中运行了以下脚本进行微调。这是示例代码
python3 optimum-habana/examples/gaudi_spawn.py \
--world_size 8 --use_mpi optimum-habana/examples/image-to-text/run_image2text_lora_finetune.py \
--model_name_or_path meta-llama/Llama-3.2-11B-Vision-Instruct \
--dataset_name nielsr/docvqa_1200_examples \
--bf16 True \
--output_dir ./model_lora_llama_11b \
--num_train_epochs 2 \
--per_device_train_batch_size 2 \
--per_device_eval_batch_size 1 \
--gradient_accumulation_steps 16 \
--weight_decay 0.01 \
--logging_steps 25 \
--eval_strategy "no" \
--save_strategy "no" \
--learning_rate 5e-5 \
--warmup_steps 50 \
--lr_scheduler_type "constant" \
--input_column_names 'image' 'query' \
--output_column_names 'answers' \
--remove_unused_columns False \
--do_train \
--do_eval \
--use_habana \
--use_lazy_mode \
--lora_rank=8 \
--lora_alpha=8 \
--lora_dropout=0.1 \
--low_cpu_mem_usage True \
--max_seq_length=512 \
下载基础模型(大约 10 分钟)后,在 8 块 Intel Gaudi 2 显卡上训练大约需要 20 分钟。训练结束时的输出如下
[2025-01-28 16:09:05,995] [INFO] [real_accelerator.py:203:get_accelerator] Setting ds_accelerator to hpu (auto detect)
[INFO|trainer.py:826] 2025-01-28 16:09:10,247 >> ***** Running training *****
[INFO|trainer.py:827] 2025-01-28 16:09:10,247 >> Num examples = 1,000
[INFO|trainer.py:828] 2025-01-28 16:09:10,247 >> Num Epochs = 2
[INFO|trainer.py:829] 2025-01-28 16:09:10,247 >> Instantaneous batch size per device = 2
[INFO|trainer.py:832] 2025-01-28 16:09:10,247 >> Total train batch size (w. parallel, distributed & accumulation) = 256
[INFO|trainer.py:833] 2025-01-28 16:09:10,247 >> Gradient Accumulation steps = 16
[INFO|trainer.py:834] 2025-01-28 16:09:10,247 >> Total optimization steps = 6
[INFO|trainer.py:835] 2025-01-28 16:09:10,255 >> Number of trainable parameters = 26,214,400
100%|██████████| 6/6 [07:20<00:00, 46.81s/it][INFO|trainer.py:1123] 2025-01-28 16:16:30,543 >>
Training completed. Do not forget to share your model on huggingface.co/models =)
{'train_runtime': 451.3828, 'train_samples_per_second': 4.431, 'train_steps_per_second': 0.013, 'train_loss': 2.194087028503418, 'epoch': 1.52, 'memory_allocated (GB)': 47.11, 'max_memory_allocated (GB)': 92.95, 'total_memory_available (GB)': 94.62}
100%|██████████| 6/6 [07:31<00:00, 75.24s/it]
[INFO|trainer.py:1656] 2025-01-28 16:16:41,712 >> Saving model checkpoint to ./model_lora_llama_11b
[INFO|configuration_utils.py:125] 2025-01-28 16:16:57,573 >> Configuration saved in ./model_lora_llama_11b/gaudi_config.json
***** train metrics *****
epoch = 1.5238
max_memory_allocated (GB) = 92.95
memory_allocated (GB) = 47.11
total_flos = 44372460GF
total_memory_available (GB) = 94.62
train_loss = 2.1941
train_runtime = 0:07:31.38
train_samples_per_second = 4.431
train_steps_per_second = 0.013
01/28/2025 16:17:12 - INFO - __main__ - generated: ['\n\nBengaluru']
100%|██████████| 200/200 [04:10<00:00, 1.25s/it]
***** eval metrics *****
eval_accuracy = 0.9142
推理
现在我们已经有了 Llama-3.2 11B Vision Instruct 模型的微调版本,我们应该在未见过的(测试)数据上测试这两个模型。测试数据集总共有 200 个样本。我对两个模型都使用了相同的提示
Answer briefly. Which brand has 10x Vitamin E in the picture?
这是一张测试图像(val_146),两个模型的答案,以及原始字幕。
两个模型在这种情况下都表现良好。Llama-3.2 模型在答案中更详细,但我们在提示中要求模型简明扼要。微调模型可能遵循其标记的训练数据,其中答案更简洁,因为它只用一个词回答。
亲自动手尝试
我们成功地通过一个实际操作的例子,在英特尔 AI 加速器上微调了 Llama-3.2 11B Vision Instruct 多模态大型语言模型。您可以在 Intel® Tiber™ AI Cloud 上亲自尝试功能强大的英特尔加速器。有关新帐户入门的文档可在此处找到:此处,有关更多英特尔 AI 软件文档和教程,请参阅 英特尔 AI 开发资源。
欢迎加入英特尔 Discord 服务器:Intel DevHub,与其他开发者交流。
此外,请随时在下面的文章中发表评论,或通过 领英 与我联系。祝您编程愉快!