Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions bonsai/models/dinov3/modeling.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import dataclasses
from typing import Literal

import jax
import jax.numpy as jnp
Expand All @@ -13,7 +14,7 @@ class ModelConfig:
intermediate_size: int = 1536
num_hidden_layers: int = 12
num_attention_heads: int = 6
hidden_act: str = "gelu"
hidden_act: Literal["gelu", "silu"] = "gelu"
layer_norm_eps: float = 1e-5
rope_theta: float = 100.0
image_size: int = 224
Expand Down Expand Up @@ -127,12 +128,12 @@ def __init__(self, config: ModelConfig):
self.base = config.rope_theta
self.head_dim = config.hidden_size // config.num_attention_heads
self.num_patches_h = config.image_size // config.patch_size[0]
self.num_patches_w = config.image_size // config.patch_size[0]
self.num_patches_w = config.image_size // config.patch_size[1]
Comment on lines 130 to +131

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

These attributes self.num_patches_h and self.num_patches_w are initialized here but are never used. In the __call__ method, local variables with the same names are computed from the input tensor's shape and used instead. To avoid confusion and redundant code, these lines should be removed.


def __call__(self, pixel_values: Array) -> tuple[Array, Array]:
_, _, height, width = pixel_values.shape
num_patches_h = height // self.config.patch_size[0]
num_patches_w = width // self.config.patch_size[0]
num_patches_w = width // self.config.patch_size[1]

coords_h = jnp.arange(0.5, num_patches_h, dtype=jnp.float32) / num_patches_h # [H]
coords_w = jnp.arange(0.5, num_patches_w, dtype=jnp.float32) / num_patches_w # [W]
Expand All @@ -157,7 +158,7 @@ def __init__(self, config: ModelConfig):
self.lambda1 = nnx.Param(jnp.full((config.hidden_size,), config.layerscale_value, dtype=jnp.float32))

def __call__(self, x: Array) -> Array:
return x * self.lambda1
return x * self.lambda1[...]


def rotate_half(x: Array) -> Array:
Expand Down
20 changes: 20 additions & 0 deletions bonsai/models/dinov3/tests/test_outputs_dinov3.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,25 @@ def test_pooled_output_embeddings(self):
np.testing.assert_allclose(jy, ty.detach().cpu().numpy(), rtol=1e-5, atol=2e-2)


class TestRopePositionEmbedding(absltest.TestCase):
def test_non_square_patch_size_uses_width_patch_dimension(self):
config = model_lib.ModelConfig(
patch_size=(16, 8),
hidden_size=64,
num_attention_heads=1,
image_size=64,
)
rope = model_lib.Dinov3ViTRopePositionEmbedding(config)

x = jnp.zeros((1, 3, 64, 40), dtype=jnp.float32)
cos, sin = rope(x)

_, _, height, width = x.shape
expected_num_patches = (height // config.patch_size[0]) * (width // config.patch_size[1])
expected_head_dim = config.hidden_size // config.num_attention_heads
self.assertEqual(cos.shape, (expected_num_patches, expected_head_dim))
self.assertEqual(sin.shape, (expected_num_patches, expected_head_dim))


if __name__ == "__main__":
absltest.main()