passionMan commited on
Commit
bdab9d2
·
verified ·
1 Parent(s): 30b022c

Add processing_brain_ocr.py

Browse files
Files changed (1) hide show
  1. processing_brain_ocr.py +199 -0
processing_brain_ocr.py ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+ # Modified from HunyuanVL processor for BrainOCR.
4
+
5
+ import numpy as np
6
+ import torch
7
+ from transformers.feature_extraction_utils import BatchFeature
8
+ from transformers.image_utils import ImageInput
9
+ from transformers.processing_utils import ProcessorMixin
10
+ from transformers.tokenization_utils_base import PreTokenizedInput, TextInput
11
+ from transformers.video_utils import VideoInput
12
+
13
+
14
+ class BrainOCRProcessor(ProcessorMixin):
15
+ attributes = ["image_processor", "tokenizer"]
16
+ valid_kwargs = ["chat_template"]
17
+ image_processor_class = "AutoImageProcessor"
18
+ tokenizer_class = "AutoTokenizer"
19
+
20
+ def __init__(
21
+ self,
22
+ image_processor=None,
23
+ tokenizer=None,
24
+ chat_template=None,
25
+ **kwargs,
26
+ ):
27
+ self.tokenizer = tokenizer
28
+ self.image_token_id = 120120
29
+ self.image_token = self.tokenizer.convert_ids_to_tokens(self.image_token_id)
30
+ self.im_start_token_id = 120118
31
+ self.im_start_token = self.tokenizer.convert_ids_to_tokens(
32
+ self.im_start_token_id
33
+ )
34
+ self.im_end_token_id = 120119
35
+ self.im_end_token = self.tokenizer.convert_ids_to_tokens(self.im_end_token_id)
36
+ self.placeholder_token = self.tokenizer.convert_ids_to_tokens(
37
+ self.tokenizer.vocab_size - 1
38
+ )
39
+ self.pad_id = 120002
40
+
41
+ super().__init__(image_processor, tokenizer, chat_template=chat_template)
42
+
43
+ def __call__(
44
+ self,
45
+ images: ImageInput = None,
46
+ text: TextInput
47
+ | PreTokenizedInput
48
+ | list[TextInput]
49
+ | list[PreTokenizedInput] = None,
50
+ videos: VideoInput = None,
51
+ **kwargs,
52
+ ) -> BatchFeature:
53
+ image_inputs = {}
54
+ if images is not None:
55
+ image_inputs = self.image_processor(images=images)
56
+ image_grid_thw = image_inputs["image_grid_thw"]
57
+
58
+ if not isinstance(text, list):
59
+ text = [text]
60
+
61
+ text = text.copy()
62
+
63
+ image_tokens_cumsum = [0]
64
+ if images is not None:
65
+ index = 0
66
+ for i in range(len(text)):
67
+ while self.image_token in text[i]:
68
+ grid_h, grid_w = image_grid_thw[index][-2:]
69
+ patch_h = grid_h // self.image_processor.merge_size
70
+ patch_w = grid_w // self.image_processor.merge_size
71
+ num_image_tokens = patch_h * (patch_w + 1) + 2
72
+ image_tokens_cumsum.append(
73
+ image_tokens_cumsum[-1] + num_image_tokens
74
+ )
75
+ text[i] = text[i].replace(
76
+ self.image_token, self.placeholder_token * num_image_tokens, 1
77
+ )
78
+ index += 1
79
+ text[i] = text[i].replace(self.placeholder_token, self.image_token)
80
+
81
+ text_inputs = self.tokenizer(text, add_special_tokens=False, **kwargs)
82
+ self._check_special_mm_tokens(text, text_inputs, modalities=["image"])
83
+
84
+ input_ids = text_inputs["input_ids"]
85
+ position_ids = torch.arange(len(input_ids[0]))
86
+ position_ids_w = torch.arange(len(input_ids[0]))
87
+ position_ids_h = torch.arange(len(input_ids[0]))
88
+ position_ids_t = torch.arange(len(input_ids[0]))
89
+
90
+ if images is not None:
91
+ image_token_pos_indices = torch.where(input_ids[0] == self.image_token_id)[
92
+ 0
93
+ ]
94
+ for i in range(len(image_grid_thw)):
95
+ grid_h, grid_w = image_grid_thw[i][-2:]
96
+ patch_h = grid_h // self.image_processor.merge_size
97
+ patch_w = grid_w // self.image_processor.merge_size
98
+ start_pos = image_token_pos_indices[image_tokens_cumsum[i]].item() + 1
99
+ replace_num = (patch_w + 1) * patch_h
100
+ position_ids_w[start_pos : start_pos + replace_num] = torch.tensor(
101
+ list(range(patch_w + 1)) * patch_h, dtype=torch.int64
102
+ )
103
+ patch_h_list = []
104
+ for h in range(patch_h):
105
+ patch_h_list += [h] * (patch_w + 1)
106
+ position_ids_h[start_pos : start_pos + replace_num] = torch.tensor(
107
+ patch_h_list, dtype=torch.int64
108
+ )
109
+ position_ids_t[start_pos : start_pos + replace_num] = 0
110
+
111
+ position_ids = torch.stack(
112
+ [position_ids, position_ids_w, position_ids_h, position_ids_t]
113
+ ).unsqueeze(0)
114
+ text_inputs["position_ids"] = position_ids
115
+
116
+ attention_mask = input_ids.ne(self.pad_id)
117
+ text_inputs["attention_mask"] = attention_mask
118
+ text_inputs["imgs_pos"] = [self.get_imgs_pos(e) for e in input_ids]
119
+
120
+ return_tensors = kwargs.pop("return_tensors", None)
121
+ return BatchFeature(
122
+ data={**text_inputs, **image_inputs},
123
+ tensor_type=return_tensors,
124
+ )
125
+
126
+ def batch_decode(self, *args, **kwargs):
127
+ return self.tokenizer.batch_decode(*args, **kwargs)
128
+
129
+ def decode(self, *args, **kwargs):
130
+ return self.tokenizer.decode(*args, **kwargs)
131
+
132
+ def post_process_image_text_to_text(
133
+ self,
134
+ generated_outputs,
135
+ skip_special_tokens=True,
136
+ clean_up_tokenization_spaces=False,
137
+ **kwargs,
138
+ ):
139
+ assert 0
140
+
141
+ def apply_chat_template(self, *args, **kwargs):
142
+ kwargs["return_dict"] = False
143
+ return self.tokenizer.apply_chat_template(*args, **kwargs)
144
+
145
+ def get_imgs_pos(self, doc_ids):
146
+ doc_ids = np.array(doc_ids, dtype=np.int64)
147
+ img_begin_index = np.where(doc_ids == self.im_start_token_id)[0]
148
+ img_end_index = np.where(doc_ids == self.im_end_token_id)[0]
149
+ imgs_pos = np.concatenate(
150
+ (
151
+ np.reshape(img_begin_index + 1, (-1, 1)),
152
+ np.reshape(img_end_index, (-1, 1)),
153
+ ),
154
+ axis=-1,
155
+ ).tolist()
156
+ return imgs_pos
157
+
158
+ @property
159
+ def model_input_names(self):
160
+ tokenizer_input_names = self.tokenizer.model_input_names
161
+ image_processor_input_names = self.image_processor.model_input_names
162
+ return list(dict.fromkeys(tokenizer_input_names + image_processor_input_names))
163
+
164
+
165
+ def split_image_into_patch_blocks(
166
+ pixel_values: torch.Tensor,
167
+ patch_size: int = 16,
168
+ adaptor_patch_div: int = 4,
169
+ ) -> torch.Tensor:
170
+ """Split image tensor into patch blocks for the vision encoder."""
171
+ batch_size, channels, height, width = pixel_values.shape
172
+ assert channels == 3, "Pixel values must have 3 channels in dim=1"
173
+ assert height % patch_size == 0 and width % patch_size == 0, (
174
+ "H and W must be divisible by patch_size"
175
+ )
176
+
177
+ patch_height_num = height // patch_size
178
+ patch_width_num = width // patch_size
179
+
180
+ img = pixel_values.reshape(
181
+ batch_size, 3, patch_height_num, patch_size, patch_width_num, patch_size
182
+ )
183
+
184
+ img = img.reshape(
185
+ batch_size,
186
+ 3,
187
+ patch_height_num,
188
+ patch_size // adaptor_patch_div,
189
+ adaptor_patch_div,
190
+ patch_width_num,
191
+ patch_size // adaptor_patch_div,
192
+ adaptor_patch_div,
193
+ )
194
+
195
+ img = img.permute(0, 2, 5, 3, 6, 1, 4, 7)
196
+
197
+ patches = img.reshape(-1, 3, patch_size, patch_size)
198
+
199
+ return patches