Skip to content

Commit 8e6a550

Browse files
authored
Merge branch 'master' into feat/api-nodes/meshy-7
2 parents 7c41bda + b78cec8 commit 8e6a550

62 files changed

Lines changed: 22778 additions & 503 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/cla.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@ jobs:
3535
# For each commit emit the GitHub login when the author/committer email resolves to a GitHub account
3636
# otherwise fall back to the raw git name.
3737
run: |
38-
others=$(gh api "repos/${{ github.repository }}/pulls/${PR_NUMBER}/commits" --paginate \
39-
--jq '.[] | (.author.login // .commit.author.name // empty), (.committer.login // .commit.committer.name // empty)' \
40-
| sort -u | grep -vix "${PR_AUTHOR}" | paste -sd, -)
38+
if ! commit_authors=$(gh api "repos/${{ github.repository }}/pulls/${PR_NUMBER}/commits" --paginate \
39+
--jq '.[] | (.author.login // .commit.author.name // empty), (.committer.login // .commit.committer.name // empty)'); then
40+
echo "Failed to fetch pull request commits" >&2
41+
exit 1
42+
fi
43+
others=$(printf '%s\n' "$commit_authors" | sort -u | grep -vix "${PR_AUTHOR}" | paste -sd, -)
4144
if [ -n "$others" ]; then
4245
echo "allowlist=${BASE_ALLOWLIST},${others}" >> "$GITHUB_OUTPUT"
4346
else

comfy/clip_vision.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import comfy.clip_model
1111
import comfy.image_encoders.dino2
1212
import comfy.image_encoders.dino3
13+
from comfy.image_encoders.naf import NAF
1314

1415
class Output:
1516
def __getitem__(self, key):
@@ -53,6 +54,7 @@ def __init__(self, json_config):
5354
self.model.eval()
5455

5556
self.patcher = comfy.model_patcher.CoreModelPatcher(self.model, load_device=self.load_device, offload_device=offload_device)
57+
self.naf = None
5658

5759
def load_sd(self, sd):
5860
return self.model.load_state_dict(sd, strict=False, assign=self.patcher.is_dynamic())
@@ -141,6 +143,8 @@ def load_clipvision_from_sd(sd, prefix="", convert_keys=False):
141143
json_config = os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "image_encoders"), "dino2_large.json")
142144
elif 'layer.0.mlp.gate_proj.weight' in sd and 'layer.31.norm1.weight' in sd: # Dinov3 ViT-H/16+ (SwiGLU gated MLP, 32 layers)
143145
json_config = comfy.image_encoders.dino3.DINOV3_VITH_CONFIG
146+
elif 'layer.23.attention.o_proj.bias' in sd: # dinov3 large (24 layers)
147+
json_config = os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "image_encoders"), "dino3_large.json")
144148
else:
145149
return None
146150

@@ -153,6 +157,14 @@ def load_clipvision_from_sd(sd, prefix="", convert_keys=False):
153157
for k in keys:
154158
if k not in u:
155159
sd.pop(k)
160+
# NAF feature upsampler bundled into the DINOv3 file under the `naf.` prefix.
161+
naf_keys = [k for k in sd if k.startswith("naf.")]
162+
if naf_keys:
163+
naf_sd = {k[len("naf."):]: sd.pop(k) for k in naf_keys}
164+
naf = NAF(operations=comfy.ops.manual_cast).eval()
165+
naf.load_state_dict(naf_sd)
166+
naf.to(comfy.model_management.text_encoder_dtype(clip.load_device))
167+
clip.naf = comfy.model_patcher.CoreModelPatcher(naf, load_device=clip.load_device, offload_device=comfy.model_management.text_encoder_offload_device())
156168
return clip
157169

158170
def load(ckpt_path):

comfy/image_encoders/dino3.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,11 @@ def forward(self, pixel_values):
156156

157157

158158
class DINOv3ViTEmbeddings(nn.Module):
159-
def __init__(self, hidden_size, num_register_tokens, num_channels, patch_size, dtype, device, operations):
159+
def __init__(self, hidden_size, num_register_tokens, num_channels, patch_size, dtype, device, operations, use_mask_token=True):
160160
super().__init__()
161161
self.cls_token = nn.Parameter(torch.empty(1, 1, hidden_size, device=device, dtype=dtype))
162-
self.mask_token = nn.Parameter(torch.empty(1, 1, hidden_size, device=device, dtype=dtype))
162+
self.mask_token = nn.Parameter(torch.empty(1, 1, hidden_size, device=device, dtype=dtype)) if use_mask_token else None
163+
163164
self.register_tokens = nn.Parameter(torch.empty(1, num_register_tokens, hidden_size, device=device, dtype=dtype))
164165
self.patch_embeddings = operations.Conv2d(
165166
num_channels, hidden_size, kernel_size=patch_size, stride=patch_size, device=device, dtype=dtype
@@ -212,7 +213,7 @@ def forward(self, hidden_states, attention_mask=None, position_embeddings=None):
212213

213214

214215
class DINOv3ViTModel(nn.Module):
215-
def __init__(self, config, dtype, device, operations):
216+
def __init__(self, config, dtype, device, operations, use_mask_token=True):
216217
super().__init__()
217218
num_hidden_layers = config["num_hidden_layers"]
218219
hidden_size = config["hidden_size"]
@@ -228,7 +229,7 @@ def __init__(self, config, dtype, device, operations):
228229

229230
self.embeddings = DINOv3ViTEmbeddings(
230231
hidden_size, num_register_tokens, num_channels=num_channels, patch_size=patch_size,
231-
dtype=dtype, device=device, operations=operations
232+
dtype=dtype, device=device, operations=operations, use_mask_token=use_mask_token
232233
)
233234
self.rope_embeddings = DINOv3ViTRopePositionEmbedding(
234235
rope_theta, hidden_size, num_attention_heads, patch_size=patch_size, dtype=dtype, device=device
@@ -240,6 +241,10 @@ def __init__(self, config, dtype, device, operations):
240241
for _ in range(num_hidden_layers)])
241242
self.norm = operations.LayerNorm(hidden_size, eps=layer_norm_eps, dtype=dtype, device=device)
242243

244+
self.patch_size = patch_size
245+
self.embed_dim = self.embed_dims = hidden_size
246+
self.num_prefix_tokens = 1 + num_register_tokens # cls + register
247+
243248
def get_input_embeddings(self):
244249
return self.embeddings.patch_embeddings
245250

@@ -257,3 +262,11 @@ def forward(self, pixel_values, bool_masked_pos=None, **kwargs):
257262
sequence_output = norm(hidden_states)
258263
pooled_output = sequence_output[:, 0, :]
259264
return sequence_output, None, pooled_output, None
265+
266+
def forward_features(self, pixel_values, **kwargs):
267+
sequence_output = self.forward(pixel_values, **kwargs)[0]
268+
b = pixel_values.shape[0]
269+
h = pixel_values.shape[-2] // self.patch_size
270+
w = pixel_values.shape[-1] // self.patch_size
271+
patches = sequence_output[:, self.num_prefix_tokens:, :]
272+
return patches.reshape(b, h, w, self.embed_dim).permute(0, 3, 1, 2).contiguous()
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"model_type": "dinov3",
3+
"hidden_size": 1024,
4+
"image_size": 224,
5+
"initializer_range": 0.02,
6+
"intermediate_size": 4096,
7+
"key_bias": false,
8+
"layer_norm_eps": 1e-05,
9+
"mlp_bias": true,
10+
"num_attention_heads": 16,
11+
"num_channels": 3,
12+
"num_hidden_layers": 24,
13+
"num_register_tokens": 4,
14+
"patch_size": 16,
15+
"pos_embed_rescale": 2.0,
16+
"proj_bias": true,
17+
"query_bias": true,
18+
"rope_theta": 100.0,
19+
"use_gated_mlp": false,
20+
"value_bias": true,
21+
"image_mean": [0.485, 0.456, 0.406],
22+
"image_std": [0.229, 0.224, 0.225]
23+
}

0 commit comments

Comments
 (0)