bounty commited on
Commit
505474b
·
1 Parent(s): 10101c1

final working rotary fix and removed image cache waste

Browse files
Files changed (5) hide show
  1. moondream2/layers.py +1 -1
  2. moondream2/moondream.py +44 -141
  3. moondream2/rope.py +18 -21
  4. moondream2/text.py +13 -7
  5. notes.ipynb +199 -293
moondream2/layers.py CHANGED
@@ -16,7 +16,7 @@ class LinearWeights:
16
 
17
 
18
  def linear(x: torch.Tensor, w: LinearWeights) -> torch.Tensor:
19
- return F.linear(x, w.weight(), w.bias())
20
 
21
 
22
  @dataclass
 
16
 
17
 
18
  def linear(x: torch.Tensor, w: LinearWeights) -> torch.Tensor:
19
+ return F.linear(x, w.weight, w.bias)
20
 
21
 
22
  @dataclass
moondream2/moondream.py CHANGED
@@ -40,8 +40,25 @@ DEFAULT_MAX_OBJECTS = 50
40
  @dataclass(frozen=True)
41
  class EncodedImage:
42
  pos: int
 
43
 
 
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  class MoondreamModel(nn.Module):
46
  def __init__(self, config: MoondreamConfig, dtype=torch.float16, setup_caches=True):
47
  super().__init__()
@@ -104,6 +121,25 @@ class MoondreamModel(nn.Module):
104
  attn_mask[..., :prefix_attn_len, :prefix_attn_len] = 1
105
  self.register_buffer("attn_mask", attn_mask, persistent=False)
106
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  @property
108
  def device(self):
109
  return self.vision.pos_emb.device
@@ -115,12 +151,12 @@ class MoondreamModel(nn.Module):
115
  return vision_projection(g, r, self.vision, self.config.vision)
116
 
117
  def _prefill(self, x: torch.Tensor, attn_mask: torch.Tensor, pos_ids: torch.Tensor):
118
- return text_decoder(x, self.text, attn_mask, self.config.text, self.rope)
119
 
120
  def _decode_one_tok(
121
  self, x: torch.Tensor, attn_mask: torch.Tensor, pos_ids: torch.Tensor
122
  ):
123
- hidden = text_decoder(x, self.text, attn_mask, self.config.text, self.rope)
124
  logits = lm_head(hidden, self.text)
125
  return logits, hidden
126
 
@@ -178,7 +214,8 @@ class MoondreamModel(nn.Module):
178
  self._prefill(inputs_embeds, mask, pos_ids)
179
 
180
  return EncodedImage(
181
- pos=inputs_embeds.size(1)
 
182
  )
183
 
184
  def _apply_top_p(self, probs: torch.Tensor, top_p: float):
@@ -212,99 +249,11 @@ class MoondreamModel(nn.Module):
212
  pos = pos + prompt_emb.size(1)
213
  return logits, hidden, next_token, pos
214
 
215
- def _generate_text(
216
- self,
217
- prompt_tokens: torch.Tensor,
218
- pos: int,
219
- settings: Optional[TextSamplingSettings] = None,
220
- ):
221
- max_tokens = (
222
- settings.get("max_tokens", DEFAULT_MAX_TOKENS)
223
- if settings
224
- else DEFAULT_MAX_TOKENS
225
- )
226
- temperature = (
227
- settings.get("temperature", DEFAULT_TEMPERATURE)
228
- if settings
229
- else DEFAULT_TEMPERATURE
230
- )
231
- top_p = settings.get("top_p", DEFAULT_TOP_P) if settings else DEFAULT_TOP_P
232
-
233
- _, _, next_token, pos = self._prefill_prompt(
234
- prompt_tokens, pos, temperature, top_p
235
- )
236
-
237
- def generator(next_token, pos):
238
- mask = torch.zeros(1, 1, 2048, device=self.device, dtype=torch.bool)
239
- mask[:, :, :pos] = 1
240
- pos_ids = torch.tensor([pos], device=self.device, dtype=torch.long)
241
- generated_tokens = 0
242
-
243
- # For properly handling token streaming with Unicode
244
- token_cache = []
245
- print_len = 0
246
-
247
- while (
248
- next_token_id := next_token.item()
249
- ) != self.config.tokenizer.eos_id and generated_tokens < max_tokens:
250
- # Add token to our cache
251
- token_cache.append(next_token_id)
252
-
253
- # Decode all tokens collected so far
254
- text = self.tokenizer.decode(token_cache)
255
-
256
- # After a newline, we flush the cache completely
257
- if text.endswith("\n"):
258
- printable_text = text[print_len:]
259
- token_cache = []
260
- print_len = 0
261
- if printable_text:
262
- yield printable_text
263
- # If the last token is a CJK character, we can safely print it
264
- elif len(text) > 0 and _is_cjk_char(ord(text[-1])):
265
- printable_text = text[print_len:]
266
- print_len += len(printable_text)
267
- if printable_text:
268
- yield printable_text
269
- # Otherwise, only print up to the last space to avoid cutting words
270
- else:
271
- last_space_idx = text.rfind(" ", print_len)
272
- if last_space_idx >= print_len:
273
- printable_text = text[print_len : last_space_idx + 1]
274
- print_len += len(printable_text)
275
- if printable_text:
276
- yield printable_text
277
-
278
- with torch.inference_mode():
279
- next_emb = text_encoder(next_token, self.text)
280
- mask[:, :, pos], pos_ids[0] = 1, pos
281
- logits, _ = self._decode_one_tok(next_emb, mask, pos_ids)
282
- pos += 1
283
-
284
- if temperature == 0:
285
- next_token = torch.argmax(logits, dim=-1).unsqueeze(1) # (1, 1)
286
- else:
287
- probs = torch.softmax(logits / temperature, dim=-1) # (1, V)
288
- probs = self._apply_top_p(probs, top_p)
289
- next_token = torch.multinomial(probs, num_samples=1) # (1, 1)
290
-
291
- generated_tokens += 1
292
-
293
- # Flush any remaining text in the cache
294
- if token_cache:
295
- text = self.tokenizer.decode(token_cache)
296
- printable_text = text[print_len:]
297
- if printable_text:
298
- yield printable_text
299
-
300
- return generator(next_token, pos)
301
-
302
  def _generate_points(
303
  self,
304
  hidden: torch.Tensor,
305
  next_token: torch.Tensor,
306
  pos: int,
307
- include_size: bool = True,
308
  max_objects: int = DEFAULT_MAX_OBJECTS,
309
  ):
310
  out = []
@@ -333,44 +282,7 @@ class MoondreamModel(nn.Module):
333
  y_center.to(dtype=y_logits.dtype), self.region
334
  ).unsqueeze(0)
335
 
336
- # Decode size
337
- if include_size:
338
- mask[:, :, pos], pos_ids[0] = 1, pos
339
- logits, hidden = self._decode_one_tok(next_emb, mask, pos_ids)
340
- pos += 1
341
- size_logits = decode_size(hidden, self.region)
342
-
343
- # Get bin indices from the logits
344
- w_bin = torch.argmax(size_logits[0], dim=-1)
345
- h_bin = torch.argmax(size_logits[1], dim=-1)
346
-
347
- # Convert from bin indices to actual size values using the inverse of the log-scale mapping
348
- # Formula: size = 2^((bin / 1023.0) * 10.0 - 10.0)
349
- w = torch.pow(2.0, (w_bin.float() / 1023.0) * 10.0 - 10.0)
350
- h = torch.pow(2.0, (h_bin.float() / 1023.0) * 10.0 - 10.0)
351
-
352
- next_emb = (
353
- encode_size(
354
- torch.tensor(
355
- [w, h], device=self.device, dtype=size_logits.dtype
356
- ),
357
- self.region,
358
- )
359
- .unsqueeze(0)
360
- .unsqueeze(0)
361
- )
362
-
363
- # Add object
364
- out.append(
365
- {
366
- "x_min": x_center.item() - w.item() / 2,
367
- "y_min": y_center.item() - h.item() / 2,
368
- "x_max": x_center.item() + w.item() / 2,
369
- "y_max": y_center.item() + h.item() / 2,
370
- }
371
- )
372
- else:
373
- out.append({"x": x_center.item(), "y": y_center.item()})
374
 
375
  # Decode next token (x-coordinate, or eos)
376
  mask[:, :, pos], pos_ids[0] = 1, pos
@@ -411,19 +323,10 @@ class MoondreamModel(nn.Module):
411
  else DEFAULT_MAX_OBJECTS
412
  )
413
  objects = self._generate_points(
414
- hidden, next_token, pos, include_size=False, max_objects=max_objects
415
  )
416
 
417
  return {"points": objects}
418
 
419
- def _is_cjk_char(cp):
420
- """Checks whether CP is the codepoint of a CJK character."""
421
- # This defines a "chinese character" as anything in the CJK Unicode block:
422
- # https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_(Unicode_block)
423
- if (
424
- (cp >= 0x4E00 and cp <= 0x9FFF)
425
- or (cp >= 0x3400 and cp <= 0x4DBF)
426
- or (cp >= 0x2F800 and cp <= 0x2FA1F)
427
- ):
428
- return True
429
- return False
 
40
  @dataclass(frozen=True)
41
  class EncodedImage:
42
  pos: int
43
+ caches: List[Tuple[torch.Tensor, torch.Tensor]]
44
 
45
+ class KVCache(nn.Module):
46
 
47
+ def __init__(self, n_heads, n_kv_heads, max_context, dim, device, dtype):
48
+ super().__init__()
49
+ cache_shape = (1, n_kv_heads, max_context, dim // n_heads)
50
+ self.register_buffer(
51
+ "k_cache", torch.zeros(*cache_shape, device=device, dtype=dtype)
52
+ )
53
+ self.register_buffer(
54
+ "v_cache", torch.zeros(*cache_shape, device=device, dtype=dtype)
55
+ )
56
+
57
+ def update(self, pos_ids, k, v):
58
+ kout, vout = self.k_cache, self.v_cache
59
+ kout[:, :, pos_ids, :] = k
60
+ vout[:, :, pos_ids, :] = v
61
+ return kout, vout
62
  class MoondreamModel(nn.Module):
63
  def __init__(self, config: MoondreamConfig, dtype=torch.float16, setup_caches=True):
64
  super().__init__()
 
121
  attn_mask[..., :prefix_attn_len, :prefix_attn_len] = 1
122
  self.register_buffer("attn_mask", attn_mask, persistent=False)
123
 
124
+ # Initialize KV caches.
125
+ if setup_caches:
126
+ self._setup_caches()
127
+
128
+ def _setup_caches(self):
129
+ c = self.config.text
130
+ for b in self.text.blocks:
131
+ b.kv_cache = KVCache(
132
+ c.n_heads,
133
+ c.n_kv_heads,
134
+ c.max_context,
135
+ c.dim,
136
+ device=self.device,
137
+ dtype=self.vision.pos_emb.dtype,
138
+ )
139
+ def load_encoded_image(self, encoded_image: EncodedImage):
140
+ for b, (k, v) in zip(self.text.blocks, encoded_image.caches):
141
+ b.kv_cache.k_cache[:, :, : k.size(2), :] = k
142
+ b.kv_cache.v_cache[:, :, : v.size(2), :] = v
143
  @property
144
  def device(self):
145
  return self.vision.pos_emb.device
 
151
  return vision_projection(g, r, self.vision, self.config.vision)
152
 
153
  def _prefill(self, x: torch.Tensor, attn_mask: torch.Tensor, pos_ids: torch.Tensor):
154
+ return text_decoder(x, self.text, attn_mask, self.config.text, self.rope, pos_ids)
155
 
156
  def _decode_one_tok(
157
  self, x: torch.Tensor, attn_mask: torch.Tensor, pos_ids: torch.Tensor
158
  ):
159
+ hidden = text_decoder(x, self.text, attn_mask, self.config.text, self.rope, pos_ids)
160
  logits = lm_head(hidden, self.text)
161
  return logits, hidden
162
 
 
214
  self._prefill(inputs_embeds, mask, pos_ids)
215
 
216
  return EncodedImage(
217
+ pos=inputs_embeds.size(1),
218
+ caches=[]
219
  )
220
 
221
  def _apply_top_p(self, probs: torch.Tensor, top_p: float):
 
249
  pos = pos + prompt_emb.size(1)
250
  return logits, hidden, next_token, pos
251
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  def _generate_points(
253
  self,
254
  hidden: torch.Tensor,
255
  next_token: torch.Tensor,
256
  pos: int,
 
257
  max_objects: int = DEFAULT_MAX_OBJECTS,
258
  ):
259
  out = []
 
282
  y_center.to(dtype=y_logits.dtype), self.region
283
  ).unsqueeze(0)
284
 
285
+ out.append({"x": x_center.item(), "y": y_center.item()})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
 
287
  # Decode next token (x-coordinate, or eos)
288
  mask[:, :, pos], pos_ids[0] = 1, pos
 
323
  else DEFAULT_MAX_OBJECTS
324
  )
325
  objects = self._generate_points(
326
+ hidden, next_token, pos, max_objects=max_objects
327
  )
328
 
329
  return {"points": objects}
330
 
331
+ def forward(self, image: Union[Image.Image, EncodedImage], prompt: str, settings: Optional[ObjectSamplingSettings] = None):
332
+ return self.point(image, prompt, settings)
 
 
 
 
 
 
 
 
 
moondream2/rope.py CHANGED
@@ -22,32 +22,29 @@ class RotaryEmbedding(nn.Module):
22
  self.register_buffer('cos_cache', cos_vals, persistent=False)
23
  self.register_buffer('sin_cache', sin_vals, persistent=False)
24
 
25
- def apply(self, x: torch.Tensor) -> torch.Tensor:
26
  """
27
- WARNING: This modifies the input tensor in-place for maximum speed!
28
- If you need the original tensor, make a copy before calling this.
29
-
30
- Must match RotaryEmbedding output exactly.
31
  """
32
- seq_len = x.shape[1]
33
  d = self.rot_dim // 2
34
-
35
- # Get cos/sin with same broadcasting as RotaryEmbedding
36
- cos = self.cos_cache[:seq_len].unsqueeze(0).unsqueeze(2)
37
- sin = self.sin_cache[:seq_len].unsqueeze(0).unsqueeze(2)
38
-
39
- # Split rotated part into real/imaginary components
40
- xq_r = x[..., :d] # First half of rot_dim
41
- xq_i = x[..., d:d*2] # Second half of rot_dim
42
-
 
 
 
 
43
  # Apply rotation
44
  xq_out_r = xq_r * cos - xq_i * sin
45
  xq_out_i = xq_r * sin + xq_i * cos
46
-
47
- # Vectorized interleaving using torch.stack and view
48
- # Stack creates [d, ..., 2] then view as [..., d*2]
49
  x[..., :self.rot_dim] = torch.stack([xq_out_r, xq_out_i], dim=-1).view(*x.shape[:-1], self.rot_dim)
50
-
51
- # x_pass part (x[..., self.rot_dim:]) remains unchanged automatically
52
-
53
  return x
 
22
  self.register_buffer('cos_cache', cos_vals, persistent=False)
23
  self.register_buffer('sin_cache', sin_vals, persistent=False)
24
 
25
+ def apply(self, x: torch.Tensor, position_ids: torch.Tensor) -> torch.Tensor:
26
  """
27
+ Now works with [..., heads, seq_len, head_dim] - no permutation needed!
 
 
 
28
  """
 
29
  d = self.rot_dim // 2
30
+
31
+ # Get cos/sin for positions - shape: [seq_len, d]
32
+ cos = self.cos_cache[position_ids] # [seq_len, d]
33
+ sin = self.sin_cache[position_ids] # [seq_len, d]
34
+
35
+ # Broadcast to match x: [..., heads, seq_len, d]
36
+ cos = cos.unsqueeze(0).unsqueeze(0) # [1, 1, seq_len, d]
37
+ sin = sin.unsqueeze(0).unsqueeze(0) # [1, 1, seq_len, d]
38
+
39
+ # Split rotated part
40
+ xq_r = x[..., :d] # [..., heads, seq_len, d]
41
+ xq_i = x[..., d:d*2] # [..., heads, seq_len, d]
42
+
43
  # Apply rotation
44
  xq_out_r = xq_r * cos - xq_i * sin
45
  xq_out_i = xq_r * sin + xq_i * cos
46
+
47
+ # Update in-place
 
48
  x[..., :self.rot_dim] = torch.stack([xq_out_r, xq_out_i], dim=-1).view(*x.shape[:-1], self.rot_dim)
49
+
 
 
50
  return x
moondream2/text.py CHANGED
@@ -14,13 +14,14 @@ if TYPE_CHECKING:
14
  def text_encoder(input_ids: torch.Tensor, w: nn.Module):
15
  return F.embedding(input_ids, w.wte)
16
 
17
-
18
  def attn(
19
  x: torch.Tensor,
20
  w: nn.Module,
21
  attn_mask: torch.Tensor,
22
  n_heads: int,
23
- rope: "RotaryEmbedding"
 
 
24
  ):
25
  bsz, q_len, d_model = x.shape
26
  head_dim = d_model // n_heads
@@ -37,8 +38,11 @@ def attn(
37
  # 3. Unpack/Split along the first dimension (which now separates Q, K, V)
38
  q, k, v = qkv_permuted[0], qkv_permuted[1], qkv_permuted[2]
39
 
40
- q = rope.apply(q.permute(0, 2, 1, 3))
41
- k = rope.apply(k.permute(0, 2, 1, 3))
 
 
 
42
 
43
  out = F.scaled_dot_product_attention(
44
  q, k, v, attn_mask=attn_mask
@@ -47,15 +51,15 @@ def attn(
47
  out = w.proj(out)
48
  return out
49
 
50
-
51
  def text_decoder(
52
  x: torch.Tensor,
53
  w: nn.Module,
54
  attn_mask: torch.Tensor,
55
  config: TextConfig,
56
- rope: "RotaryEmbedding"
57
-
58
  ):
 
59
  for i, block in enumerate(w.blocks):
60
  l_in = layer_norm(x, block.ln)
61
  l_attn = attn(
@@ -64,6 +68,8 @@ def text_decoder(
64
  attn_mask=attn_mask,
65
  n_heads=config.n_heads,
66
  rope=rope,
 
 
67
  )
68
  l_mlp = mlp(l_in, block.mlp)
69
  x = x + l_attn + l_mlp
 
14
  def text_encoder(input_ids: torch.Tensor, w: nn.Module):
15
  return F.embedding(input_ids, w.wte)
16
 
 
17
  def attn(
18
  x: torch.Tensor,
19
  w: nn.Module,
20
  attn_mask: torch.Tensor,
21
  n_heads: int,
22
+ rope: "RotaryEmbedding",
23
+ kv_cache: nn.Module,
24
+ pos_ids: torch.Tensor,
25
  ):
26
  bsz, q_len, d_model = x.shape
27
  head_dim = d_model // n_heads
 
38
  # 3. Unpack/Split along the first dimension (which now separates Q, K, V)
39
  q, k, v = qkv_permuted[0], qkv_permuted[1], qkv_permuted[2]
40
 
41
+ q = rope.apply(q, pos_ids)
42
+ k = rope.apply(k, pos_ids)
43
+
44
+ k, v = kv_cache.update(pos_ids, k, v)
45
+
46
 
47
  out = F.scaled_dot_product_attention(
48
  q, k, v, attn_mask=attn_mask
 
51
  out = w.proj(out)
52
  return out
53
 
 
54
  def text_decoder(
55
  x: torch.Tensor,
56
  w: nn.Module,
57
  attn_mask: torch.Tensor,
58
  config: TextConfig,
59
+ rope: "RotaryEmbedding",
60
+ pos_ids: torch.Tensor,
61
  ):
62
+
63
  for i, block in enumerate(w.blocks):
64
  l_in = layer_norm(x, block.ln)
65
  l_attn = attn(
 
68
  attn_mask=attn_mask,
69
  n_heads=config.n_heads,
70
  rope=rope,
71
+ kv_cache=block.kv_cache,
72
+ pos_ids=pos_ids,
73
  )
74
  l_mlp = mlp(l_in, block.mlp)
75
  x = x + l_attn + l_mlp
notes.ipynb CHANGED
@@ -1,95 +1,16 @@
1
  {
2
  "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 2,
6
- "metadata": {},
7
- "outputs": [
8
- {
9
- "data": {
10
- "text/plain": [
11
- "20"
12
- ]
13
- },
14
- "execution_count": 2,
15
- "metadata": {},
16
- "output_type": "execute_result"
17
- }
18
- ],
19
- "source": [
20
- "import torch\n",
21
- "import gc\n",
22
- "# ... your code that uses GPU tensors ...\n",
23
- "# For example:\n",
24
- "# x = torch.randn(1000, 1000, device='cuda')\n",
25
- "# del x # or x = None\n",
26
- "\n",
27
- "# This is the key command:\n",
28
- "torch.cuda.empty_cache()\n",
29
- "\n",
30
- "# Optionally, run Python's garbage collector too\n",
31
- "gc.collect()"
32
- ]
33
- },
34
- {
35
- "cell_type": "code",
36
- "execution_count": 1,
37
- "metadata": {},
38
- "outputs": [
39
- {
40
- "name": "stderr",
41
- "output_type": "stream",
42
- "text": [
43
- "/home/pixel/Desktop/moondream/venv/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
44
- " from .autonotebook import tqdm as notebook_tqdm\n"
45
- ]
46
- },
47
- {
48
- "data": {
49
- "text/plain": [
50
- "False"
51
- ]
52
- },
53
- "execution_count": 1,
54
- "metadata": {},
55
- "output_type": "execute_result"
56
- }
57
- ],
58
- "source": [
59
- "from transformers.utils import is_flash_attn_2_available\n",
60
- "is_flash_attn_2_available()\n"
61
- ]
62
- },
63
  {
64
  "cell_type": "code",
65
  "execution_count": 1,
66
  "metadata": {},
67
  "outputs": [],
68
- "source": [
69
- "import torch"
70
- ]
71
- },
72
- {
73
- "cell_type": "code",
74
- "execution_count": 1,
75
- "metadata": {},
76
- "outputs": [
77
- {
78
- "name": "stderr",
79
- "output_type": "stream",
80
- "text": [
81
- "/home/pixel/Desktop/moondream/venv/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
82
- " from .autonotebook import tqdm as notebook_tqdm\n"
83
- ]
84
- }
85
- ],
86
  "source": [
87
  "# auto reload jupyter notebook\n",
88
  "%load_ext autoreload\n",
89
  "%autoreload 2\n",
90
  "\n",
91
  "import os\n",
92
- "os.environ[\"PYTORCH_CUDA_ALLOC_CONF\"] = \"expandable_segments:True\"\n",
93
  "\n",
94
  "import torch\n",
95
  "from moondream2.config import MoondreamConfig\n",
@@ -101,257 +22,125 @@
101
  " model = MoondreamModel(config, setup_caches=False)\n",
102
  " from safetensors.torch import load_model\n",
103
  " weights_path = \"moondream2/model.safetensors\" # Path to your local weights file\n",
104
- " state_dict = load_model(model, weights_path)\n"
105
- ]
106
- },
107
- {
108
- "cell_type": "code",
109
- "execution_count": 2,
110
- "metadata": {},
111
- "outputs": [],
112
- "source": [
113
- "import torch.nn as nn\n",
114
- "from torch.quantization import quantize_dynamic\n",
115
- "\n",
116
  "\n",
117
- "model_quantized = quantize_dynamic(\n",
118
- " model, \n",
119
- " {nn.Linear}, # Only quantize these layer types\n",
120
- " dtype=torch.qint8\n",
121
- ")\n"
122
  ]
123
  },
124
  {
125
  "cell_type": "code",
126
- "execution_count": 6,
127
  "metadata": {},
128
- "outputs": [],
 
 
 
 
 
 
 
 
 
129
  "source": [
130
- "real = model.get_submodule(\"vision\").proj_mlp.get_submodule(\"fc1\")"
 
 
 
 
 
 
 
 
 
131
  ]
132
  },
133
  {
134
  "cell_type": "code",
135
- "execution_count": 8,
136
  "metadata": {},
137
  "outputs": [
138
  {
139
- "data": {
140
- "text/plain": [
141
- "tensor([[ 0.0198, 0.0356, -0.0158, ..., 0.0119, 0.0487, 0.0448],\n",
142
- " [ 0.0198, 0.0277, 0.0725, ..., 0.0079, 0.0343, 0.0435],\n",
143
- " [-0.0422, 0.0356, -0.0263, ..., -0.0145, -0.0250, 0.0184],\n",
144
- " ...,\n",
145
- " [-0.0356, -0.0474, -0.0237, ..., -0.0198, 0.0277, 0.0263],\n",
146
- " [ 0.0013, 0.0263, 0.0395, ..., -0.0422, 0.0329, -0.0316],\n",
147
- " [ 0.0303, -0.0527, -0.0356, ..., 0.0382, -0.0171, -0.0171]],\n",
148
- " size=(8192, 2304), dtype=torch.qint8,\n",
149
- " quantization_scheme=torch.per_tensor_affine, scale=0.0013174019986763597,\n",
150
- " zero_point=0)"
151
- ]
152
- },
153
- "execution_count": 8,
154
- "metadata": {},
155
- "output_type": "execute_result"
156
  }
157
  ],
158
  "source": [
159
- "real."
 
 
 
 
 
 
 
 
160
  ]
161
  },
162
  {
163
  "cell_type": "code",
164
- "execution_count": 9,
165
  "metadata": {},
166
  "outputs": [],
167
  "source": [
168
- "vision = model_quantized.get_submodule(\"vision\")"
169
  ]
170
  },
171
  {
172
  "cell_type": "code",
173
- "execution_count": 10,
174
  "metadata": {},
175
  "outputs": [],
176
  "source": [
177
- "fcc = vision.proj_mlp.get_submodule(\"fc1\")"
 
 
 
 
178
  ]
179
  },
180
  {
181
- "cell_type": "code",
182
- "execution_count": null,
183
  "metadata": {},
184
- "outputs": [
185
- {
186
- "data": {
187
- "text/plain": [
188
- "tensor([[ 0.0198, 0.0356, -0.0158, ..., 0.0119, 0.0487, 0.0448],\n",
189
- " [ 0.0198, 0.0277, 0.0725, ..., 0.0079, 0.0343, 0.0435],\n",
190
- " [-0.0422, 0.0356, -0.0263, ..., -0.0145, -0.0250, 0.0184],\n",
191
- " ...,\n",
192
- " [-0.0356, -0.0474, -0.0237, ..., -0.0198, 0.0277, 0.0263],\n",
193
- " [ 0.0013, 0.0263, 0.0395, ..., -0.0422, 0.0329, -0.0316],\n",
194
- " [ 0.0303, -0.0527, -0.0356, ..., 0.0382, -0.0171, -0.0171]],\n",
195
- " size=(8192, 2304), dtype=torch.qint8,\n",
196
- " quantization_scheme=torch.per_tensor_affine, scale=0.0013174019986763597,\n",
197
- " zero_point=0)"
198
- ]
199
- },
200
- "execution_count": 13,
201
- "metadata": {},
202
- "output_type": "execute_result"
203
- }
204
- ],
205
  "source": [
206
- "fcc.weight()"
 
 
 
207
  ]
208
  },
209
  {
210
- "cell_type": "code",
211
- "execution_count": 3,
212
  "metadata": {},
213
- "outputs": [],
214
  "source": [
 
 
215
  "\n",
216
- "model = model.to(device)"
217
  ]
218
  },
219
  {
220
  "cell_type": "code",
221
- "execution_count": 5,
222
  "metadata": {},
223
  "outputs": [
224
  {
225
  "data": {
226
  "text/plain": [
227
- "MoondreamModel(\n",
228
- " (vision): ModuleDict(\n",
229
- " (patch_emb): DynamicQuantizedLinear(in_features=588, out_features=1152, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
230
- " (blocks): ModuleList(\n",
231
- " (0-26): 27 x ModuleDict(\n",
232
- " (ln1): LayerNorm((1152,), eps=1e-05, elementwise_affine=True)\n",
233
- " (attn): ModuleDict(\n",
234
- " (qkv): DynamicQuantizedLinear(in_features=1152, out_features=3456, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
235
- " (proj): DynamicQuantizedLinear(in_features=1152, out_features=1152, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
236
- " )\n",
237
- " (ln2): LayerNorm((1152,), eps=1e-05, elementwise_affine=True)\n",
238
- " (mlp): ModuleDict(\n",
239
- " (fc1): DynamicQuantizedLinear(in_features=1152, out_features=4304, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
240
- " (fc2): DynamicQuantizedLinear(in_features=4304, out_features=1152, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
241
- " )\n",
242
- " )\n",
243
- " )\n",
244
- " (post_ln): LayerNorm((1152,), eps=1e-05, elementwise_affine=True)\n",
245
- " (proj_mlp): ModuleDict(\n",
246
- " (fc1): DynamicQuantizedLinear(in_features=2304, out_features=8192, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
247
- " (fc2): DynamicQuantizedLinear(in_features=8192, out_features=2048, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
248
- " )\n",
249
- " )\n",
250
- " (text): ModuleDict(\n",
251
- " (blocks): ModuleList(\n",
252
- " (0-23): 24 x ModuleDict(\n",
253
- " (ln): LayerNorm((2048,), eps=1e-05, elementwise_affine=True)\n",
254
- " (attn): ModuleDict(\n",
255
- " (qkv): DynamicQuantizedLinear(in_features=2048, out_features=6144, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
256
- " (proj): DynamicQuantizedLinear(in_features=2048, out_features=2048, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
257
- " )\n",
258
- " (mlp): ModuleDict(\n",
259
- " (fc1): DynamicQuantizedLinear(in_features=2048, out_features=8192, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
260
- " (fc2): DynamicQuantizedLinear(in_features=8192, out_features=2048, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
261
- " )\n",
262
- " )\n",
263
- " )\n",
264
- " (post_ln): LayerNorm((2048,), eps=1e-05, elementwise_affine=True)\n",
265
- " (lm_head): DynamicQuantizedLinear(in_features=2048, out_features=51200, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
266
- " )\n",
267
- " (rotary_emb): RotaryPositionalEmbeddings()\n",
268
- " (region): ModuleDict(\n",
269
- " (coord_encoder): DynamicQuantizedLinear(in_features=256, out_features=2048, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
270
- " (coord_decoder): ModuleDict(\n",
271
- " (fc1): DynamicQuantizedLinear(in_features=2048, out_features=8192, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
272
- " (fc2): DynamicQuantizedLinear(in_features=8192, out_features=1024, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
273
- " )\n",
274
- " (size_encoder): DynamicQuantizedLinear(in_features=512, out_features=2048, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
275
- " (size_decoder): ModuleDict(\n",
276
- " (fc1): DynamicQuantizedLinear(in_features=2048, out_features=8192, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
277
- " (fc2): DynamicQuantizedLinear(in_features=8192, out_features=2048, dtype=torch.qint8, qscheme=torch.per_tensor_affine)\n",
278
- " )\n",
279
- " )\n",
280
- ")"
281
  ]
282
  },
283
- "execution_count": 5,
284
  "metadata": {},
285
  "output_type": "execute_result"
286
  }
287
  ],
288
  "source": [
289
- "model"
290
- ]
291
- },
292
- {
293
- "cell_type": "code",
294
- "execution_count": 4,
295
- "metadata": {},
296
- "outputs": [
297
- {
298
- "name": "stdout",
299
- "output_type": "stream",
300
- "text": [
301
- "model size: 203.238MB\n"
302
- ]
303
- }
304
- ],
305
- "source": [
306
- "param_size = 0\n",
307
- "for param in model.parameters():\n",
308
- " param_size += param.nelement() * param.element_size()\n",
309
- "buffer_size = 0\n",
310
- "for buffer in model.buffers():\n",
311
- " buffer_size += buffer.nelement() * buffer.element_size()\n",
312
- "\n",
313
- "size_all_mb = (param_size + buffer_size) / 1024**2\n",
314
- "print('model size: {:.3f}MB'.format(size_all_mb))"
315
- ]
316
- },
317
- {
318
- "cell_type": "code",
319
- "execution_count": 3,
320
- "metadata": {},
321
- "outputs": [],
322
- "source": [
323
- "model = model_quantized.to(device)"
324
- ]
325
- },
326
- {
327
- "cell_type": "code",
328
- "execution_count": 4,
329
- "metadata": {},
330
- "outputs": [
331
- {
332
- "ename": "RuntimeError",
333
- "evalue": "self and mat2 must have the same dtype, but got Half and QInt8",
334
- "output_type": "error",
335
- "traceback": [
336
- "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
337
- "\u001b[31mRuntimeError\u001b[39m Traceback (most recent call last)",
338
- "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[4]\u001b[39m\u001b[32m, line 5\u001b[39m\n\u001b[32m 3\u001b[39m image = Image.open(\u001b[33m\"\u001b[39m\u001b[33mexample.png\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 4\u001b[39m query = \u001b[33m\"\u001b[39m\u001b[33mhome icon at the bottom of the screen is visible\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m5\u001b[39m points = \u001b[43mmodel\u001b[49m\u001b[43m.\u001b[49m\u001b[43mpoint\u001b[49m\u001b[43m(\u001b[49m\u001b[43mimage\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mquery\u001b[49m\u001b[43m)\u001b[49m[\u001b[33m\"\u001b[39m\u001b[33mpoints\u001b[39m\u001b[33m\"\u001b[39m]\n",
339
- "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/moondream/moondream2/moondream.py:396\u001b[39m, in \u001b[36mMoondreamModel.point\u001b[39m\u001b[34m(self, image, object, settings)\u001b[39m\n\u001b[32m 393\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m.config.tokenizer.templates[\u001b[33m\"\u001b[39m\u001b[33mpoint\u001b[39m\u001b[33m\"\u001b[39m] \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 394\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mNotImplementedError\u001b[39;00m(\u001b[33m\"\u001b[39m\u001b[33mModel does not support pointing.\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m396\u001b[39m image = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mencode_image\u001b[49m\u001b[43m(\u001b[49m\u001b[43mimage\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 398\u001b[39m prompt_tokens = torch.tensor(\n\u001b[32m 399\u001b[39m [\n\u001b[32m 400\u001b[39m \u001b[38;5;28mself\u001b[39m.config.tokenizer.templates[\u001b[33m\"\u001b[39m\u001b[33mpoint\u001b[39m\u001b[33m\"\u001b[39m][\u001b[33m\"\u001b[39m\u001b[33mprefix\u001b[39m\u001b[33m\"\u001b[39m]\n\u001b[32m (...)\u001b[39m\u001b[32m 404\u001b[39m device=\u001b[38;5;28mself\u001b[39m.device,\n\u001b[32m 405\u001b[39m )\n\u001b[32m 407\u001b[39m _, hidden, next_token, pos = \u001b[38;5;28mself\u001b[39m._prefill_prompt(\n\u001b[32m 408\u001b[39m prompt_tokens, image.pos, temperature=\u001b[32m0\u001b[39m, top_p=\u001b[32m0\u001b[39m\n\u001b[32m 409\u001b[39m )\n",
340
- "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/moondream/moondream2/moondream.py:174\u001b[39m, in \u001b[36mMoondreamModel.encode_image\u001b[39m\u001b[34m(self, image)\u001b[39m\n\u001b[32m 170\u001b[39m \u001b[38;5;28;01mwith\u001b[39;00m torch.inference_mode():\n\u001b[32m 172\u001b[39m bos = torch.tensor([[\u001b[38;5;28mself\u001b[39m.config.tokenizer.bos_id]], device=\u001b[38;5;28mself\u001b[39m.device)\n\u001b[32m--> \u001b[39m\u001b[32m174\u001b[39m img_emb = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_run_vision_encoder\u001b[49m\u001b[43m(\u001b[49m\u001b[43mimage\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 175\u001b[39m bos_emb = text_encoder(\n\u001b[32m 176\u001b[39m bos,\n\u001b[32m 177\u001b[39m \u001b[38;5;28mself\u001b[39m.text,\n\u001b[32m 178\u001b[39m )\n\u001b[32m 179\u001b[39m inputs_embeds = torch.cat([bos_emb, img_emb[\u001b[38;5;28;01mNone\u001b[39;00m]], dim=\u001b[32m1\u001b[39m)\n",
341
- "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/moondream/moondream2/moondream.py:143\u001b[39m, in \u001b[36mMoondreamModel._run_vision_encoder\u001b[39m\u001b[34m(self, image)\u001b[39m\n\u001b[32m 140\u001b[39m all_crops, tiling = prepare_crops(image, \u001b[38;5;28mself\u001b[39m.config.vision, device=\u001b[38;5;28mself\u001b[39m.device)\n\u001b[32m 141\u001b[39m torch._dynamo.mark_dynamic(all_crops, \u001b[32m0\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m143\u001b[39m outputs = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_vis_enc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mall_crops\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 145\u001b[39m global_features = outputs[\u001b[32m0\u001b[39m]\n\u001b[32m 146\u001b[39m local_features = outputs[\u001b[32m1\u001b[39m:].view(\n\u001b[32m 147\u001b[39m -\u001b[32m1\u001b[39m,\n\u001b[32m 148\u001b[39m \u001b[38;5;28mself\u001b[39m.config.vision.enc_n_layers,\n\u001b[32m 149\u001b[39m \u001b[38;5;28mself\u001b[39m.config.vision.enc_n_layers,\n\u001b[32m 150\u001b[39m \u001b[38;5;28mself\u001b[39m.config.vision.enc_dim,\n\u001b[32m 151\u001b[39m )\n",
342
- "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/moondream/moondream2/moondream.py:116\u001b[39m, in \u001b[36mMoondreamModel._vis_enc\u001b[39m\u001b[34m(self, x)\u001b[39m\n\u001b[32m 115\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m_vis_enc\u001b[39m(\u001b[38;5;28mself\u001b[39m, x: torch.Tensor):\n\u001b[32m--> \u001b[39m\u001b[32m116\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mvision_encoder\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvision\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m.\u001b[49m\u001b[43mvision\u001b[49m\u001b[43m)\u001b[49m\n",
343
- "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/moondream/moondream2/vision.py:71\u001b[39m, in \u001b[36mvision_encoder\u001b[39m\u001b[34m(input_BCHW, w, config)\u001b[39m\n\u001b[32m 68\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mvision_encoder\u001b[39m(input_BCHW: torch.Tensor, w: nn.Module, config: VisionConfig):\n\u001b[32m 69\u001b[39m x = create_patches(input_BCHW, config.enc_patch_size)\n\u001b[32m---> \u001b[39m\u001b[32m71\u001b[39m x = \u001b[43mlinear\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mw\u001b[49m\u001b[43m.\u001b[49m\u001b[43mpatch_emb\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 72\u001b[39m x = x + w.pos_emb\n\u001b[32m 73\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m block \u001b[38;5;129;01min\u001b[39;00m w.blocks:\n",
344
- "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/moondream/moondream2/layers.py:19\u001b[39m, in \u001b[36mlinear\u001b[39m\u001b[34m(x, w)\u001b[39m\n\u001b[32m 18\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mlinear\u001b[39m(x: torch.Tensor, w: LinearWeights) -> torch.Tensor:\n\u001b[32m---> \u001b[39m\u001b[32m19\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mF\u001b[49m\u001b[43m.\u001b[49m\u001b[43mlinear\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mw\u001b[49m\u001b[43m.\u001b[49m\u001b[43mweight\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mw\u001b[49m\u001b[43m.\u001b[49m\u001b[43mbias\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
345
- "\u001b[31mRuntimeError\u001b[39m: self and mat2 must have the same dtype, but got Half and QInt8"
346
- ]
347
- }
348
- ],
349
- "source": [
350
- "from PIL import Image\n",
351
- "with torch.inference_mode():\n",
352
- " image = Image.open(\"example.png\")\n",
353
- " query = \"home icon at the bottom of the screen is visible\"\n",
354
- " points = model.point(image, query)[\"points\"]\n"
355
  ]
356
  },
357
  {
@@ -409,19 +198,18 @@
409
  },
410
  {
411
  "cell_type": "code",
412
- "execution_count": 17,
413
  "metadata": {},
414
  "outputs": [
415
  {
416
- "ename": "IndexError",
417
- "evalue": "list index out of range",
418
- "output_type": "error",
419
- "traceback": [
420
- "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
421
- "\u001b[31mIndexError\u001b[39m Traceback (most recent call last)",
422
- "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[17]\u001b[39m\u001b[32m, line 29\u001b[39m\n\u001b[32m 27\u001b[39m plt.axis(\u001b[33m'\u001b[39m\u001b[33moff\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m 28\u001b[39m plt.show()\n\u001b[32m---> \u001b[39m\u001b[32m29\u001b[39m show_point_on_image(\u001b[43mpoints\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m0\u001b[39;49m\u001b[43m]\u001b[49m[\u001b[33m'\u001b[39m\u001b[33mx\u001b[39m\u001b[33m'\u001b[39m], points[\u001b[32m0\u001b[39m][\u001b[33m'\u001b[39m\u001b[33my\u001b[39m\u001b[33m'\u001b[39m])\n",
423
- "\u001b[31mIndexError\u001b[39m: list index out of range"
424
- ]
425
  }
426
  ],
427
  "source": [
@@ -525,6 +313,76 @@
525
  "is_flash_attn_2_available()\n"
526
  ]
527
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
528
  {
529
  "cell_type": "code",
530
  "execution_count": 4,
@@ -533,7 +391,7 @@
533
  {
534
  "data": {
535
  "text/plain": [
536
- "Linear(in_features=10, out_features=10, bias=True)"
537
  ]
538
  },
539
  "execution_count": 4,
@@ -542,20 +400,68 @@
542
  }
543
  ],
544
  "source": [
545
- "import torch \n",
546
- "import torch.nn as nn\n",
547
- "\n",
548
- "linear = nn.Linear(10, 10, dtype=torch.float16)\n",
549
- "\n",
550
- "linear"
551
  ]
552
  },
553
  {
554
  "cell_type": "code",
555
- "execution_count": null,
556
  "metadata": {},
557
- "outputs": [],
558
- "source": []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
559
  },
560
  {
561
  "cell_type": "code",
@@ -581,7 +487,7 @@
581
  "name": "python",
582
  "nbconvert_exporter": "python",
583
  "pygments_lexer": "ipython3",
584
- "version": "3.13.3"
585
  }
586
  },
587
  "nbformat": 4,
 
1
  {
2
  "cells": [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  {
4
  "cell_type": "code",
5
  "execution_count": 1,
6
  "metadata": {},
7
  "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  "source": [
9
  "# auto reload jupyter notebook\n",
10
  "%load_ext autoreload\n",
11
  "%autoreload 2\n",
12
  "\n",
13
  "import os\n",
 
14
  "\n",
15
  "import torch\n",
16
  "from moondream2.config import MoondreamConfig\n",
 
22
  " model = MoondreamModel(config, setup_caches=False)\n",
23
  " from safetensors.torch import load_model\n",
24
  " weights_path = \"moondream2/model.safetensors\" # Path to your local weights file\n",
25
+ " state_dict = load_model(model, weights_path)\n",
26
+ " model = model.to(device)\n",
27
+ " model._setup_caches()\n",
 
 
 
 
 
 
 
 
 
28
  "\n",
29
+ "\n"
 
 
 
 
30
  ]
31
  },
32
  {
33
  "cell_type": "code",
34
+ "execution_count": 1,
35
  "metadata": {},
36
+ "outputs": [
37
+ {
38
+ "name": "stderr",
39
+ "output_type": "stream",
40
+ "text": [
41
+ "WARNING:torchao.kernel.intmm:Warning: Detected no triton, on systems without Triton certain kernels will not work\n",
42
+ "W0612 18:34:05.382000 19960 Lib\\site-packages\\torch\\distributed\\elastic\\multiprocessing\\redirects.py:29] NOTE: Redirects are currently not supported in Windows or MacOs.\n"
43
+ ]
44
+ }
45
+ ],
46
  "source": [
47
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
48
+ "from PIL import Image\n",
49
+ "\n",
50
+ "model = AutoModelForCausalLM.from_pretrained(\n",
51
+ " \"vikhyatk/moondream2\",\n",
52
+ " revision=\"2025-04-14\",\n",
53
+ " trust_remote_code=True,\n",
54
+ " # Uncomment to run on GPU.\n",
55
+ " device_map={\"\": \"cuda\"}\n",
56
+ ")"
57
  ]
58
  },
59
  {
60
  "cell_type": "code",
61
+ "execution_count": 2,
62
  "metadata": {},
63
  "outputs": [
64
  {
65
+ "name": "stdout",
66
+ "output_type": "stream",
67
+ "text": [
68
+ "model size: 3680.163MB\n"
69
+ ]
 
 
 
 
 
 
 
 
 
 
 
 
70
  }
71
  ],
72
  "source": [
73
+ "param_size = 0\n",
74
+ "for param in model.parameters():\n",
75
+ " param_size += param.nelement() * param.element_size()\n",
76
+ "buffer_size = 0\n",
77
+ "for buffer in model.buffers():\n",
78
+ " buffer_size += buffer.nelement() * buffer.element_size()\n",
79
+ "\n",
80
+ "size_all_mb = (param_size + buffer_size) / 1024**2\n",
81
+ "print('model size: {:.3f}MB'.format(size_all_mb))"
82
  ]
83
  },
84
  {
85
  "cell_type": "code",
86
+ "execution_count": 2,
87
  "metadata": {},
88
  "outputs": [],
89
  "source": [
90
+ "import torch"
91
  ]
92
  },
93
  {
94
  "cell_type": "code",
95
+ "execution_count": 3,
96
  "metadata": {},
97
  "outputs": [],
98
  "source": [
99
+ "from PIL import Image\n",
100
+ "with torch.inference_mode():\n",
101
+ " image = Image.open(\"example.png\")\n",
102
+ " query = \"home icon at the bottom of the screen is visible\"\n",
103
+ " points = model.point(image, query)[\"points\"]\n"
104
  ]
105
  },
106
  {
107
+ "cell_type": "markdown",
 
108
  "metadata": {},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  "source": [
110
+ "[ 0.0176, -0.0376, 0.0052, 0.0004, 0.0118, -0.0132, -0.0063, 0.0014, -0.0128, 0.0145, -0.0002, -0.0107, 0.0170, 0.0015, -0.0156]\n",
111
+ "\n",
112
+ "\n",
113
+ "[ 3.5352, 0.1851, 0.9316, -0.5625, -4.0078, -4.2891, 2.7910, -1.6973, -4.7578, 4.3867, 2.9668, -3.5859, -3.4434, -0.6079, 0.2891]\n"
114
  ]
115
  },
116
  {
117
+ "cell_type": "markdown",
 
118
  "metadata": {},
 
119
  "source": [
120
+ "[ 0.0176, -0.0376, 0.0052, 0.0004, 0.0118, -0.0132, -0.0063, 0.0014,\n",
121
+ " -0.0128, 0.0145, -0.0002, -0.0107, 0.0170, 0.0015, -0.0156]\n",
122
  "\n",
123
+ "[ 3.5352, 0.1851, 0.9316, -0.5625, -4.0078, -4.2891, 2.7910, -1.6973, -4.7578, 4.3867, 2.9668, -3.5859, -3.4434, -0.6079, 0.2891]"
124
  ]
125
  },
126
  {
127
  "cell_type": "code",
128
+ "execution_count": 4,
129
  "metadata": {},
130
  "outputs": [
131
  {
132
  "data": {
133
  "text/plain": [
134
+ "[{'x': 0.0859375, 'y': 0.9453125}]"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  ]
136
  },
137
+ "execution_count": 4,
138
  "metadata": {},
139
  "output_type": "execute_result"
140
  }
141
  ],
142
  "source": [
143
+ "points"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  ]
145
  },
146
  {
 
198
  },
199
  {
200
  "cell_type": "code",
201
+ "execution_count": 5,
202
  "metadata": {},
203
  "outputs": [
204
  {
205
+ "data": {
206
+ "image/png": "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",
207
+ "text/plain": [
208
+ "<Figure size 640x480 with 1 Axes>"
209
+ ]
210
+ },
211
+ "metadata": {},
212
+ "output_type": "display_data"
 
213
  }
214
  ],
215
  "source": [
 
313
  "is_flash_attn_2_available()\n"
314
  ]
315
  },
316
+ {
317
+ "cell_type": "code",
318
+ "execution_count": 1,
319
+ "metadata": {},
320
+ "outputs": [],
321
+ "source": [
322
+ "import torch\n",
323
+ "\n",
324
+ "q_custom_before_rope = torch.load(\"q_custom_before_rope.pt\")\n",
325
+ "k_custom_before_rope = torch.load(\"k_custom_before_rope.pt\")\n",
326
+ "v_custom_before_rope = torch.load(\"v_custom_before_rope.pt\")\n",
327
+ "\n",
328
+ "q_custom_after_rope = torch.load(\"q_custom_after_rope.pt\")\n",
329
+ "k_custom_after_rope = torch.load(\"k_custom_after_rope.pt\")\n",
330
+ "v_custom_after_rope = torch.load(\"v_custom_after_rope.pt\")\n",
331
+ "\n",
332
+ "q_before_rot_main = torch.load(\"q_before_rot_main.pt\")\n",
333
+ "k_before_rot_main = torch.load(\"k_before_rot_main.pt\")\n",
334
+ "v_before_rot_main = torch.load(\"v_before_rot_main.pt\")\n",
335
+ "\n",
336
+ "q_after_rot_main = torch.load(\"q_after_rot_main.pt\")\n",
337
+ "k_after_rot_main = torch.load(\"k_after_rot_main.pt\")\n",
338
+ "v_after_rot_main = torch.load(\"v_after_rot_main.pt\")\n",
339
+ "\n",
340
+ "\n",
341
+ "\n",
342
+ "\n",
343
+ "\n"
344
+ ]
345
+ },
346
+ {
347
+ "cell_type": "code",
348
+ "execution_count": null,
349
+ "metadata": {},
350
+ "outputs": [
351
+ {
352
+ "data": {
353
+ "text/plain": [
354
+ "True"
355
+ ]
356
+ },
357
+ "execution_count": 2,
358
+ "metadata": {},
359
+ "output_type": "execute_result"
360
+ }
361
+ ],
362
+ "source": [
363
+ "torch.equal(q_before_rot_main, q_custom_before_rope)"
364
+ ]
365
+ },
366
+ {
367
+ "cell_type": "code",
368
+ "execution_count": 3,
369
+ "metadata": {},
370
+ "outputs": [
371
+ {
372
+ "data": {
373
+ "text/plain": [
374
+ "True"
375
+ ]
376
+ },
377
+ "execution_count": 3,
378
+ "metadata": {},
379
+ "output_type": "execute_result"
380
+ }
381
+ ],
382
+ "source": [
383
+ "torch.equal(q_after_rot_main, q_custom_after_rope)"
384
+ ]
385
+ },
386
  {
387
  "cell_type": "code",
388
  "execution_count": 4,
 
391
  {
392
  "data": {
393
  "text/plain": [
394
+ "True"
395
  ]
396
  },
397
  "execution_count": 4,
 
400
  }
401
  ],
402
  "source": [
403
+ "torch.equal(v_after_rot_main, v_custom_after_rope)"
 
 
 
 
 
404
  ]
405
  },
406
  {
407
  "cell_type": "code",
408
+ "execution_count": 5,
409
  "metadata": {},
410
+ "outputs": [
411
+ {
412
+ "data": {
413
+ "text/plain": [
414
+ "True"
415
+ ]
416
+ },
417
+ "execution_count": 5,
418
+ "metadata": {},
419
+ "output_type": "execute_result"
420
+ }
421
+ ],
422
+ "source": [
423
+ "torch.equal(k_after_rot_main, k_custom_after_rope)"
424
+ ]
425
+ },
426
+ {
427
+ "cell_type": "code",
428
+ "execution_count": 5,
429
+ "metadata": {},
430
+ "outputs": [
431
+ {
432
+ "data": {
433
+ "text/plain": [
434
+ "torch.Size([1, 32, 730, 64])"
435
+ ]
436
+ },
437
+ "execution_count": 5,
438
+ "metadata": {},
439
+ "output_type": "execute_result"
440
+ }
441
+ ],
442
+ "source": [
443
+ "v_after_rot_main.shape"
444
+ ]
445
+ },
446
+ {
447
+ "cell_type": "code",
448
+ "execution_count": 6,
449
+ "metadata": {},
450
+ "outputs": [
451
+ {
452
+ "data": {
453
+ "text/plain": [
454
+ "torch.Size([1, 32, 2048, 64])"
455
+ ]
456
+ },
457
+ "execution_count": 6,
458
+ "metadata": {},
459
+ "output_type": "execute_result"
460
+ }
461
+ ],
462
+ "source": [
463
+ "v_custom_after_rope.shape"
464
+ ]
465
  },
466
  {
467
  "cell_type": "code",
 
487
  "name": "python",
488
  "nbconvert_exporter": "python",
489
  "pygments_lexer": "ipython3",
490
+ "version": "3.12.9"
491
  }
492
  },
493
  "nbformat": 4,