Ligeng-Zhu commited on
Commit
82f8bf8
·
verified ·
1 Parent(s): 10b5d1d

Upload files with `vila-upload`.

Browse files

Upload added_tokens.json
Upload processing_nvila_lite.py
Upload generation_config.json
Upload chat_template.jinja
Upload modeling_nvila_lite.py
Upload configuration_nvila_lite.py
Upload merges.txt
Upload special_tokens_map.json
Upload config.json
Upload vocab.json
Upload tokenizer_config.json
Upload processor_config.json
Upload preprocessor_config.json
Upload model.safetensors

added_tokens.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "<image>": 151649,
3
+ "<vila/sentinel>": 151648,
4
+ "<vila/video>": 151650,
5
+ "<|endoftext|>": 151643,
6
+ "<|im_end|>": 151645,
7
+ "<|im_start|>": 151644,
8
+ "[BOS]": 151646,
9
+ "[PAD]": 151647
10
+ }
chat_template.jinja ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {% for message in messages %}{% if loop.first and message['role'] != 'system' %}{{ '<|im_start|>system
2
+ You are a helpful assistant<|im_end|>
3
+ ' }}{% endif %}{{ '<|im_start|>' + message['role'] + '
4
+ ' }}{% if message['content'] is string %}{{ message['content'] + '<|im_end|>
5
+ ' }}{% else %}{% for content in message['content'] %}{% if content['type'] == 'image' or 'image' in content or 'image_url' in content %}{{ '<image>' }}{% elif content['type'] == 'video' or 'video' in content %}{{ '<vila/video>' }}{% elif 'text' in content %}{{ content['text'] }}{% endif %}{% endfor %}{{ '<|im_end|>
6
+ ' }}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant
7
+ ' }}{% endif %}
config.json ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "NVILALiteForConditionalGeneration"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_nvila_lite.NVILALiteConfig",
7
+ "AutoModel": "modeling_nvila_lite.NVILALiteForConditionalGeneration",
8
+ "AutoModelForCausalLM": "modeling_nvila.NVILAForConditionalGeneration",
9
+ "AutoModelForImageTextToText": "modeling_nvila.NVILAForConditionalGeneration",
10
+ "AutoModelForVision2Seq": "modeling_nvila.NVILAForConditionalGeneration"
11
+ },
12
+ "image_token_id": 151649,
13
+ "model_type": "nvila_lite",
14
+ "text_config": {
15
+ "_attn_implementation_autoset": false,
16
+ "architectures": [
17
+ "Qwen2ForCausalLM"
18
+ ],
19
+ "attention_dropout": 0.0,
20
+ "bos_token_id": 151643,
21
+ "eos_token_id": 151645,
22
+ "hidden_act": "silu",
23
+ "hidden_size": 1536,
24
+ "initializer_range": 0.02,
25
+ "intermediate_size": 8960,
26
+ "layer_types": [
27
+ "full_attention",
28
+ "full_attention",
29
+ "full_attention",
30
+ "full_attention",
31
+ "full_attention",
32
+ "full_attention",
33
+ "full_attention",
34
+ "full_attention",
35
+ "full_attention",
36
+ "full_attention",
37
+ "full_attention",
38
+ "full_attention",
39
+ "full_attention",
40
+ "full_attention",
41
+ "full_attention",
42
+ "full_attention",
43
+ "full_attention",
44
+ "full_attention",
45
+ "full_attention",
46
+ "full_attention",
47
+ "full_attention",
48
+ "full_attention",
49
+ "full_attention",
50
+ "full_attention",
51
+ "full_attention",
52
+ "full_attention",
53
+ "full_attention",
54
+ "full_attention"
55
+ ],
56
+ "max_position_embeddings": 32768,
57
+ "max_window_layers": 28,
58
+ "model_max_length": 4096,
59
+ "model_type": "qwen2",
60
+ "num_attention_heads": 12,
61
+ "num_hidden_layers": 28,
62
+ "num_key_value_heads": 2,
63
+ "rms_norm_eps": 1e-06,
64
+ "rope_scaling": null,
65
+ "rope_theta": 1000000.0,
66
+ "sliding_window": null,
67
+ "tie_word_embeddings": true,
68
+ "tokenizer_model_max_length": 4096,
69
+ "tokenizer_padding_side": "right",
70
+ "torch_dtype": "bfloat16",
71
+ "use_cache": true,
72
+ "use_sliding_window": false,
73
+ "vocab_size": 151651
74
+ },
75
+ "torch_dtype": "bfloat16",
76
+ "transformers_version": "4.55.4",
77
+ "video_token_id": 151650,
78
+ "vision_config": {
79
+ "_attn_implementation_autoset": false,
80
+ "architectures": [
81
+ "SiglipVisionModel"
82
+ ],
83
+ "attention_dropout": 0.0,
84
+ "hidden_act": "gelu_pytorch_tanh",
85
+ "hidden_size": 1152,
86
+ "image_size": 448,
87
+ "intermediate_size": 4304,
88
+ "layer_norm_eps": 1e-06,
89
+ "model_type": "siglip_vision_model",
90
+ "num_attention_heads": 16,
91
+ "num_channels": 3,
92
+ "num_hidden_layers": 27,
93
+ "num_image_tokens": 256,
94
+ "patch_size": 14,
95
+ "projection_dim": 2048,
96
+ "projector_hidden_act": "gelu_fast",
97
+ "torch_dtype": "bfloat16",
98
+ "vision_use_head": false
99
+ }
100
+ }
configuration_nvila_lite.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any
2
+
3
+ from transformers.configuration_utils import PretrainedConfig
4
+ from transformers.models.qwen2 import Qwen2Config
5
+ from transformers.models.siglip import SiglipVisionConfig
6
+
7
+
8
+ class NVILALiteConfig(PretrainedConfig):
9
+ model_type = "nvila_lite"
10
+ sub_configs = {
11
+ "text_config": Qwen2Config,
12
+ "vision_config": SiglipVisionConfig,
13
+ }
14
+ _auto_class = "AutoConfig"
15
+
16
+ def __init__(
17
+ self,
18
+ *,
19
+ text_config: dict[str, Any] | None = None,
20
+ vision_config: dict[str, Any] | None = None,
21
+ image_token_id: int | None = None,
22
+ video_token_id: int | None = None,
23
+ **kwargs,
24
+ ):
25
+ self.text_config = Qwen2Config(**text_config) if text_config is not None else Qwen2Config()
26
+ self.vision_config = SiglipVisionConfig(**vision_config) if vision_config is not None else SiglipVisionConfig()
27
+
28
+ self.image_token_id = image_token_id if image_token_id is not None else -1
29
+ self.video_token_id = video_token_id if video_token_id is not None else -1
30
+
31
+ super().__init__(**kwargs)
generation_config.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 151643,
4
+ "eos_token_id": 151645,
5
+ "transformers_version": "4.55.4"
6
+ }
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4ec45647914f31abc6564289047ef9ec65001d5d2068d91161b25b1790991567
3
+ size 4000375952
modeling_nvila_lite.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import contextlib
2
+ import math
3
+
4
+ import einops
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from torch import Tensor
9
+ from transformers import Qwen2ForCausalLM, SiglipVisionModel
10
+ from transformers.generation.utils import GenerationMixin
11
+ from transformers.modeling_outputs import BaseModelOutputWithPooling, CausalLMOutputWithPast
12
+ from transformers.modeling_utils import PreTrainedModel
13
+
14
+ from .configuration_nvila_lite import NVILALiteConfig
15
+
16
+ MM_HIDDEN_SIZE = 1152
17
+
18
+
19
+ class NVILALiteMultiModalProjectorDownsampleBlock(nn.Module):
20
+ def forward(self, x: Tensor) -> Tensor:
21
+ batch_size, sequence_length, hidden_size = x.shape
22
+
23
+ feat_size = math.isqrt(sequence_length)
24
+
25
+ features = x.reshape(batch_size, feat_size, feat_size, hidden_size)
26
+
27
+ pad_after = (3 - feat_size % 3) % 3
28
+ if pad_after > 0:
29
+ features = F.pad(features, (0, 0, 0, pad_after, 0, pad_after))
30
+ feat_size = feat_size + pad_after
31
+
32
+ features = features.reshape(batch_size, feat_size // 3, 3, feat_size // 3, 3, hidden_size)
33
+ features = features.permute(0, 1, 3, 2, 4, 5).contiguous()
34
+ features = features.reshape(batch_size, -1, 9 * hidden_size)
35
+
36
+ return features
37
+
38
+
39
+ class NVILALiteMultiModalProjector(nn.Module):
40
+ def __init__(self, config: NVILALiteConfig):
41
+ super().__init__()
42
+
43
+ self.layers = nn.Sequential(
44
+ NVILALiteMultiModalProjectorDownsampleBlock(),
45
+ nn.LayerNorm(MM_HIDDEN_SIZE * 9),
46
+ nn.Linear(MM_HIDDEN_SIZE * 9, MM_HIDDEN_SIZE * 3),
47
+ nn.GELU(),
48
+ nn.LayerNorm(MM_HIDDEN_SIZE * 3),
49
+ nn.Linear(MM_HIDDEN_SIZE * 3, config.text_config.hidden_size),
50
+ nn.GELU(),
51
+ nn.Linear(config.text_config.hidden_size, config.text_config.hidden_size),
52
+ )
53
+
54
+ def forward(self, x: Tensor) -> Tensor:
55
+ return self.layers(x)
56
+
57
+
58
+ class NVILALiteForConditionalGeneration(PreTrainedModel, GenerationMixin):
59
+ config_class = NVILALiteConfig
60
+ base_model_prefix = "llm"
61
+ _auto_class = "AutoModel"
62
+ _supports_flash_attn = True
63
+ _supports_sdpa = True
64
+
65
+ def __init__(self, config: NVILALiteConfig):
66
+ super().__init__(config)
67
+
68
+ self.config: NVILALiteConfig
69
+
70
+ @contextlib.contextmanager
71
+ def default_torch_dtype(dtype):
72
+ original_dtype = torch.get_default_dtype()
73
+ torch.set_default_dtype(dtype)
74
+ try:
75
+ yield
76
+ finally:
77
+ torch.set_default_dtype(original_dtype)
78
+
79
+ with default_torch_dtype(config.torch_dtype):
80
+ self.vision_tower = SiglipVisionModel(config.vision_config)
81
+ self.mm_projector = NVILALiteMultiModalProjector(config)
82
+ self.llm = Qwen2ForCausalLM(config.text_config)
83
+
84
+ self.post_init()
85
+
86
+ def forward(
87
+ self,
88
+ *,
89
+ input_ids: Tensor | None = None,
90
+ inputs_embeds: Tensor | None = None,
91
+ pixel_values: Tensor | None = None,
92
+ pixel_values_videos: Tensor | None = None,
93
+ **kwargs,
94
+ ) -> CausalLMOutputWithPast:
95
+ assert (input_ids is None) != (
96
+ inputs_embeds is None
97
+ ), "Exactly one of `input_ids` or `inputs_embeds` must be specified."
98
+
99
+ if input_ids is not None and torch.any(
100
+ torch.isin(
101
+ input_ids,
102
+ torch.tensor(
103
+ [self.config.image_token_id, self.config.video_token_id],
104
+ device=input_ids.device,
105
+ ),
106
+ ).any()
107
+ ): # Prefill
108
+ inputs_embeds = self._embed(
109
+ input_ids=input_ids,
110
+ pixel_values=pixel_values,
111
+ pixel_values_videos=pixel_values_videos,
112
+ )
113
+ input_ids = None
114
+
115
+ outputs = self.llm(
116
+ input_ids=input_ids,
117
+ inputs_embeds=inputs_embeds,
118
+ **kwargs,
119
+ )
120
+
121
+ return outputs
122
+
123
+ def _embed(
124
+ self,
125
+ *,
126
+ input_ids: Tensor,
127
+ pixel_values: Tensor | None,
128
+ pixel_values_videos: Tensor | None,
129
+ ) -> Tensor:
130
+ inputs_embeds: Tensor = self.llm.model.embed_tokens(input_ids)
131
+
132
+ for pixel_values, media_token_id in [
133
+ (pixel_values, self.config.image_token_id),
134
+ (pixel_values_videos, self.config.video_token_id),
135
+ ]:
136
+ if pixel_values is None:
137
+ continue
138
+
139
+ vision_features = self._encode_vision(pixel_values)
140
+ vision_features = einops.rearrange(vision_features, "n p d -> (n p) d")
141
+
142
+ inputs_embeds[input_ids == media_token_id] = vision_features
143
+
144
+ return inputs_embeds
145
+
146
+ def _encode_vision(self, pixel_values: Tensor) -> Tensor:
147
+ vision_tower_output: BaseModelOutputWithPooling = self.vision_tower(
148
+ pixel_values,
149
+ output_hidden_states=True,
150
+ )
151
+ assert vision_tower_output.hidden_states is not None
152
+
153
+ vision_features = vision_tower_output.hidden_states[-2]
154
+
155
+ vision_features = self.mm_projector(vision_features)
156
+
157
+ return vision_features
preprocessor_config.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "auto_map": {
3
+ "AutoProcessor": "processing_nvila_lite.NVILALiteProcessor"
4
+ },
5
+ "do_convert_rgb": null,
6
+ "do_normalize": true,
7
+ "do_rescale": true,
8
+ "do_resize": true,
9
+ "image_mean": [
10
+ 0.5,
11
+ 0.5,
12
+ 0.5
13
+ ],
14
+ "image_processor_type": "SiglipImageProcessor",
15
+ "image_std": [
16
+ 0.5,
17
+ 0.5,
18
+ 0.5
19
+ ],
20
+ "processor_class": "NVILALiteProcessor",
21
+ "resample": 3,
22
+ "rescale_factor": 0.00392156862745098,
23
+ "size": {
24
+ "height": 448,
25
+ "width": 448
26
+ }
27
+ }
processing_nvila_lite.py ADDED
@@ -0,0 +1,389 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ from typing import cast
3
+
4
+ import numpy as np
5
+ import transformers.image_transforms as image_transforms
6
+ import transformers.image_utils as image_utils
7
+ import transformers.video_utils as video_utils
8
+ from PIL.Image import Image
9
+ from transformers.feature_extraction_utils import BatchFeature
10
+ from transformers.image_utils import ImageInput
11
+ from transformers.models.qwen2 import Qwen2Tokenizer, Qwen2TokenizerFast
12
+ from transformers.models.siglip import SiglipImageProcessor, SiglipImageProcessorFast
13
+ from transformers.processing_utils import ProcessingKwargs, ProcessorMixin, Unpack, VideosKwargs
14
+ from transformers.tokenization_utils_base import BatchEncoding, TextInput
15
+ from transformers.video_utils import VideoInput, VideoMetadata
16
+
17
+
18
+ class NVILALiteProcessorKwargs(ProcessingKwargs, total=False):
19
+ _defaults = {} # type: ignore
20
+
21
+
22
+ class NVILALiteProcessor(ProcessorMixin):
23
+ attributes = [
24
+ "image_processor",
25
+ "tokenizer",
26
+ ]
27
+ image_processor_class = "AutoImageProcessor"
28
+ tokenizer_class = "AutoTokenizer"
29
+ _auto_class = "AutoProcessor"
30
+
31
+ def __init__(
32
+ self,
33
+ image_processor: SiglipImageProcessor | SiglipImageProcessorFast,
34
+ tokenizer: Qwen2Tokenizer | Qwen2TokenizerFast,
35
+ chat_template: str | None = None,
36
+ **kwargs,
37
+ ):
38
+ super().__init__(
39
+ image_processor,
40
+ tokenizer,
41
+ chat_template=chat_template,
42
+ **kwargs,
43
+ )
44
+
45
+ self.image_processor: SiglipImageProcessor | SiglipImageProcessorFast
46
+ self.tokenizer: Qwen2Tokenizer | Qwen2TokenizerFast
47
+
48
+ def __call__(
49
+ self,
50
+ *,
51
+ text: TextInput | list[TextInput],
52
+ images: ImageInput | None = None,
53
+ videos: VideoInput | None = None,
54
+ **kwargs: Unpack[NVILALiteProcessorKwargs],
55
+ ) -> BatchFeature:
56
+ normalized_text, normalized_images, normalized_videos = self._normalize_inputs(
57
+ text=text,
58
+ images=images,
59
+ videos=videos,
60
+ )
61
+
62
+ images_inputs, image_token_padding_strategy = (
63
+ self._preprocess_images(
64
+ normalized_images,
65
+ **kwargs,
66
+ )
67
+ if len(normalized_images) > 0
68
+ else (BatchFeature(), [])
69
+ )
70
+
71
+ videos_inputs, video_token_padding_strategy = (
72
+ self._preprocess_videos(
73
+ normalized_videos,
74
+ **kwargs,
75
+ )
76
+ if len(normalized_videos) > 0
77
+ else (BatchFeature(), [])
78
+ )
79
+
80
+ text_inputs = self._preprocess_text(
81
+ normalized_text,
82
+ image_token_padding_strategy=image_token_padding_strategy,
83
+ video_token_padding_strategy=video_token_padding_strategy,
84
+ **kwargs,
85
+ )
86
+
87
+ return BatchFeature(
88
+ {
89
+ **text_inputs,
90
+ **images_inputs,
91
+ **videos_inputs,
92
+ }
93
+ )
94
+
95
+ def batch_decode(self, *args, **kwargs) -> list[str]:
96
+ return self.tokenizer.batch_decode(*args, **kwargs)
97
+
98
+ def _normalize_inputs(
99
+ self,
100
+ *,
101
+ text: TextInput | list[TextInput],
102
+ images: ImageInput | None,
103
+ videos: VideoInput | None,
104
+ ) -> tuple[list[str], list[Image], list[list[Image]]]:
105
+ if isinstance(text, list):
106
+ normalized_text = text
107
+ else:
108
+ normalized_text = [text]
109
+
110
+ if images is not None and images != []:
111
+ image_flat_list = cast(list, image_utils.make_flat_list_of_images(images))
112
+ normalized_images = [cast(Image, image_transforms.to_pil_image(image)) for image in image_flat_list]
113
+ else:
114
+ normalized_images = []
115
+
116
+ if videos is not None and videos != []:
117
+ video_list = cast(list[list], video_utils.make_batched_videos(videos))
118
+ normalized_videos = [
119
+ [cast(Image, image_transforms.to_pil_image(image)) for image in video] for video in video_list
120
+ ]
121
+ else:
122
+ normalized_videos = []
123
+
124
+ return normalized_text, normalized_images, normalized_videos
125
+
126
+ def _preprocess_images(
127
+ self,
128
+ images: list[Image],
129
+ **kwargs: Unpack[NVILALiteProcessorKwargs],
130
+ ) -> tuple[BatchFeature, list[list[int]]]:
131
+ merged_kwargs = self._merge_kwargs(
132
+ NVILALiteProcessorKwargs, # type: ignore
133
+ tokenizer_init_kwargs=self.tokenizer.init_kwargs,
134
+ **kwargs,
135
+ )
136
+
137
+ images = [image.convert("RGB") for image in images]
138
+
139
+ if len(images) == 1:
140
+ assert self.image_processor.size["height"] == self.image_processor.size["width"]
141
+
142
+ image_tiles = dynamic_preprocess(
143
+ images[0],
144
+ min_num=1,
145
+ max_num=12,
146
+ image_size=self.image_processor.size["height"],
147
+ )
148
+
149
+ pixel_values = self.image_processor(
150
+ image_tiles,
151
+ **merged_kwargs["images_kwargs"],
152
+ )["pixel_values"]
153
+
154
+ images_inputs = BatchFeature(
155
+ {
156
+ "pixel_values": pixel_values,
157
+ }
158
+ )
159
+
160
+ padding_strategy = [[121] * len(image_tiles)]
161
+
162
+ else:
163
+ pixel_values = self.image_processor(
164
+ images,
165
+ **merged_kwargs["images_kwargs"],
166
+ )["pixel_values"]
167
+
168
+ images_inputs = BatchFeature(
169
+ {
170
+ "pixel_values": pixel_values,
171
+ }
172
+ )
173
+
174
+ padding_strategy = [[121]] * len(images)
175
+
176
+ return images_inputs, padding_strategy
177
+
178
+ def _preprocess_text(
179
+ self,
180
+ text: list[str],
181
+ *,
182
+ image_token_padding_strategy: list[list[int]],
183
+ video_token_padding_strategy: list[list[int]],
184
+ **kwargs: Unpack[NVILALiteProcessorKwargs],
185
+ ) -> BatchEncoding:
186
+ # Pad media tokens.
187
+ assert isinstance(self.tokenizer.image_token, str)
188
+ assert isinstance(self.tokenizer.video_token, str)
189
+
190
+ for media_token, padding_strategy in (
191
+ (self.tokenizer.image_token, image_token_padding_strategy),
192
+ (self.tokenizer.video_token, video_token_padding_strategy),
193
+ ):
194
+ assert sum([s.count(media_token) for s in text]) == len(padding_strategy)
195
+
196
+ # Pad to number of tiles.
197
+ pad_lens = [len(x) for x in padding_strategy]
198
+ text = [re.sub(rf"({re.escape(media_token)})", lambda _: media_token * pad_lens.pop(0), s) for s in text]
199
+
200
+ # HACK: NVILA mistakenly suffixes line feeds to some media tokens.
201
+ if len(image_token_padding_strategy) == 1 and media_token == self.tokenizer.image_token:
202
+ image_token = self.tokenizer.image_token
203
+ assert isinstance(image_token, str)
204
+
205
+ text = [re.sub(rf"({re.escape(image_token)})", r"\1\n", s) for s in text]
206
+
207
+ # Pad to number of features.
208
+ pad_lens = [y for x in padding_strategy for y in x]
209
+ pad_lens = [x + 1 for x in pad_lens] # Reserve for lf ending.
210
+ text = [re.sub(rf"({re.escape(media_token)})", lambda _: media_token * pad_lens.pop(0), s) for s in text]
211
+
212
+ merged_kwargs = self._merge_kwargs(
213
+ NVILALiteProcessorKwargs, # type: ignore
214
+ tokenizer_init_kwargs=self.tokenizer.init_kwargs,
215
+ **kwargs,
216
+ )
217
+
218
+ text_inputs = self.tokenizer(
219
+ text=text,
220
+ **merged_kwargs["text_kwargs"],
221
+ )
222
+
223
+ # Replace last token id of every image tile with lf token id.
224
+ lf_token_id = self.tokenizer.encode("\n")[0]
225
+ assert isinstance(self.tokenizer.image_token_id, int)
226
+ assert isinstance(self.tokenizer.video_token_id, int)
227
+
228
+ input_ids = text_inputs.input_ids
229
+
230
+ for media_token_id, padding_strategy in [
231
+ (self.tokenizer.image_token_id, image_token_padding_strategy),
232
+ (self.tokenizer.video_token_id, video_token_padding_strategy),
233
+ ]:
234
+ pad_lens = [y for x in padding_strategy for y in x]
235
+
236
+ for i in range(len(input_ids)):
237
+ j = 0
238
+ while j < len(input_ids[i]):
239
+ if input_ids[i][j] != media_token_id:
240
+ j += 1
241
+ continue
242
+
243
+ j += pad_lens.pop(0)
244
+ input_ids[i][j] = lf_token_id
245
+
246
+ j += 1
247
+
248
+ return text_inputs
249
+
250
+ def _preprocess_videos(
251
+ self,
252
+ videos: list[list[Image]],
253
+ **kwargs: Unpack[NVILALiteProcessorKwargs],
254
+ ) -> tuple[BatchFeature, list[list[int]]]:
255
+ merged_kwargs = self._merge_kwargs(
256
+ NVILALiteProcessorKwargs, # type: ignore
257
+ tokenizer_init_kwargs=self.tokenizer.init_kwargs,
258
+ **kwargs,
259
+ )
260
+
261
+ # Support sampling frames.
262
+ if merged_kwargs["videos_kwargs"].get("do_sample_frames"):
263
+ videos = [
264
+ self._sample_frames(
265
+ video,
266
+ **merged_kwargs["videos_kwargs"],
267
+ )
268
+ for video in videos
269
+ ]
270
+
271
+ videos = [[image.convert("RGB") for image in video] for video in videos]
272
+
273
+ frames = [image for video in videos for image in video]
274
+ pixel_values_videos = self.image_processor(
275
+ frames,
276
+ **merged_kwargs["images_kwargs"],
277
+ )["pixel_values"]
278
+
279
+ videos_inputs = BatchFeature(
280
+ {
281
+ "pixel_values_videos": pixel_values_videos,
282
+ }
283
+ )
284
+
285
+ padding_strategy = [[121] * len(video) for video in videos]
286
+
287
+ return videos_inputs, padding_strategy
288
+
289
+ def _sample_frames(
290
+ self,
291
+ video: list[Image],
292
+ **kwargs: Unpack[VideosKwargs],
293
+ ) -> list[Image]:
294
+ fps = kwargs.get("fps")
295
+ num_frames = kwargs.get("num_frames")
296
+
297
+ if num_frames is not None and fps is None:
298
+ indices = np.round(np.linspace(0, len(video) - 1, num_frames)).astype(int)
299
+
300
+ return [video[i] for i in indices]
301
+
302
+ elif num_frames is None and fps is not None:
303
+ video_metadata = kwargs.get("video_metadata")
304
+
305
+ if isinstance(video_metadata, VideoMetadata):
306
+ total_num_frames = video_metadata.total_num_frames
307
+ duration = video_metadata.duration
308
+
309
+ elif isinstance(video_metadata, dict):
310
+ total_num_frames = video_metadata.get("total_num_frames")
311
+ duration = video_metadata.get("duration")
312
+
313
+ assert total_num_frames is not None
314
+ assert duration is not None
315
+
316
+ else:
317
+ raise NotImplementedError
318
+
319
+ indices = np.round(np.linspace(0, total_num_frames - 1, int(fps * duration))).astype(int)
320
+
321
+ return [video[i] for i in indices]
322
+
323
+ else:
324
+ raise NotImplementedError
325
+
326
+
327
+ # NOTE: The following functions are directly copied from VILA codebase.
328
+
329
+
330
+ def dynamic_preprocess(
331
+ image: Image, min_num: int, max_num: int, image_size: int, use_thumbnail: bool = True
332
+ ) -> list[Image]:
333
+ orig_width, orig_height = image.size
334
+ aspect_ratio = orig_width / orig_height
335
+
336
+ # calculate the existing image aspect ratio
337
+ target_ratios = {
338
+ (i, j)
339
+ for n in range(min_num, max_num + 1)
340
+ for i in range(1, n + 1)
341
+ for j in range(1, n + 1)
342
+ if i * j <= max_num and i * j >= min_num
343
+ }
344
+ target_ratios = sorted(target_ratios, key=lambda x: x[0] * x[1])
345
+
346
+ # find the closest aspect ratio to the target
347
+ target_aspect_ratio = find_closest_aspect_ratio(aspect_ratio, target_ratios, orig_width, orig_height, image_size)
348
+
349
+ # calculate the target width and height
350
+ target_width = image_size * target_aspect_ratio[0]
351
+ target_height = image_size * target_aspect_ratio[1]
352
+ blocks = target_aspect_ratio[0] * target_aspect_ratio[1]
353
+
354
+ # resize the image
355
+ resized_img = image.resize((target_width, target_height))
356
+ processed_images = []
357
+ for i in range(blocks):
358
+ box = (
359
+ (i % (target_width // image_size)) * image_size,
360
+ (i // (target_width // image_size)) * image_size,
361
+ ((i % (target_width // image_size)) + 1) * image_size,
362
+ ((i // (target_width // image_size)) + 1) * image_size,
363
+ )
364
+ # split the image
365
+ split_img = resized_img.crop(box)
366
+ processed_images.append(split_img)
367
+ assert len(processed_images) == blocks
368
+ if use_thumbnail and len(processed_images) != 1:
369
+ thumbnail_img = image.resize((image_size, image_size))
370
+ processed_images.append(thumbnail_img)
371
+ return processed_images
372
+
373
+
374
+ def find_closest_aspect_ratio(
375
+ aspect_ratio: float, target_ratios: list[tuple[int, int]], width: int, height: int, image_size: int
376
+ ) -> tuple[int, int]:
377
+ best_ratio_diff = float("inf")
378
+ best_ratio = (1, 1)
379
+ area = width * height
380
+ for ratio in target_ratios:
381
+ target_aspect_ratio = ratio[0] / ratio[1]
382
+ ratio_diff = abs(aspect_ratio - target_aspect_ratio)
383
+ if ratio_diff < best_ratio_diff:
384
+ best_ratio_diff = ratio_diff
385
+ best_ratio = ratio
386
+ elif ratio_diff == best_ratio_diff:
387
+ if area > 0.5 * image_size * image_size * ratio[0] * ratio[1]:
388
+ best_ratio = ratio
389
+ return best_ratio
processor_config.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "auto_map": {
3
+ "AutoProcessor": "processing_nvila_lite.NVILALiteProcessor"
4
+ },
5
+ "processor_class": "NVILALiteProcessor"
6
+ }
special_tokens_map.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<|im_start|>",
4
+ "<|im_end|>"
5
+ ],
6
+ "bos_token": {
7
+ "content": "[BOS]",
8
+ "lstrip": false,
9
+ "normalized": false,
10
+ "rstrip": false,
11
+ "single_word": false
12
+ },
13
+ "eos_token": {
14
+ "content": "<|im_end|>",
15
+ "lstrip": false,
16
+ "normalized": false,
17
+ "rstrip": false,
18
+ "single_word": false
19
+ },
20
+ "image_token": "<image>",
21
+ "pad_token": {
22
+ "content": "[PAD]",
23
+ "lstrip": false,
24
+ "normalized": false,
25
+ "rstrip": false,
26
+ "single_word": false
27
+ },
28
+ "sentinel_token": "<vila/sentinel>",
29
+ "video_token": "<vila/video>"
30
+ }
tokenizer_config.json ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ "151646": {
29
+ "content": "[BOS]",
30
+ "lstrip": false,
31
+ "normalized": false,
32
+ "rstrip": false,
33
+ "single_word": false,
34
+ "special": true
35
+ },
36
+ "151647": {
37
+ "content": "[PAD]",
38
+ "lstrip": false,
39
+ "normalized": false,
40
+ "rstrip": false,
41
+ "single_word": false,
42
+ "special": true
43
+ },
44
+ "151648": {
45
+ "content": "<vila/sentinel>",
46
+ "lstrip": false,
47
+ "normalized": false,
48
+ "rstrip": false,
49
+ "single_word": false,
50
+ "special": true
51
+ },
52
+ "151649": {
53
+ "content": "<image>",
54
+ "lstrip": false,
55
+ "normalized": false,
56
+ "rstrip": false,
57
+ "single_word": false,
58
+ "special": true
59
+ },
60
+ "151650": {
61
+ "content": "<vila/video>",
62
+ "lstrip": false,
63
+ "normalized": false,
64
+ "rstrip": false,
65
+ "single_word": false,
66
+ "special": true
67
+ }
68
+ },
69
+ "additional_special_tokens": [
70
+ "<|im_start|>",
71
+ "<|im_end|>"
72
+ ],
73
+ "auto_map": {
74
+ "AutoProcessor": "processing_nvila_lite.NVILALiteProcessor"
75
+ },
76
+ "bos_token": "[BOS]",
77
+ "clean_up_tokenization_spaces": false,
78
+ "eos_token": "<|im_end|>",
79
+ "errors": "replace",
80
+ "extra_special_tokens": {
81
+ "image_token": "<image>",
82
+ "sentinel_token": "<vila/sentinel>",
83
+ "video_token": "<vila/video>"
84
+ },
85
+ "image_token": "<image>",
86
+ "legacy": false,
87
+ "model_max_length": 4096,
88
+ "pad_token": "[PAD]",
89
+ "padding_side": "left",
90
+ "processor_class": "NVILALiteProcessor",
91
+ "sentinel_token": "<vila/sentinel>",
92
+ "split_special_tokens": false,
93
+ "tokenizer_class": "Qwen2Tokenizer",
94
+ "unk_token": null,
95
+ "video_token": "<vila/video>"
96
+ }
vocab.json ADDED
The diff for this file is too large to render. See raw diff