comdoleger commited on
Commit
ef4eb40
·
verified ·
1 Parent(s): 27d9d3a

Upload extensions_built_in/dataset_tools/SuperTagger.py with huggingface_hub

Browse files
extensions_built_in/dataset_tools/SuperTagger.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ import json
3
+ import os
4
+ from collections import OrderedDict
5
+ import gc
6
+ import traceback
7
+ import torch
8
+ from PIL import Image, ImageOps
9
+ from tqdm import tqdm
10
+
11
+ from .tools.dataset_tools_config_modules import RAW_DIR, TRAIN_DIR, Step, ImgInfo
12
+ from .tools.fuyu_utils import FuyuImageProcessor
13
+ from .tools.image_tools import load_image, ImageProcessor, resize_to_max
14
+ from .tools.llava_utils import LLaVAImageProcessor
15
+ from .tools.caption import default_long_prompt, default_short_prompt, default_replacements
16
+ from jobs.process import BaseExtensionProcess
17
+ from .tools.sync_tools import get_img_paths
18
+
19
+ img_ext = ['.jpg', '.jpeg', '.png', '.webp']
20
+
21
+
22
+ def flush():
23
+ torch.cuda.empty_cache()
24
+ gc.collect()
25
+
26
+
27
+ VERSION = 2
28
+
29
+
30
+ class SuperTagger(BaseExtensionProcess):
31
+
32
+ def __init__(self, process_id: int, job, config: OrderedDict):
33
+ super().__init__(process_id, job, config)
34
+ parent_dir = config.get('parent_dir', None)
35
+ self.dataset_paths: list[str] = config.get('dataset_paths', [])
36
+ self.device = config.get('device', 'cuda')
37
+ self.steps: list[Step] = config.get('steps', [])
38
+ self.caption_method = config.get('caption_method', 'llava:default')
39
+ self.caption_prompt = config.get('caption_prompt', default_long_prompt)
40
+ self.caption_short_prompt = config.get('caption_short_prompt', default_short_prompt)
41
+ self.force_reprocess_img = config.get('force_reprocess_img', False)
42
+ self.caption_replacements = config.get('caption_replacements', default_replacements)
43
+ self.caption_short_replacements = config.get('caption_short_replacements', default_replacements)
44
+ self.master_dataset_dict = OrderedDict()
45
+ self.dataset_master_config_file = config.get('dataset_master_config_file', None)
46
+ if parent_dir is not None and len(self.dataset_paths) == 0:
47
+ # find all folders in the patent_dataset_path
48
+ self.dataset_paths = [
49
+ os.path.join(parent_dir, folder)
50
+ for folder in os.listdir(parent_dir)
51
+ if os.path.isdir(os.path.join(parent_dir, folder))
52
+ ]
53
+ else:
54
+ # make sure they exist
55
+ for dataset_path in self.dataset_paths:
56
+ if not os.path.exists(dataset_path):
57
+ raise ValueError(f"Dataset path does not exist: {dataset_path}")
58
+
59
+ print(f"Found {len(self.dataset_paths)} dataset paths")
60
+
61
+ self.image_processor: ImageProcessor = self.get_image_processor()
62
+
63
+ def get_image_processor(self):
64
+ if self.caption_method.startswith('llava'):
65
+ return LLaVAImageProcessor(device=self.device)
66
+ elif self.caption_method.startswith('fuyu'):
67
+ return FuyuImageProcessor(device=self.device)
68
+ else:
69
+ raise ValueError(f"Unknown caption method: {self.caption_method}")
70
+
71
+ def process_image(self, img_path: str):
72
+ root_img_dir = os.path.dirname(os.path.dirname(img_path))
73
+ filename = os.path.basename(img_path)
74
+ filename_no_ext = os.path.splitext(filename)[0]
75
+ train_dir = os.path.join(root_img_dir, TRAIN_DIR)
76
+ train_img_path = os.path.join(train_dir, filename)
77
+ json_path = os.path.join(train_dir, f"{filename_no_ext}.json")
78
+
79
+ # check if json exists, if it does load it as image info
80
+ if os.path.exists(json_path):
81
+ with open(json_path, 'r') as f:
82
+ img_info = ImgInfo(**json.load(f))
83
+ else:
84
+ img_info = ImgInfo()
85
+
86
+ # always send steps first in case other processes need them
87
+ img_info.add_steps(copy.deepcopy(self.steps))
88
+ img_info.set_version(VERSION)
89
+ img_info.set_caption_method(self.caption_method)
90
+
91
+ image: Image = None
92
+ caption_image: Image = None
93
+
94
+ did_update_image = False
95
+
96
+ # trigger reprocess of steps
97
+ if self.force_reprocess_img:
98
+ img_info.trigger_image_reprocess()
99
+
100
+ # set the image as updated if it does not exist on disk
101
+ if not os.path.exists(train_img_path):
102
+ did_update_image = True
103
+ image = load_image(img_path)
104
+ if img_info.force_image_process:
105
+ did_update_image = True
106
+ image = load_image(img_path)
107
+
108
+ # go through the needed steps
109
+ for step in copy.deepcopy(img_info.state.steps_to_complete):
110
+ if step == 'caption':
111
+ # load image
112
+ if image is None:
113
+ image = load_image(img_path)
114
+ if caption_image is None:
115
+ caption_image = resize_to_max(image, 1024, 1024)
116
+
117
+ if not self.image_processor.is_loaded:
118
+ print('Loading Model. Takes a while, especially the first time')
119
+ self.image_processor.load_model()
120
+
121
+ img_info.caption = self.image_processor.generate_caption(
122
+ image=caption_image,
123
+ prompt=self.caption_prompt,
124
+ replacements=self.caption_replacements
125
+ )
126
+ img_info.mark_step_complete(step)
127
+ elif step == 'caption_short':
128
+ # load image
129
+ if image is None:
130
+ image = load_image(img_path)
131
+
132
+ if caption_image is None:
133
+ caption_image = resize_to_max(image, 1024, 1024)
134
+
135
+ if not self.image_processor.is_loaded:
136
+ print('Loading Model. Takes a while, especially the first time')
137
+ self.image_processor.load_model()
138
+ img_info.caption_short = self.image_processor.generate_caption(
139
+ image=caption_image,
140
+ prompt=self.caption_short_prompt,
141
+ replacements=self.caption_short_replacements
142
+ )
143
+ img_info.mark_step_complete(step)
144
+ elif step == 'contrast_stretch':
145
+ # load image
146
+ if image is None:
147
+ image = load_image(img_path)
148
+ image = ImageOps.autocontrast(image, cutoff=(0.1, 0), preserve_tone=True)
149
+ did_update_image = True
150
+ img_info.mark_step_complete(step)
151
+ else:
152
+ raise ValueError(f"Unknown step: {step}")
153
+
154
+ os.makedirs(os.path.dirname(train_img_path), exist_ok=True)
155
+ if did_update_image:
156
+ image.save(train_img_path)
157
+
158
+ if img_info.is_dirty:
159
+ with open(json_path, 'w') as f:
160
+ json.dump(img_info.to_dict(), f, indent=4)
161
+
162
+ if self.dataset_master_config_file:
163
+ # add to master dict
164
+ self.master_dataset_dict[train_img_path] = img_info.to_dict()
165
+
166
+ def run(self):
167
+ super().run()
168
+ imgs_to_process = []
169
+ # find all images
170
+ for dataset_path in self.dataset_paths:
171
+ raw_dir = os.path.join(dataset_path, RAW_DIR)
172
+ raw_image_paths = get_img_paths(raw_dir)
173
+ for raw_image_path in raw_image_paths:
174
+ imgs_to_process.append(raw_image_path)
175
+
176
+ if len(imgs_to_process) == 0:
177
+ print(f"No images to process")
178
+ else:
179
+ print(f"Found {len(imgs_to_process)} to process")
180
+
181
+ for img_path in tqdm(imgs_to_process, desc="Processing images"):
182
+ try:
183
+ self.process_image(img_path)
184
+ except Exception:
185
+ # print full stack trace
186
+ print(traceback.format_exc())
187
+ continue
188
+ # self.process_image(img_path)
189
+
190
+ if self.dataset_master_config_file is not None:
191
+ # save it as json
192
+ with open(self.dataset_master_config_file, 'w') as f:
193
+ json.dump(self.master_dataset_dict, f, indent=4)
194
+
195
+ del self.image_processor
196
+ flush()