重要提示
您正在查看 NeMo 2.0 文档。此版本对 API 和新的库 NeMo Run 进行了重大更改。我们目前正在将 NeMo 1.0 中的所有功能移植到 2.0。有关先前版本或 2.0 中尚不可用的功能的文档,请参阅 NeMo 24.07 文档。
NeVA (LLaVA)#
NeVA 源自 LLaVA v1.5 (大型语言和视觉助手),是 NeMo 多模态生态系统的关键补充。此模型集成了以大型语言为中心的模型(如 Nemotron、Llama 3、Mistral 等)与视觉编码器,并使用机器生成的多模态语言-图像指令跟随数据进行训练。NeVA 在 LLaVA 奠定的基础上,通过利用 NeMo LLM 框架的功能(如模型并行、序列并行、激活检查点、AMP O2、CuDNN/Flash Attention 等)进一步增强了训练。
从 Hugging Face 导入到 NeMo 2.0#
要导入 Hugging Face (HF) 模型并将其转换为 NeMo 2.0 格式,请运行以下命令。此步骤只需执行一次
from nemo.collections.llm import import_ckpt
from nemo.collections import vlm
if __name__ == '__main__':
# Specify the Hugging Face model ID
hf_model_id = "llava-hf/llava-1.5-7b-hf"
# Import the model and convert to NeMo 2.0 format
import_ckpt(
model=vlm.LlavaModel(vlm.Llava15Config7B()), # Model configuration
source=f"hf://{hf_model_id}", # Hugging Face model source
)
上面的命令将转换后的文件保存在 NeMo 缓存文件夹中,位置:~/.cache/nemo
。
如果需要,您可以通过在运行脚本之前设置 NEMO_CACHE_DIR
环境变量来更改默认缓存目录。
NeMo 2.0 微调配方#
我们提供了使用 NeMo 2.0 和 NeMo-Run 微调 LLaVA v1.5 的预定义配方。这些配方为 NeMo 2.0 中引入的 nemo.collections.llm api 函数之一配置了 run.Partial
。这些配方托管在 llava15_7b 和 llava15_11b 文件中。这些配方使用模拟数据集进行训练。
注意
这些配方使用 MockDataModule
作为 data
参数。您需要将 MockDataModule
替换为您自定义的数据集。
默认情况下,加载非指令版本的模型。要加载不同的模型,请设置 finetune.resume.restore_config.path=nemo://<hf_model_id>
或 finetune.resume.restore_config.path=<local_model_path>
。
我们在下面提供了一个示例,说明如何调用默认配方并覆盖数据参数
from nemo.collections import vlm
finetune = vlm.llava15_7b.finetune_recipe(
name="llava15_7b_finetune",
dir=f"/path/to/checkpoints",
num_nodes=1,
num_gpus_per_node=8,
peft_scheme='lora', # 'lora', 'none'
)
默认情况下,微调配方将 LoRA 应用于语言模型中的所有线性层,包括交叉注意力层,同时保持视觉模型不冻结。
配置要应用 LoRA 的层:设置
finetune.peft.target_modules
。例如,要仅对自注意力 qkv 投影层应用 LoRA,请设置finetune.peft.target_modules=["*.language_model.*.linear_qkv"]
。冻结视觉模型:设置
finetune.peft.freeze_vision_model=True
。在没有 LoRA 的情况下微调整个模型:在配方参数中设置
peft_scheme='none'
。
注意
配方中的配置是使用 NeMo-Run run.Config
和 run.Partial
配置对象完成的。请查看 NeMo-Run 文档,以了解有关其配置和执行系统的更多信息。
一旦您准备好最终配置,您就可以在任何 NeMo-Run 支持的执行器上执行它。最简单的是本地执行器,它只是在本地的单独进程中运行预训练。您可以按如下方式使用它
import nemo_run as run
run.run(finetune, executor=run.LocalExecutor())
此外,您也可以在同一个 Python 进程中直接运行它,如下所示
run.run(finetune, direct=True)
自带数据#
将默认配方中的 MockDataModule
替换为您自定义的数据集。下面,我们展示了一个使用类似 llava 数据集的示例
from nemo.collections import vlm
# Define the fine-tuning recipe
finetune = vlm.llava15_7b.finetune_recipe(
name="llava15_7b_finetune",
dir="/path/to/checkpoints",
num_nodes=1,
num_gpus_per_node=8,
peft_scheme='lora', # 'lora', 'none'
)
# The following is an example of a custom dataset configuration.
data_config = vlm.ImageDataConfig(
image_folder="/path/to/images",
conv_template="v1", # Customize based on your dataset needs
)
# Data module setup
custom_data = vlm.NevaLazyDataModule(
paths="/path/to/dataset.json", # Path to your dataset
data_config=data_config,
seq_length=2048,
global_batch_size=16, # Global batch size
micro_batch_size=1, # Micro batch size
tokenizer=None, # Define your tokenizer if needed
image_processor=None, # Add an image processor if required
num_workers=8, # Number of workers for data loading
)
# Assign custom data to the fine-tuning recipe
finetune.data = custom_data
使用 Energon 数据加载器#
Energon 数据加载器可以与 NeVA 一起使用,以处理用于训练的多模态数据集。本节介绍如何设置和自定义数据加载器,重点介绍关键组件,例如 task_encoder 和 multimodal_sample_config。有关准备数据以与数据模块一起使用的详细信息,请参阅 数据准备 部分。
下面是如何将 Energon 数据加载器与 NeVA 一起用于训练的示例
from nemo.collections.multimodal.data.energon import (
ImageToken,
MultiModalSampleConfig,
EnergonMultiModalDataModule,
)
from transformers import AutoProcessor
# Load processor, tokenizer, and image processor from pre-trained model
processor = AutoProcessor.from_pretrained("llava-hf/llava-1.5-7b-hf")
tokenizer = processor.tokenizer
image_processor = processor.image_processor
# Define dataset path
dataset_path = "<path_to_dataset>"
# Configure multimodal samples
config = MultiModalSampleConfig(
image_token=ImageToken(token_str="<image>", token_id=-200),
ignore_place_holder=-100
)
# Initialize the data module
data_module = EnergonMultiModalDataModule(
path=dataset_path,
tokenizer=tokenizer,
image_processor=image_processor,
seq_length=2048,
micro_batch_size=1,
global_batch_size=16,
num_workers=0,
multimodal_sample_config=config,
)
# Note: `EnergonMultiModalDataModule` defaults to `MultiModalTaskEncoder` if no custom task encoder is provided.
path: 数据集的路径。
tokenizer: 用于处理文本数据的分词器。
`image_processor`: 图像处理器,用于预处理图像并准备它们以输入到视觉模型。ImageProcessor。
seq_length: 标记化文本的最大序列长度(默认值:2048)。
micro_batch_size`: 每个 GPU 或进程的批大小(默认值:1)。
global_batch_size: 所有 GPU 或进程的总批大小(默认值:1)。
num_workers: 用于数据加载的工作进程数(默认值:1)。
multimodal_sample_config: 多模态样本的配置,允许自定义图像标记、占位符值和模板配置。
task_encoder: 如果需要,可以提供自定义任务编码器。默认情况下,EnergonMultiModalDataModule 使用 MultiModalTaskEncoder。
任务编码器: MultiModalTaskEncoder 是一种灵活的编码器,能够处理各种多模态样本类型,例如 VQA、字幕、交错和相似性交错样本。默认情况下,如果没有提供自定义任务编码器,则 task_encoder 默认为 MultiModalTaskEncoder。这使得入门变得容易,同时仍然允许为高级用例进行自定义。
它足够灵活,可以为新的样本类型注册其他自定义编码器。编码器将样本处理成批次,并准备它们以输入到 NeVA 模型。有关样本类型的更多详细信息,请参阅 Energon 文档 - Megatron-Energon 样本类型。
这种模块化设计确保它可以适应各种多模态训练场景。
MultiModalSampleConfig: MultiModalSampleConfig 定义了多模态样本的配置。它包括以下默认值,可以根据需要进行自定义
image_token: 图像的默认标记配置。默认情况下,图像的占位符字符串是字符串
'<image>'
,标记 ID 为-200
。ignore_place_holder: 默认值为 -100,用于表示在损失计算期间要忽略的占位符标记。
conversation_template_config: 默认值为
LLaVATemplateConfig
。此配置用于多模态对话模板,用于在标记化之前将提示模板应用于输入文本。如果提供了 conversation_template_config,它将用于生成对话提示。否则,如果分词器定义了聊天模板 (tokenizer.chat_template),则将使用分词器的聊天模板。如果分词器和 conversation_template_config 都没有定义聊天模板,则会为 VQA 样本引发 ValueError。image_following_text: 一个布尔值,指示图像标记是否应跟随文本标记。它默认为
True
。
以下是对话模板配置的示例
class BaseConversationTemplateConfig: """Conversation template config related parameters""" system: Optional[str] = ( "A chat between a curious user and artificial assistant agent. The assistant gives helpful, detailed, and polite answers to user's questions.".format() ) # fmt: off roles: List[str] = field(default_factory=lambda: ['user', 'assistant']) stop_string: str = "</s>" chat_template = """ {%- for message in messages %} {%- if message['role'] == 'system' %} {{- message['content'].strip() + ' ' -}} {%- elif message['role'] == 'user' %} {{- 'USER: ' -}} {{- message['content'].strip() + ' ' -}} {%- elif message['role'] == 'assistant' %} {{- 'ASSISTANT: ' -}} {{- message['content'].strip() -}} {{- '</s>' -}} {%- endif %} {%- endfor -%} """
此配置包括以下参数
system: 一个字符串,用于定义系统的描述或目的,例如“好奇用户和人工智能助理代理之间的聊天。”
roles: 对话中的角色列表(默认值:[‘user’, ‘assistant’])。
stop_string: 一个字符串,用于指示对话的结束(默认值:</s>)。
chat_template: 一个 Jinja2 模板,用于将对话格式化为一系列消息,以进行输入标记化。
如果提供了 conversation_template_config,它将优先使用并用于格式化对话。
如果未提供 conversation_template_config,但存在 tokenizer.chat_template,则将使用分词器的模板。
如果 conversation_template_config 和 tokenizer.chat_template 都不存在,则会为 VQA 样本引发 ValueError。
支持的功能#
序列打包:有关更多信息,请参阅 在 NeVA 中使用打包序列运行 SFT/PEFT。
其他模型并行性:请查看我们的 示例微调脚本,以获取有关设置其他模型并行性的完整示例。
序列并行:在
MegatronStrategy
中添加sequence_parallel=True
from nemo import lightning as nl strategy = nl.MegatronStrategy( tensor_model_parallel_size=tp_size, pipeline_model_parallel_size=pp_size, ... sequence_parallel=True, )
上下文并行:在
MegatronStrategy
中添加context_parallel_size=cp_size
from nemo import lightning as nl strategy = nl.MegatronStrategy( tensor_model_parallel_size=tp_size, pipeline_model_parallel_size=pp_size, ... context_parallel_size=cp_size, )
上下文并行当前仅适用于语言模型。视觉编码器将在这些 rank 上复制。我们正在研究更好的策略。
虚拟流水线并行:在
MegatronStrategy
中添加virtual_pipeline_model_parallel_size=vpp_size
from nemo import lightning as nl strategy = nl.MegatronStrategy( tensor_model_parallel_size=tp_size, pipeline_model_parallel_size=pp_size, ... virtual_pipeline_model_parallel_size=vpp_size, )
支持的视觉编码器:NeMo 支持以下视觉编码器
CLIPViT 视觉编码器(Hugging Face 和 Megatron Core 后端)
SigLIPViT 视觉编码器(Megatron Core 后端)
InternViT 视觉编码器(Megatron Core 后端)
您可以定义相应的视觉 Transformer 配置,并将其插入到 Neva 配置的定义中。请查看我们的 示例微调脚本,以获取完整示例。
对于 Megatron 后端模型,您必须首先将模块权重转换为 NeMo 格式,然后再使用 vision_model_from_pretrained 加载它们,否则视觉编码器内部将是随机权重。以下是将 InternViT 转换的示例;类似的步骤适用于 CLIP 和 SigLIP。
from nemo.collections import vlm from nemo.collections.llm import import_ckpt if __name__ == '__main__': model_id = "OpenGVLab/InternViT-300M-448px-V2_5" model = vlm.InternViTModel(vlm.InternViT_300M_448px_Config()) import_ckpt(model=model, source=f'hf://{model_id}', )
上面的命令将转换后的文件保存在 NeMo 缓存文件夹中,位置:
~/.cache/nemo
。from nemo.collections import vlm vision_transformer_config = vlm.HFCLIPVisionConfig( pretrained_model_name_or_path="openai/clip-vit-large-patch14-336" # Change model ID here ) neva_config = vlm.NevaConfig( vision_transformer_config=vision_transformer_config, ... )
from nemo.collections import vlm vision_transformer_config = vlm.CLIPViTL_14_336_Config() neva_config = vlm.NevaConfig( vision_transformer_config=vision_transformer_config, vision_model_from_pretrained="/path/to/converted/clip_vit_model", ... )
from nemo.collections import vlm vision_transformer_config = vlm.CLIPViTL_14_336_Config() neva_config = vlm.NevaConfig( vision_transformer_config=vision_transformer_config, vision_model_from_pretrained="/path/to/converted/siglip_vit_model", ... )
from nemo.collections import vlm vision_transformer_config = vlm.InternViT_300M_448px_Config() neva_config = vlm.NevaConfig( vision_transformer_config=vision_transformer_config, vision_model_from_pretrained="/path/to/converted/intern_vit_model", ... )
FP8 训练:要启用 FP8 训练,您需要配置
MegatronMixedPrecision
插件并设置适当的 FP8 参数。有关更多详细信息,请查看 Transformer Engine 用户指南。
from nemo import lightning as nl
import torch
trainer = nl.Trainer(
num_nodes=1,
devices=8,
...
plugins=nl.MegatronMixedPrecision(
precision="bf16-mixed",
params_dtype=torch.bfloat16,
fp8='hybrid',
fp8_amax_history_len=16,
fp8_amax_compute_algo="max",
),
)
以下是我们目前支持或计划很快支持的预训练配方的完整列表
配方 |
状态 |
---|---|
LLaVA 1.5 7B LoRA |
是 |
LLaVA 1.5 7B 完全微调 |
是 |
LLaVA 1.5 11B LoRA |
是 |
LLaVA 1.5 11B 完全微调 |
是 |