使用open_clip的CLIP模型获取单token嵌入遇输出形状不符问题
问题
我正在使用open_clip模块从CLIP模型中获取文本嵌入。当我对单个文本序列的列表进行分词,并传入模型的encode_text方法时,期望得到形状为[77, 1024]的嵌入,但实际输出形状为[1, 1024]。相关代码如下:
import open_clip model, preprocess_train, preprocess_val = open_clip.create_model_and_transforms('hf-hub:laion/CLIP-ViT-H-14-laion2B-s32B-b79K') tokenizer = open_clip.get_tokenizer('hf-hub:laion/CLIP-ViT-H-14-laion2B-s32B-b79K') text_inputs = ["cat"] tokenized_inputs = tokenizer(text_inputs) print(len(tokenized_inputs)) # This prints 77 text_embeddings = model.encode_text(tokenized_inputs) print(text_embeddings.shape) # This prints [1, 1024]
请问我在使用分词器或encode_text方法时是否存在疏漏?如何获取77个token序列中每个token的单独嵌入?
解决方法
你没有使用错误,只是默认行为如此:CLIP的
encode_text方法默认返回的是<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]>(序列末尾的特殊token)的嵌入,对应形状为[batch_size, embed_dim],这里batch_size为1,所以输出[1,1024]。获取每个token的嵌入只需修改调用参数:调用
encode_text时传入return_all_tokens=True,就能得到所有token的嵌入,形状为[batch_size, seq_len, embed_dim],对应你的场景就是[1,77,1024]。若要去掉batch维度,用.squeeze(0)即可得到[77,1024]的结果。
修改后的代码示例:
import open_clip model, preprocess_train, preprocess_val = open_clip.create_model_and_transforms('hf-hub:laion/CLIP-ViT-H-14-laion2B-s32B-b79K') tokenizer = open_clip.get_tokenizer('hf-hub:laion/CLIP-ViT-H-14-laion2B-s32B-b79K') text_inputs = ["cat"] tokenized_inputs = tokenizer(text_inputs) print(tokenized_inputs['input_ids'].shape) # 实际为[1,77],之前的len(tokenized_inputs)打印的是字典键的数量,并非序列长度 # 获取所有token的嵌入 text_embeddings = model.encode_text(tokenized_inputs, return_all_tokens=True) print(text_embeddings.shape) # 输出[1,77,1024] # 去掉batch维度得到[77,1024] single_seq_embeddings = text_embeddings.squeeze(0) print(single_seq_embeddings.shape) # 输出[77,1024]
- 补充说明:你之前用
len(tokenized_inputs)得到77,是因为分词器返回的是包含input_ids、attention_mask等键的字典,该字典的键数量为77,并非token序列长度,正确查看序列长度应访问tokenized_inputs['input_ids'].shape。
内容的提问来源于stack exchange,提问作者hanugm
相关产品推荐
相关产品推荐

