本节导读:探索Embedding技术跨越文本边界的应用,理解多模态向量表示的原理与实践
跨模态Embedding的目标是将不同类型的数据(文本、图像、音频、视频等)映射到同一个向量空间,使得不同模态的数据可以通过向量相似度进行关联和检索。
核心价值:
CLIP(Contrastive Language-Image Pre-training)是OpenAI提出的经典跨模态模型。它的核心思想是通过对比学习将文本和图像映射到同一空间。
训练方法:
模型组成:
环境准备:
# 安装依赖 # pip install torch transformers pillow from transformers import CLIPProcessor, CLIPModel from PIL import Image import torch class CLIPImageSearch: def __init__(self, model_name: str = "openai/clip-vit-base-patch32"): self.device = "cuda" if torch.cuda.is_available() else "cpu" self.model = CLIPModel.from_pretrained(model_name).to(self.device) self.processor = CLIPProcessor.from_pretrained(model_name) def get_image_embedding(self, image_path: str) -> list: """获取单张图片的Embedding""" image = Image.open(image_path) inputs = self.processor(images=image, return_tensors="pt").to(self.device) with torch.no_grad(): embedding = self.model.get_image_features(**inputs) # 归一化 embedding = embedding / embedding.norm(dim=-1, keepdim=True) return embedding.cpu().numpy().tolist()[0] def get_text_embedding(self, text: str) -> list: """获取文本的Embedding""" inputs = self.processor(text=[text], return_tensors="pt", padding=True).to(self.device) with torch.no_grad(): embedding = self.model.get_text_features(**inputs) embedding = embedding / embedding.norm(dim=-1, keepdim=True) return embedding.cpu().numpy().tolist()[0]
import numpy as np from typing import List, Tuple class CrossModalSearchEngine: def __init__(self, model_name: str = "openai/clip-vit-base-patch32"): self.clip = CLIPImageSearch(model_name) self.image_paths: List[str] = [] self.image_embeddings: np.ndarray = None def index_images(self, image_paths: List[str]): """索引图片集合""" self.image_paths = image_paths embeddings = [] for path in image_paths: emb = self.clip.get_image_embedding(path) embeddings.append(emb) self.image_embeddings = np.array(embeddings) def text_to_image_search(self, query: str, top_k: int = 5) -> List[Tuple[str, float]]: """用文字搜索图片""" text_emb = np.array(self.clip.get_text_embedding(query)) # 计算余弦相似度 similarities = np.dot(self.image_embeddings, text_emb) top_indices = np.argsort(similarities)[::-1][:top_k] return [(self.image_paths[i], float(similarities[i])) for i in top_indices] def image_to_text_search(self, image_path: str, candidate_texts: List[str], top_k: int = 5) -> List[Tuple[str, float]]: """用图片搜索最相关的文字描述""" image_emb = np.array(self.clip.get_image_embedding(image_path)) text_embeddings = np.array([self.clip.get_text_embedding(t) for t in candidate_texts]) similarities = np.dot(text_embeddings, image_emb) top_indices = np.argsort(similarities)[::-1][:top_k] return [(candidate_texts[i], float(similarities[i])) for i in top_indices] # 使用示例 engine = CrossModalSearchEngine() engine.index_images(["photo1.jpg", "photo2.jpg", "photo3.jpg"]) # 文字搜图片 results = engine.text_to_image_search("一只在草地上奔跑的金毛犬", top_k=2) for path, score in results: print(f"[相似度: {score:.4f}] {path}")
def compute_clip_similarity(model, processor, image_path: str, text: str) -> float: """计算单张图片与文本的相似度""" device = "cuda" if torch.cuda.is_available() else "cpu" image = Image.open(image_path) inputs = processor(text=[text], images=image, return_tensors="pt", padding=True).to(device) with torch.no_grad(): outputs = model(**inputs) # logits即为相似度分数 logits = outputs.logits_per_image probs = logits.softmax(dim=-1) return float(probs[0][0].cpu()) def zero_shot_classification(model, processor, image_path: str, labels: List[str]) -> dict: """零样本图像分类:给定候选标签,返回概率分布""" device = "cuda" if torch.cuda.is_available() else "cpu" image = Image.open(image_path) inputs = processor(text=labels, images=image, return_tensors="pt", padding=True).to(device) with torch.no_grad(): outputs = model(**inputs) probs = outputs.logits_per_image.softmax(dim=-1) return {label: float(probs[0][i]) for i, label in enumerate(labels)} # 使用示例 # result = zero_shot_classification(model, processor, "cat.jpg", ["一只猫", "一只狗", "一辆车"])
音频Embedding将声音信号转换为向量表示,适用于语音检索、音乐推荐、声音分类等场景。
常用方法:
# 使用CLAP进行音频-文本对齐(伪代码示意) # pip install clap def audio_text_search(audio_path: str, query_texts: List[str]) -> List[Tuple[str, float]]: """ 使用CLAP模型搜索与音频最相关的文字描述 CLAP模型可以将音频和文本映射到同一向量空间 """ # 1. 加载CLAP模型 # 2. 将音频编码为向量 # 3. 将候选文本编码为向量 # 4. 计算余弦相似度并排序 # 具体实现参考CLAP官方仓库 pass
视频Embedding需要同时处理时序和视觉信息,常见方法包括:
方法一:关键帧提取+图像Embedding
方法二:端到端视频模型
def video_to_embedding(video_path: str, sample_rate: int = 1) -> np.ndarray: """ 通过关键帧提取将视频转为Embedding sample_rate: 每隔多少秒提取一帧 """ import cv2 cap = cv2.VideoCapture(video_path) fps = cap.get(cv2.CAP_PROP_FPS) frame_interval = int(fps * sample_rate) frames = [] frame_count = 0 while cap.isOpened(): ret, frame = cap.read() if not ret: break if frame_count % frame_interval == 0: frames.append(frame) frame_count += 1 cap.release() # 对每个关键帧提取Embedding,然后取平均 # 此处使用CLIP图像编码器(实际代码需补充) frame_embeddings = [] for frame in frames: # frame_emb = clip_model.encode_image(frame) # frame_embeddings.append(frame_emb) pass if frame_embeddings: return np.mean(frame_embeddings, axis=0) return np.array([])
在电商场景中,用户可以上传图片搜索相似商品,或用文字描述搜索商品图片:
class ProductSearchEngine: def __init__(self): self.clip = CLIPImageSearch() self.products: List[dict] = [] self.product_embeddings: np.ndarray = None def index_products(self, products: List[dict]): """索引商品,商品需包含图片路径和描述""" self.products = products embeddings = [] for product in products: # 融合图片和文本的Embedding image_emb = np.array(self.clip.get_image_embedding(product["image_path"])) text_emb = np.array(self.clip.get_text_embedding(product["description"])) # 简单加权融合 combined = 0.7 * image_emb + 0.3 * text_emb # 重新归一化 combined = combined / np.linalg.norm(combined) embeddings.append(combined) self.product_embeddings = np.array(embeddings) def search_by_image(self, query_image: str, top_k: int = 10): """以图搜图""" query_emb = np.array(self.clip.get_image_embedding(query_image)) similarities = np.dot(self.product_embeddings, query_emb) top_indices = np.argsort(similarities)[::-1][:top_k] return [self.products[i] for i in top_indices] def search_by_text(self, query: str, top_k: int = 10): """以文搜图""" query_emb = np.array(self.clip.get_text_embedding(query)) similarities = np.dot(self.product_embeddings, query_emb) top_indices = np.argsort(similarities)[::-1][:top_k] return [(self.products[i], float(similarities[i])) for i in top_indices]
利用跨模态Embedding可以构建智能内容审核系统,判断文本和图片内容是否匹配,或检测违规内容:
def content_consistency_check(image_path: str, text: str, threshold: float = 0.2) -> dict: """ 检查图文内容一致性 返回是否匹配及相似度分数 """ # 使用CLIP计算图文相似度 # similarity = compute_clip_similarity(model, processor, image_path, text) # return {"consistent": similarity > threshold, "similarity": similarity} pass
Q:CLIP模型对中文支持如何?
A:原始CLIP模型主要在英文数据上训练,对中文支持有限。可以使用中文CLIP模型(如Chinese-CLIP)或结合翻译策略,先将中文翻译为英文再使用CLIP。Chinese-CLIP在阿里开源的中文图文数据上训练,中文效果更好。
Q:跨模态Embedding的向量维度如何选择?
A:维度越高表达能力越强,但计算和存储成本也越大。CLIP-base为512维,CLIP-large为768维。实际应用中需在精度和性能之间平衡。
Q:如何处理多语言跨模态场景?
A:选择支持多语言的多模态模型(如SigLIP、mCLIP等),或使用翻译预处理将文本统一为模型支持的语种。
Q:跨模态Embedding的局限性有哪些?
A:主要局限包括:对细粒度区分能力有限(如区分不同品种的狗),对罕见概念理解不足,计算资源需求较高(尤其是图像编码)。
本节系统介绍了跨模态Embedding的概念、原理和实践。从CLIP模型的图文对齐基础,到图文检索系统、音频和视频Embedding方法,再到电商搜索和内容审核等实际应用场景,全面展示了Embedding技术跨越单一模态的能力边界。掌握跨模态Embedding是构建现代AI应用的重要技能。
关键词:跨模态, CLIP, 图文检索, 多模态Embedding, 零样本分类, Chinese-CLIP, 视频Embedding, 音频Embedding
难度:中级
预计阅读:50分钟