VisualGLM¶
VisualGLM是由清华大学的GLM团队推出的一个新的多模态对话语言模型,支持图像、中文和英文的输入和输出。VisualGLM大幅度地提升了多模态对话的SOTA水平,创造了令人惊叹的效果,能够根据图像和文本的内容生成符合人类偏好的回答,成为了多模态领域的新时代引领者。 VisualGLM完全开源可商用,基于 Transformer 结构,语言模型部分基于 ChatGLM-6B ,具有 62 亿参数;图像部分通过训练 BLIP2-Qformer 构建起视觉模型与语言模型的桥梁,整体模型共 78 亿参数。
VisualGLM-6B¶
VisualGLM-6B 依靠来自于 CogView 数据集的30M高质量中文图文对,与300M经过筛选的英文图文对进行预训练,中英文权重相同。该训练方式较好地将视觉信息对齐到ChatGLM的语义空间;之后的微调阶段,模型在长视觉问答数据上训练,以生成符合人类偏好的答案。
前期准备¶
环境要求¶
硬件: Atlas 800T A2
MindSpore: 2.2.10
MindSpore Lite: 2.2.10
MindFormers: dev
Mindpet: 1.0.2
注: VisualGLM-6B推理可以在单卡上完成部署,全量微调至少需要8卡。
生成RANK_TABLE_FILE(多卡运行必须环节)¶
运行mindformers/tools/hccl_tools.py生成RANK_TABLE_FILE的json文件
# 运行如下命令,生成当前机器的RANK_TABLE_FILE的json文件
python mindformers/tools/hccl_tools.py --device_num "[0,8)"
注: 若使用ModelArts的notebook环境,可从 /user/config/jobstart_hccl.json
路径下直接获取rank table,无需手动生成
VisualGLM-6B 预训练权重下载和转换¶
1. 从huggingface下载tokenizer权重后转换¶
从HuggingFace网站下载visualglm 6b词库的文件 ice_text.model。 下载地址:https://huggingface.co/THUDM/visualglm-6b/tree/main
2. 从SAT仓库下载visualglm权重¶
推荐使用rclone工具下载模型
步骤
下载rclone工具 下载地址:https://rclone.org/downloads/ 根据服务器的类型和处理器,选择对应的文件。 下载完以后解压,把其中的脚本拷贝出来,放到执行目录下: cp rclone*/rclone /usr/local/bin/
创建rclone配置文件
在home目录创建rclone.conf文件
Windows系统对于的目录:C:\Users\用户名.config\rclone\rclone.conf;
linux系统对应的目录:~/.config/rclone/rclone.conf
配置内容,这里的配置不需要修改:
[r2]
type = s3
provider = Cloudflare
access_key_id = eb4d69e273848089c7f9b9599cdcd983
secret_access_key = 367e9b21fef313f187026320016962b47b74ca4ada7d64d551c43c51e195d7a5
endpoint = https://c8a00746a80e06c4632028e37de24d6e.r2.cloudflarestorage.com
acl = private
使用rclone脚本来下载权重文件
参数说明
THREAD_COUNT:下载的线程数量,可以根据实际带宽来调整。
cd 模型下载路径/
rclone copy -P --multi-thread-streams THREAD_COUNT --no-check-certificate -vv --size-only r2:/sat/visualglm-6b.zip ./
执行权重转换脚本
cd research/visualglm
python convert_weight.py --torch_path TORCH_CKPT_DIR --vit_mindspore_path VIT_CKPT_PATH --qformer_mindspore_path QFORMER_CKPT_PATH --glm_mindspore_path GLM_CKPT_PATH
参数说明
TORCH_CKPT_DIR: huggingface VisualGLM-6B权重保存目录路径,路径要指定到文件;
VIT_CKPT_PATH: vit模型mindspore权重文件保存路径,路径要指定到文件;
QFORMER_CKPT_PATH: qformer模型mindspore权重文件保存路径,路径要指定到文件;
GLM_CKPT_PATH: glm模型mindspore权重文件保存路径和名称,路径要指定到文件。
注意:
请安装torch=2.0.1和transformers=4.33.2版本,cuda版本11.6及以上
该脚本会在glm模型的路径下生成glm_6b_for_lite.ckpt文件,该权重是用于lite推理的。
MindSpore推理¶
接口说明请参考API接口
注意
图片路径:推理用的参考图片在代码仓库的examples路径下
提示词:每张图片都有一个对应的参考提示词,可以在example_inputs.jsonl文件找到
由于visualglm模型的权重需要用户自行下载,因此在启动前,请先行在配置文件中将权重的路径配置完成。 打开配置文件 research/visualglm/run_visualglm_6b_image_to_text_generation.yaml,修改如下:
替换/path/to/visualglm_qformer.ckpt为上面转换的qformer权重的实际路径
替换/path/to/visualglm_vit.ckpt为上面转换的vit权重的实际路径
替换/path/to/glm_6b.ckpt为上面转换的glm权重的实际路径
替换/path/to/ice_text.model为上面下载的ice_text.model的实际路径
model:
model_config:
type: VisualGLMConfig
#...
checkpoint_name_or_path: "/path/to/visualglm_qformer.ckpt" # visualglm qformer weight
vision_config:
#...
checkpoint_name_or_path: "/path/to/visualglm_vit.ckpt" # visualglm vit weight
text_config:
type: GLMConfig
#...
checkpoint_name_or_path: "/path/to/glm_6b.ckpt" # visualglm glm weight
processor:
type: VisualGLMProcessor
image_processor:
type: VisualGLMImageProcessor
image_size: 224 # input image size
tokenizer:
#...
checkpoint_name_or_path: "/path/to/ice_text.model"
如果使用增量推理,需要在配置文件中use_past值设置为True。
generate接口推理:
visualglm的generate接口使用脚本已集成在run_visualglm.py脚本中,运行此脚本命令:
cd research/visualglm
python run_visualglm.py --config CONFIG_PATH --image_path=IMAGE_PATH --prompt=PROMPT --device_id DEVICE_ID
#运行结果:
#['<img> </img>问:描述这张图片。\n答: 泰坦尼克号 电影截图']
# 运行结果
参数说明
CONFIG_PATH:yaml配置的路径,默认是run_visualglm_6b_image_to_text_generation.yaml
IMAGE_PATH:推理图片的路径,比如examples/titanic.jpg
PROMPT:提示词,比如”描述这张图片。”,注意要加引号
DEVICE_ID:NPU卡的编号,默认是0
pipeline接口推理
visualglm的pipeline接口推理已集成在run_visualglm_pipeline.py脚本中,运行此脚本命令示例:
cd research/visualglm
python run_visualglm_pipeline.py --config CONFIG_PATH --device_id DEVICE_ID --batch_size BATCH_SIZE --use_past True --seq_length SEQ_LENGTH \
--image_path IMAGE_PATH --prompt PROMPT
# 运行结果
#['<img> </img>问:描述这张图片。\n答: 泰坦尼克号 电影截图']
参数说明
CONFIG_PATH:yaml配置的路径,默认是run_visualglm_6b_image_to_text_generation.yaml
IMAGE_PATH:推理图片的路径,比如examples/titanic.jpg
PROMPT:提示词,比如”描述这张图片。”,注意要加引号
BATCH_SIZE: 图片批次的大小,默认是1
SEQ_LENGTH: token的长度,默认是32
DEVICE_ID:NPU卡的编号,默认是0
MindSpore Lite推理¶
ckpt转换为mindir¶
# 如果需要使用增量推理,配置文件中use_past设置为True
cd research/visualglm
python export_lite_model.py --mode export --use_past True --device_id DEVICE_ID --seq_length SEQ_LENGTH --batch_size BATCH_SIZE
参数说明
DEVICE_ID:NPU卡的编号,默认是0
SEQ_LENGTH:token长度,默认是32,建议设置512
BATCH_SIZE:批量推理的批次大小,默认是1
注意
设置use_past=True后会生成两个mindir的模型,分别在output/mindir_full_checkpoint和output/mindir_inc_checkpoint目录下。
反之不设置use_past或者use_past=False,则只生成mindir_full_checkpoint一个目录,且后续无法使用增量推理。
lite推理¶
step1. 新建context.cfg配置文件
[ascend_context]
plugin_custom_ops=All
provider=ge
[ge_session_options]
ge.exec.formatMode=1
ge.exec.precision_mode=must_keep_origin_dtype
ge.externalWeight=1
ge.exec.atomicCleanPolicy=1
step2. 配置glm模型路径
替换/path/to/glm_6b_for_lite.ckpt为实际的glm for lite模型的路径
model:
model_config:
#...
text_config:
type: GLMConfig
#...
checkpoint_name_or_path: "/path/to/glm_6b_for_lite.ckpt" # visualglm glm weight
step2. 使用shell命令启动推理
visualglm的lite推理已集成在run_visualglm_infer_lite脚本中,运行此脚本命令示例:
# 如果需要增量推理,使用inc_model_path指定路径,否则不需要
cd research
python run_visualglm_infer_lite.py --full_model_path FULL_MODEL_PATH --inc_model_path INC_MODEL_PATH \
--seq_length SEQ_LENGTH --ge_config context.cfg --device_id DEVICE_ID --image_path IMAGE_PATH --prompt PROMPT
# 运行结果:
#['<img> </img>问:描述这张图片。\n答: 泰坦尼克号 电影截图']
参数说明
FULL_MODEL_PATH:上面生成的全量模型的路径,比如:output/mindir_full_checkpoint_bs_1_512/rank_0_graph.mindir,这里中间路径会带上 batch_size和seq_length的后缀,比如batch_size为1,seq_length为512下路径为output/mindir_full_checkpoint_bs_1_512/rank_0_graph.mindir
INC_MODEL_PATH:上面生成的全量模型的路径,比如:output/mindir_inc_checkpoint_bs_1_512/rank_0_graph.mindir,这里中间路径会带上 batch_size和seq_length的后缀,比如batch_size为1,seq_length为512下路径为output/mindir_inc_checkpoint_bs_1_512/rank_0_graph.mindir
DEVICE_ID:NPU卡的编号,默认是0
SEQ_LENGTH:token长度,默认是32,建议设置512
IMAGE_PATH:推理的图片路径,比如examples/titanic.jpg
PROMPT:提示词,要加上引号
注意
推理设置的batch_size和seq_length要跟上面导出命令的batch_size和seq_length保持一致,否则会出错
MindSpore 微调¶
注意:目前lora微调只支持数据并行,不支持半自动并行和自动并行
step1. 下载微调数据集
数据集路径: https://github.com/THUDM/VisualGLM-6B/blob/main/fewshot-data.zip
下载完以后传到服务器,解压到research/visualglm下面 记录下fewhot-data/dataset.json文件的路径
step2. 修改微调配置参数
修改/research/visualglm/run_visualglm_lora.yaml文件:
修改所有path_to_vocab为ice_text.model词库文件的路径
修改所有path_to_dataset为上面数据集dataset.json文件的路径
修改path_to_qformer为上面转换的qformer权重文件visualglm_qformer.ckpt的路径
修改path_to_vit为上面转换的vit权重文件visualglm_vit.ckpt的路径
修改path_to_glm为上面转换的glm权重文件glm_6b.ckpt的路径
train_dataset: &train_dataset
tokenizer:
type: ChatGLMTokenizer
max_length: 2048
vocab_file: "/path_to_vocab/ice_text.model"
data_loader:
type: VisualGLMDataLoader
dataset_dir: "/path_to_dataset/dataset.json"
shuffle: False
file_format: json
random_mapping: True # if true enlarge original dataset "scale" times
scale: 1
model:
model_config:
type: VisualGLMConfig
#...
checkpoint_name_or_path: "/path_to_qformer/visualglm_qformer.ckpt"
vision_config:
type: ViTConfig
#...
checkpoint_name_or_path: "/path_to_vit/visualglm_vit.ckpt"
text_config:
type: GLMConfig
#...
checkpoint_name_or_path: "/path_to_glm/glm_6b.ckpt"
processor:
type: VisualGLMProcessor
image_processor:
type: VisualGLMImageProcessor
image_size: 224 # input image size
tokenizer:
type: ChatGLMTokenizer
max_length: 2048
vocab_file: "/path_to_vocab/ice_text.model"
step 3. 启动微调任务,按照以下步骤启动:
调整learning rate和warmup超参,修改/research/visualglm/run_visualglm_lora.yaml文件,根据实际业务调整下面的超参:
learning_rate: 微调的模型学习率不宜设置过大
warmup_steps:预热步数,表示在训练开始时逐渐增加学习率的步数。这样做可以避免模型在初始阶段受到过大的梯度干扰,提高模型的泛化能力。
num_iters:迭代次数,表示模型在一个epoch中处理数据的次数。一个epoch表示模型遍历整个数据集一次。
total_steps:总步数,表示模型在整个训练过程中处理数据的次数。总步数等于epoch数乘以迭代次数。如果设置为-1,表示不限制总步数,只根据epoch数来决定训练的终止条件4。
# lr sechdule
lr_schedule:
type: AnnealingLR
learning_rate: 0.00001
warmup_steps: 100
num_iters: 5000
total_steps: -1 # -1 means it will load the total steps of the dataset
layer_scale: False
layer_decay: 0.65
step4. 使用shell命令启动微调
调用下面的脚本启动微调:
cd research/visualglm
python run_visualglm_finetune.py --config CONFIG_PATH --graph_mode GRAPH_MODE --batch_size BATCH_SIZE --device_id DEVICE_ID
参数说明
CONFIG_PATH:微调配置,默认是run_visualglm_lora.yaml
GRAPH_MODE:图模式编号,默认是0。0:graph模式,1:pynative模式
BATCH_SIZE:批次大小,默认是1
DEVICE_ID:NPU卡的编号,默认是0
step5. 并行训练
运行mindformers/tools/hccl_tools.py生成RANK_TABLE_FILE的json文件 这会生成一个名字为hccl_8p_01234567_XXXX.json的文件
# 运行如下命令,生成当前机器的RANK_TABLE_FILE的json文件
python mindformers/tools/hccl_tools.py --device_num "[START_ID, END_ID)"
参数说明:
[START_ID, END_ID]: 表示卡的范围,START_ID是第一块卡的编号,END_ID是最后一块卡的编号,比如8卡为[0,8)
修改run_visualglm_lora.yaml中的并行参数
use_parallel: 改为True
parallel_mode:目前只支持数据并行,值为0
data_parallel:改为上面卡的数量,比如8卡改成8
use_parallel: True
parallel:
parallel_mode: 0
parallel_config:
data_parallel: 8
model_parallel: 1
运行run_singlenode.sh脚本来执行多卡训练
把HCCL_JSON_PATH替换为上面生成的hccl json文件的路径
[START_ID, END_ID]: 表示卡的范围,START_ID是第一块卡的编号,END_ID是最后一块卡的编号,要跟上面RANK_TABLE_FILE的配置保持一致;
CARD_COUNT: 表示使用NPU卡的数量,要跟上面RANK_TABLE_FILE的配置保持一致
cd research/visualglm
bash ../run_singlenode.sh \
"python run_visualglm_finetune.py --config CONFIG_PATH --graph_mode GRAPH_MODE --batch_size BATCH_SIZE" \
HCCL_JSON_PATH [START_ID, END_ID] CARD_COUNT
参数说明
CONFIG_PATH:微调配置,默认是run_visualglm_lora.yaml
GRAPH_MODE:图模式编号,默认是0。0:graph模式,1:pynative模式
BATCH_SIZE:批次大小,默认是1
HCCL_JSON_PATH: 多机多卡HCCL通信的配置,使用上面生成的RANK_TABLE_FILE的路径
[START_ID, END_ID]: 表示卡的范围,START_ID是第一块卡的编号,END_ID是最后一块卡的编号
CARD_COUNT:表示使用NPU卡的数量
注意
这里START_ID,END_ID和CARD_COUNT要跟上面RANK_TABLE_FILE的配置保持一致
step6. 使用shell命令启动推理
注意
图片路径:微调推理用的参考图片在代码仓库的finetune路径下
提示词:每张图片都有一个对应的参考提示词,可以在finetune_inputs.jsonl文件找到
调用预先开发好的脚本run_visualglm_with_lora.py,传入相关的图片和提示词,会得到相关的文本。
python run_visualglm_with_lora.py --lora_checkpoint CHECKPOINT_PATH --config CONFIG_PATH --image_path=IMAGE_PATH --prompt=PROMPT --device_id DEVICE_ID
#运行结果:
#['这张图片是雨天的。']
说明:
CHECKPOINT_PATH:训练完以后生成的checkpiont的绝对路径,checkpoint一般会保存在下面的路径下output/checkpoint_trainable/rank_[id]/
CONFIG_PATH: 表示yaml配置的路径,默认使用run_visualglm_lora.yaml
IMAGE_PATH:表示图片的路径,比如finetune/ghost.jpg
PROMPT:表示提示词,比如”这张图片的背景里有什么内容?”,注意外面要加引号
DEVICE_ID: 表示NPU卡的编号,默认是0