最近,微软发布了一篇有趣的论文,题为“LLM2CLIP:强大的语言模型解锁更丰富的视觉表现。”根据该论文,LLM2CLIP 可以获得比传统 CLIP 更强大的文本理解,并在许多图像标题数据集中实现了最先进的检索性能。在这篇文章中,我们将首先描述它的工作原理,并比较 Vanilla CLIP 和 LLM2CLIP 之间的能力。
LLM2CLIP:它是如何工作的?
在本节中,我们将了解LLM2CLIP的架构。LLM2CLIP严重依赖于两种技术:CLIP和LLM2Vec。因此,我们首先简要回顾一下CLIP和LLM2Vec。之后,我们将探讨LLM2CLIP的方法。
准备工作:CLIP
CLIP是由OpenAI开发的具有颠覆性的多模态模型之一。它基于Transformer架构,包含图像编码器和文本编码器,专为零样本图像分类而设计。CLIP实现零样本图像分类的方法如下所示。
在第一阶段(1)对比预训练中,CLIP通过对比损失进行训练,以使图像编码器和文本编码器的图像和文本特征对齐。直观上,对比损失使得配对的图像和文本特征相似,而未配对的图像和文本特征则不相似。因此,CLIP在图像编码器和文本编码器之间共享相同的特征空间,并能够获得从文本中区分图像的能力。
第一阶段完成后,我们就可以实现零样本分类。我们只需准备一张图像和一个文本候选集,然后选择与图像特征最相似的文本。这是不是很直接?得益于大规模的数据集和独特的方法,CLIP能够展现出卓越的多模态能力。尽管AI领域已经发布了许多优秀的多模态模型,但CLIP仍然被认为是一个强大的图像编码器。
准备工作:LLM2Vec
LLM2Vec是一种将仅解码器的大型语言模型(LLM)转换为强大的文本编码器的技术。如今,具有仅解码器架构的LLMs在大多数自然语言处理任务和基准测试中都达到了最先进的水平。然而,由于它们的因果注意力机制,仅解码器的LLMs通常不能应用于嵌入任务。因果注意力掩码使LLMs只关注句子中的前一个词,因此捕捉整个句子的语义是一项挑战。因此,作者开发了一种无监督的调整方法,通过三个简单的步骤将LLM转换为编码器:
在第一步中,LLM2Vec将因果注意力掩码替换为双向注意力掩码。编码器模型(如BERT)使用的双向注意力掩码更适合于更好的嵌入表示,因为它们可以理解词与词之间的关系。因此,LLM2Vec将因果注意力掩码转换为双向注意力掩码,以便能够关注整个句子。
在第二步中,LLM2Vec利用掩码下一个词预测(MNTP)。MNTP随机掩码输入词汇的一部分,并根据过去和未来的序列预测被掩码的词汇。MNTP从整个序列中学习每个词的表示,使LLM能够获得更好的嵌入表示,这种表示考虑了语义和上下文。
在最后一步中,LLM2Vec应用无监督对比学习来获得句子之间更好的区分性。虽然前两个步骤只关注每个词(词汇)的更好嵌入表示,但这对于区分句子来说是不够的。使用一种称为SimCSE的对比学习技术,我们可以使相似句子的嵌入更接近,而使不相似句子的嵌入更远。因此,LLM可以考虑整个句子的语义来区分句子。
LLM2Vec在基于公开模型训练的模型中,在嵌入任务(如MTEB)上取得了最优结果。这表明最近的仅解码器LLM也可以应用于嵌入任务。
LLM2CLIP架构解析
随着大型语言模型(LLM)展现出广泛的自然语言处理能力,CLIP文本编码器被认为能力有限,因为它无法处理长和复杂的文本信息。这是一个大问题,因为CLIP文本编码器的限制导致了CLIP图像编码器进一步改进的限制。因此,作者开发了LLM2CLIP来利用LLM,使CLIP能够学习更强大、更细致和更丰富的视觉表示。
但是,如何实现呢?LLM2CLIP可以分为以下两个步骤:
在第一步中,LLM2CLIP首先使用LLM2Vec方法将LLM转换为编码器。但为什么我们不能直接用CLIP文本编码器替换LLM呢?你可以在下面的表格和作者对一些模型进行的标题到标题检索任务的实验示例中查看这一事实。
如你所见,Llama(Llama3–8B和Llama3.2–1B)在标题检索任务上的表现不如CLIP文本编码器。在右侧的图中,Llama无法检索到相关的示例。因此,作者首先应用LLM2Vec来使LLM与嵌入任务对齐。模型名称中包含“cc”的模型是应用了LLM2Vec的模型,它们在表中的表现优于CLIP。在这一阶段,所有训练都是使用LoRA进行的,因此这种方法在计算资源方面是高效的。
在第二步中,我们需要对齐CLIP的视觉特征空间和LLM的特征空间。我们在上一步中获得了一个强大的文本编码器,但它们的特征空间还没有对齐。为了减少所需的计算资源,作者冻结了LLM的权重,并引入了适配器和投影层来对齐视觉编码器。训练概览如下所示。
在微调它们时,LLM2CLIP仅使用了CLIP损失。关于训练效率,虽然原始的CLIP需要超过500个V100 GPU进行训练,但LLM2CLIP仅需8个H100 GPU。此外,整个训练过程仅需9小时。
尽管训练成本高效,但LLM2CLIP仍能在图像标注任务上取得最优结果。根据LLM的不同,存在多种规模变体。我们可以根据环境选择使用1B、8B或12B的LLM。当然,模型规模越大,结果越好。你也可以为LLM2CLIP训练自己的LLM。
实践应用:文本到图像和图像到图像的相似性搜索中CLIP和LLM2CLIP嵌入的比较
在本节中,我们将实现LLM2CLIP和CLIP,并将它们应用于文本到图像和图像到图像的相似性搜索任务。我们将使用Flickr30k数据集[5]和Faiss库进行相似性搜索。为了你的了解,Faiss是一个基于近似最近邻搜索算法的高效相似性搜索库。现在,让我们来准备环境。
环境设置
我使用了一个带有Python 3.8的conda环境。我在Ubuntu 20.04系统上进行了实验,该系统配备了cuda 12.0和16 GB的显存。
conda create -n llm2clip python=3.8 -ycreate -n llm2clip python=3.8 -y
conda activate llm2clip
接下来,我们需要通过conda和pip安装以下库。尽管作者也提供了HuggingFace仓库,但我遇到了一些依赖错误。因此,我建议你安装源代码仓库。此外,当你从官方仓库安装requirements.txt时,可能会遇到一些依赖错误,但你可以忽略它们。
git clone https://github.com/microsoft/LLM2CLIP.gitclone https://github.com/microsoft/LLM2CLIP.git
git clone https://github.com/McGill-NLP/llm2vec.git
cd LLM2CLIP/llm2clip
pip install -r requirements.txt
cd ../llm2vec
pip install -e .
conda install -c pytorch faiss-cpu
LLM2CLIP与CLIP在文本到图像、图像到图像相似性搜索上的比较
现在,我们将实现LLM2CLIP和CLIP,并比较它们在文本到图像和图像到图像相似性搜索任务上的能力。我们该如何实现它们呢?让我们来看看基本的代码。
LLM2CLIP
对于LLM2CLIP,我们需要分别加载CLIP和LLM部分。
# Prepare CLIP part in LLM2CLIP
processor = CLIPImageProcessor.from_pretrained("openai/clip-vit-large-patch14-336")
model_name_or_path = "microsoft/LLM2CLIP-Openai-L-14-336" # or /path/to/local/LLM2CLIP-Openai-L-14-336
model = AutoModel.from_pretrained(
model_name_or_path,
torch_dtype=torch.bfloat16,
trust_remote_code=True).to('cuda').eval()
# Prepare LLM part in LLM2CLIP
llm_model_name = 'microsoft/LLM2CLIP-Llama-3-8B-Instruct-CC-Finetuned'
config = AutoConfig.from_pretrained(
llm_model_name, trust_remote_code=True
)
llm_model = AutoModel.from_pretrained(llm_model_name, torch_dtype=torch.bfloat16, config=config, trust_remote_code=True)
tokenizer = AutoTokenizer.from_pretrained(llm_model_name)
llm_model.config._name_or_path = 'meta-llama/Meta-Llama-3-8B-Instruct' # Workaround for LLM2VEC
l2v = LLM2Vec(llm_model, tokenizer, pooling_mode="mean", max_length=512, doc_max_length=512)
我们可以像下面的代码一样轻松地提取嵌入。
with torch.no_grad(), torch.cuda.amp.autocast():.no_grad(), torch.cuda.amp.autocast():
image_features = model.get_image_features(input_pixels)
text_features = model.get_text_features(text_features)
对于CLIP,我们可以使用HuggingFace库。因此,我们需要实例化Tokenizer(分词器)和Model(模型)类。
processor = CLIPImageProcessor.from_pretrained("openai/clip-vit-large-patch14-336")"openai/clip-vit-large-patch14-336")
model_name_or_path = "openai/clip-vit-large-patch14"
model = CLIPModel.from_pretrained(
model_name_or_path,
attn_implementation="flash_attention_2",
torch_dtype=torch.float16,
trust_remote_code=True).to('cuda').eval()
我们可以像下面的代码一样轻松地提取嵌入。
with torch.no_grad():
out = model.get_image_features(input_pixels)
out = model.get_text_features(text_features)
关于文本到图像和图像到图像的搜索,我们提前使用Faiss对图像嵌入进行索引。然后,我们使用文本和图像嵌入进行搜索。以下是比较结果。
图像到图像的搜索
基本上,LLM2CLIP的视觉识别能力相比CLIP有所提升。LLM2CLIP能够吸收来自LLM的开放世界知识,并反映在其嵌入中。
文本到图像的搜索
文本到图像搜索的质量差异更为显著。LLM2CLIP能够理解相对较长的上下文,并挑选出相似的图像。而CLIP有时则无法选择相关的图像,而是选择那些只有部分与文本相关的图像。
综上所述,LLM2CLIP能够融入来自LLM的知识,并成功提升其嵌入质量。尽管我们需要的计算能力比CLIP更多,但检索能力却有了显著提升。此外,其微调成本也相对较低,因此我们可以开发自己的LLM2CLIP。请尝试在你的数据集上使用这个超级模型!