大家好呀,今天我们一起来看看MiniGPT4的forward流程。
MiniGPT4/model文件夹里面一共有7个文件。视觉模型在eva_vit.py里面定义,注释掉了原始ViT中很多后面的层,只留下encoder的结构;modeling_llama中重写了一下LlamaForCausalLM的forward函数,使之计算论文里需要的loss;Qformer.py里面写了关于Bert的一堆东西,后面的多模态融合层Qformer就是使用BertLMHeadModel来定义的。Qformer的主要目标是学习到一系列的learned queries,使之能够学会从视觉embedding中提取出跟描述最关键的部分。
整个模型的定义又分成三个类(文件),从base_model.py到minigpt_base.py再到minigpt4.py。
base_model.py里写了一些权重载入,配置config的method,最关键的是两个函数:init_vision_encoder与init_llm,在这里能够完成模型的创建和权重冻结。其中vision_encoder由注释了半拉只剩下encoder的ViT,以及一层LayerNorm组成;llm由tokenizer和llama_model组成。
这里额外分享一个实操的小秘密:由于视觉模型和语言模型都较大,把他们俩都载进来且放在RAM的时候会爆内存,在载入ViT的时候进程总是会自动被Killed。合理的方式是先载入语言模型,然后将语言模型放在cuda(我的显卡是24GB 3090)上,再在RAM中载入视觉模型和Qformer,就不会有问题了。
还有另外一个实战调试的时候比较耗时间的一个问题,就是大语言模型预训练权重的载入。一个7B的模型载入动辄就需要4-5分钟,这对于频繁调试来说肯定是难以接受的。有没有什么办法能够定义好了模型但不载入预训练权重,以节约调试时间呢?有的!
可以到eva_vit.py的文件里面找到create_eva_vit_g这个函数,把下面的句子全部注释掉,就不会花费载入权重的时间:
# url = "https://storage.googleapis.com/sfr-vision-language-research/LAVIS/models/BLIP2/eva_vit_g.pth"
# cached_file = download_cached_file(
# url, check_hash=False, progress=True
# )
# cached_file = "/home/xixuhu/MiniGPT-4/eva_vit_g.pth"
# state_dict = torch.load(cached_file, map_location="cpu")
# interpolate_pos_embed(model,state_dict)
# incompatible_keys = model.load_state_dict(state_dict, strict=False)
然后再回到base_model.py的init_llm函数里,把原本的这一行
llama_model = LlamaForCausalLM.from_pretrained(
llama_model_path,
torch_dtype=torch.float16,
)
改成
config = AutoConfig.from_pretrained('/MiniGPT-4/minigpt4/checkpoint/llama/Llama-2-7b-chat-hf/config.json') #这里只需要放入config文件
llama_model = LlamaForCausalLM.from_config(config)
llama_model = llama_model.to('cuda:0')
即可实现只定义模型,省去载入预训练权重的超长时间。
好了,今天就讲到这里,我们下次再见吧!