moondream 1.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
moondream/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ from .torch.inference import run_inference
2
+
3
+ __version__ = "1.0.2"
4
+ __all__ = ["run_inference"]
5
+
@@ -0,0 +1,9 @@
1
+ # moondream/torch/__init__.py
2
+ from .inference import run_inference
3
+ from .layers import *
4
+ from .rope import *
5
+ from .text import *
6
+ from .vision import *
7
+ from .weights import *
8
+
9
+ __all__ = ["run_inference"]
@@ -0,0 +1,108 @@
1
+ import torch
2
+ import argparse
3
+ import os
4
+ from PIL import Image
5
+ from transformers import AutoTokenizer
6
+ from .weights import load_from_safetensors
7
+ from .vision import encode_image
8
+ from .text import text_encoder, text_decoder, lm_head
9
+ from .rope import precompute_freqs_cis
10
+
11
+ def run_inference(image_path: str, prompt: str, model_path: str, max_tokens: int = 200, sampler: str = "greedy"):
12
+ """
13
+ Run inference on an image with a given prompt.
14
+
15
+ Args:
16
+ image_path (str): Path to the image file
17
+ prompt (str): Question to ask about the image
18
+ model_path (str): Path to the model weights
19
+ max_tokens (int, optional): Maximum number of tokens to generate. Defaults to 200.
20
+ sampler (str, optional): Sampling strategy ("greedy" or "multinomial"). Defaults to "greedy".
21
+
22
+ Returns:
23
+ str: Generated answer
24
+ """
25
+ if torch.cuda.is_available():
26
+ torch.set_default_device("cuda")
27
+ elif torch.backends.mps.is_available():
28
+ torch.set_default_device("mps")
29
+
30
+ # Load model
31
+ if not os.path.exists(model_path):
32
+ raise FileNotFoundError(f"Model not found at {model_path}")
33
+ model = load_from_safetensors(model_path)
34
+
35
+ # Your existing inference code here...
36
+ # [Rest of your original code from sample.py goes here,
37
+ # wrapped in the function with appropriate returns]
38
+ if not os.path.exists(image_path):
39
+ raise FileNotFoundError(f"Image not found at {image_path}")
40
+ image = Image.open(image_path)
41
+ image = image.resize((378, 378))
42
+ image_tensor = encode_image(image, model.vision)
43
+
44
+ # Encode text, and create inputs_embeds.
45
+ tokenizer = AutoTokenizer.from_pretrained("vikhyatk/moondream2")
46
+ prompt = f"\n\nQuestion: {prompt}\n\nAnswer:"
47
+ input_ids = tokenizer(prompt, return_tensors="pt")["input_ids"]
48
+ input_ids = torch.cat([torch.tensor([[tokenizer.eos_token_id]]), input_ids], dim=1)
49
+ inputs_embeds = text_encoder(input_ids, model.text)
50
+ inputs_embeds = torch.cat(
51
+ [
52
+ inputs_embeds[:, 0:1, :],
53
+ image_tensor.unsqueeze(0),
54
+ inputs_embeds[:, 1:, :],
55
+ ],
56
+ dim=1,
57
+ )
58
+
59
+ kv_cache = torch.empty(24, 2, 1, 32, 0, 64, dtype=torch.float16)
60
+ freqs_cis = precompute_freqs_cis(32, 2048)
61
+
62
+ for _ in range(max_tokens):
63
+ with torch.no_grad():
64
+ hidden, kv_cache = text_decoder(
65
+ inputs_embeds, model.text, kv_cache, freqs_cis
66
+ )
67
+ logits = lm_head(hidden, model.text)
68
+
69
+ if sampler == "multinomial":
70
+ next_token = torch.multinomial(
71
+ torch.softmax(logits, dim=-1), num_samples=1
72
+ ).squeeze(0)
73
+ elif sampler == "greedy":
74
+ next_token = torch.argmax(logits, dim=-1)
75
+ else:
76
+ raise ValueError(f"Invalid sampler: {sampler}")
77
+
78
+ if next_token == tokenizer.eos_token_id:
79
+ print()
80
+ break
81
+
82
+ input_ids = next_token.unsqueeze(0)
83
+ inputs_embeds = text_encoder(input_ids, model.text)
84
+
85
+ output_text = tokenizer.batch_decode(input_ids)[0]
86
+
87
+ print(output_text, end="", flush=True)
88
+
89
+ def main():
90
+ parser = argparse.ArgumentParser()
91
+ parser.add_argument("--image", "-i", type=str, required=True)
92
+ parser.add_argument("--prompt", "-p", type=str, required=True)
93
+ parser.add_argument("--model", "-m", type=str, required=True)
94
+ parser.add_argument("--max-tokens", "-t", type=int, default=200)
95
+ parser.add_argument("--sampler", "-s", type=str, default="greedy")
96
+ args = parser.parse_args()
97
+
98
+ result = run_inference(
99
+ args.image,
100
+ args.prompt,
101
+ args.model,
102
+ max_tokens=args.max_tokens,
103
+ sampler=args.sampler
104
+ )
105
+ print(result)
106
+
107
+ if __name__ == "__main__":
108
+ main()
@@ -0,0 +1,68 @@
1
+ import torch
2
+ import math
3
+ from typing import Literal
4
+ from torch import nn
5
+ from torch.nn import functional as F
6
+ from dataclasses import dataclass
7
+
8
+
9
+ def gelu_approx(x):
10
+ return F.gelu(x, approximate="tanh")
11
+
12
+
13
+ @dataclass
14
+ class LinearWeights:
15
+ weight: torch.Tensor
16
+ bias: torch.Tensor
17
+
18
+
19
+ def linear(x: torch.Tensor, w: LinearWeights) -> torch.Tensor:
20
+ return F.linear(x, w.weight, w.bias)
21
+
22
+
23
+ @dataclass
24
+ class LayerNormWeights:
25
+ weight: torch.Tensor
26
+ bias: torch.Tensor
27
+
28
+
29
+ def layer_norm(x: torch.Tensor, w: LayerNormWeights) -> torch.Tensor:
30
+ return F.layer_norm(x, w.bias.shape, w.weight, w.bias)
31
+
32
+
33
+ @dataclass
34
+ class MLPWeights:
35
+ fc1: LinearWeights
36
+ fc2: LinearWeights
37
+ act: Literal["gelu_approx"] = "gelu_approx"
38
+
39
+
40
+ def mlp(x: torch.Tensor, w: MLPWeights) -> torch.Tensor:
41
+ x = linear(x, w.fc1)
42
+ if w.act == "gelu_approx":
43
+ x = gelu_approx(x)
44
+ else:
45
+ raise NotImplementedError(f"Activation function {w.act} not implemented.")
46
+ x = linear(x, w.fc2)
47
+ return x
48
+
49
+
50
+ @dataclass
51
+ class AttentionWeights:
52
+ qkv: LinearWeights
53
+ proj: LinearWeights
54
+ n_heads: int
55
+
56
+
57
+ def attn(x: torch.Tensor, w: AttentionWeights) -> torch.Tensor:
58
+ bsz, q_len, d_model = x.shape
59
+ n_heads, head_dim = w.n_heads, d_model // w.n_heads
60
+
61
+ q, k, v = [
62
+ t.view(bsz, q_len, n_heads, head_dim).transpose(1, 2)
63
+ for t in linear(x, w.qkv).chunk(3, dim=-1)
64
+ ]
65
+ out = F.scaled_dot_product_attention(q, k, v)
66
+ out = out.transpose(1, 2).reshape(bsz, q_len, d_model)
67
+ out = linear(out, w.proj)
68
+ return out
@@ -0,0 +1,49 @@
1
+ # Ethically sourced from https://github.com/xjdr-alt/entropix
2
+
3
+ import torch
4
+ from typing import Tuple
5
+
6
+
7
+ def precompute_freqs_cis(
8
+ dim: int,
9
+ end: int,
10
+ theta: float = 10000.0,
11
+ use_scaled: bool = False,
12
+ dtype: torch.dtype = torch.float32,
13
+ ) -> torch.Tensor:
14
+ freqs = 1.0 / (theta ** (torch.arange(0, dim, 2, dtype=dtype)[: (dim // 2)] / dim))
15
+ t = torch.arange(end, dtype=dtype).unsqueeze(1)
16
+ freqs = t * freqs.unsqueeze(0)
17
+ freqs = torch.exp(1j * freqs)
18
+ return torch.stack([freqs.real, freqs.imag], dim=-1)
19
+
20
+
21
+ def apply_rotary_emb(
22
+ xq: torch.Tensor,
23
+ xk: torch.Tensor,
24
+ freqs_cis: torch.Tensor,
25
+ interleave: bool = False,
26
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
27
+ if interleave:
28
+ xq_r = xq.float().reshape(*xq.shape[:-1], -1, 2)[..., 0]
29
+ xq_i = xq.float().reshape(*xq.shape[:-1], -1, 2)[..., 1]
30
+ xk_r = xk.float().reshape(*xk.shape[:-1], -1, 2)[..., 0]
31
+ xk_i = xk.float().reshape(*xk.shape[:-1], -1, 2)[..., 1]
32
+ else:
33
+ d_q, d_k = xq.shape[-1] // 2, xk.shape[-1] // 2
34
+ xq_r, xq_i = xq[..., :d_q], xq[..., d_q:]
35
+ xk_r, xk_i = xk[..., :d_k], xk[..., d_k:]
36
+
37
+ freqs_cos = freqs_cis[..., 0].unsqueeze(0).unsqueeze(0)
38
+ freqs_sin = freqs_cis[..., 1].unsqueeze(0).unsqueeze(0)
39
+
40
+ # Complex multiplication: (a + bi) * (c + di) = (ac - bd) + (ad + bc)i
41
+ xq_out_r = xq_r * freqs_cos - xq_i * freqs_sin
42
+ xq_out_i = xq_r * freqs_sin + xq_i * freqs_cos
43
+ xk_out_r = xk_r * freqs_cos - xk_i * freqs_sin
44
+ xk_out_i = xk_r * freqs_sin + xk_i * freqs_cos
45
+
46
+ xq_out = torch.stack((xq_out_r, xq_out_i), dim=-1).flatten(-2)
47
+ xk_out = torch.stack((xk_out_r, xk_out_i), dim=-1).flatten(-2)
48
+
49
+ return xq_out.to(xq.dtype), xk_out.to(xk.dtype)
@@ -0,0 +1,92 @@
1
+ import torch
2
+ from typing import Dict, Tuple, Optional, List
3
+ from torch.nn import functional as F
4
+
5
+ from .rope import apply_rotary_emb, precompute_freqs_cis
6
+ from .layers import layer_norm, linear, mlp
7
+ from .weights import TextModel, AttentionWeights, load_from_safetensors
8
+
9
+
10
+ def text_encoder(input_ids: torch.Tensor, w: TextModel):
11
+ return F.embedding(input_ids, w.wte)
12
+
13
+
14
+ def attn_mask(pos, seq_len):
15
+ """
16
+ Create an attention mask that aligns with the bottom right of the
17
+ attention matrix. For example, if q_len = 2 and kv_len = 5, we want the
18
+ following:
19
+
20
+ 1 1 1 1 0
21
+ 1 1 1 1 1
22
+
23
+ and not this, which is what we get by default if we just set is_causal.
24
+
25
+ 1 0 0 0 0
26
+ 1 1 0 0 0
27
+ """
28
+ mask = torch.ones(seq_len, pos + seq_len, dtype=torch.bool)
29
+ mask[:, pos:] = torch.tril(torch.ones(seq_len, seq_len, dtype=torch.bool))
30
+ mask = mask.unsqueeze(0).unsqueeze(0) # Add batch and head dimensions
31
+ return mask
32
+
33
+
34
+ def attn(
35
+ x: torch.Tensor,
36
+ w: AttentionWeights,
37
+ freqs_cis: torch.Tensor,
38
+ layer_kv_cache: torch.Tensor,
39
+ ):
40
+ bsz, q_len, d_model = x.shape
41
+ pos = 0 if layer_kv_cache is None else layer_kv_cache.shape[3]
42
+ n_heads, head_dim = w.n_heads, d_model // w.n_heads
43
+
44
+ q, k, v = [
45
+ t.view(bsz, q_len, n_heads, head_dim).transpose(1, 2)
46
+ for t in linear(x, w.qkv).chunk(3, dim=-1)
47
+ ]
48
+
49
+ q_rot, q_pass = q.chunk(2, dim=-1)
50
+ k_rot, k_pass = k.chunk(2, dim=-1)
51
+ q_rot, k_rot = apply_rotary_emb(q_rot, k_rot, freqs_cis[pos : pos + q_len])
52
+ q = torch.cat([q_rot, q_pass], dim=-1)
53
+ k = torch.cat([k_rot, k_pass], dim=-1)
54
+
55
+ if layer_kv_cache is not None:
56
+ k = torch.cat([layer_kv_cache[0], k], dim=2)
57
+ v = torch.cat([layer_kv_cache[1], v], dim=2)
58
+
59
+ out = F.scaled_dot_product_attention(q, k, v, attn_mask=attn_mask(pos, q_len)).to(
60
+ # This type conversion isn't needed when running in PyTorch directly, but the
61
+ # ONNX export runs attention in float32 because the attention mask is cast to
62
+ # float32.
63
+ x.dtype
64
+ )
65
+ out = out.transpose(1, 2).reshape(bsz, q_len, d_model)
66
+ out = linear(out, w.proj)
67
+ return out, torch.stack([k, v])
68
+
69
+
70
+ def text_decoder(
71
+ inputs_embeds: torch.Tensor,
72
+ w: TextModel,
73
+ kv_cache: torch.Tensor,
74
+ freqs_cis: torch.Tensor,
75
+ ):
76
+ hidden_BTC = inputs_embeds
77
+ new_kv_cache = [torch.empty(0)] * len(w.blocks)
78
+
79
+ for i, block in enumerate(w.blocks):
80
+ l_in = layer_norm(hidden_BTC, block.ln)
81
+ l_attn, new_kv_cache[i] = attn(l_in, block.attn, freqs_cis, kv_cache[i])
82
+ l_mlp = mlp(l_in, block.mlp)
83
+ hidden_BTC = hidden_BTC + l_attn + l_mlp
84
+
85
+ return hidden_BTC, torch.stack(new_kv_cache)
86
+
87
+
88
+ def lm_head(hidden_BTC: torch.Tensor, w: TextModel):
89
+ hidden_BC = hidden_BTC[:, -1, :]
90
+ hidden_BC = layer_norm(hidden_BC, w.post_ln)
91
+ logits = linear(hidden_BC, w.lm_head)
92
+ return logits
@@ -0,0 +1,107 @@
1
+ import torch
2
+ import math
3
+ from typing import List, Tuple, Union
4
+ from einops import rearrange
5
+ from torch.nn import functional as F
6
+ from PIL import Image
7
+ from torchvision.transforms.v2 import InterpolationMode
8
+ from torchvision.transforms.v2.functional import (
9
+ resize as tv_resize,
10
+ to_image,
11
+ to_dtype,
12
+ normalize,
13
+ )
14
+
15
+ from .weights import VisionModel, load_from_safetensors
16
+ from .layers import attn, linear, layer_norm, mlp
17
+
18
+
19
+ def im_resize(
20
+ image: Image.Image,
21
+ size: List[int],
22
+ interpolation: InterpolationMode = InterpolationMode.BICUBIC,
23
+ ) -> Image.Image:
24
+ """
25
+ The 'resize' function from torchvision has bad type signatures.
26
+ it accepts both PIL images and torch tensors, but the type signature
27
+ only allows tensors.
28
+ """
29
+ return tv_resize(
30
+ image, # type: ignore
31
+ size,
32
+ InterpolationMode.BICUBIC,
33
+ )
34
+
35
+
36
+ def create_patches(
37
+ image: Image.Image, image_patch_size=378
38
+ ) -> Tuple[List[Image.Image], Tuple[int, int]]:
39
+ """
40
+ Split the given image into a variable number of patches depending upon its
41
+ resolution.
42
+ """
43
+ # Start off with the global patch.
44
+ patches = [im_resize(image, [image_patch_size, image_patch_size])]
45
+
46
+ # Find the closest resolution template.
47
+ res_templates = [(1, 2), (2, 1), (2, 2)]
48
+ im_width, im_height = image.size
49
+ max_dim = max(im_width, im_height)
50
+ if max_dim < image_patch_size * 1.4:
51
+ # If the image is already small, we just do a single patch that is a
52
+ # duplicate of the global patch. This creates a small amount of
53
+ # redundant computation now, but it is simpler and future-proofs us
54
+ # if/when we condition the vision encoder on the patch type.
55
+ res_template = (1, 1)
56
+ patches.append(patches[0])
57
+ else:
58
+ aspect_ratio = im_width / im_height
59
+ res_template = min(
60
+ res_templates, key=lambda size: abs((size[1] / size[0]) - aspect_ratio)
61
+ )
62
+ # TODO: Actually implement patching... just going to put in the global
63
+ # patch for now to make progress on other aspects.
64
+ patches.append(patches[0])
65
+
66
+ return patches, res_template
67
+
68
+
69
+ def encode_image(image: Image.Image, weights: VisionModel) -> torch.Tensor:
70
+ patches, res_template = create_patches(image.convert("RGB"))
71
+ patches = torch.stack(
72
+ [
73
+ normalize(
74
+ to_dtype(to_image(patch), torch.float16, scale=True),
75
+ mean=[0.5, 0.5, 0.5],
76
+ std=[0.5, 0.5, 0.5],
77
+ )
78
+ for patch in patches
79
+ ]
80
+ )
81
+
82
+ outputs = vision_encoder(patches, weights)
83
+
84
+ # TODO: Merge sub-image patch outputs properly... for now we'll just assume
85
+ # that the global patch is repeated.
86
+ assert outputs.shape[0] == 2, "Expected single image patch."
87
+ outputs = torch.cat([outputs[0], outputs[1]], dim=-1)
88
+
89
+ return mlp(outputs, weights.proj_mlp)
90
+
91
+
92
+ def vision_encoder(input_BCHW: torch.Tensor, w: VisionModel):
93
+ x = rearrange(
94
+ input_BCHW,
95
+ "b c (h p1) (w p2) -> b (h w) (c p1 p2)",
96
+ p1=w.patch_size,
97
+ p2=w.patch_size,
98
+ ) # B3HW -> B(HxW)(3xP1xP2), aka BTC
99
+
100
+ x = linear(x, w.patch_emb)
101
+ x = x + w.pos_emb
102
+ for block in w.blocks:
103
+ x = x + attn(layer_norm(x, block.ln1), block.attn)
104
+ x = x + mlp(layer_norm(x, block.ln2), block.mlp)
105
+ x = layer_norm(x, w.post_ln)
106
+
107
+ return x
@@ -0,0 +1,189 @@
1
+ import torch
2
+ import math
3
+ import safetensors
4
+ from typing import Dict, Union, Literal, List, Any
5
+ from contextlib import contextmanager
6
+ from dataclasses import dataclass
7
+
8
+ from .layers import LinearWeights, LayerNormWeights, MLPWeights, AttentionWeights
9
+
10
+
11
+ @dataclass
12
+ class VisionBlock:
13
+ ln1: LayerNormWeights
14
+ attn: AttentionWeights
15
+ ln2: LayerNormWeights
16
+ mlp: MLPWeights
17
+
18
+
19
+ @dataclass
20
+ class VisionModel:
21
+ patch_size: int
22
+ patch_emb: LinearWeights
23
+ pos_emb: torch.Tensor
24
+ blocks: List[VisionBlock]
25
+ post_ln: LayerNormWeights
26
+ proj_mlp: MLPWeights
27
+
28
+
29
+ @dataclass
30
+ class TextBlock:
31
+ ln: LayerNormWeights
32
+ attn: AttentionWeights
33
+ mlp: MLPWeights
34
+
35
+
36
+ @dataclass
37
+ class TextModel:
38
+ wte: torch.Tensor
39
+ blocks: List[TextBlock]
40
+ post_ln: LayerNormWeights
41
+ lm_head: LinearWeights
42
+
43
+
44
+ @dataclass
45
+ class MoondreamModel:
46
+ vision: VisionModel
47
+ text: TextModel
48
+
49
+
50
+ @contextmanager
51
+ def safetensors_open(safetensors_file: str):
52
+ """
53
+ Simplify interfacing with safetensors files. Eliminates the need to ignore
54
+ type errors when using the `safe_open` function.
55
+ """
56
+ with safetensors.safe_open(
57
+ safetensors_file, framework="pt"
58
+ ) as st: # pyright: ignore
59
+
60
+ def get_tensor(name: str) -> torch.Tensor:
61
+ return st.get_tensor(name)
62
+
63
+ yield get_tensor
64
+
65
+
66
+ def load_from_safetensors(
67
+ safetensors_file: str,
68
+ vision_blocks: int = 27,
69
+ text_blocks: int = 24,
70
+ ) -> MoondreamModel:
71
+ with safetensors_open(safetensors_file) as get_tensor:
72
+ ## Vision encoder
73
+ prefix = "vision_encoder.encoder.model.visual.patch_embed.linear"
74
+ patch_emb = LinearWeights(
75
+ weight=get_tensor(f"{prefix}.weight"), bias=get_tensor(f"{prefix}.bias")
76
+ )
77
+ patch_size = int(math.sqrt(patch_emb.weight.shape[1] // 3))
78
+ pos_emb = get_tensor("vision_encoder.encoder.model.visual.pos_embed")
79
+ post_ln = LayerNormWeights(
80
+ weight=get_tensor("vision_encoder.encoder.model.visual.norm.weight"),
81
+ bias=get_tensor("vision_encoder.encoder.model.visual.norm.bias"),
82
+ )
83
+ blocks = []
84
+ for i in range(vision_blocks):
85
+ prefix = f"vision_encoder.encoder.model.visual.blocks.{i}"
86
+ blocks.append(
87
+ VisionBlock(
88
+ ln1=LayerNormWeights(
89
+ weight=get_tensor(f"{prefix}.norm1.weight"),
90
+ bias=get_tensor(f"{prefix}.norm1.bias"),
91
+ ),
92
+ attn=AttentionWeights(
93
+ qkv=LinearWeights(
94
+ weight=get_tensor(f"{prefix}.attn.qkv.weight"),
95
+ bias=get_tensor(f"{prefix}.attn.qkv.bias"),
96
+ ),
97
+ proj=LinearWeights(
98
+ weight=get_tensor(f"{prefix}.attn.proj.weight"),
99
+ bias=get_tensor(f"{prefix}.attn.proj.bias"),
100
+ ),
101
+ n_heads=16,
102
+ ),
103
+ ln2=LayerNormWeights(
104
+ weight=get_tensor(f"{prefix}.norm2.weight"),
105
+ bias=get_tensor(f"{prefix}.norm2.bias"),
106
+ ),
107
+ mlp=MLPWeights(
108
+ fc1=LinearWeights(
109
+ weight=get_tensor(f"{prefix}.mlp.fc1.weight"),
110
+ bias=get_tensor(f"{prefix}.mlp.fc1.bias"),
111
+ ),
112
+ fc2=LinearWeights(
113
+ weight=get_tensor(f"{prefix}.mlp.fc2.weight"),
114
+ bias=get_tensor(f"{prefix}.mlp.fc2.bias"),
115
+ ),
116
+ ),
117
+ )
118
+ )
119
+ proj_mlp = MLPWeights(
120
+ fc1=LinearWeights(
121
+ weight=get_tensor("vision_encoder.projection.mlp.fc1.weight"),
122
+ bias=get_tensor("vision_encoder.projection.mlp.fc1.bias"),
123
+ ),
124
+ fc2=LinearWeights(
125
+ weight=get_tensor("vision_encoder.projection.mlp.fc2.weight"),
126
+ bias=get_tensor("vision_encoder.projection.mlp.fc2.bias"),
127
+ ),
128
+ act="gelu_approx",
129
+ )
130
+ vision = VisionModel(
131
+ patch_size=patch_size,
132
+ patch_emb=patch_emb,
133
+ pos_emb=pos_emb,
134
+ blocks=blocks,
135
+ post_ln=post_ln,
136
+ proj_mlp=proj_mlp,
137
+ )
138
+
139
+ ## Text decoder model
140
+ wte = get_tensor("text_model.transformer.embd.wte.weight")
141
+ post_ln = LayerNormWeights(
142
+ weight=get_tensor("text_model.lm_head.ln.weight"),
143
+ bias=get_tensor("text_model.lm_head.ln.bias"),
144
+ )
145
+ lm_head = LinearWeights(
146
+ weight=get_tensor("text_model.lm_head.linear.weight"),
147
+ bias=get_tensor("text_model.lm_head.linear.bias"),
148
+ )
149
+ blocks = []
150
+ for i in range(text_blocks):
151
+ prefix = f"text_model.transformer.h.{i}"
152
+ blocks.append(
153
+ TextBlock(
154
+ ln=LayerNormWeights(
155
+ weight=get_tensor(f"{prefix}.ln.weight"),
156
+ bias=get_tensor(f"{prefix}.ln.bias"),
157
+ ),
158
+ attn=AttentionWeights(
159
+ qkv=LinearWeights(
160
+ weight=get_tensor(f"{prefix}.mixer.Wqkv.weight"),
161
+ bias=get_tensor(f"{prefix}.mixer.Wqkv.bias"),
162
+ ),
163
+ proj=LinearWeights(
164
+ weight=get_tensor(f"{prefix}.mixer.out_proj.weight"),
165
+ bias=get_tensor(f"{prefix}.mixer.out_proj.bias"),
166
+ ),
167
+ n_heads=32,
168
+ ),
169
+ mlp=MLPWeights(
170
+ fc1=LinearWeights(
171
+ weight=get_tensor(f"{prefix}.mlp.fc1.weight"),
172
+ bias=get_tensor(f"{prefix}.mlp.fc1.bias"),
173
+ ),
174
+ fc2=LinearWeights(
175
+ weight=get_tensor(f"{prefix}.mlp.fc2.weight"),
176
+ bias=get_tensor(f"{prefix}.mlp.fc2.bias"),
177
+ ),
178
+ act="gelu_approx",
179
+ ),
180
+ )
181
+ )
182
+ text = TextModel(wte=wte, blocks=blocks, post_ln=post_ln, lm_head=lm_head)
183
+
184
+ return MoondreamModel(vision=vision, text=text)
185
+
186
+
187
+ if __name__ == "__main__":
188
+ weights = load_from_safetensors("model.safetensors")
189
+ print(weights)
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Moondream
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.1
2
+ Name: moondream
3
+ Version: 1.0.2
4
+ Summary: A package for image-based question answering using Moondream
5
+ Home-page: https://github.com/1997MarsRover/moondream
6
+ Author: 1997marsrover
7
+ Author-email: antonygithinji11156@gmail.com
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Requires-Python: >=3.7
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: torch
19
+ Requires-Dist: Pillow
20
+ Requires-Dist: transformers
21
+
@@ -0,0 +1,14 @@
1
+ moondream/__init__.py,sha256=E3ndp0duYUi6CLWsoIFpltrlvf-OK4QQfrCbgT4Kf6A,95
2
+ moondream/torch/__init__.py,sha256=AttwzPDVjIPtRGFHq83__VI2i2pemSCblQ4C1pyo1ek,202
3
+ moondream/torch/inference.py,sha256=IrzYiSU-YF6beOevyng-BmwEGWECFRh_zWtx5bJPawc,3847
4
+ moondream/torch/layers.py,sha256=u6E-0JmMuKryzpMPWmxI_n5SRXFRlPXc-slKg-501UE,1556
5
+ moondream/torch/rope.py,sha256=FU017lf51z7iSS2bs_4KDk7-frz8P4pVEl-0pUWhNQA,1741
6
+ moondream/torch/text.py,sha256=4JodKX937h9ghWm4oNyhQgKtZVogV8CvxyfyEg2OUVQ,2920
7
+ moondream/torch/vision.py,sha256=4RfTFvtNYpM005XDklqAeZebgVWtJAF9zhF4Igl-Q9M,3393
8
+ moondream/torch/weights.py,sha256=C5whBJPmrKacRAwmylQnz6H-m8z36T6YFF43FcwlwD0,6599
9
+ moondream-1.0.2.dist-info/LICENSE,sha256=6LnNiERg1JyLVd1l0jpDHgTAeNouDbfhXrAnVfEDTCA,1065
10
+ moondream-1.0.2.dist-info/METADATA,sha256=yr43jlIOrQ9fvNpRlHrSlgXsoDj8sw1-m4gvliju3UI,750
11
+ moondream-1.0.2.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
12
+ moondream-1.0.2.dist-info/entry_points.txt,sha256=iuQDF-fzfsB8YXZ0XxhGecvZ1c6lyibrL_D67EWCE6w,61
13
+ moondream-1.0.2.dist-info/top_level.txt,sha256=m_eOqzX4m1xP9Njpi_vHQeOP5B720mGJazO2gurLn28,10
14
+ moondream-1.0.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.3.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ moondream = moondream.torch.inference:main
@@ -0,0 +1 @@
1
+ moondream