Image-Text-to-Text
Transformers
PyTorch
English
doubutsu
custom_code
Inference Endpoints
qtnx commited on
Commit
4b953b6
1 Parent(s): 66abf06

Upload folder using huggingface_hub

Browse files
added_tokens.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "<|endoftext|>": 151643,
3
+ "<|im_end|>": 151645,
4
+ "<|im_start|>": 151644
5
+ }
config.json ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "auto_map": {
3
+ "AutoConfig": "configuration_doubutsu.DoubutsuConfig",
4
+ "AutoModelForCausalLM": "modeling_doubutsu.Doubutsu"
5
+ },
6
+ "model_type": "doubutsu",
7
+ "text_config": {
8
+ "_name_or_path": "Qwen/Qwen2-1.5B-Instruct",
9
+ "architectures": [
10
+ "Qwen2ForCausalLM"
11
+ ],
12
+ "bos_token_id": 151643,
13
+ "eos_token_id": 151645,
14
+ "hidden_size": 1536,
15
+ "intermediate_size": 8960,
16
+ "max_length": 32768,
17
+ "model_type": "qwen2",
18
+ "num_attention_heads": 12,
19
+ "num_hidden_layers": 28,
20
+ "num_key_value_heads": 2,
21
+ "rope_theta": 1000000.0,
22
+ "sliding_window": 32768,
23
+ "tie_word_embeddings": true,
24
+ "torch_dtype": "bfloat16"
25
+ },
26
+ "transformers_version": "4.40.1",
27
+ "vision_config": {
28
+ "_name_or_path": "google/siglip-so400m-patch14-384",
29
+ "hidden_size": 1152,
30
+ "image_size": 384,
31
+ "intermediate_size": 4304,
32
+ "model_type": "siglip_vision_model",
33
+ "num_attention_heads": 16,
34
+ "num_hidden_layers": 27,
35
+ "patch_size": 14
36
+ }
37
+ }
configuration_doubutsu.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import PretrainedConfig, Qwen2Config, SiglipVisionConfig
2
+
3
+
4
+ class DoubutsuConfig(PretrainedConfig):
5
+ model_type = "doubutsu"
6
+
7
+ def __init__(self, **kwargs):
8
+ self.text_config = Qwen2Config(
9
+ **kwargs.pop(
10
+ "text_config",
11
+ {},
12
+ ),
13
+ )
14
+ self.vision_config = SiglipVisionConfig(**kwargs.pop("vision_config", {}))
15
+ super().__init__(**kwargs)
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
modeling_doubutsu.py ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ from transformers import (
4
+ PreTrainedModel,
5
+ AutoModelForCausalLM,
6
+ AutoModel,
7
+ SiglipImageProcessor,
8
+ )
9
+ from .configuration_doubutsu import DoubutsuConfig
10
+
11
+
12
+ class ProjectionModule(nn.Module):
13
+ def __init__(self, mm_hidden_size=1152, hidden_size=1536):
14
+ super(ProjectionModule, self).__init__()
15
+
16
+ self.model = nn.Sequential(
17
+ nn.Linear(mm_hidden_size, hidden_size),
18
+ nn.GELU(),
19
+ nn.Linear(hidden_size, hidden_size),
20
+ )
21
+
22
+ def forward(self, x):
23
+ return self.model(x)
24
+
25
+
26
+ class Doubutsu(PreTrainedModel):
27
+ config_class = DoubutsuConfig
28
+
29
+ def __init__(self, config):
30
+ super().__init__(config)
31
+
32
+ self.vision_model = AutoModel.from_config(self.config.vision_config)
33
+ self.text_model = AutoModelForCausalLM.from_config(self.config.text_config)
34
+ self.processor = SiglipImageProcessor()
35
+ self.mm_projector = ProjectionModule(
36
+ mm_hidden_size=config.vision_config.hidden_size,
37
+ hidden_size=config.text_config.hidden_size,
38
+ )
39
+
40
+ @property
41
+ def device(self):
42
+ return self.text_model.device
43
+
44
+ def encode_image(self, image):
45
+ image = image.convert("RGB")
46
+ image = self.processor(
47
+ images=image,
48
+ return_tensors="pt",
49
+ do_resize=True,
50
+ size={"height": 378, "width": 378},
51
+ )["pixel_values"].to(
52
+ device=self.vision_model.device, dtype=self.vision_model.dtype
53
+ )
54
+ with torch.no_grad():
55
+ return self.vision_model(image, output_hidden_states=True).hidden_states[-2]
56
+
57
+ def input_embeds(self, prompt, image_embeds, tokenizer):
58
+ def _tokenize(txt):
59
+ return tokenizer(
60
+ txt, return_tensors="pt", add_special_tokens=False
61
+ ).input_ids.to(self.device)
62
+
63
+ text_emb = self.text_model.get_input_embeddings()
64
+ embeds = []
65
+ tokenized_prompt = _tokenize(prompt)
66
+
67
+ # Add BOS token if it exists and isn't already at the start of the prompt
68
+ if tokenizer.bos_token_id is not None:
69
+ if tokenized_prompt[0][0] == tokenizer.bos_token_id:
70
+ tokenized_prompt = tokenized_prompt[:, 1:] # Remove existing BOS
71
+ embeds.append(
72
+ text_emb(torch.tensor([[tokenizer.bos_token_id]], device=self.device))
73
+ )
74
+
75
+ # Add image embeds
76
+ projected_image_embeds = self.mm_projector(image_embeds.to(self.device))
77
+ embeds.append(projected_image_embeds)
78
+
79
+ # Add text embeds
80
+ embeds.append(text_emb(tokenized_prompt))
81
+
82
+ return torch.cat(embeds, dim=1)
83
+
84
+ def get_input_embeddings(self):
85
+ return self.text_model.get_input_embeddings()
86
+
87
+ def generate(
88
+ self,
89
+ image_embeds,
90
+ prompt,
91
+ tokenizer,
92
+ max_new_tokens=128,
93
+ temperature=0.1,
94
+ **kwargs,
95
+ ):
96
+ generate_config = {
97
+ "eos_token_id": tokenizer.eos_token_id,
98
+ "bos_token_id": tokenizer.bos_token_id,
99
+ "pad_token_id": tokenizer.pad_token_id,
100
+ "max_new_tokens": max_new_tokens,
101
+ "temperature": temperature,
102
+ **kwargs,
103
+ }
104
+
105
+ with torch.no_grad():
106
+ inputs_embeds = self.input_embeds(prompt, image_embeds, tokenizer)
107
+ output_ids = self.text_model.generate(
108
+ inputs_embeds=inputs_embeds,
109
+ do_sample=True,
110
+ **generate_config,
111
+ )
112
+ return tokenizer.batch_decode(output_ids, skip_special_tokens=True)
113
+
114
+ def answer_question(self, image, question, tokenizer, **kwargs):
115
+ image_embeds = self.encode_image(image)
116
+
117
+ chat = [
118
+ {
119
+ "role": "system",
120
+ "content": "You are a helpful AI assistant that can see images and answer questions about them.",
121
+ },
122
+ {"role": "user", "content": question},
123
+ ]
124
+ prompt = tokenizer.apply_chat_template(
125
+ chat, tokenize=False, add_generation_prompt=True
126
+ )
127
+
128
+ # Generate the answer
129
+ with torch.no_grad():
130
+ output = self.generate(
131
+ image_embeds=image_embeds,
132
+ prompt=prompt,
133
+ tokenizer=tokenizer,
134
+ **kwargs,
135
+ )[0]
136
+
137
+ # Clean and return the answer
138
+ cleaned_answer = output.strip()
139
+ return cleaned_answer
pytorch_model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c10024a70443cf96a47827579df1f55adcdaef649c9e9c1dc33481f64573cb44
3
+ size 3952463074
special_tokens_map.json ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<|im_start|>",
4
+ "<|im_end|>"
5
+ ],
6
+ "eos_token": {
7
+ "content": "<|im_end|>",
8
+ "lstrip": false,
9
+ "normalized": false,
10
+ "rstrip": false,
11
+ "single_word": false
12
+ },
13
+ "pad_token": {
14
+ "content": "<|endoftext|>",
15
+ "lstrip": false,
16
+ "normalized": false,
17
+ "rstrip": false,
18
+ "single_word": false
19
+ }
20
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "added_tokens_decoder": {
4
+ "151643": {
5
+ "content": "<|endoftext|>",
6
+ "lstrip": false,
7
+ "normalized": false,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ },
12
+ "151644": {
13
+ "content": "<|im_start|>",
14
+ "lstrip": false,
15
+ "normalized": false,
16
+ "rstrip": false,
17
+ "single_word": false,
18
+ "special": true
19
+ },
20
+ "151645": {
21
+ "content": "<|im_end|>",
22
+ "lstrip": false,
23
+ "normalized": false,
24
+ "rstrip": false,
25
+ "single_word": false,
26
+ "special": true
27
+ }
28
+ },
29
+ "additional_special_tokens": [
30
+ "<|im_start|>",
31
+ "<|im_end|>"
32
+ ],
33
+ "bos_token": null,
34
+ "chat_template": "{% for message in messages %}{% if loop.first and messages[0]['role'] != 'system' %}{{ '<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n' }}{% endif %}{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}",
35
+ "clean_up_tokenization_spaces": false,
36
+ "eos_token": "<|im_end|>",
37
+ "errors": "replace",
38
+ "model_max_length": 32768,
39
+ "pad_token": "<|endoftext|>",
40
+ "split_special_tokens": false,
41
+ "tokenizer_class": "Qwen2Tokenizer",
42
+ "unk_token": null
43
+ }
vocab.json ADDED
The diff for this file is too large to render. See raw diff