赞
踩
随着自媒体的不断发展,多种模态数据例如图像、文本、语音、视频等不断增长,创造了互联网上丰富多彩的世界。为了准确建模用户的多模态内容,跨模态检索是跨模态理解的重要任务,采用一种模态的数据作为数据,检索另一种模态的数据。其中,图文检索是跨模态检索的一种主流任务,广泛应用于各种网络应用中,其难点在于跨模态的表示鸿沟(Representation Gap)。具体来说,文本和图像的数据处于不同的向量空间,无法直接去度量他们的相似性。OpenAI提出了CLIP(Contrastive Language-Image Pre-training)模型,在大规模图文数据集上进行了对比学习训练,在多个数据集上的准确度表明,CLIP优于各种基于ImageNet的模型,也具有良好的零样本学习(Zero-shot Learning)能力。
EasyNLP是阿里云机器学习PAI 团队基于 PyTorch 开发的易用且丰富的中文NLP算法框架,支持常用的中文预训练模型和大模型落地技术,并且提供了从训练到部署的一站式 NLP 开发体验。EasyNLP 提供了简洁的接口供用户开发 NLP 模型,包括NLP应用 AppZoo 和预训练 ModelZoo,同时提供技术帮助用户高效的落地超大预训练模型到业务。由于跨模态理解需求的不断增加,EasyNLP也将支持各种跨模态模型,特别是中文领域的跨模态模型,推向开源社区,希望能够服务更多的 NLP 和多模态算法开发者和研究者,也希望和社区一起推动 NLP /多模态技术的发展和模型落地。
本文简要介绍CLIP的技术解读,以及如何在EasyNLP框架中玩转CLIP模型。
CLIP的模型结构相对比较简单,体现了“大道至简”的设计原则,其模型框架图如下图所示:
为了建立图像和文本的关联性,CLIP首先分别构建了图像和文本的Encoder,分别对图像和文本进行特征抽取。对于图像而言,CLIP使用的Backbone可以是经典的ResNet系列模型,也可以是更先进的Transfomer类模型,例如VIT等;对于文本,CLIP一般使用BERT类模型进行特征抽取,也包括RoBERTa等。在特征抽取之后,CLIP分别对提取的向量进行Normalization,从而可以直接进行内积相似度计算。在模型Loss Function层面,由于图像和文本向量都进行了Normalization,我们直接使用相乘来计算余弦距离,使得同一图文对的结果趋近于1,不同图文对的结果趋近于0;并且使用对比学习损失InfoNCE进行损失计算。
当模型预训练结束后,我们可以直接使用CLIP进行图文的检索,因为CLIP已经将图文的表示映射到同一个向量空间。CLIP的另一个优势在于可以进行Zero-shot Classification。如下图所示,我们设计输入文本“A photo of a {object}.”,并且使用目标图像作为输出。如果文本“A photo of a dog.”于当前图像最匹配(余弦相似度最高),我们可以说明,当前图像的物体是“dog”。由此可见,预训练后的CLIP模型可以直接用于图像分类,而不需要额外的训练。
CLIP模型的训练过程也可以直接参考原作者给出的伪代码实现:
在EasyNLP框架中,我们在模型层构建了CLIP模型的Backbone,核心代码如下所示:
- self.text_model = CLIPTextTransformer(text_config)
- self.vision_model = CLIPVisionTransformer(vision_config)
-
- self.visual_projection = nn.Linear(self.vision_embed_dim, self.projection_dim, bias=False)
- self.text_projection = nn.Linear(self.text_embed_dim, self.projection_dim, bias=False
其中,CLIPTextTransformer和CLIPVisionTransformer分别是基于BERT和VIT的特征提取器。前向传播的过程也比较简洁:
- vision_outputs = self.vision_model(...)
- text_outputs = self.text_model(...)
-
- image_embeds = vision_outputs[1]
- image_embeds = self.visual_projection(image_embeds)
- image_embeds = image_embeds / image_embeds.norm(dim=-1, keepdim=True)
-
- text_embeds = text_outputs[1]
- text_embeds = self.text_projection(text_embeds)
- text_embeds = text_embeds / text_embeds.norm(dim=-1, keepdim=True)
-
- logit_scale = self.logit_scale.exp()
- logits_per_text = torch.matmul(text_embeds, image_embeds.t()) * logit_scale
- loss = clip_loss(logits_per_text)
此外,由于CLIP模型本身具备文本和图像的编码器,我们直接调用他们的前向推理函数就可以实现特征的提取。对于文本我们有:
- text_outputs = self.text_model(...)
- pooled_output = text_outputs[1]
- text_features = self.text_projection(pooled_output)
对图像的操作也与文本类似:
- vision_outputs = self.vision_model(...)
- pooled_output = vision_outputs[1]
- image_features = self.visual_projection(pooled_output)
此外,我们在多个公开数据集上验证了EasyNLP框架中CLIP模型在各种任务上的精度。以零样本学习为例,我们使用EasyNLP加载了开源的
openai/clip-vit-large-patch14模型,对比了Top-1精度和CLIP官方论文的结果,如下所示:
数据集 | Top-1 Accuracy (复现结果) | CLIP 论文汇报结果 |
Food101 | 90.9 | 92.9 |
CIFAR100 | 78.6 | 77.9 |
EuroSAT | 60.1 | 59.9 |
Oxford Pets | 93.0 | 93.5 |
Fllickr30k-TR | 85.3 | 88.0 |
Fllickr30k-IR | 65.0 | 68.7 |
我们的实验也说明,如果采用特定数据集的数据对CLIP进行进一步Fine-tune,CLIP能取得更好的效果。以Fllickr30k数据集为例,CLIP模型在零样本学习和Fine-tune对比结果如下:
img2txt (r1/r5/r10) | img2txt mean | txt2img (r1/r5/r10) | txt2img mean | |
CLIP Fine-tune | 91.0/99.0/99.7 | 95.57 | 76.38/94.06/97.28 | 89.24 |
CLIP Zero-shot | 85.3/97.40/99.2 | 94.0 | 65.02/87.2/92.0 | 81.41 |
我们也在中文数据集上进行了预训练,并且评测了模型在COCO-CN和Fllickr30k-CN数据集上的效果。模型的设置与WukongViT对齐(详见参考文献),进行了复现,结果如下所示:
数据集 | 模型 | img2txt mean | txt2img mean |
COCO-CN | WukongViT | 96.4 | 89.8 |
CLIP | 96.1 | 88.4 | |
Fllickr30k-CN | WukongViT | 85.9 | 87.8 |
CLIP | 86.0 | 86.1 |
由上述结果可见,EasyNLP框架训练的CLIP模型在下游任务的Finetune结果与WukongViT基本对齐。结果少量差异性的原因在于:1. MindSpore与PyTorch的内部实现差异性(WukongViT作者采用MindSpore实现)以及2. 超参数和随机种子的选择。
为了方便用户的使用,EasyNLP进一步提供了AppZoo层面的接口,使得用户可以在不实现任何代码的情况下调用CLIP模型,这一部分内容在下一节介绍。
以下简要介绍在EasyNLP框架使用CLIP模型。由于用户数据一般于CLIP预训练数据在分布上存在差距。我们提供CLIP模型的训练和向量提取功能
安装EasyNLP
用户可以直接参考链接的说明安装EasyNLP算法框架。
数据准备
首先准备训练数据与验证数据,为tsv文件。这一文件包含以制表符\t分隔的两列,第一列为文本,第二列为图片的base64编码。用于提取向量接入向量检索系统的输入文件为单列,仅包含文本或图片的base64编码。
为了方便开发者,我们也提供了转换图片到base64编码的示例代码:
- import base64
- from io import BytesIO
- from PIL import Image
-
- img = Image.open(fn)
- img_buffer = BytesIO()
- img.save(img_buffer, format=img.format)
- byte_data = img_buffer.getvalue()
- base64_str = base64.b64encode(byte_data) # bytes
下列文件已经完成预处理,可用于测试:
- # train
- https://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/CLIP/MUGE_MR_train_base64_part.tsv
-
- # valid
- https://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/CLIP/MUGE_MR_valid_base64_part.tsv
-
- # text
- https://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/CLIP/MUGE_MR_test_base64_part_text.tsv
-
- # image
- https://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/CLIP/MUGE_MR_test_base64_part_image.tsv
模型训练和评测
我们采用以下命令对CLIP模型进行fine-tune:
- easynlp \
- --mode train \
- --worker_gpu=1 \
- --tables=./MUGE_MR_train_base64_part.tsv,./MUGE_MR_valid_base64_part.tsv \
- --input_schema=text:str:1,image:str:1 \
- --first_sequence=text \
- --second_sequence=image \
- --checkpoint_dir=./clip_model/ \
- --learning_rate=1e-4 \
- --epoch_num=1 \
- --random_seed=42 \
- --logging_steps=100 \
- --save_checkpoint_steps 200 \
- --sequence_length=32 \
- --micro_batch_size=32 \
- --app_name=clip \
- --save_all_checkpoints \
- --user_defined_parameters='pretrain_model_name_or_path=clip_chinese_roberta_large_with_vit_large fix_vision=True mode=finetune'
训练完成后模型被保存到./clip_model/。训练结束后,我们可以对模型进行评估:
- easynlp \
- --mode evaluate \
- --worker_gpu=1 \
- --tables=./MUGE_MR_valid_base64_part.tsv \
- --input_schema=text:str:1,image:str:1 \
- --first_sequence=text \
- --second_sequence=image \
- --checkpoint_dir=./clip_model/ \
- --random_seed=42 \
- --logging_steps=100 \
- --save_checkpoint_steps=500 \
- --sequence_length=32 \
- --micro_batch_size=32 \
- --app_name=clip
文本或图片特征提取
模型训练完毕后,我们可以将其用于文本或图片的特征提取,示例如下:
- easynlp \
- --mode predict \
- --worker_gpu=1 \
- --tables=./MUGE_MR_test_base64_part_text.tsv \
- --input_schema=text:str:1 \
- --output_schema=text_feat \
- --outputs=./text_feat.tsv \
- --first_sequence=text \
- --checkpoint_dir=./clip_model/ \
- --random_seed=42 \
- --logging_steps=100 \
- --save_checkpoint_steps=500 \
- --sequence_length=32 \
- --micro_batch_size=2 \
- --app_name=clip
- easynlp \
- --mode predict \
- --worker_gpu=1 \
- --tables=./MUGE_MR_test_base64_part_image.tsv \
- --input_schema=image:str:1 \
- --output_schema=image_feat \
- --outputs=./image_feat.tsv \
- --first_sequence=image \
- --checkpoint_dir=./clip_model/ \
- --random_seed=42 \
- --logging_steps=100 \
- --save_checkpoint_steps=500 \
- --sequence_length=32 \
- --micro_batch_size=2 \
- --app_name=clip
提取出的特征存储在一个tsv文件中,每行对应输入中的一个文本或一个图片,维度之间采用制表符\t分隔。
在未来,我们计划在EasyNLP框架中公开以PyTorch实现的CLIP模型,覆盖各个常见中文领域,敬请期待。我们也将在EasyNLP框架中集成更多SOTA模型(特别是中文模型),来支持各种NLP和多模态任务。此外,阿里云机器学习PAI团队也在持续推进中文多模态模型的自研工作,欢迎用户持续关注我们,也欢迎加入我们的开源社区,共建中文NLP和多模态算法库!
Github地址:
https://github.com/alibaba/EasyNLP
本文为阿里云原创内容,未经允许不得转载。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。