[CLIP-VIT-L + Qwen] 多模态大模型学习笔记 - 5
参考repo:WatchTower-Liu/VLM-learning; url: VLLM-BASE
前情提要
有关多模态大模型架构中的语言模型部分(MQwen.py)的代码请看(多模态大模型源码阅读 - 1、 多模态大模型源码阅读 - 2, 多模态大模型源码阅读 - 3,多模态大模型源码阅读 - 4)
本节中将阅读视觉模型部分,即重构后的visual-encoder的源码,位于文件夹visual下的CLIP_VIT.py文件,模型选择的是clip-vit-large-patch14。
源码解读(visualModel类)
init函数
class visualModel(CLIPModel):
def __init__(self, config: CLIPConfig):
super().__init__(config)
整体含义
利用传入的通用配置模型参数初始化父类。
逐行解读
class visualModel(CLIPModel):
def __init__(self, config: CLIPConfig):
super().__init__(config)
定义一个继承CLIPModel成员变量和成员方法的visualModel类,在python3.5之后,可以对传递参数的类型进行注解,这里的CLIPModel是一个特定的自定义参数类型,用于指定传入的config参数是CLIPConfig类型,并使用传递的一般配置参数初始化父类。
get_image_features函数(重构)
@add_start_docstrings_to_model_forward(CLIP_VISION_INPUTS_DOCSTRING)
def get_image_features(
self,
pixel_values: Optional[torch.FloatTensor] = None,
output_attentions: Optional[bool] = None,
output_hidden_states: Optional[bool] = None,
return_dict: Optional[bool] = None,
) -> torch.FloatTensor:
# Use CLIP model's config for some fields (if specified) instead of those of vision & text components.
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
output_hidden_states = (
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
)
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
vision_outputs = self.vision_model(
pixel_values=pixel_values,
output_attentions=output_attentions,
output_hidden_states=output_hidden_states,
return_dict=return_dict,
)
pooled_output = vision_outputs.last_hidden_state # pooled_output
# print(pooled_output.shape)
return pooled_output
整体含义
经典的特征提取函数,对传入的像素值进行特征提取,并用于后续进一步的处理。重构的目的在于让操作更灵活,可以使用自定义输入和直接获取池化输出。
逐行解读
@add_start_docstrings_to_model_forward(CLIP_VISION_INPUTS_DOCSTRING)
def get_image_features(
self,
pixel_values: Optional[torch.FloatTensor] = None,
output_attentions: Optional[bool] = None,
output_hidden_states: Optional[bool] = None,
return_dict: Optional[bool] = None,
) -> torch.FloatTensor:
这里的装饰器是为了给函数添加文档字符串,其中CLIP_VISION_INPUTS_DOCSTRING从transformers.models.clip.modeling_clip导入,这个装饰器可有可无,不必在意。
pixel_values:一个包含图像像素值的浮点数张量
其余的三个参数结尾bool值类型参数,分别代表是否输出注意力权重,是否输出每一层的隐藏层状态,返回值形式是否为字典类型。
# Use CLIP model's config for some fields (if specified) instead of those of vision & text components.
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
output_hidden_states = (
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
)
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
这段代码主要判断是使用传入的参数还是使用配置中的默认参数,保证既可以自定义参数,也可以和配置参数保持一致。
vision_outputs = self.vision_model(
pixel_values=pixel_values,
output_attentions=output_attentions,
output_hidden_states=output_hidden_states,
return_dict=return_dict,
)
调用成员变量vision_model处理像素信息,并输出包含多个返回值的vision_outputs,传递入的参数在前文已经说明,这里不再赘述。
pooled_output = vision_outputs.last_hidden_state # pooled_output
# print(pooled_output.shape)
return pooled_output
获取最后一个时间步的隐藏层状态作为池化输出,并将其返回。这个隐藏层状态包含了模型对输入图像的压缩表示或汇总特征。
main函数
def main():
modle_path = "F:/huggingface_model/clip-vit-large-patch14"
model = visualModel.from_pretrained(modle_path)
processor = CLIPProcessor.from_pretrained(modle_path)
test_img = Image.open("D:/code/multimodal/data/000000391895.jpg")
P_input = processor(images=test_img, return_tensors="pt")
print(model.get_image_features(**P_input).shape)
整体含义
一个完整的测试流程,加载图像后利用processer预处理图像获得像素信息,并用视觉模型根据传入的像素信息提取图片特征。
逐行解读
def main():
modle_path = "huggingface_model/clip-vit-large-patch14"
model = visualModel.from_pretrained(modle_path)
processor = CLIPProcessor.from_pretrained(modle_path)
test_img = Image.open("D:/code/multimodal/data/000000391895.jpg")
P_input = processor(images=test_img, return_tensors="pt")
print(model.get_image_features(**P_input).shape)
这里的model_path可以是自己下载的文件夹,也可以直接从huggingface上加载(需要魔法),使用模型地址加载processor和model,加载测试图片后用processor获取图片像素信息,之后会重构后的模型提取池化特征输出表示。
至此,visual_model中的CLIP-VIT源码阅读完毕,有关项目中的另一个视觉模型SIGLIP模型有兴趣的童鞋可以自行阅读。