Views
No views yet
transformers version of Duoduo CLIP: Efficient 3D Understanding with Multi-View Images. DuoduoCLIP learns 3D object representations from multi-view rendered images instead of point clouds, while keeping the familiar CLIP-style text and image embedding interface.1import torch
2import torch.nn.functional as F
3from huggingface_hub import hf_hub_download
4from PIL import Image
5from transformers import AutoModel, AutoProcessor
6
7repo_id = "3dlg-hcvc/DuoduoCLIP-B-32"
8device = "cuda" if torch.cuda.is_available() else "cpu"
9
10model = AutoModel.from_pretrained(
11 repo_id,
12 trust_remote_code=True,
13 attn_implementation="sdpa",
14 dtype=torch.float32,
15 device_map=device,
16)
17processor = AutoProcessor.from_pretrained(repo_id)
18model.eval()
19
20def load_demo_shape():
21 view_paths = [
22 hf_hub_download(repo_id=repo_id, filename=f"assets/demo/view_{view_id:03d}.png")
23 for view_id in range(3)
24 ]
25 return [Image.open(path).convert("RGB") for path in view_paths]
26
27@torch.inference_mode()
28def encode_shape(view_images):
29 image_inputs = processor(images=view_images, return_tensors="pt").to(device)
30 pixel_values = image_inputs["pixel_values"].unsqueeze(0)
31 return F.normalize(model.get_image_features(pixel_values=pixel_values), dim=-1)
32
33@torch.inference_mode()
34def encode_text(texts):
35 text_inputs = processor(text=texts, return_tensors="pt", padding=True).to(device)
36 return F.normalize(model.get_text_features(**text_inputs), dim=-1)1texts = ["a 3D model of a telephone", "a 3D model of a chair", "a 3D model of a sofa"]
2text_features = encode_text(texts)
3
4shape_features = encode_shape(load_demo_shape())
5text_shape_scores = shape_features @ text_features.T
6print(text_shape_scores.softmax(dim=-1))1query_shape = load_demo_shape()[:2]
2gallery_names = ["telephone"]
3gallery_shapes = [load_demo_shape()]
4
5query_features = encode_shape(query_shape)
6gallery_features = torch.cat([encode_shape(shape) for shape in gallery_shapes], dim=0)
7shape_shape_scores = query_features @ gallery_features.T
8print(gallery_names[shape_shape_scores.argmax(dim=-1).item()])get_image_features are unnormalized projected features, so normalize them before retrieval.(B, F, 3, H, W), where F is the number of views:1image_inputs = processor(images=view_images, return_tensors="pt").to(device)
2pixel_values = image_inputs["pixel_values"].unsqueeze(0)
3image_features = F.normalize(model.get_image_features(pixel_values=pixel_values), dim=-1)(B * F, 3, H, W) tensor is also supported when num_views=F is provided.1image_inputs = processor(images=view_images[0], return_tensors="pt").to(device)
2image_features = F.normalize(model.get_image_features(**image_inputs), dim=-1)get_text_features and get_image_features follow Hugging Face CLIP semantics and return unnormalized projected features. Use torch.nn.functional.normalize before computing retrieval similarities. Calling the full model forward returns normalized text_embeds, normalized image_embeds, and CLIP-style logits.1@inproceedings{lee2025duoduo,
2 title={Duoduo CLIP: Efficient 3D understanding with multi-view images},
3 author={Lee, Han-Hung and Zhang, Yiming and Chang, Angel},
4 booktitle={International Conference on Learning Representations},
5 volume={2025},
6 pages={48070--48091},
7 year={2025}
8}