Spaces:
Sleeping
Sleeping
Upload 139 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- __init__.py +0 -0
- app.py +793 -0
- dataset/__init__.py +0 -0
- dataset/__pycache__/__init__.cpython-38.pyc +0 -0
- dataset/__pycache__/catalog.cpython-38.pyc +0 -0
- dataset/__pycache__/concat_dataset.cpython-38.pyc +0 -0
- dataset/base_dataset.py +220 -0
- dataset/catalog.py +72 -0
- dataset/cd_dataset.py +250 -0
- dataset/concat_dataset.py +65 -0
- dataset/grounding_dataset.py +205 -0
- dataset/layout_dataset.py +237 -0
- dataset/tsv.py +212 -0
- dataset/tsv_dataset.py +326 -0
- dataset/utils.py +116 -0
- environment.yaml +29 -0
- example_component.py +805 -0
- gligen/.DS_Store +0 -0
- gligen/SD_input_conv_weight_bias.pth +3 -0
- gligen/__init__.py +10 -0
- gligen/__pycache__/__init__.cpython-38.pyc +0 -0
- gligen/__pycache__/distributed.cpython-38.pyc +0 -0
- gligen/__pycache__/evaluator.cpython-38.pyc +0 -0
- gligen/__pycache__/task_grounded_generation.cpython-38.pyc +0 -0
- gligen/__pycache__/trainer.cpython-38.pyc +0 -0
- gligen/create_meta.py +170 -0
- gligen/distributed.py +122 -0
- gligen/evaluator.py +225 -0
- gligen/ldm/.DS_Store +0 -0
- gligen/ldm/__pycache__/util.cpython-38.pyc +0 -0
- gligen/ldm/data/.DS_Store +0 -0
- gligen/ldm/data/__init__.py +0 -0
- gligen/ldm/data/base.py +23 -0
- gligen/ldm/data/imagenet.py +394 -0
- gligen/ldm/data/imagenet_clsidx_to_label.txt +1000 -0
- gligen/ldm/data/imagenet_train_hr_indices.p +3 -0
- gligen/ldm/data/imagenet_val_hr_indices.p +3 -0
- gligen/ldm/data/index_synset.yaml +1000 -0
- gligen/ldm/data/lsun.py +92 -0
- gligen/ldm/lr_scheduler.py +98 -0
- gligen/ldm/models/.DS_Store +0 -0
- gligen/ldm/models/__pycache__/autoencoder.cpython-38.pyc +0 -0
- gligen/ldm/models/autoencoder.py +52 -0
- gligen/ldm/models/diffusion/__init__.py +0 -0
- gligen/ldm/models/diffusion/__pycache__/__init__.cpython-38.pyc +0 -0
- gligen/ldm/models/diffusion/__pycache__/ddim.cpython-38.pyc +0 -0
- gligen/ldm/models/diffusion/__pycache__/ddpm.cpython-38.pyc +0 -0
- gligen/ldm/models/diffusion/__pycache__/gaussian_smoothing.cpython-38.pyc +0 -0
- gligen/ldm/models/diffusion/__pycache__/ldm.cpython-38.pyc +0 -0
- gligen/ldm/models/diffusion/__pycache__/loss.cpython-38.pyc +0 -0
__init__.py
ADDED
File without changes
|
app.py
ADDED
@@ -0,0 +1,793 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import torch
|
3 |
+
from omegaconf import OmegaConf
|
4 |
+
from gligen.task_grounded_generation import grounded_generation_box, load_ckpt, load_common_ckpt
|
5 |
+
|
6 |
+
import json
|
7 |
+
import numpy as np
|
8 |
+
from PIL import Image, ImageDraw, ImageFont
|
9 |
+
from functools import partial
|
10 |
+
from collections import Counter
|
11 |
+
import math
|
12 |
+
import gc
|
13 |
+
|
14 |
+
from gradio import processing_utils
|
15 |
+
from typing import Optional
|
16 |
+
|
17 |
+
import warnings
|
18 |
+
|
19 |
+
from datetime import datetime
|
20 |
+
|
21 |
+
from example_component import create_examples
|
22 |
+
|
23 |
+
from huggingface_hub import hf_hub_download
|
24 |
+
hf_hub_download = partial(hf_hub_download, library_name="gligen_demo")
|
25 |
+
import cv2
|
26 |
+
import sys
|
27 |
+
sys.tracebacklimit = 0
|
28 |
+
|
29 |
+
|
30 |
+
def load_from_hf(repo_id, filename='diffusion_pytorch_model.bin', subfolder=None):
|
31 |
+
cache_file = hf_hub_download(repo_id=repo_id, filename=filename, subfolder=subfolder)
|
32 |
+
return torch.load(cache_file, map_location='cpu')
|
33 |
+
|
34 |
+
def load_ckpt_config_from_hf(modality):
|
35 |
+
ckpt = load_from_hf('gligen/demo_ckpts_legacy', filename=f'{modality}.pth', subfolder='model')
|
36 |
+
config = load_from_hf('gligen/demo_ckpts_legacy', filename=f'{modality}.pth', subfolder='config')
|
37 |
+
return ckpt, config
|
38 |
+
|
39 |
+
|
40 |
+
def ckpt_load_helper(modality, is_inpaint, is_style, common_instances=None):
|
41 |
+
pretrained_ckpt_gligen, config = load_ckpt_config_from_hf(modality)
|
42 |
+
config = OmegaConf.create( config["_content"] ) # config used in training
|
43 |
+
config.alpha_scale = 1.0
|
44 |
+
|
45 |
+
if common_instances is None:
|
46 |
+
common_ckpt = load_from_hf('gligen/demo_ckpts_legacy', filename=f'common.pth', subfolder='model')
|
47 |
+
common_instances = load_common_ckpt(config, common_ckpt)
|
48 |
+
|
49 |
+
loaded_model_list = load_ckpt(config, pretrained_ckpt_gligen, common_instances)
|
50 |
+
|
51 |
+
return loaded_model_list, common_instances
|
52 |
+
|
53 |
+
|
54 |
+
class Instance:
|
55 |
+
def __init__(self, capacity = 2):
|
56 |
+
self.model_type = 'base'
|
57 |
+
self.loaded_model_list = {}
|
58 |
+
self.counter = Counter()
|
59 |
+
self.global_counter = Counter()
|
60 |
+
self.loaded_model_list['base'], self.common_instances = ckpt_load_helper(
|
61 |
+
'gligen-generation-text-box',
|
62 |
+
is_inpaint=False, is_style=False, common_instances=None
|
63 |
+
)
|
64 |
+
self.capacity = capacity
|
65 |
+
|
66 |
+
def _log(self, model_type, batch_size, instruction, phrase_list):
|
67 |
+
self.counter[model_type] += 1
|
68 |
+
self.global_counter[model_type] += 1
|
69 |
+
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
70 |
+
print('[{}] Current: {}, All: {}. Samples: {}, prompt: {}, phrases: {}'.format(
|
71 |
+
current_time, dict(self.counter), dict(self.global_counter), batch_size, instruction, phrase_list
|
72 |
+
))
|
73 |
+
|
74 |
+
def get_model(self, model_type, batch_size, instruction, phrase_list):
|
75 |
+
if model_type in self.loaded_model_list:
|
76 |
+
self._log(model_type, batch_size, instruction, phrase_list)
|
77 |
+
return self.loaded_model_list[model_type]
|
78 |
+
|
79 |
+
if self.capacity == len(self.loaded_model_list):
|
80 |
+
least_used_type = self.counter.most_common()[-1][0]
|
81 |
+
del self.loaded_model_list[least_used_type]
|
82 |
+
del self.counter[least_used_type]
|
83 |
+
gc.collect()
|
84 |
+
torch.cuda.empty_cache()
|
85 |
+
|
86 |
+
self.loaded_model_list[model_type] = self._get_model(model_type)
|
87 |
+
self._log(model_type, batch_size, instruction, phrase_list)
|
88 |
+
return self.loaded_model_list[model_type]
|
89 |
+
|
90 |
+
def _get_model(self, model_type):
|
91 |
+
if model_type == 'base':
|
92 |
+
return ckpt_load_helper(
|
93 |
+
'gligen-generation-text-box',
|
94 |
+
is_inpaint=False, is_style=False, common_instances=self.common_instances
|
95 |
+
)[0]
|
96 |
+
elif model_type == 'inpaint':
|
97 |
+
return ckpt_load_helper(
|
98 |
+
'gligen-inpainting-text-box',
|
99 |
+
is_inpaint=True, is_style=False, common_instances=self.common_instances
|
100 |
+
)[0]
|
101 |
+
elif model_type == 'style':
|
102 |
+
return ckpt_load_helper(
|
103 |
+
'gligen-generation-text-image-box',
|
104 |
+
is_inpaint=False, is_style=True, common_instances=self.common_instances
|
105 |
+
)[0]
|
106 |
+
|
107 |
+
assert False
|
108 |
+
|
109 |
+
instance = Instance()
|
110 |
+
|
111 |
+
|
112 |
+
def load_clip_model():
|
113 |
+
from transformers import CLIPProcessor, CLIPModel
|
114 |
+
version = "openai/clip-vit-large-patch14"
|
115 |
+
model = CLIPModel.from_pretrained(version).cuda()
|
116 |
+
processor = CLIPProcessor.from_pretrained(version)
|
117 |
+
|
118 |
+
return {
|
119 |
+
'version': version,
|
120 |
+
'model': model,
|
121 |
+
'processor': processor,
|
122 |
+
}
|
123 |
+
|
124 |
+
clip_model = load_clip_model()
|
125 |
+
|
126 |
+
|
127 |
+
class ImageMask(gr.components.Image):
|
128 |
+
"""
|
129 |
+
Sets: source="canvas", tool="sketch"
|
130 |
+
"""
|
131 |
+
|
132 |
+
is_template = True
|
133 |
+
|
134 |
+
def __init__(self, **kwargs):
|
135 |
+
super().__init__(source="upload", tool="sketch", interactive=True, **kwargs)
|
136 |
+
|
137 |
+
def preprocess(self, x):
|
138 |
+
if x is None:
|
139 |
+
return x
|
140 |
+
if self.tool == "sketch" and self.source in ["upload", "webcam"] and type(x) != dict:
|
141 |
+
|
142 |
+
decode_image = processing_utils.decode_base64_to_image(x)
|
143 |
+
width, height = decode_image.size
|
144 |
+
img = np.asarray(decode_image)
|
145 |
+
return {'image':img, 'mask':binarize_2(img)}
|
146 |
+
|
147 |
+
mask = np.zeros((height, width, 4), dtype=np.uint8)
|
148 |
+
|
149 |
+
mask[..., -1] = 255
|
150 |
+
mask = self.postprocess(mask)
|
151 |
+
x = {'image': x, 'mask': mask}
|
152 |
+
print('vao preprocess-------------------------')
|
153 |
+
hh = super().preprocess(x)
|
154 |
+
if (hh['image'].min()!=255) and (hh['mask'][:,:,:3].max()==0):
|
155 |
+
|
156 |
+
hh['mask'] = binarize_2(hh['image'])
|
157 |
+
|
158 |
+
return hh
|
159 |
+
|
160 |
+
|
161 |
+
class Blocks(gr.Blocks):
|
162 |
+
|
163 |
+
def __init__(
|
164 |
+
self,
|
165 |
+
theme: str = "default",
|
166 |
+
analytics_enabled: Optional[bool] = None,
|
167 |
+
mode: str = "blocks",
|
168 |
+
title: str = "Gradio",
|
169 |
+
css: Optional[str] = None,
|
170 |
+
**kwargs,
|
171 |
+
):
|
172 |
+
|
173 |
+
self.extra_configs = {
|
174 |
+
'thumbnail': kwargs.pop('thumbnail', ''),
|
175 |
+
'url': kwargs.pop('url', 'https://gradio.app/'),
|
176 |
+
'creator': kwargs.pop('creator', '@teamGradio'),
|
177 |
+
}
|
178 |
+
|
179 |
+
super(Blocks, self).__init__(theme, analytics_enabled, mode, title, css, **kwargs)
|
180 |
+
warnings.filterwarnings("ignore")
|
181 |
+
|
182 |
+
def get_config_file(self):
|
183 |
+
config = super(Blocks, self).get_config_file()
|
184 |
+
|
185 |
+
for k, v in self.extra_configs.items():
|
186 |
+
config[k] = v
|
187 |
+
|
188 |
+
return config
|
189 |
+
|
190 |
+
'''
|
191 |
+
inference model
|
192 |
+
'''
|
193 |
+
|
194 |
+
# @torch.no_grad()
|
195 |
+
def inference(task, language_instruction, phrase_list, location_list, inpainting_boxes_nodrop, image,
|
196 |
+
alpha_sample, guidance_scale, batch_size,
|
197 |
+
fix_seed, rand_seed, actual_mask, style_image,
|
198 |
+
*args, **kwargs):
|
199 |
+
# import pdb; pdb.set_trace()
|
200 |
+
|
201 |
+
# grounding_instruction = json.loads(grounding_instruction)
|
202 |
+
# phrase_list, location_list = [], []
|
203 |
+
# for k, v in grounding_instruction.items():
|
204 |
+
# phrase_list.append(k)
|
205 |
+
# location_list.append(v)
|
206 |
+
|
207 |
+
placeholder_image = Image.open('images/teddy.jpg').convert("RGB")
|
208 |
+
image_list = [placeholder_image] * len(phrase_list) # placeholder input for visual prompt, which is disabled
|
209 |
+
|
210 |
+
batch_size = int(batch_size)
|
211 |
+
if not 1 <= batch_size <= 4:
|
212 |
+
batch_size = 1
|
213 |
+
|
214 |
+
if style_image == None:
|
215 |
+
has_text_mask = 1
|
216 |
+
has_image_mask = 0 # then we hack above 'image_list'
|
217 |
+
else:
|
218 |
+
valid_phrase_len = len(phrase_list)
|
219 |
+
|
220 |
+
phrase_list += ['placeholder']
|
221 |
+
has_text_mask = [1]*valid_phrase_len + [0]
|
222 |
+
|
223 |
+
image_list = [placeholder_image]*valid_phrase_len + [style_image]
|
224 |
+
has_image_mask = [0]*valid_phrase_len + [1]
|
225 |
+
|
226 |
+
location_list += [ [0.0, 0.0, 1, 0.01] ] # style image grounding location
|
227 |
+
|
228 |
+
instruction = dict(
|
229 |
+
prompt = language_instruction,
|
230 |
+
phrases = phrase_list,
|
231 |
+
images = image_list,
|
232 |
+
locations = location_list,
|
233 |
+
alpha_type = [alpha_sample, 0, 1.0 - alpha_sample],
|
234 |
+
has_text_mask = has_text_mask,
|
235 |
+
has_image_mask = has_image_mask,
|
236 |
+
save_folder_name = language_instruction,
|
237 |
+
guidance_scale = guidance_scale,
|
238 |
+
batch_size = batch_size,
|
239 |
+
fix_seed = bool(fix_seed),
|
240 |
+
rand_seed = int(rand_seed),
|
241 |
+
actual_mask = actual_mask,
|
242 |
+
inpainting_boxes_nodrop = inpainting_boxes_nodrop,
|
243 |
+
)
|
244 |
+
|
245 |
+
get_model = partial(instance.get_model,
|
246 |
+
batch_size=batch_size,
|
247 |
+
instruction=language_instruction,
|
248 |
+
phrase_list=phrase_list)
|
249 |
+
|
250 |
+
with torch.autocast(device_type='cuda', dtype=torch.float16):
|
251 |
+
if task == 'User provide boxes' or 'Available boxes':
|
252 |
+
if style_image == None:
|
253 |
+
result = grounded_generation_box(get_model('base'), instruction, *args, **kwargs)
|
254 |
+
torch.cuda.empty_cache()
|
255 |
+
return result
|
256 |
+
else:
|
257 |
+
return grounded_generation_box(get_model('style'), instruction, *args, **kwargs)
|
258 |
+
|
259 |
+
|
260 |
+
def draw_box(boxes=[], texts=[], img=None):
|
261 |
+
if len(boxes) == 0 and img is None:
|
262 |
+
return None
|
263 |
+
|
264 |
+
if img is None:
|
265 |
+
img = Image.new('RGB', (512, 512), (255, 255, 255))
|
266 |
+
colors = ["red", "olive", "blue", "green", "orange", "brown", "cyan", "purple"]
|
267 |
+
draw = ImageDraw.Draw(img)
|
268 |
+
font = ImageFont.truetype("DejaVuSansMono.ttf", size=18)
|
269 |
+
for bid, box in enumerate(boxes):
|
270 |
+
draw.rectangle([box[0], box[1], box[2], box[3]], outline=colors[bid % len(colors)], width=4)
|
271 |
+
anno_text = texts[bid]
|
272 |
+
draw.rectangle([box[0], box[3] - int(font.size * 1.2), box[0] + int((len(anno_text) + 0.8) * font.size * 0.6), box[3]], outline=colors[bid % len(colors)], fill=colors[bid % len(colors)], width=4)
|
273 |
+
draw.text([box[0] + int(font.size * 0.2), box[3] - int(font.size*1.2)], anno_text, font=font, fill=(255,255,255))
|
274 |
+
return img
|
275 |
+
|
276 |
+
def get_concat(ims):
|
277 |
+
if len(ims) == 1:
|
278 |
+
n_col = 1
|
279 |
+
else:
|
280 |
+
n_col = 2
|
281 |
+
n_row = math.ceil(len(ims) / 2)
|
282 |
+
dst = Image.new('RGB', (ims[0].width * n_col, ims[0].height * n_row), color="white")
|
283 |
+
for i, im in enumerate(ims):
|
284 |
+
row_id = i // n_col
|
285 |
+
col_id = i % n_col
|
286 |
+
dst.paste(im, (im.width * col_id, im.height * row_id))
|
287 |
+
return dst
|
288 |
+
|
289 |
+
|
290 |
+
def auto_append_grounding(language_instruction, grounding_texts):
|
291 |
+
for grounding_text in grounding_texts:
|
292 |
+
if grounding_text.lower() not in language_instruction.lower() and grounding_text != 'auto':
|
293 |
+
language_instruction += "; " + grounding_text
|
294 |
+
return language_instruction
|
295 |
+
|
296 |
+
|
297 |
+
|
298 |
+
|
299 |
+
def generate(task, language_instruction, grounding_texts, sketch_pad,
|
300 |
+
alpha_sample, guidance_scale, batch_size,
|
301 |
+
fix_seed, rand_seed, use_actual_mask, append_grounding, style_cond_image,
|
302 |
+
state):
|
303 |
+
|
304 |
+
if 'boxes' not in state:
|
305 |
+
state['boxes'] = []
|
306 |
+
|
307 |
+
boxes = state['boxes']
|
308 |
+
grounding_texts = [x.strip() for x in grounding_texts.split(';')]
|
309 |
+
# assert len(boxes) == len(grounding_texts)
|
310 |
+
if len(boxes) != len(grounding_texts):
|
311 |
+
if len(boxes) < len(grounding_texts):
|
312 |
+
raise ValueError("""The number of boxes should be equal to the number of grounding objects.
|
313 |
+
Number of boxes drawn: {}, number of grounding tokens: {}.
|
314 |
+
Please draw boxes accordingly on the sketch pad.""".format(len(boxes), len(grounding_texts)))
|
315 |
+
grounding_texts = grounding_texts + [""] * (len(boxes) - len(grounding_texts))
|
316 |
+
|
317 |
+
boxes = (np.asarray(boxes) / 512).tolist()
|
318 |
+
grounding_instruction = json.dumps({obj: box for obj,box in zip(grounding_texts, boxes)})
|
319 |
+
image = None
|
320 |
+
actual_mask = None
|
321 |
+
|
322 |
+
|
323 |
+
if append_grounding:
|
324 |
+
language_instruction = auto_append_grounding(language_instruction, grounding_texts)
|
325 |
+
|
326 |
+
gen_images, gen_overlays = inference(
|
327 |
+
task, language_instruction, grounding_texts,boxes, boxes, image,
|
328 |
+
alpha_sample, guidance_scale, batch_size,
|
329 |
+
fix_seed, rand_seed, actual_mask, style_cond_image, clip_model=clip_model,
|
330 |
+
)
|
331 |
+
blank_samples = batch_size % 2 if batch_size > 1 else 0
|
332 |
+
gen_images = [gr.Image.update(value=x, visible=True) for i,x in enumerate(gen_images)] \
|
333 |
+
+ [gr.Image.update(value=None, visible=True) for _ in range(blank_samples)] \
|
334 |
+
+ [gr.Image.update(value=None, visible=False) for _ in range(4 - batch_size - blank_samples)]
|
335 |
+
|
336 |
+
return gen_images + [state]
|
337 |
+
|
338 |
+
|
339 |
+
def binarize(x):
|
340 |
+
return (x != 0).astype('uint8') * 255
|
341 |
+
def binarize_2(x):
|
342 |
+
gray_image = cv2.cvtColor(x, cv2.COLOR_BGR2GRAY)
|
343 |
+
return (gray_image!=255).astype('uint8') * 255
|
344 |
+
|
345 |
+
def sized_center_crop(img, cropx, cropy):
|
346 |
+
y, x = img.shape[:2]
|
347 |
+
startx = x // 2 - (cropx // 2)
|
348 |
+
starty = y // 2 - (cropy // 2)
|
349 |
+
return img[starty:starty+cropy, startx:startx+cropx]
|
350 |
+
|
351 |
+
def sized_center_fill(img, fill, cropx, cropy):
|
352 |
+
y, x = img.shape[:2]
|
353 |
+
startx = x // 2 - (cropx // 2)
|
354 |
+
starty = y // 2 - (cropy // 2)
|
355 |
+
img[starty:starty+cropy, startx:startx+cropx] = fill
|
356 |
+
return img
|
357 |
+
|
358 |
+
def sized_center_mask(img, cropx, cropy):
|
359 |
+
y, x = img.shape[:2]
|
360 |
+
startx = x // 2 - (cropx // 2)
|
361 |
+
starty = y // 2 - (cropy // 2)
|
362 |
+
center_region = img[starty:starty+cropy, startx:startx+cropx].copy()
|
363 |
+
img = (img * 0.2).astype('uint8')
|
364 |
+
img[starty:starty+cropy, startx:startx+cropx] = center_region
|
365 |
+
return img
|
366 |
+
|
367 |
+
def center_crop(img, HW=None, tgt_size=(512, 512)):
|
368 |
+
if HW is None:
|
369 |
+
H, W = img.shape[:2]
|
370 |
+
HW = min(H, W)
|
371 |
+
img = sized_center_crop(img, HW, HW)
|
372 |
+
img = Image.fromarray(img)
|
373 |
+
img = img.resize(tgt_size)
|
374 |
+
return np.array(img)
|
375 |
+
|
376 |
+
def draw(task, input, grounding_texts, new_image_trigger, state, generate_parsed, box_image):
|
377 |
+
print('input', generate_parsed)
|
378 |
+
|
379 |
+
if type(input) == dict:
|
380 |
+
image = input['image']
|
381 |
+
mask = input['mask']
|
382 |
+
if generate_parsed==1:
|
383 |
+
generate_parsed = 0
|
384 |
+
# import pdb; pdb.set_trace()
|
385 |
+
print('do nothing')
|
386 |
+
|
387 |
+
return [box_image, new_image_trigger, 1., state, generate_parsed]
|
388 |
+
|
389 |
+
else:
|
390 |
+
mask = input
|
391 |
+
|
392 |
+
if mask.ndim == 3:
|
393 |
+
mask = mask[..., 0]
|
394 |
+
|
395 |
+
image_scale = 1.0
|
396 |
+
|
397 |
+
print('vao draw--------------------')
|
398 |
+
mask = binarize(mask)
|
399 |
+
if mask.shape != (512, 512):
|
400 |
+
# assert False, "should not receive any non- 512x512 masks."
|
401 |
+
if 'original_image' in state and state['original_image'].shape[:2] == mask.shape:
|
402 |
+
mask = center_crop(mask, state['inpaint_hw'])
|
403 |
+
image = center_crop(state['original_image'], state['inpaint_hw'])
|
404 |
+
else:
|
405 |
+
mask = np.zeros((512, 512), dtype=np.uint8)
|
406 |
+
mask = binarize(mask)
|
407 |
+
|
408 |
+
if type(mask) != np.ndarray:
|
409 |
+
mask = np.array(mask)
|
410 |
+
#
|
411 |
+
if mask.sum() == 0:
|
412 |
+
state = {}
|
413 |
+
print('delete state')
|
414 |
+
|
415 |
+
if True:
|
416 |
+
image = None
|
417 |
+
else:
|
418 |
+
image = Image.fromarray(image)
|
419 |
+
|
420 |
+
if 'boxes' not in state:
|
421 |
+
state['boxes'] = []
|
422 |
+
|
423 |
+
if 'masks' not in state or len(state['masks']) == 0 :
|
424 |
+
state['masks'] = []
|
425 |
+
last_mask = np.zeros_like(mask)
|
426 |
+
else:
|
427 |
+
last_mask = state['masks'][-1]
|
428 |
+
|
429 |
+
if type(mask) == np.ndarray and mask.size > 1 :
|
430 |
+
diff_mask = mask - last_mask
|
431 |
+
else:
|
432 |
+
diff_mask = np.zeros([])
|
433 |
+
|
434 |
+
if diff_mask.sum() > 0:
|
435 |
+
x1x2 = np.where(diff_mask.max(0) > 1)[0]
|
436 |
+
y1y2 = np.where(diff_mask.max(1) > 1)[0]
|
437 |
+
y1, y2 = y1y2.min(), y1y2.max()
|
438 |
+
x1, x2 = x1x2.min(), x1x2.max()
|
439 |
+
|
440 |
+
if (x2 - x1 > 5) and (y2 - y1 > 5):
|
441 |
+
state['masks'].append(mask.copy())
|
442 |
+
state['boxes'].append((x1, y1, x2, y2))
|
443 |
+
|
444 |
+
grounding_texts = [x.strip() for x in grounding_texts.split(';')]
|
445 |
+
grounding_texts = [x for x in grounding_texts if len(x) > 0]
|
446 |
+
if len(grounding_texts) < len(state['boxes']):
|
447 |
+
grounding_texts += [f'Obj. {bid+1}' for bid in range(len(grounding_texts), len(state['boxes']))]
|
448 |
+
|
449 |
+
box_image = draw_box(state['boxes'], grounding_texts, image)
|
450 |
+
generate_parsed = 0
|
451 |
+
|
452 |
+
return [box_image, new_image_trigger, image_scale, state, generate_parsed]
|
453 |
+
|
454 |
+
def change_state(bboxes,layout, state, instruction, trigger_stage, boxes):
|
455 |
+
if trigger_stage ==0 :
|
456 |
+
return [boxes, state, 0]
|
457 |
+
# mask =
|
458 |
+
state['boxes'] = []
|
459 |
+
state['masks'] = []
|
460 |
+
image = None
|
461 |
+
list_boxes = bboxes.split('/')
|
462 |
+
result =[]
|
463 |
+
for b in list_boxes:
|
464 |
+
ints = b[1:-1].split(',')
|
465 |
+
l = []
|
466 |
+
for i in ints:
|
467 |
+
l.append(int(i))
|
468 |
+
result.append(l)
|
469 |
+
print('run change state')
|
470 |
+
|
471 |
+
for box in result:
|
472 |
+
state['boxes'].append(box)
|
473 |
+
grounding_texts = [x.strip() for x in instruction.split(';')]
|
474 |
+
grounding_texts = [x for x in grounding_texts if len(x) > 0]
|
475 |
+
if len(grounding_texts) < len(result):
|
476 |
+
grounding_texts += [f'Obj. {bid+1}' for bid in range(len(grounding_texts), len(result))]
|
477 |
+
|
478 |
+
box_image = draw_box(result, grounding_texts)
|
479 |
+
|
480 |
+
mask = binarize_2(layout['image'])
|
481 |
+
state['masks'].append(mask.copy())
|
482 |
+
# print('done change state', state)
|
483 |
+
print('done change state')
|
484 |
+
# import pdb; pdb.set_trace()
|
485 |
+
return [box_image,state, trigger_stage]
|
486 |
+
|
487 |
+
def example_click(name, grounding_instruction, instruction, bboxes,generate_parsed, trigger_parsed):
|
488 |
+
|
489 |
+
list_boxes = bboxes.split('/')
|
490 |
+
result =[]
|
491 |
+
|
492 |
+
for b in list_boxes:
|
493 |
+
ints = b[1:-1].split(',')
|
494 |
+
l = []
|
495 |
+
for i in ints:
|
496 |
+
l.append(int(i))
|
497 |
+
result.append(l)
|
498 |
+
print('run change state')
|
499 |
+
|
500 |
+
box_image = draw_box(result, instruction)
|
501 |
+
trigger_parsed += 1
|
502 |
+
print('done the example click')
|
503 |
+
return [box_image, trigger_parsed]
|
504 |
+
|
505 |
+
def clear(task, sketch_pad_trigger, batch_size, state,trigger_stage, switch_task=False):
|
506 |
+
|
507 |
+
sketch_pad_trigger = sketch_pad_trigger + 1
|
508 |
+
trigger_stage = 0
|
509 |
+
blank_samples = batch_size % 2 if batch_size > 1 else 0
|
510 |
+
out_images = [gr.Image.update(value=None, visible=True) for i in range(batch_size)] \
|
511 |
+
+ [gr.Image.update(value=None, visible=True) for _ in range(blank_samples)] \
|
512 |
+
+ [gr.Image.update(value=None, visible=False) for _ in range(4 - batch_size - blank_samples)]
|
513 |
+
state = {}
|
514 |
+
return [None, sketch_pad_trigger, None, 1.0] + out_images + [state] + [trigger_stage]
|
515 |
+
|
516 |
+
css = """
|
517 |
+
#img2img_image, #img2img_image > .fixed-height, #img2img_image > .fixed-height > div, #img2img_image > .fixed-height > div > img
|
518 |
+
{
|
519 |
+
height: var(--height) !important;
|
520 |
+
max-height: var(--height) !important;
|
521 |
+
min-height: var(--height) !important;
|
522 |
+
}
|
523 |
+
#paper-info a {
|
524 |
+
color:#008AD7;
|
525 |
+
text-decoration: none;
|
526 |
+
}
|
527 |
+
#paper-info a:hover {
|
528 |
+
cursor: pointer;
|
529 |
+
text-decoration: none;
|
530 |
+
}
|
531 |
+
#my_image > div.fixed-height
|
532 |
+
{
|
533 |
+
height: var(--height) !important;
|
534 |
+
}
|
535 |
+
"""
|
536 |
+
|
537 |
+
rescale_js = """
|
538 |
+
function(x) {
|
539 |
+
const root = document.querySelector('gradio-app').shadowRoot || document.querySelector('gradio-app');
|
540 |
+
let image_scale = parseFloat(root.querySelector('#image_scale input').value) || 1.0;
|
541 |
+
const image_width = root.querySelector('#img2img_image').clientWidth;
|
542 |
+
const target_height = parseInt(image_width * image_scale);
|
543 |
+
document.body.style.setProperty('--height', `${target_height}px`);
|
544 |
+
root.querySelectorAll('button.justify-center.rounded')[0].style.display='none';
|
545 |
+
root.querySelectorAll('button.justify-center.rounded')[1].style.display='none';
|
546 |
+
return x;
|
547 |
+
}
|
548 |
+
"""
|
549 |
+
# [<a href="https://arxiv.org/abs/2301.07093" target="_blank">Paper</a>]
|
550 |
+
with Blocks(
|
551 |
+
css=css,
|
552 |
+
analytics_enabled=False,
|
553 |
+
title="Attention-refocusing demo",
|
554 |
+
) as main:
|
555 |
+
description = """<p style="text-align: center; font-weight: bold;">
|
556 |
+
<span style="font-size: 28px">Grounded Text-to-Image Synthesis with Attention Refocusing</span>
|
557 |
+
<br>
|
558 |
+
<span style="font-size: 18px" id="paper-info">
|
559 |
+
[<a href="https://attention-refocusing.github.io/" target="_blank">Project Page</a>]
|
560 |
+
|
561 |
+
[<a href="https://github.com/Attention-Refocusing/attention-refocusing" target="_blank">GitHub</a>]
|
562 |
+
</span>
|
563 |
+
</p>
|
564 |
+
<p>
|
565 |
+
To identify the areas of interest based on specific spatial parameters, you need to (1) ⌨️ input the names of the concepts you're interested in <em> Grounding Instruction</em>, and (2) 🖱️ draw their corresponding bounding boxes using <em> Sketch Pad</em> -- the parsed boxes will automatically be showed up once you've drawn them.
|
566 |
+
<br>
|
567 |
+
For faster inference without waiting in queue, you may duplicate the space and upgrade to GPU in settings. <a href="https://huggingface.co/spaces/gligen/demo?duplicate=true"><img style="display: inline; margin-top: 0em; margin-bottom: 0em" src="https://bit.ly/3gLdBN6" alt="Duplicate Space" /></a>
|
568 |
+
</p>
|
569 |
+
"""
|
570 |
+
gr.HTML(description)
|
571 |
+
|
572 |
+
with gr.Row():
|
573 |
+
with gr.Column(scale=4):
|
574 |
+
sketch_pad_trigger = gr.Number(value=0, visible=False)
|
575 |
+
sketch_pad_resize_trigger = gr.Number(value=0, visible=False)
|
576 |
+
trigger_stage = gr.Number(value=0, visible=False)
|
577 |
+
|
578 |
+
init_white_trigger = gr.Number(value=0, visible=False)
|
579 |
+
image_scale = gr.Number(value=1.0, elem_id="image_scale", visible=False)
|
580 |
+
new_image_trigger = gr.Number(value=0, visible=False)
|
581 |
+
text_box = gr.Textbox(visible=False)
|
582 |
+
generate_parsed = gr.Number(value=0, visible=False)
|
583 |
+
|
584 |
+
task = gr.Radio(
|
585 |
+
choices=["Available boxes", 'User provide boxes'],
|
586 |
+
type="value",
|
587 |
+
value="User provide boxes",
|
588 |
+
label="Task",
|
589 |
+
visible=False
|
590 |
+
|
591 |
+
)
|
592 |
+
language_instruction = gr.Textbox(
|
593 |
+
label="Language instruction",
|
594 |
+
)
|
595 |
+
grounding_instruction = gr.Textbox(
|
596 |
+
label="Grounding instruction (Separated by semicolon)",
|
597 |
+
)
|
598 |
+
with gr.Row():
|
599 |
+
sketch_pad = ImageMask(label="Sketch Pad", elem_id="img2img_image")
|
600 |
+
out_imagebox = gr.Image(type="pil",elem_id="my_image" ,label="Parsed Sketch Pad", shape=(512,512))
|
601 |
+
with gr.Row():
|
602 |
+
clear_btn = gr.Button(value='Clear')
|
603 |
+
gen_btn = gr.Button(value='Generate')
|
604 |
+
with gr.Row():
|
605 |
+
parsed_btn = gr.Button(value='generate parsed boxes', visible=False)
|
606 |
+
|
607 |
+
with gr.Accordion("Advanced Options", open=False):
|
608 |
+
with gr.Column():
|
609 |
+
alpha_sample = gr.Slider(minimum=0, maximum=1.0, step=0.1, value=0.3, label="Scheduled Sampling (τ)")
|
610 |
+
guidance_scale = gr.Slider(minimum=0, maximum=50, step=0.5, value=7.5, label="Guidance Scale")
|
611 |
+
batch_size = gr.Slider(minimum=1, maximum=4,visible=False, step=1, value=1, label="Number of Samples")
|
612 |
+
append_grounding = gr.Checkbox(value=True, label="Append grounding instructions to the caption")
|
613 |
+
use_actual_mask = gr.Checkbox(value=False, label="Use actual mask for inpainting", visible=False)
|
614 |
+
with gr.Row():
|
615 |
+
fix_seed = gr.Checkbox(value=True, label="Fixed seed")
|
616 |
+
rand_seed = gr.Slider(minimum=0, maximum=1000, step=1, value=0, label="Seed")
|
617 |
+
|
618 |
+
with gr.Row():
|
619 |
+
use_style_cond = gr.Checkbox(value=False,visible=False, label="Enable Style Condition")
|
620 |
+
style_cond_image = gr.Image(type="pil",visible=False, label="Style Condition", interactive=True)
|
621 |
+
with gr.Column(scale=4):
|
622 |
+
gr.HTML('<span style="font-size: 20px; font-weight: bold">Generated Images</span>')
|
623 |
+
with gr.Row():
|
624 |
+
out_gen_1 = gr.Image(type="pil", visible=True, show_label=False)
|
625 |
+
out_gen_2 = gr.Image(type="pil", visible=False, show_label=False)
|
626 |
+
with gr.Row():
|
627 |
+
out_gen_3 = gr.Image(type="pil", visible=False, show_label=False)
|
628 |
+
out_gen_4 = gr.Image(type="pil", visible=False, show_label=False)
|
629 |
+
|
630 |
+
state = gr.State({})
|
631 |
+
|
632 |
+
|
633 |
+
class Controller:
|
634 |
+
def __init__(self):
|
635 |
+
self.calls = 0
|
636 |
+
self.tracks = 0
|
637 |
+
self.resizes = 0
|
638 |
+
self.scales = 0
|
639 |
+
|
640 |
+
def init_white(self, init_white_trigger):
|
641 |
+
self.calls += 1
|
642 |
+
return np.ones((512, 512), dtype='uint8') * 255, 1.0, init_white_trigger+1
|
643 |
+
|
644 |
+
def change_n_samples(self, n_samples):
|
645 |
+
blank_samples = n_samples % 2 if n_samples > 1 else 0
|
646 |
+
return [gr.Image.update(visible=True) for _ in range(n_samples + blank_samples)] \
|
647 |
+
+ [gr.Image.update(visible=False) for _ in range(4 - n_samples - blank_samples)]
|
648 |
+
|
649 |
+
controller = Controller()
|
650 |
+
main.load(
|
651 |
+
lambda x:x+1,
|
652 |
+
inputs=sketch_pad_trigger,
|
653 |
+
outputs=sketch_pad_trigger,
|
654 |
+
queue=False)
|
655 |
+
|
656 |
+
sketch_pad.edit(
|
657 |
+
draw,
|
658 |
+
inputs=[task, sketch_pad, grounding_instruction, sketch_pad_resize_trigger, state, generate_parsed, out_imagebox],
|
659 |
+
outputs=[out_imagebox, sketch_pad_resize_trigger, image_scale, state, generate_parsed],
|
660 |
+
queue=False,
|
661 |
+
)
|
662 |
+
trigger_stage.change(
|
663 |
+
change_state,
|
664 |
+
inputs=[text_box,sketch_pad, state, grounding_instruction, trigger_stage,out_imagebox],
|
665 |
+
outputs=[out_imagebox,state,trigger_stage],
|
666 |
+
queue=True
|
667 |
+
)
|
668 |
+
grounding_instruction.change(
|
669 |
+
draw,
|
670 |
+
inputs=[task, sketch_pad, grounding_instruction, sketch_pad_resize_trigger, state, generate_parsed,out_imagebox],
|
671 |
+
outputs=[out_imagebox, sketch_pad_resize_trigger, image_scale, state, generate_parsed],
|
672 |
+
queue=False,
|
673 |
+
)
|
674 |
+
clear_btn.click(
|
675 |
+
clear,
|
676 |
+
inputs=[task, sketch_pad_trigger, batch_size,trigger_stage, state],
|
677 |
+
outputs=[sketch_pad, sketch_pad_trigger, out_imagebox, image_scale, out_gen_1, out_gen_2, out_gen_3, out_gen_4, state, trigger_stage],
|
678 |
+
queue=False)
|
679 |
+
|
680 |
+
sketch_pad_trigger.change(
|
681 |
+
controller.init_white,
|
682 |
+
inputs=[init_white_trigger],
|
683 |
+
outputs=[sketch_pad, image_scale, init_white_trigger],
|
684 |
+
queue=False)
|
685 |
+
|
686 |
+
gen_btn.click(
|
687 |
+
generate,
|
688 |
+
inputs=[
|
689 |
+
task, language_instruction, grounding_instruction, sketch_pad,
|
690 |
+
alpha_sample, guidance_scale, batch_size,
|
691 |
+
fix_seed, rand_seed,
|
692 |
+
use_actual_mask,
|
693 |
+
append_grounding, style_cond_image,
|
694 |
+
state,
|
695 |
+
],
|
696 |
+
outputs=[out_gen_1, out_gen_2, out_gen_3, out_gen_4, state],
|
697 |
+
queue=True
|
698 |
+
)
|
699 |
+
init_white_trigger.change(
|
700 |
+
None,
|
701 |
+
None,
|
702 |
+
init_white_trigger,
|
703 |
+
_js=rescale_js,
|
704 |
+
queue=False)
|
705 |
+
examples = [
|
706 |
+
[
|
707 |
+
'guide_imgs/0_a_cat_on_the_right_of_a_dog.jpg',
|
708 |
+
"a cat;a dog",
|
709 |
+
"a cat on the right of a dog",
|
710 |
+
'(291, 88, 481, 301)/(25, 64, 260, 391)',
|
711 |
+
1, 1
|
712 |
+
],
|
713 |
+
[
|
714 |
+
'guide_imgs/0_a_bus_on_the_left_of_a_car.jpg',#'guide_imgs/0_a_bus_on_the_left_of_a_car.jpg',
|
715 |
+
"a bus;a car",
|
716 |
+
"a bus and a car",
|
717 |
+
'(8,128,266,384)/(300,196,502,316)', #'(8,128,266,384)', #/(300,196,502,316)
|
718 |
+
1, 2
|
719 |
+
],
|
720 |
+
[
|
721 |
+
'guide_imgs/1_Two_cars_on_the_street..jpg',
|
722 |
+
"a car;a car",
|
723 |
+
"Two cars on the street.",
|
724 |
+
'(34, 98, 247, 264)/(271, 122, 481, 293)',
|
725 |
+
1, 3
|
726 |
+
],
|
727 |
+
[
|
728 |
+
'guide_imgs/80_two_apples_lay_side_by_side_on_a_wooden_table,_their_glossy_red_and_green_skins_glinting_in_the_sunlight..jpg',
|
729 |
+
"an apple;an apple",
|
730 |
+
"two apples lay side by side on a wooden table, their glossy red and green skins glinting in the sunlight.",
|
731 |
+
'(40, 210, 235, 450)/(275, 210, 470, 450)',
|
732 |
+
1, 4
|
733 |
+
],
|
734 |
+
[
|
735 |
+
'guide_imgs/10_A_banana_on_the_left_of_an_apple..jpg',
|
736 |
+
"a banana;an apple",
|
737 |
+
"A banana on the left of an apple.",
|
738 |
+
'(62, 193, 225, 354)/(300, 184, 432, 329)',
|
739 |
+
1, 5
|
740 |
+
],
|
741 |
+
[
|
742 |
+
'guide_imgs/15_A_pizza_on_the_right_of_a_suitcase..jpg',
|
743 |
+
"a pizza ;a suitcase",
|
744 |
+
"A pizza on the right of a suitcase.",
|
745 |
+
'(307, 112, 490, 280)/(41, 120, 244, 270)',
|
746 |
+
1, 6
|
747 |
+
],
|
748 |
+
[
|
749 |
+
'guide_imgs/1_A_wine_glass_on_top_of_a_dog..jpg',
|
750 |
+
"a wine glass;a dog",
|
751 |
+
"A wine glass on top of a dog.",
|
752 |
+
'(206, 78, 306, 214)/(137, 222, 367, 432)',
|
753 |
+
1, 7
|
754 |
+
]
|
755 |
+
,
|
756 |
+
[
|
757 |
+
'guide_imgs/2_A_bicycle_on_top_of_a_boat..jpg',
|
758 |
+
"a bicycle;a boat",
|
759 |
+
"A bicycle on top of a boat.",
|
760 |
+
'(185, 110, 335, 205)/(111, 228, 401, 373)',
|
761 |
+
1, 8
|
762 |
+
]
|
763 |
+
,
|
764 |
+
[
|
765 |
+
'guide_imgs/4_A_laptop_on_top_of_a_teddy_bear..jpg',
|
766 |
+
"a laptop;a teddy bear",
|
767 |
+
"A laptop on top of a teddy bear.",
|
768 |
+
'(180, 70, 332, 210)/(150, 240, 362, 420)',
|
769 |
+
1, 9
|
770 |
+
]
|
771 |
+
,
|
772 |
+
[
|
773 |
+
'guide_imgs/0_A_train_on_top_of_a_surfboard..jpg',
|
774 |
+
"a train;a surfboard",
|
775 |
+
"A train on top of a surfboard.",
|
776 |
+
'(130, 80, 385, 240)/(75, 260, 440, 450)',
|
777 |
+
1, 10
|
778 |
+
]
|
779 |
+
]
|
780 |
+
|
781 |
+
with gr.Column():
|
782 |
+
|
783 |
+
create_examples(
|
784 |
+
examples=examples,
|
785 |
+
inputs=[sketch_pad, grounding_instruction,language_instruction , text_box, generate_parsed, trigger_stage],
|
786 |
+
outputs=None,
|
787 |
+
fn=None,
|
788 |
+
cache_examples=False,
|
789 |
+
|
790 |
+
)
|
791 |
+
|
792 |
+
main.queue(concurrency_count=1, api_open=False)
|
793 |
+
main.launch(share=False, show_api=False, show_error=True, debug=False, server_name="0.0.0.0")
|
dataset/__init__.py
ADDED
File without changes
|
dataset/__pycache__/__init__.cpython-38.pyc
ADDED
Binary file (139 Bytes). View file
|
|
dataset/__pycache__/catalog.cpython-38.pyc
ADDED
Binary file (1.11 kB). View file
|
|
dataset/__pycache__/concat_dataset.cpython-38.pyc
ADDED
Binary file (1.88 kB). View file
|
|
dataset/base_dataset.py
ADDED
@@ -0,0 +1,220 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from PIL import Image, ImageDraw
|
3 |
+
import torchvision.transforms as transforms
|
4 |
+
import torchvision
|
5 |
+
from zipfile import ZipFile
|
6 |
+
import os
|
7 |
+
import multiprocessing
|
8 |
+
import math
|
9 |
+
import numpy as np
|
10 |
+
import random
|
11 |
+
from io import BytesIO
|
12 |
+
|
13 |
+
VALID_IMAGE_TYPES = ['.jpg', '.jpeg', '.tiff', '.bmp', '.png']
|
14 |
+
|
15 |
+
|
16 |
+
def check_filenames_in_zipdata(filenames, ziproot):
|
17 |
+
samples = []
|
18 |
+
for fst in ZipFile(ziproot).infolist():
|
19 |
+
fname = fst.filename
|
20 |
+
if fname.endswith('/') or fname.startswith('.') or fst.file_size == 0:
|
21 |
+
continue
|
22 |
+
if os.path.splitext(fname)[1].lower() in VALID_IMAGE_TYPES:
|
23 |
+
samples.append((fname))
|
24 |
+
filenames = set(filenames)
|
25 |
+
samples = set(samples)
|
26 |
+
assert filenames.issubset(samples), 'Something wrong with your zip data'
|
27 |
+
|
28 |
+
|
29 |
+
|
30 |
+
def draw_box(img, boxes):
|
31 |
+
colors = ["red", "olive", "blue", "green", "orange", "brown", "cyan", "purple"]
|
32 |
+
draw = ImageDraw.Draw(img)
|
33 |
+
for bid, box in enumerate(boxes):
|
34 |
+
draw.rectangle([box[0], box[1], box[2], box[3]], outline =colors[bid % len(colors)], width=4)
|
35 |
+
# draw.rectangle([box[0], box[1], box[2], box[3]], outline ="red", width=2) # x0 y0 x1 y1
|
36 |
+
return img
|
37 |
+
|
38 |
+
|
39 |
+
|
40 |
+
def to_valid(x0, y0, x1, y1, image_size, min_box_size):
|
41 |
+
valid = True
|
42 |
+
|
43 |
+
if x0>image_size or y0>image_size or x1<0 or y1<0:
|
44 |
+
valid = False # no way to make this box vide, it is completely cropped out
|
45 |
+
return valid, (None, None, None, None)
|
46 |
+
|
47 |
+
x0 = max(x0, 0)
|
48 |
+
y0 = max(y0, 0)
|
49 |
+
x1 = min(x1, image_size)
|
50 |
+
y1 = min(y1, image_size)
|
51 |
+
|
52 |
+
if (x1-x0)*(y1-y0) / (image_size*image_size) < min_box_size:
|
53 |
+
valid = False
|
54 |
+
return valid, (None, None, None, None)
|
55 |
+
|
56 |
+
return valid, (x0, y0, x1, y1)
|
57 |
+
|
58 |
+
|
59 |
+
|
60 |
+
|
61 |
+
|
62 |
+
def recalculate_box_and_verify_if_valid(x, y, w, h, trans_info, image_size, min_box_size):
|
63 |
+
"""
|
64 |
+
x,y,w,h: the original annotation corresponding to the raw image size.
|
65 |
+
trans_info: what resizing and cropping have been applied to the raw image
|
66 |
+
image_size: what is the final image size
|
67 |
+
"""
|
68 |
+
|
69 |
+
x0 = x * trans_info["performed_scale"] - trans_info['crop_x']
|
70 |
+
y0 = y * trans_info["performed_scale"] - trans_info['crop_y']
|
71 |
+
x1 = (x + w) * trans_info["performed_scale"] - trans_info['crop_x']
|
72 |
+
y1 = (y + h) * trans_info["performed_scale"] - trans_info['crop_y']
|
73 |
+
|
74 |
+
|
75 |
+
# at this point, box annotation has been recalculated based on scaling and cropping
|
76 |
+
# but some point may fall off the image_size region (e.g., negative value), thus we
|
77 |
+
# need to clamp them into 0-image_size. But if all points falling outsize of image
|
78 |
+
# region, then we will consider this is an invalid box.
|
79 |
+
valid, (x0, y0, x1, y1) = to_valid(x0, y0, x1, y1, image_size, min_box_size)
|
80 |
+
|
81 |
+
if valid:
|
82 |
+
# we also perform random flip.
|
83 |
+
# Here boxes are valid, and are based on image_size
|
84 |
+
if trans_info["performed_flip"]:
|
85 |
+
x0, x1 = image_size-x1, image_size-x0
|
86 |
+
|
87 |
+
return valid, (x0, y0, x1, y1)
|
88 |
+
|
89 |
+
|
90 |
+
|
91 |
+
class BaseDataset(torch.utils.data.Dataset):
|
92 |
+
def __init__(self, image_root, random_crop, random_flip, image_size):
|
93 |
+
super().__init__()
|
94 |
+
self.image_root = image_root
|
95 |
+
self.random_crop = random_crop
|
96 |
+
self.random_flip = random_flip
|
97 |
+
self.image_size = image_size
|
98 |
+
self.use_zip = False
|
99 |
+
|
100 |
+
if image_root[-4::] == 'zip':
|
101 |
+
self.use_zip = True
|
102 |
+
self.zip_dict = {}
|
103 |
+
|
104 |
+
if self.random_crop:
|
105 |
+
assert False, 'NOT IMPLEMENTED'
|
106 |
+
|
107 |
+
|
108 |
+
def fetch_zipfile(self, ziproot):
|
109 |
+
pid = multiprocessing.current_process().pid # get pid of this process.
|
110 |
+
if pid not in self.zip_dict:
|
111 |
+
self.zip_dict[pid] = ZipFile(ziproot)
|
112 |
+
zip_file = self.zip_dict[pid]
|
113 |
+
return zip_file
|
114 |
+
|
115 |
+
def fetch_image(self, filename):
|
116 |
+
if self.use_zip:
|
117 |
+
zip_file = self.fetch_zipfile(self.image_root)
|
118 |
+
image = Image.open( BytesIO(zip_file.read(filename)) ).convert('RGB')
|
119 |
+
return image
|
120 |
+
else:
|
121 |
+
image = Image.open( os.path.join(self.image_root,filename) ).convert('RGB')
|
122 |
+
return image
|
123 |
+
|
124 |
+
|
125 |
+
def vis_getitem_data(self, index=None, out=None, return_tensor=False, name="res.jpg", print_caption=True):
|
126 |
+
|
127 |
+
if out is None:
|
128 |
+
out = self[index]
|
129 |
+
|
130 |
+
img = torchvision.transforms.functional.to_pil_image( out["image"]*0.5+0.5 )
|
131 |
+
canvas = torchvision.transforms.functional.to_pil_image( torch.ones_like(out["image"]) )
|
132 |
+
W, H = img.size
|
133 |
+
|
134 |
+
if print_caption:
|
135 |
+
caption = out["caption"]
|
136 |
+
print(caption)
|
137 |
+
print(" ")
|
138 |
+
|
139 |
+
boxes = []
|
140 |
+
for box in out["boxes"]:
|
141 |
+
x0,y0,x1,y1 = box
|
142 |
+
boxes.append( [float(x0*W), float(y0*H), float(x1*W), float(y1*H)] )
|
143 |
+
img = draw_box(img, boxes)
|
144 |
+
|
145 |
+
if return_tensor:
|
146 |
+
return torchvision.transforms.functional.to_tensor(img)
|
147 |
+
else:
|
148 |
+
img.save(name)
|
149 |
+
|
150 |
+
|
151 |
+
def transform_image(self, pil_image):
|
152 |
+
if self.random_crop:
|
153 |
+
assert False
|
154 |
+
arr = random_crop_arr(pil_image, self.image_size)
|
155 |
+
else:
|
156 |
+
arr, info = center_crop_arr(pil_image, self.image_size)
|
157 |
+
|
158 |
+
info["performed_flip"] = False
|
159 |
+
if self.random_flip and random.random()<0.5:
|
160 |
+
arr = arr[:, ::-1]
|
161 |
+
info["performed_flip"] = True
|
162 |
+
|
163 |
+
arr = arr.astype(np.float32) / 127.5 - 1
|
164 |
+
arr = np.transpose(arr, [2,0,1])
|
165 |
+
|
166 |
+
return torch.tensor(arr), info
|
167 |
+
|
168 |
+
|
169 |
+
|
170 |
+
def center_crop_arr(pil_image, image_size):
|
171 |
+
# We are not on a new enough PIL to support the `reducing_gap`
|
172 |
+
# argument, which uses BOX downsampling at powers of two first.
|
173 |
+
# Thus, we do it by hand to improve downsample quality.
|
174 |
+
WW, HH = pil_image.size
|
175 |
+
|
176 |
+
while min(*pil_image.size) >= 2 * image_size:
|
177 |
+
pil_image = pil_image.resize(
|
178 |
+
tuple(x // 2 for x in pil_image.size), resample=Image.BOX
|
179 |
+
)
|
180 |
+
|
181 |
+
scale = image_size / min(*pil_image.size)
|
182 |
+
|
183 |
+
pil_image = pil_image.resize(
|
184 |
+
tuple(round(x * scale) for x in pil_image.size), resample=Image.BICUBIC
|
185 |
+
)
|
186 |
+
|
187 |
+
# at this point, the min of pil_image side is desired image_size
|
188 |
+
performed_scale = image_size / min(WW, HH)
|
189 |
+
|
190 |
+
arr = np.array(pil_image)
|
191 |
+
crop_y = (arr.shape[0] - image_size) // 2
|
192 |
+
crop_x = (arr.shape[1] - image_size) // 2
|
193 |
+
|
194 |
+
info = {"performed_scale":performed_scale, 'crop_y':crop_y, 'crop_x':crop_x, "WW":WW, 'HH':HH}
|
195 |
+
|
196 |
+
return arr[crop_y : crop_y + image_size, crop_x : crop_x + image_size], info
|
197 |
+
|
198 |
+
|
199 |
+
def random_crop_arr(pil_image, image_size, min_crop_frac=0.8, max_crop_frac=1.0):
|
200 |
+
min_smaller_dim_size = math.ceil(image_size / max_crop_frac)
|
201 |
+
max_smaller_dim_size = math.ceil(image_size / min_crop_frac)
|
202 |
+
smaller_dim_size = random.randrange(min_smaller_dim_size, max_smaller_dim_size + 1)
|
203 |
+
|
204 |
+
# We are not on a new enough PIL to support the `reducing_gap`
|
205 |
+
# argument, which uses BOX downsampling at powers of two first.
|
206 |
+
# Thus, we do it by hand to improve downsample quality.
|
207 |
+
while min(*pil_image.size) >= 2 * smaller_dim_size:
|
208 |
+
pil_image = pil_image.resize(
|
209 |
+
tuple(x // 2 for x in pil_image.size), resample=Image.BOX
|
210 |
+
)
|
211 |
+
|
212 |
+
scale = smaller_dim_size / min(*pil_image.size)
|
213 |
+
pil_image = pil_image.resize(
|
214 |
+
tuple(round(x * scale) for x in pil_image.size), resample=Image.BICUBIC
|
215 |
+
)
|
216 |
+
|
217 |
+
arr = np.array(pil_image)
|
218 |
+
crop_y = random.randrange(arr.shape[0] - image_size + 1)
|
219 |
+
crop_x = random.randrange(arr.shape[1] - image_size + 1)
|
220 |
+
return arr[crop_y : crop_y + image_size, crop_x : crop_x + image_size]
|
dataset/catalog.py
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
class DatasetCatalog:
|
4 |
+
def __init__(self, ROOT, which_embedder):
|
5 |
+
assert which_embedder in ['clip', 'bert']
|
6 |
+
|
7 |
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
|
8 |
+
|
9 |
+
|
10 |
+
self.VGGrounding = {
|
11 |
+
"target": "dataset.tsv_dataset.TSVDataset",
|
12 |
+
"train_params": dict(
|
13 |
+
tsv_path=os.path.join(ROOT,'GROUNDING/gqa/tsv/train-00.tsv'),
|
14 |
+
)
|
15 |
+
}
|
16 |
+
|
17 |
+
|
18 |
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
|
19 |
+
|
20 |
+
|
21 |
+
self.FlickrGrounding = {
|
22 |
+
"target": "dataset.tsv_dataset.TSVDataset",
|
23 |
+
"train_params":dict(
|
24 |
+
tsv_path=os.path.join(ROOT,'GROUNDING/flickr30k/tsv/train-00.tsv'),
|
25 |
+
)
|
26 |
+
}
|
27 |
+
|
28 |
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
|
29 |
+
|
30 |
+
self.SBUGrounding = {
|
31 |
+
"target": "dataset.tsv_dataset.TSVDataset",
|
32 |
+
"train_params":dict(
|
33 |
+
tsv_path=os.path.join(ROOT,'GROUNDING/SBU/tsv/train-00.tsv'),
|
34 |
+
)
|
35 |
+
}
|
36 |
+
|
37 |
+
|
38 |
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
|
39 |
+
|
40 |
+
|
41 |
+
self.CC3MGrounding = {
|
42 |
+
"target": "dataset.tsv_dataset.TSVDataset",
|
43 |
+
"train_params":dict(
|
44 |
+
tsv_path=os.path.join(ROOT,'GROUNDING/CC3M/tsv/train-00.tsv'),
|
45 |
+
)
|
46 |
+
}
|
47 |
+
|
48 |
+
|
49 |
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
|
50 |
+
|
51 |
+
|
52 |
+
self.CC12MGrounding = {
|
53 |
+
"target": "dataset.tsv_dataset.TSVDataset",
|
54 |
+
"train_params":dict(
|
55 |
+
tsv_path=os.path.join(ROOT,'GROUNDING/CC12M/tsv/train-00.tsv'),
|
56 |
+
)
|
57 |
+
}
|
58 |
+
|
59 |
+
|
60 |
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
|
61 |
+
|
62 |
+
# temp = 'category_embedding_clip.pth' if which_embedder == 'clip' else 'category_embedding_bert.pth'
|
63 |
+
# obj365_category_embedding_path = os.path.join(ROOT, 'OBJECTS365', temp)
|
64 |
+
|
65 |
+
self.Obj365Detection = {
|
66 |
+
"target": "dataset.tsv_dataset.TSVDataset",
|
67 |
+
"train_params":dict(
|
68 |
+
tsv_path=os.path.join(ROOT,'OBJECTS365/tsv/train-00.tsv'),
|
69 |
+
),
|
70 |
+
}
|
71 |
+
|
72 |
+
|
dataset/cd_dataset.py
ADDED
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json, os, random, math
|
2 |
+
from collections import defaultdict
|
3 |
+
from copy import deepcopy
|
4 |
+
|
5 |
+
import torch
|
6 |
+
from torch.utils.data import Dataset
|
7 |
+
import torchvision.transforms as transforms
|
8 |
+
|
9 |
+
import numpy as np
|
10 |
+
from PIL import Image
|
11 |
+
from .base_dataset import BaseDataset, check_filenames_in_zipdata, recalculate_box_and_verify_if_valid
|
12 |
+
from io import BytesIO
|
13 |
+
|
14 |
+
|
15 |
+
|
16 |
+
def not_in_at_all(list1, list2):
|
17 |
+
for a in list1:
|
18 |
+
if a in list2:
|
19 |
+
return False
|
20 |
+
return True
|
21 |
+
|
22 |
+
|
23 |
+
def clean_annotations(annotations):
|
24 |
+
for anno in annotations:
|
25 |
+
anno.pop("segmentation", None)
|
26 |
+
anno.pop("area", None)
|
27 |
+
anno.pop("iscrowd", None)
|
28 |
+
# anno.pop("id", None)
|
29 |
+
|
30 |
+
|
31 |
+
def make_a_sentence(obj_names, clean=False):
|
32 |
+
|
33 |
+
if clean:
|
34 |
+
obj_names = [ name[:-6] if ("-other" in name) else name for name in obj_names]
|
35 |
+
|
36 |
+
caption = ""
|
37 |
+
tokens_positive = []
|
38 |
+
for obj_name in obj_names:
|
39 |
+
start_len = len(caption)
|
40 |
+
caption += obj_name
|
41 |
+
end_len = len(caption)
|
42 |
+
caption += ", "
|
43 |
+
tokens_positive.append(
|
44 |
+
[[start_len, end_len]] # in real caption, positive tokens can be disjoint, thus using list of list
|
45 |
+
)
|
46 |
+
caption = caption[:-2] # remove last ", "
|
47 |
+
|
48 |
+
return caption #, tokens_positive
|
49 |
+
|
50 |
+
|
51 |
+
def check_all_have_same_images(instances_data, stuff_data, caption_data):
|
52 |
+
if stuff_data is not None:
|
53 |
+
assert instances_data["images"] == stuff_data["images"]
|
54 |
+
if caption_data is not None:
|
55 |
+
assert instances_data["images"] == caption_data["images"]
|
56 |
+
|
57 |
+
|
58 |
+
class CDDataset(BaseDataset):
|
59 |
+
"CD: Caption Detection"
|
60 |
+
def __init__(self,
|
61 |
+
image_root,
|
62 |
+
category_embedding_path,
|
63 |
+
instances_json_path = None,
|
64 |
+
stuff_json_path = None,
|
65 |
+
caption_json_path = None,
|
66 |
+
prob_real_caption = 0,
|
67 |
+
fake_caption_type = 'empty',
|
68 |
+
image_size=256,
|
69 |
+
max_images=None,
|
70 |
+
min_box_size=0.01,
|
71 |
+
max_boxes_per_image=8,
|
72 |
+
include_other=False,
|
73 |
+
random_crop = False,
|
74 |
+
random_flip = True,
|
75 |
+
):
|
76 |
+
super().__init__(random_crop, random_flip, image_size)
|
77 |
+
|
78 |
+
self.image_root = image_root
|
79 |
+
self.category_embedding_path = category_embedding_path
|
80 |
+
self.instances_json_path = instances_json_path
|
81 |
+
self.stuff_json_path = stuff_json_path
|
82 |
+
self.caption_json_path = caption_json_path
|
83 |
+
self.prob_real_caption = prob_real_caption
|
84 |
+
self.fake_caption_type = fake_caption_type
|
85 |
+
self.max_images = max_images
|
86 |
+
self.min_box_size = min_box_size
|
87 |
+
self.max_boxes_per_image = max_boxes_per_image
|
88 |
+
self.include_other = include_other
|
89 |
+
|
90 |
+
|
91 |
+
assert fake_caption_type in ["empty", "made"]
|
92 |
+
if prob_real_caption > 0:
|
93 |
+
assert caption_json_path is not None, "caption json must be given"
|
94 |
+
|
95 |
+
|
96 |
+
# Load all jsons
|
97 |
+
with open(instances_json_path, 'r') as f:
|
98 |
+
instances_data = json.load(f) # keys: 'info', 'images', 'licenses', 'categories', 'annotations'
|
99 |
+
clean_annotations(instances_data["annotations"])
|
100 |
+
self.instances_data = instances_data
|
101 |
+
|
102 |
+
self.stuff_data = None
|
103 |
+
if stuff_json_path is not None:
|
104 |
+
with open(stuff_json_path, 'r') as f:
|
105 |
+
stuff_data = json.load(f) # keys: 'info', 'images', 'licenses', 'categories', 'annotations'
|
106 |
+
clean_annotations(stuff_data["annotations"])
|
107 |
+
self.stuff_data = stuff_data
|
108 |
+
|
109 |
+
self.captions_data = None
|
110 |
+
if caption_json_path is not None:
|
111 |
+
with open(caption_json_path, 'r') as f:
|
112 |
+
captions_data = json.load(f) # keys: 'info', 'images', 'licenses', 'categories', 'annotations'
|
113 |
+
clean_annotations(captions_data["annotations"])
|
114 |
+
self.captions_data = captions_data
|
115 |
+
|
116 |
+
|
117 |
+
# Load preprocessed name embedding
|
118 |
+
self.category_embeddings = torch.load(category_embedding_path)
|
119 |
+
self.embedding_len = list( self.category_embeddings.values() )[0].shape[0]
|
120 |
+
|
121 |
+
|
122 |
+
# Misc
|
123 |
+
self.image_ids = [] # main list for selecting images
|
124 |
+
self.image_id_to_filename = {} # file names used to read image
|
125 |
+
check_all_have_same_images(self.instances_data, self.stuff_data, self.captions_data)
|
126 |
+
for image_data in self.instances_data['images']:
|
127 |
+
image_id = image_data['id']
|
128 |
+
filename = image_data['file_name']
|
129 |
+
self.image_ids.append(image_id)
|
130 |
+
self.image_id_to_filename[image_id] = filename
|
131 |
+
|
132 |
+
|
133 |
+
# All category names (including things and stuff)
|
134 |
+
self.object_idx_to_name = {}
|
135 |
+
for category_data in self.instances_data['categories']:
|
136 |
+
self.object_idx_to_name[category_data['id']] = category_data['name']
|
137 |
+
if self.stuff_data is not None:
|
138 |
+
for category_data in self.stuff_data['categories']:
|
139 |
+
self.object_idx_to_name[category_data['id']] = category_data['name']
|
140 |
+
|
141 |
+
|
142 |
+
# Add object data from instances and stuff
|
143 |
+
self.image_id_to_objects = defaultdict(list)
|
144 |
+
self.select_objects( self.instances_data['annotations'] )
|
145 |
+
if self.stuff_data is not None:
|
146 |
+
self.select_objects( self.stuff_data['annotations'] )
|
147 |
+
|
148 |
+
# Add caption data
|
149 |
+
if self.captions_data is not None:
|
150 |
+
self.image_id_to_captions = defaultdict(list)
|
151 |
+
self.select_captions( self.captions_data['annotations'] )
|
152 |
+
|
153 |
+
# Check if all filenames can be found in the zip file
|
154 |
+
# all_filenames = [self.image_id_to_filename[idx] for idx in self.image_ids]
|
155 |
+
# check_filenames_in_zipdata(all_filenames, image_root)
|
156 |
+
|
157 |
+
|
158 |
+
def select_objects(self, annotations):
|
159 |
+
for object_anno in annotations:
|
160 |
+
image_id = object_anno['image_id']
|
161 |
+
object_name = self.object_idx_to_name[object_anno['category_id']]
|
162 |
+
other_ok = object_name != 'other' or self.include_other
|
163 |
+
if other_ok:
|
164 |
+
self.image_id_to_objects[image_id].append(object_anno)
|
165 |
+
|
166 |
+
|
167 |
+
def select_captions(self, annotations):
|
168 |
+
for caption_data in annotations:
|
169 |
+
image_id = caption_data['image_id']
|
170 |
+
self.image_id_to_captions[image_id].append(caption_data)
|
171 |
+
|
172 |
+
|
173 |
+
def total_images(self):
|
174 |
+
return len(self)
|
175 |
+
|
176 |
+
|
177 |
+
def __getitem__(self, index):
|
178 |
+
if self.max_boxes_per_image > 99:
|
179 |
+
assert False, "Are you sure setting such large number of boxes?"
|
180 |
+
|
181 |
+
out = {}
|
182 |
+
|
183 |
+
image_id = self.image_ids[index]
|
184 |
+
out['id'] = image_id
|
185 |
+
|
186 |
+
# Image
|
187 |
+
filename = self.image_id_to_filename[image_id]
|
188 |
+
image = self.fetch_image(filename)
|
189 |
+
#WW, HH = image.size
|
190 |
+
image_tensor, trans_info = self.transform_image(image)
|
191 |
+
out["image"] = image_tensor
|
192 |
+
|
193 |
+
|
194 |
+
# Select valid boxes after cropping (center or random)
|
195 |
+
this_image_obj_annos = deepcopy(self.image_id_to_objects[image_id])
|
196 |
+
areas = []
|
197 |
+
all_obj_names = []
|
198 |
+
all_boxes = []
|
199 |
+
all_masks = []
|
200 |
+
all_positive_embeddings = []
|
201 |
+
for object_anno in this_image_obj_annos:
|
202 |
+
|
203 |
+
x, y, w, h = object_anno['bbox']
|
204 |
+
valid, (x0, y0, x1, y1) = recalculate_box_and_verify_if_valid(x, y, w, h, trans_info, self.image_size, self.min_box_size)
|
205 |
+
|
206 |
+
if valid:
|
207 |
+
areas.append( (x1-x0)*(y1-y0) )
|
208 |
+
obj_name = self.object_idx_to_name[ object_anno['category_id'] ]
|
209 |
+
all_obj_names.append(obj_name)
|
210 |
+
all_boxes.append( torch.tensor([x0,y0,x1,y1]) / self.image_size ) # scale to 0-1
|
211 |
+
all_masks.append(1)
|
212 |
+
all_positive_embeddings.append( self.category_embeddings[obj_name] )
|
213 |
+
|
214 |
+
wanted_idxs = torch.tensor(areas).sort(descending=True)[1]
|
215 |
+
wanted_idxs = wanted_idxs[0:self.max_boxes_per_image]
|
216 |
+
obj_names = [] # used for making a sentence
|
217 |
+
boxes = torch.zeros(self.max_boxes_per_image, 4)
|
218 |
+
masks = torch.zeros(self.max_boxes_per_image)
|
219 |
+
positive_embeddings = torch.zeros(self.max_boxes_per_image, self.embedding_len)
|
220 |
+
for i, idx in enumerate(wanted_idxs):
|
221 |
+
obj_names.append( all_obj_names[idx] )
|
222 |
+
boxes[i] = all_boxes[idx]
|
223 |
+
masks[i] = all_masks[idx]
|
224 |
+
positive_embeddings[i] = all_positive_embeddings[idx]
|
225 |
+
|
226 |
+
# Caption
|
227 |
+
if random.uniform(0, 1) < self.prob_real_caption:
|
228 |
+
caption_data = self.image_id_to_captions[image_id]
|
229 |
+
idx = random.randint(0, len(caption_data)-1 )
|
230 |
+
caption = caption_data[idx]["caption"]
|
231 |
+
else:
|
232 |
+
if self.fake_caption_type == "empty":
|
233 |
+
caption = ""
|
234 |
+
else:
|
235 |
+
caption = make_a_sentence(obj_names, clean=True)
|
236 |
+
|
237 |
+
|
238 |
+
out["caption"] = caption
|
239 |
+
out["boxes"] = boxes
|
240 |
+
out["masks"] = masks
|
241 |
+
out["positive_embeddings"] = positive_embeddings
|
242 |
+
|
243 |
+
return out
|
244 |
+
|
245 |
+
|
246 |
+
def __len__(self):
|
247 |
+
if self.max_images is None:
|
248 |
+
return len(self.image_ids)
|
249 |
+
return min(len(self.image_ids), self.max_images)
|
250 |
+
|
dataset/concat_dataset.py
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from .catalog import DatasetCatalog
|
2 |
+
from ldm.util import instantiate_from_config
|
3 |
+
import torch
|
4 |
+
|
5 |
+
|
6 |
+
|
7 |
+
|
8 |
+
class ConCatDataset():
|
9 |
+
def __init__(self, dataset_name_list, ROOT, which_embedder, train=True, repeats=None):
|
10 |
+
self.datasets = []
|
11 |
+
cul_previous_dataset_length = 0
|
12 |
+
offset_map = []
|
13 |
+
which_dataset = []
|
14 |
+
|
15 |
+
if repeats is None:
|
16 |
+
repeats = [1] * len(dataset_name_list)
|
17 |
+
else:
|
18 |
+
assert len(repeats) == len(dataset_name_list)
|
19 |
+
|
20 |
+
|
21 |
+
Catalog = DatasetCatalog(ROOT, which_embedder)
|
22 |
+
for dataset_idx, (dataset_name, yaml_params) in enumerate(dataset_name_list.items()):
|
23 |
+
repeat = repeats[dataset_idx]
|
24 |
+
|
25 |
+
dataset_dict = getattr(Catalog, dataset_name)
|
26 |
+
|
27 |
+
target = dataset_dict['target']
|
28 |
+
params = dataset_dict['train_params'] if train else dataset_dict['val_params']
|
29 |
+
if yaml_params is not None:
|
30 |
+
params.update(yaml_params)
|
31 |
+
dataset = instantiate_from_config( dict(target=target, params=params) )
|
32 |
+
|
33 |
+
self.datasets.append(dataset)
|
34 |
+
for _ in range(repeat):
|
35 |
+
offset_map.append( torch.ones(len(dataset))*cul_previous_dataset_length )
|
36 |
+
which_dataset.append( torch.ones(len(dataset))*dataset_idx )
|
37 |
+
cul_previous_dataset_length += len(dataset)
|
38 |
+
offset_map = torch.cat(offset_map, dim=0).long()
|
39 |
+
self.total_length = cul_previous_dataset_length
|
40 |
+
|
41 |
+
self.mapping = torch.arange(self.total_length) - offset_map
|
42 |
+
self.which_dataset = torch.cat(which_dataset, dim=0).long()
|
43 |
+
|
44 |
+
|
45 |
+
def total_images(self):
|
46 |
+
count = 0
|
47 |
+
for dataset in self.datasets:
|
48 |
+
print(dataset.total_images())
|
49 |
+
count += dataset.total_images()
|
50 |
+
return count
|
51 |
+
|
52 |
+
|
53 |
+
|
54 |
+
def __getitem__(self, idx):
|
55 |
+
dataset = self.datasets[ self.which_dataset[idx] ]
|
56 |
+
return dataset[ self.mapping[idx] ]
|
57 |
+
|
58 |
+
|
59 |
+
def __len__(self):
|
60 |
+
return self.total_length
|
61 |
+
|
62 |
+
|
63 |
+
|
64 |
+
|
65 |
+
|
dataset/grounding_dataset.py
ADDED
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from tkinter.messagebox import NO
|
2 |
+
import torch
|
3 |
+
import json
|
4 |
+
from collections import defaultdict
|
5 |
+
from PIL import Image, ImageDraw
|
6 |
+
from copy import deepcopy
|
7 |
+
import os
|
8 |
+
import torchvision.transforms as transforms
|
9 |
+
import torchvision
|
10 |
+
from .base_dataset import BaseDataset, check_filenames_in_zipdata, recalculate_box_and_verify_if_valid
|
11 |
+
from io import BytesIO
|
12 |
+
import random
|
13 |
+
|
14 |
+
def check_unique(images, fields):
|
15 |
+
for field in fields:
|
16 |
+
temp_list = []
|
17 |
+
for img_info in images:
|
18 |
+
temp_list.append(img_info[field])
|
19 |
+
assert len(set(temp_list)) == len(temp_list), field
|
20 |
+
|
21 |
+
def clean_data(data):
|
22 |
+
for data_info in data:
|
23 |
+
data_info.pop("original_img_id", None)
|
24 |
+
data_info.pop("original_id", None)
|
25 |
+
data_info.pop("sentence_id", None) # sentence id for each image (multiple sentences for one image)
|
26 |
+
data_info.pop("dataset_name", None)
|
27 |
+
data_info.pop("data_source", None)
|
28 |
+
data_info["data_id"] = data_info.pop("id")
|
29 |
+
|
30 |
+
|
31 |
+
def clean_annotations(annotations):
|
32 |
+
for anno_info in annotations:
|
33 |
+
anno_info.pop("iscrowd", None) # I have checked that all 0 for flickr, vg, coco
|
34 |
+
anno_info.pop("category_id", None) # I have checked that all 1 for flickr vg. This is not always 1 for coco, but I do not think we need this annotation
|
35 |
+
anno_info.pop("area", None)
|
36 |
+
# anno_info.pop("id", None)
|
37 |
+
anno_info["data_id"] = anno_info.pop("image_id")
|
38 |
+
|
39 |
+
|
40 |
+
def draw_box(img, boxes):
|
41 |
+
draw = ImageDraw.Draw(img)
|
42 |
+
for box in boxes:
|
43 |
+
draw.rectangle([box[0], box[1], box[2], box[3]], outline ="red", width=2) # x0 y0 x1 y1
|
44 |
+
return img
|
45 |
+
|
46 |
+
|
47 |
+
def xyhw2xyxy(box):
|
48 |
+
x0, y0, w, h = box
|
49 |
+
return [ x0, y0, x0+w, y0+h ]
|
50 |
+
|
51 |
+
|
52 |
+
|
53 |
+
class GroundingDataset(BaseDataset):
|
54 |
+
def __init__(self,
|
55 |
+
image_root,
|
56 |
+
json_path,
|
57 |
+
annotation_embedding_path,
|
58 |
+
prob_real_caption=1,
|
59 |
+
image_size=256,
|
60 |
+
min_box_size=0.01,
|
61 |
+
max_boxes_per_data=8,
|
62 |
+
max_images=None, # set as 30K used to eval
|
63 |
+
random_crop = False,
|
64 |
+
random_flip = True,
|
65 |
+
):
|
66 |
+
super().__init__(image_root, random_crop, random_flip, image_size)
|
67 |
+
self.image_root = image_root
|
68 |
+
self.json_path = json_path
|
69 |
+
self.annotation_embedding_path = annotation_embedding_path
|
70 |
+
self.prob_real_caption = prob_real_caption
|
71 |
+
self.min_box_size = min_box_size
|
72 |
+
self.max_boxes_per_data = max_boxes_per_data
|
73 |
+
self.max_images = max_images
|
74 |
+
|
75 |
+
|
76 |
+
# Load raw data
|
77 |
+
with open(json_path, 'r') as f:
|
78 |
+
json_raw = json.load(f) # keys: 'info', 'images', 'licenses', 'categories', 'annotations'
|
79 |
+
self.data = json_raw["images"] # donot name it images, which is misleading
|
80 |
+
self.annotations = json_raw["annotations"]
|
81 |
+
|
82 |
+
|
83 |
+
# Load preprocessed name embedding
|
84 |
+
if 'bert' in annotation_embedding_path:
|
85 |
+
self.embedding_len = 1280
|
86 |
+
elif 'clip' in annotation_embedding_path:
|
87 |
+
self.embedding_len = 768
|
88 |
+
else:
|
89 |
+
assert False
|
90 |
+
|
91 |
+
|
92 |
+
# clean data and annotation
|
93 |
+
check_unique( self.data, ['id'] )
|
94 |
+
check_unique( self.annotations, ['id'] )
|
95 |
+
clean_data(self.data)
|
96 |
+
clean_annotations(self.annotations)
|
97 |
+
self.data_id_list = [ datum['data_id'] for datum in self.data ]
|
98 |
+
self.data = { datum['data_id']:datum for datum in self.data } # map self.data from a list into a dict
|
99 |
+
|
100 |
+
|
101 |
+
# data point to its annotation mapping
|
102 |
+
self.data_id_to_annos = defaultdict(list)
|
103 |
+
for anno in self.annotations:
|
104 |
+
self.data_id_to_annos[ anno["data_id"] ].append(anno)
|
105 |
+
|
106 |
+
|
107 |
+
|
108 |
+
# These are not used that offen, but are useful in some cases
|
109 |
+
self.file_names = [] # all training images
|
110 |
+
self.file_name_to_data_ids = defaultdict(list) # for each image, there are multiple data points (captions)
|
111 |
+
for data_id in self.data_id_list:
|
112 |
+
fine_name = self.data[data_id]["file_name"]
|
113 |
+
self.file_names.append(fine_name)
|
114 |
+
self.file_name_to_data_ids[fine_name].append(data_id)
|
115 |
+
self.file_names = list(set(self.file_names))
|
116 |
+
|
117 |
+
|
118 |
+
if self.max_images is not None:
|
119 |
+
"This is only used as COCO2017P evulation, when we set max_images as 30k"
|
120 |
+
assert False, 'I have commented out the following code to save cpu memory'
|
121 |
+
# new_data_id_list = []
|
122 |
+
# new_file_name_to_data_ids = defaultdict(list)
|
123 |
+
# self.file_names = self.file_names[0:self.max_images]
|
124 |
+
# for file_name in self.file_names:
|
125 |
+
# data_id = self.file_name_to_data_ids[file_name][0]
|
126 |
+
# new_data_id_list.append(data_id)
|
127 |
+
# new_file_name_to_data_ids[file_name].append(data_id)
|
128 |
+
# self.data_id_list = new_data_id_list
|
129 |
+
# self.file_name_to_data_ids = new_file_name_to_data_ids
|
130 |
+
|
131 |
+
|
132 |
+
# Check if all filenames can be found in the zip file
|
133 |
+
# all_filenames = [self.data[idx]['file_name'] for idx in self.data_id_list ]
|
134 |
+
# check_filenames_in_zipdata(all_filenames, image_root)
|
135 |
+
|
136 |
+
|
137 |
+
def total_images(self):
|
138 |
+
return len(self.file_names)
|
139 |
+
|
140 |
+
|
141 |
+
def __getitem__(self, index):
|
142 |
+
if self.max_boxes_per_data > 99:
|
143 |
+
assert False, "Are you sure setting such large number of boxes?"
|
144 |
+
|
145 |
+
out = {}
|
146 |
+
|
147 |
+
data_id = self.data_id_list[index]
|
148 |
+
out['id'] = data_id
|
149 |
+
|
150 |
+
|
151 |
+
# Image and caption
|
152 |
+
file_name = self.data[data_id]['file_name']
|
153 |
+
image = self.fetch_image(file_name)
|
154 |
+
image_tensor, trans_info = self.transform_image(image)
|
155 |
+
out["image"] = image_tensor
|
156 |
+
|
157 |
+
if random.uniform(0, 1) < self.prob_real_caption:
|
158 |
+
out["caption"] = self.data[data_id]["caption"]
|
159 |
+
else:
|
160 |
+
out["caption"] = ""
|
161 |
+
|
162 |
+
|
163 |
+
|
164 |
+
annos = deepcopy(self.data_id_to_annos[data_id])
|
165 |
+
areas = []
|
166 |
+
all_boxes = []
|
167 |
+
all_masks = []
|
168 |
+
all_positive_embeddings = []
|
169 |
+
|
170 |
+
|
171 |
+
for anno in annos:
|
172 |
+
|
173 |
+
x, y, w, h = anno['bbox']
|
174 |
+
valid, (x0, y0, x1, y1) = recalculate_box_and_verify_if_valid(x, y, w, h, trans_info, self.image_size, self.min_box_size)
|
175 |
+
|
176 |
+
if valid:
|
177 |
+
areas.append( (x1-x0)*(y1-y0) )
|
178 |
+
all_boxes.append( torch.tensor([x0,y0,x1,y1]) / self.image_size ) # scale to 0-1
|
179 |
+
all_masks.append(1)
|
180 |
+
all_positive_embeddings.append( torch.load(os.path.join(self.annotation_embedding_path,str(anno["id"])), map_location='cpu' ) )
|
181 |
+
|
182 |
+
wanted_idxs = torch.tensor(areas).sort(descending=True)[1]
|
183 |
+
wanted_idxs = wanted_idxs[0:self.max_boxes_per_data]
|
184 |
+
|
185 |
+
boxes = torch.zeros(self.max_boxes_per_data, 4)
|
186 |
+
masks = torch.zeros(self.max_boxes_per_data)
|
187 |
+
positive_embeddings = torch.zeros(self.max_boxes_per_data, self.embedding_len)
|
188 |
+
for i, idx in enumerate(wanted_idxs):
|
189 |
+
boxes[i] = all_boxes[idx]
|
190 |
+
masks[i] = all_masks[idx]
|
191 |
+
positive_embeddings[i] = all_positive_embeddings[idx]
|
192 |
+
|
193 |
+
|
194 |
+
out["boxes"] = boxes
|
195 |
+
out["masks"] = masks
|
196 |
+
out["positive_embeddings"] = positive_embeddings
|
197 |
+
|
198 |
+
return out
|
199 |
+
|
200 |
+
|
201 |
+
|
202 |
+
def __len__(self):
|
203 |
+
return len(self.data_id_list)
|
204 |
+
|
205 |
+
|
dataset/layout_dataset.py
ADDED
@@ -0,0 +1,237 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json, os, random, math
|
2 |
+
from collections import defaultdict
|
3 |
+
from copy import deepcopy
|
4 |
+
|
5 |
+
import torch
|
6 |
+
from torch.utils.data import Dataset
|
7 |
+
import torchvision.transforms as transforms
|
8 |
+
|
9 |
+
import numpy as np
|
10 |
+
from PIL import Image, ImageOps
|
11 |
+
from .base_dataset import BaseDataset, check_filenames_in_zipdata
|
12 |
+
from io import BytesIO
|
13 |
+
|
14 |
+
|
15 |
+
|
16 |
+
|
17 |
+
def clean_annotations(annotations):
|
18 |
+
for anno in annotations:
|
19 |
+
anno.pop("segmentation", None)
|
20 |
+
anno.pop("area", None)
|
21 |
+
anno.pop("iscrowd", None)
|
22 |
+
anno.pop("id", None)
|
23 |
+
|
24 |
+
|
25 |
+
def make_a_sentence(obj_names, clean=False):
|
26 |
+
|
27 |
+
if clean:
|
28 |
+
obj_names = [ name[:-6] if ("-other" in name) else name for name in obj_names]
|
29 |
+
|
30 |
+
caption = ""
|
31 |
+
tokens_positive = []
|
32 |
+
for obj_name in obj_names:
|
33 |
+
start_len = len(caption)
|
34 |
+
caption += obj_name
|
35 |
+
end_len = len(caption)
|
36 |
+
caption += ", "
|
37 |
+
tokens_positive.append(
|
38 |
+
[[start_len, end_len]] # in real caption, positive tokens can be disjoint, thus using list of list
|
39 |
+
)
|
40 |
+
caption = caption[:-2] # remove last ", "
|
41 |
+
|
42 |
+
return caption #, tokens_positive
|
43 |
+
|
44 |
+
|
45 |
+
class LayoutDataset(BaseDataset):
|
46 |
+
"""
|
47 |
+
Note: this dataset can somehow be achieved in cd_dataset.CDDataset
|
48 |
+
Since if you donot set prob_real_caption=0 in CDDataset, then that
|
49 |
+
dataset will only use detection annotations. However, in that dataset,
|
50 |
+
we do not remove images but remove boxes.
|
51 |
+
|
52 |
+
However, in layout2img works, people will just resize raw image data into 256*256,
|
53 |
+
thus they pre-calculate box size and apply min_box_size before min/max_boxes_per_image.
|
54 |
+
And then they will remove images if does not follow the rule.
|
55 |
+
|
56 |
+
These two different methods will lead to different number of training/val images.
|
57 |
+
Thus this dataset here is only for layout2img.
|
58 |
+
|
59 |
+
"""
|
60 |
+
def __init__(self,
|
61 |
+
image_root,
|
62 |
+
instances_json_path,
|
63 |
+
stuff_json_path,
|
64 |
+
category_embedding_path,
|
65 |
+
fake_caption_type = 'empty',
|
66 |
+
image_size=256,
|
67 |
+
max_samples=None,
|
68 |
+
min_box_size=0.02,
|
69 |
+
min_boxes_per_image=3,
|
70 |
+
max_boxes_per_image=8,
|
71 |
+
include_other=False,
|
72 |
+
random_flip=True
|
73 |
+
):
|
74 |
+
super().__init__(random_crop=None, random_flip=None, image_size=None) # we only use vis_getitem func in BaseDataset, donot use the others.
|
75 |
+
|
76 |
+
assert fake_caption_type in ['empty', 'made']
|
77 |
+
self.image_root = image_root
|
78 |
+
self.instances_json_path = instances_json_path
|
79 |
+
self.stuff_json_path = stuff_json_path
|
80 |
+
self.category_embedding_path = category_embedding_path
|
81 |
+
self.fake_caption_type = fake_caption_type
|
82 |
+
self.image_size = image_size
|
83 |
+
self.max_samples = max_samples
|
84 |
+
self.min_box_size = min_box_size
|
85 |
+
self.min_boxes_per_image = min_boxes_per_image
|
86 |
+
self.max_boxes_per_image = max_boxes_per_image
|
87 |
+
self.include_other = include_other
|
88 |
+
self.random_flip = random_flip
|
89 |
+
|
90 |
+
|
91 |
+
self.transform = transforms.Compose([transforms.Resize( (image_size, image_size) ),
|
92 |
+
transforms.ToTensor(),
|
93 |
+
transforms.Lambda(lambda t: (t * 2) - 1) ])
|
94 |
+
|
95 |
+
# Load all jsons
|
96 |
+
with open(instances_json_path, 'r') as f:
|
97 |
+
instances_data = json.load(f) # keys: 'info', 'images', 'licenses', 'categories', 'annotations'
|
98 |
+
clean_annotations(instances_data["annotations"])
|
99 |
+
self.instances_data = instances_data
|
100 |
+
|
101 |
+
with open(stuff_json_path, 'r') as f:
|
102 |
+
stuff_data = json.load(f) # keys: 'info', 'images', 'licenses', 'categories', 'annotations'
|
103 |
+
clean_annotations(stuff_data["annotations"])
|
104 |
+
self.stuff_data = stuff_data
|
105 |
+
|
106 |
+
|
107 |
+
# Load preprocessed name embedding
|
108 |
+
self.category_embeddings = torch.load(category_embedding_path)
|
109 |
+
self.embedding_len = list( self.category_embeddings.values() )[0].shape[0]
|
110 |
+
|
111 |
+
|
112 |
+
# Misc
|
113 |
+
self.image_ids = [] # main list for selecting images
|
114 |
+
self.image_id_to_filename = {} # file names used to read image
|
115 |
+
self.image_id_to_size = {} # original size of this image
|
116 |
+
assert instances_data['images'] == stuff_data["images"]
|
117 |
+
for image_data in instances_data['images']:
|
118 |
+
image_id = image_data['id']
|
119 |
+
filename = image_data['file_name']
|
120 |
+
width = image_data['width']
|
121 |
+
height = image_data['height']
|
122 |
+
self.image_ids.append(image_id)
|
123 |
+
self.image_id_to_filename[image_id] = filename
|
124 |
+
self.image_id_to_size[image_id] = (width, height)
|
125 |
+
|
126 |
+
# All category names (including things and stuff)
|
127 |
+
self.things_id_list = []
|
128 |
+
self.stuff_id_list = []
|
129 |
+
self.object_idx_to_name = {}
|
130 |
+
for category_data in instances_data['categories']:
|
131 |
+
self.things_id_list.append( category_data['id'] )
|
132 |
+
self.object_idx_to_name[category_data['id']] = category_data['name']
|
133 |
+
for category_data in stuff_data['categories']:
|
134 |
+
self.stuff_id_list.append( category_data['id'] )
|
135 |
+
self.object_idx_to_name[category_data['id']] = category_data['name']
|
136 |
+
self.all_categories = [ self.object_idx_to_name.get(k, None) for k in range(183+1) ]
|
137 |
+
|
138 |
+
|
139 |
+
# Add object data from instances and stuff
|
140 |
+
self.image_id_to_objects = defaultdict(list)
|
141 |
+
self.select_objects( instances_data['annotations'] )
|
142 |
+
self.select_objects( stuff_data['annotations'] )
|
143 |
+
|
144 |
+
|
145 |
+
# Prune images that have too few or too many objects
|
146 |
+
new_image_ids = []
|
147 |
+
for image_id in self.image_ids:
|
148 |
+
num_objs = len(self.image_id_to_objects[image_id])
|
149 |
+
if self.min_boxes_per_image <= num_objs <= self.max_boxes_per_image:
|
150 |
+
new_image_ids.append(image_id)
|
151 |
+
self.image_ids = new_image_ids
|
152 |
+
|
153 |
+
|
154 |
+
# Check if all filenames can be found in the zip file
|
155 |
+
all_filenames = [self.image_id_to_filename[idx] for idx in self.image_ids]
|
156 |
+
check_filenames_in_zipdata(all_filenames, image_root)
|
157 |
+
|
158 |
+
|
159 |
+
|
160 |
+
def select_objects(self, annotations):
|
161 |
+
for object_anno in annotations:
|
162 |
+
image_id = object_anno['image_id']
|
163 |
+
_, _, w, h = object_anno['bbox']
|
164 |
+
W, H = self.image_id_to_size[image_id]
|
165 |
+
box_area = (w * h) / (W * H)
|
166 |
+
box_ok = box_area > self.min_box_size
|
167 |
+
object_name = self.object_idx_to_name[object_anno['category_id']]
|
168 |
+
other_ok = object_name != 'other' or self.include_other
|
169 |
+
if box_ok and other_ok:
|
170 |
+
self.image_id_to_objects[image_id].append(object_anno)
|
171 |
+
|
172 |
+
|
173 |
+
def total_images(self):
|
174 |
+
return len(self)
|
175 |
+
|
176 |
+
|
177 |
+
def __getitem__(self, index):
|
178 |
+
if self.max_boxes_per_image > 99:
|
179 |
+
assert False, "Are you sure setting such large number of boxes?"
|
180 |
+
|
181 |
+
out = {}
|
182 |
+
|
183 |
+
image_id = self.image_ids[index]
|
184 |
+
out['id'] = image_id
|
185 |
+
|
186 |
+
flip = self.random_flip and random.random()<0.5
|
187 |
+
|
188 |
+
# Image
|
189 |
+
filename = self.image_id_to_filename[image_id]
|
190 |
+
zip_file = self.fetch_zipfile(self.image_root)
|
191 |
+
image = Image.open(BytesIO(zip_file.read(filename))).convert('RGB')
|
192 |
+
WW, HH = image.size
|
193 |
+
if flip:
|
194 |
+
image = ImageOps.mirror(image)
|
195 |
+
out["image"] = self.transform(image)
|
196 |
+
|
197 |
+
this_image_obj_annos = deepcopy(self.image_id_to_objects[image_id])
|
198 |
+
|
199 |
+
# Make a sentence
|
200 |
+
obj_names = [] # used for make a sentence
|
201 |
+
boxes = torch.zeros(self.max_boxes_per_image, 4)
|
202 |
+
masks = torch.zeros(self.max_boxes_per_image)
|
203 |
+
positive_embeddings = torch.zeros(self.max_boxes_per_image, self.embedding_len)
|
204 |
+
for idx, object_anno in enumerate(this_image_obj_annos):
|
205 |
+
obj_name = self.object_idx_to_name[ object_anno['category_id'] ]
|
206 |
+
obj_names.append(obj_name)
|
207 |
+
x, y, w, h = object_anno['bbox']
|
208 |
+
x0 = x / WW
|
209 |
+
y0 = y / HH
|
210 |
+
x1 = (x + w) / WW
|
211 |
+
y1 = (y + h) / HH
|
212 |
+
if flip:
|
213 |
+
x0, x1 = 1-x1, 1-x0
|
214 |
+
boxes[idx] = torch.tensor([x0,y0,x1,y1])
|
215 |
+
masks[idx] = 1
|
216 |
+
positive_embeddings[idx] = self.category_embeddings[obj_name]
|
217 |
+
|
218 |
+
if self.fake_caption_type == 'empty':
|
219 |
+
caption = ""
|
220 |
+
else:
|
221 |
+
caption = make_a_sentence(obj_names, clean=True)
|
222 |
+
|
223 |
+
out["caption"] = caption
|
224 |
+
out["boxes"] = boxes
|
225 |
+
out["masks"] = masks
|
226 |
+
out["positive_embeddings"] = positive_embeddings
|
227 |
+
|
228 |
+
|
229 |
+
return out
|
230 |
+
|
231 |
+
|
232 |
+
def __len__(self):
|
233 |
+
if self.max_samples is None:
|
234 |
+
return len(self.image_ids)
|
235 |
+
return min(len(self.image_ids), self.max_samples)
|
236 |
+
|
237 |
+
|
dataset/tsv.py
ADDED
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import os.path as op
|
3 |
+
import gc
|
4 |
+
import json
|
5 |
+
from typing import List
|
6 |
+
import logging
|
7 |
+
|
8 |
+
try:
|
9 |
+
from .blob_storage import BlobStorage, disk_usage
|
10 |
+
except:
|
11 |
+
class BlobStorage:
|
12 |
+
pass
|
13 |
+
|
14 |
+
|
15 |
+
def generate_lineidx(filein: str, idxout: str) -> None:
|
16 |
+
idxout_tmp = idxout + '.tmp'
|
17 |
+
with open(filein, 'r') as tsvin, open(idxout_tmp, 'w') as tsvout:
|
18 |
+
fsize = os.fstat(tsvin.fileno()).st_size
|
19 |
+
fpos = 0
|
20 |
+
while fpos != fsize:
|
21 |
+
tsvout.write(str(fpos) + "\n")
|
22 |
+
tsvin.readline()
|
23 |
+
fpos = tsvin.tell()
|
24 |
+
os.rename(idxout_tmp, idxout)
|
25 |
+
|
26 |
+
|
27 |
+
def read_to_character(fp, c):
|
28 |
+
result = []
|
29 |
+
while True:
|
30 |
+
s = fp.read(32)
|
31 |
+
assert s != ''
|
32 |
+
if c in s:
|
33 |
+
result.append(s[: s.index(c)])
|
34 |
+
break
|
35 |
+
else:
|
36 |
+
result.append(s)
|
37 |
+
return ''.join(result)
|
38 |
+
|
39 |
+
|
40 |
+
class TSVFile(object):
|
41 |
+
def __init__(self,
|
42 |
+
tsv_file: str,
|
43 |
+
if_generate_lineidx: bool = False,
|
44 |
+
lineidx: str = None,
|
45 |
+
class_selector: List[str] = None,
|
46 |
+
blob_storage: BlobStorage = None):
|
47 |
+
self.tsv_file = tsv_file
|
48 |
+
self.lineidx = op.splitext(tsv_file)[0] + '.lineidx' \
|
49 |
+
if not lineidx else lineidx
|
50 |
+
self.linelist = op.splitext(tsv_file)[0] + '.linelist'
|
51 |
+
self.chunks = op.splitext(tsv_file)[0] + '.chunks'
|
52 |
+
self._fp = None
|
53 |
+
self._lineidx = None
|
54 |
+
self._sample_indices = None
|
55 |
+
self._class_boundaries = None
|
56 |
+
self._class_selector = class_selector
|
57 |
+
self._blob_storage = blob_storage
|
58 |
+
self._len = None
|
59 |
+
# the process always keeps the process which opens the file.
|
60 |
+
# If the pid is not equal to the currrent pid, we will re-open the file.
|
61 |
+
self.pid = None
|
62 |
+
# generate lineidx if not exist
|
63 |
+
if not op.isfile(self.lineidx) and if_generate_lineidx:
|
64 |
+
generate_lineidx(self.tsv_file, self.lineidx)
|
65 |
+
|
66 |
+
def __del__(self):
|
67 |
+
self.gcidx()
|
68 |
+
if self._fp:
|
69 |
+
self._fp.close()
|
70 |
+
# physically remove the tsv file if it is retrieved by BlobStorage
|
71 |
+
if self._blob_storage and 'azcopy' in self.tsv_file and os.path.exists(self.tsv_file):
|
72 |
+
try:
|
73 |
+
original_usage = disk_usage('/')
|
74 |
+
os.remove(self.tsv_file)
|
75 |
+
logging.info("Purged %s (disk usage: %.2f%% => %.2f%%)" %
|
76 |
+
(self.tsv_file, original_usage, disk_usage('/') * 100))
|
77 |
+
except:
|
78 |
+
# Known issue: multiple threads attempting to delete the file will raise a FileNotFound error.
|
79 |
+
# TODO: try Threadling.Lock to better handle the race condition
|
80 |
+
pass
|
81 |
+
|
82 |
+
def __str__(self):
|
83 |
+
return "TSVFile(tsv_file='{}')".format(self.tsv_file)
|
84 |
+
|
85 |
+
def __repr__(self):
|
86 |
+
return str(self)
|
87 |
+
|
88 |
+
def gcidx(self):
|
89 |
+
logging.debug('Run gc collect')
|
90 |
+
self._lineidx = None
|
91 |
+
self._sample_indices = None
|
92 |
+
#self._class_boundaries = None
|
93 |
+
return gc.collect()
|
94 |
+
|
95 |
+
def get_class_boundaries(self):
|
96 |
+
return self._class_boundaries
|
97 |
+
|
98 |
+
def num_rows(self, gcf=False):
|
99 |
+
if (self._len is None):
|
100 |
+
self._ensure_lineidx_loaded()
|
101 |
+
retval = len(self._sample_indices)
|
102 |
+
|
103 |
+
if (gcf):
|
104 |
+
self.gcidx()
|
105 |
+
|
106 |
+
self._len = retval
|
107 |
+
|
108 |
+
return self._len
|
109 |
+
|
110 |
+
def seek(self, idx: int):
|
111 |
+
self._ensure_tsv_opened()
|
112 |
+
self._ensure_lineidx_loaded()
|
113 |
+
try:
|
114 |
+
pos = self._lineidx[self._sample_indices[idx]]
|
115 |
+
except:
|
116 |
+
logging.info('=> {}-{}'.format(self.tsv_file, idx))
|
117 |
+
raise
|
118 |
+
self._fp.seek(pos)
|
119 |
+
return [s.strip() for s in self._fp.readline().split('\t')]
|
120 |
+
|
121 |
+
def seek_first_column(self, idx: int):
|
122 |
+
self._ensure_tsv_opened()
|
123 |
+
self._ensure_lineidx_loaded()
|
124 |
+
pos = self._lineidx[idx]
|
125 |
+
self._fp.seek(pos)
|
126 |
+
return read_to_character(self._fp, '\t')
|
127 |
+
|
128 |
+
def get_key(self, idx: int):
|
129 |
+
return self.seek_first_column(idx)
|
130 |
+
|
131 |
+
def __getitem__(self, index: int):
|
132 |
+
return self.seek(index)
|
133 |
+
|
134 |
+
def __len__(self):
|
135 |
+
return self.num_rows()
|
136 |
+
|
137 |
+
def _ensure_lineidx_loaded(self):
|
138 |
+
if self._lineidx is None:
|
139 |
+
logging.debug('=> loading lineidx: {}'.format(self.lineidx))
|
140 |
+
with open(self.lineidx, 'r') as fp:
|
141 |
+
lines = fp.readlines()
|
142 |
+
lines = [line.strip() for line in lines]
|
143 |
+
self._lineidx = [int(line) for line in lines]
|
144 |
+
|
145 |
+
# read the line list if exists
|
146 |
+
linelist = None
|
147 |
+
if op.isfile(self.linelist):
|
148 |
+
with open(self.linelist, 'r') as fp:
|
149 |
+
linelist = sorted(
|
150 |
+
[
|
151 |
+
int(line.strip())
|
152 |
+
for line in fp.readlines()
|
153 |
+
]
|
154 |
+
)
|
155 |
+
|
156 |
+
if op.isfile(self.chunks):
|
157 |
+
self._sample_indices = []
|
158 |
+
self._class_boundaries = []
|
159 |
+
class_boundaries = json.load(open(self.chunks, 'r'))
|
160 |
+
for class_name, boundary in class_boundaries.items():
|
161 |
+
start = len(self._sample_indices)
|
162 |
+
if class_name in self._class_selector:
|
163 |
+
for idx in range(boundary[0], boundary[1] + 1):
|
164 |
+
# NOTE: potentially slow when linelist is long, try to speed it up
|
165 |
+
if linelist and idx not in linelist:
|
166 |
+
continue
|
167 |
+
self._sample_indices.append(idx)
|
168 |
+
end = len(self._sample_indices)
|
169 |
+
self._class_boundaries.append((start, end))
|
170 |
+
else:
|
171 |
+
if linelist:
|
172 |
+
self._sample_indices = linelist
|
173 |
+
else:
|
174 |
+
self._sample_indices = list(range(len(self._lineidx)))
|
175 |
+
|
176 |
+
def _ensure_tsv_opened(self):
|
177 |
+
if self._fp is None:
|
178 |
+
if self._blob_storage:
|
179 |
+
self._fp = self._blob_storage.open(self.tsv_file)
|
180 |
+
else:
|
181 |
+
self._fp = open(self.tsv_file, 'r')
|
182 |
+
self.pid = os.getpid()
|
183 |
+
|
184 |
+
if self.pid != os.getpid():
|
185 |
+
logging.debug('=> re-open {} because the process id changed'.format(self.tsv_file))
|
186 |
+
self._fp = open(self.tsv_file, 'r')
|
187 |
+
self.pid = os.getpid()
|
188 |
+
|
189 |
+
|
190 |
+
class TSVWriter(object):
|
191 |
+
def __init__(self, tsv_file):
|
192 |
+
self.tsv_file = tsv_file
|
193 |
+
self.lineidx_file = op.splitext(tsv_file)[0] + '.lineidx'
|
194 |
+
self.tsv_file_tmp = self.tsv_file + '.tmp'
|
195 |
+
self.lineidx_file_tmp = self.lineidx_file + '.tmp'
|
196 |
+
|
197 |
+
self.tsv_fp = open(self.tsv_file_tmp, 'w')
|
198 |
+
self.lineidx_fp = open(self.lineidx_file_tmp, 'w')
|
199 |
+
|
200 |
+
self.idx = 0
|
201 |
+
|
202 |
+
def write(self, values, sep='\t'):
|
203 |
+
v = '{0}\n'.format(sep.join(map(str, values)))
|
204 |
+
self.tsv_fp.write(v)
|
205 |
+
self.lineidx_fp.write(str(self.idx) + '\n')
|
206 |
+
self.idx = self.idx + len(v)
|
207 |
+
|
208 |
+
def close(self):
|
209 |
+
self.tsv_fp.close()
|
210 |
+
self.lineidx_fp.close()
|
211 |
+
os.rename(self.tsv_file_tmp, self.tsv_file)
|
212 |
+
os.rename(self.lineidx_file_tmp, self.lineidx_file)
|
dataset/tsv_dataset.py
ADDED
@@ -0,0 +1,326 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from tkinter.messagebox import NO
|
2 |
+
import torch
|
3 |
+
import json
|
4 |
+
from collections import defaultdict
|
5 |
+
from PIL import Image, ImageDraw
|
6 |
+
from copy import deepcopy
|
7 |
+
import os
|
8 |
+
import torchvision.transforms as transforms
|
9 |
+
import torchvision
|
10 |
+
from .base_dataset import BaseDataset, check_filenames_in_zipdata, recalculate_box_and_verify_if_valid
|
11 |
+
from io import BytesIO
|
12 |
+
import random
|
13 |
+
|
14 |
+
from .tsv import TSVFile
|
15 |
+
|
16 |
+
from io import BytesIO
|
17 |
+
import base64
|
18 |
+
from PIL import Image
|
19 |
+
import numpy as np
|
20 |
+
|
21 |
+
|
22 |
+
def decode_base64_to_pillow(image_b64):
|
23 |
+
return Image.open(BytesIO(base64.b64decode(image_b64))).convert('RGB')
|
24 |
+
|
25 |
+
def decode_tensor_from_string(arr_str, use_tensor=True):
|
26 |
+
arr = np.frombuffer(base64.b64decode(arr_str), dtype='float32')
|
27 |
+
if use_tensor:
|
28 |
+
arr = torch.from_numpy(arr)
|
29 |
+
return arr
|
30 |
+
|
31 |
+
def decode_item(item):
|
32 |
+
item = json.loads(item)
|
33 |
+
item['image'] = decode_base64_to_pillow(item['image'])
|
34 |
+
|
35 |
+
for anno in item['annos']:
|
36 |
+
anno['image_embedding_before'] = decode_tensor_from_string(anno['image_embedding_before'])
|
37 |
+
anno['text_embedding_before'] = decode_tensor_from_string(anno['text_embedding_before'])
|
38 |
+
anno['image_embedding_after'] = decode_tensor_from_string(anno['image_embedding_after'])
|
39 |
+
anno['text_embedding_after'] = decode_tensor_from_string(anno['text_embedding_after'])
|
40 |
+
return item
|
41 |
+
|
42 |
+
def check_unique(images, fields):
|
43 |
+
for field in fields:
|
44 |
+
temp_list = []
|
45 |
+
for img_info in images:
|
46 |
+
temp_list.append(img_info[field])
|
47 |
+
assert len(set(temp_list)) == len(temp_list), field
|
48 |
+
|
49 |
+
def clean_data(data):
|
50 |
+
for data_info in data:
|
51 |
+
data_info.pop("original_img_id", None)
|
52 |
+
data_info.pop("original_id", None)
|
53 |
+
data_info.pop("sentence_id", None) # sentence id for each image (multiple sentences for one image)
|
54 |
+
data_info.pop("dataset_name", None)
|
55 |
+
data_info.pop("data_source", None)
|
56 |
+
data_info["data_id"] = data_info.pop("id")
|
57 |
+
|
58 |
+
|
59 |
+
def clean_annotations(annotations):
|
60 |
+
for anno_info in annotations:
|
61 |
+
anno_info.pop("iscrowd", None) # I have checked that all 0 for flickr, vg, coco
|
62 |
+
anno_info.pop("category_id", None) # I have checked that all 1 for flickr vg. This is not always 1 for coco, but I do not think we need this annotation
|
63 |
+
anno_info.pop("area", None)
|
64 |
+
# anno_info.pop("id", None)
|
65 |
+
anno_info["data_id"] = anno_info.pop("image_id")
|
66 |
+
|
67 |
+
|
68 |
+
def draw_box(img, boxes):
|
69 |
+
draw = ImageDraw.Draw(img)
|
70 |
+
for box in boxes:
|
71 |
+
draw.rectangle([box[0], box[1], box[2], box[3]], outline ="red", width=2) # x0 y0 x1 y1
|
72 |
+
return img
|
73 |
+
|
74 |
+
|
75 |
+
def xyhw2xyxy(box):
|
76 |
+
x0, y0, w, h = box
|
77 |
+
return [ x0, y0, x0+w, y0+h ]
|
78 |
+
|
79 |
+
|
80 |
+
def make_a_sentence(obj_names, clean=False):
|
81 |
+
|
82 |
+
if clean:
|
83 |
+
obj_names = [ name[:-6] if ("-other" in name) else name for name in obj_names]
|
84 |
+
|
85 |
+
caption = ""
|
86 |
+
tokens_positive = []
|
87 |
+
for obj_name in obj_names:
|
88 |
+
start_len = len(caption)
|
89 |
+
caption += obj_name
|
90 |
+
end_len = len(caption)
|
91 |
+
caption += ", "
|
92 |
+
tokens_positive.append(
|
93 |
+
[[start_len, end_len]] # in real caption, positive tokens can be disjoint, thus using list of list
|
94 |
+
)
|
95 |
+
caption = caption[:-2] # remove last ", "
|
96 |
+
|
97 |
+
return caption #, tokens_positive
|
98 |
+
|
99 |
+
|
100 |
+
def mask_for_random_drop_text_or_image_feature(masks, random_drop_embedding):
|
101 |
+
"""
|
102 |
+
input masks tell how many valid grounding tokens for this image
|
103 |
+
e.g., 1,1,1,1,0,0,0,0,0,0...
|
104 |
+
|
105 |
+
If random_drop_embedding=both. we will random drop either image or
|
106 |
+
text feature for each token,
|
107 |
+
but we always make sure there is at least one feature used.
|
108 |
+
In other words, the following masks are not valid
|
109 |
+
(because for the second obj, no feature at all):
|
110 |
+
image: 1,0,1,1,0,0,0,0,0
|
111 |
+
text: 1,0,0,0,0,0,0,0,0
|
112 |
+
|
113 |
+
if random_drop_embedding=image. we will random drop image feature
|
114 |
+
and always keep the text one.
|
115 |
+
|
116 |
+
"""
|
117 |
+
N = masks.shape[0]
|
118 |
+
|
119 |
+
if random_drop_embedding=='both':
|
120 |
+
temp_mask = torch.ones(2,N)
|
121 |
+
for i in range(N):
|
122 |
+
if random.uniform(0, 1) < 0.5: # else keep both features
|
123 |
+
idx = random.sample([0,1], 1)[0] # randomly choose to drop image or text feature
|
124 |
+
temp_mask[idx,i] = 0
|
125 |
+
image_masks = temp_mask[0]*masks
|
126 |
+
text_masks = temp_mask[1]*masks
|
127 |
+
|
128 |
+
if random_drop_embedding=='image':
|
129 |
+
image_masks = masks*(torch.rand(N)>0.5)*1
|
130 |
+
text_masks = masks
|
131 |
+
|
132 |
+
return image_masks, text_masks
|
133 |
+
|
134 |
+
|
135 |
+
|
136 |
+
|
137 |
+
|
138 |
+
def project(x, projection_matrix):
|
139 |
+
"""
|
140 |
+
x (Batch*768) should be the penultimate feature of CLIP (before projection)
|
141 |
+
projection_matrix (768*768) is the CLIP projection matrix, which should be weight.data of Linear layer
|
142 |
+
defined in CLIP (out_dim, in_dim), thus we need to apply transpose below.
|
143 |
+
this function will return the CLIP feature (without normalziation)
|
144 |
+
"""
|
145 |
+
return [email protected](projection_matrix, 0, 1)
|
146 |
+
|
147 |
+
|
148 |
+
def inv_project(y, projection_matrix):
|
149 |
+
"""
|
150 |
+
y (Batch*768) should be the CLIP feature (after projection)
|
151 |
+
projection_matrix (768*768) is the CLIP projection matrix, which should be weight.data of Linear layer
|
152 |
+
defined in CLIP (out_dim, in_dim).
|
153 |
+
this function will return the CLIP penultimate feature.
|
154 |
+
|
155 |
+
Note: to make sure getting the correct penultimate feature, the input y should not be normalized.
|
156 |
+
If it is normalized, then the result will be scaled by CLIP feature norm, which is unknown.
|
157 |
+
"""
|
158 |
+
return [email protected](torch.linalg.inv(projection_matrix), 0, 1)
|
159 |
+
|
160 |
+
|
161 |
+
|
162 |
+
|
163 |
+
class TSVDataset(BaseDataset):
|
164 |
+
def __init__(self,
|
165 |
+
tsv_path,
|
166 |
+
which_embedder='clip',
|
167 |
+
which_layer=['after','after'], # text and image
|
168 |
+
prob_use_caption=1,
|
169 |
+
random_drop_embedding='none',
|
170 |
+
image_size=256,
|
171 |
+
min_box_size=0.01,
|
172 |
+
max_boxes_per_data=8,
|
173 |
+
max_images=None, # set as 30K used to eval
|
174 |
+
random_crop = False,
|
175 |
+
random_flip = True,
|
176 |
+
):
|
177 |
+
image_root = "a placeholder path as we are using tsv here"
|
178 |
+
super().__init__(image_root, random_crop, random_flip, image_size)
|
179 |
+
self.tsv_path = tsv_path
|
180 |
+
self.which_embedder = which_embedder
|
181 |
+
self.prob_use_caption = prob_use_caption
|
182 |
+
self.random_drop_embedding = random_drop_embedding
|
183 |
+
self.min_box_size = min_box_size
|
184 |
+
self.max_boxes_per_data = max_boxes_per_data
|
185 |
+
self.max_images = max_images
|
186 |
+
|
187 |
+
assert which_layer in [ ['after','after'], ['before','after_renorm'], ['before','after_reproject'] ]
|
188 |
+
assert random_drop_embedding in ['none', 'both', 'image']
|
189 |
+
self.which_layer_text = which_layer[0]
|
190 |
+
self.which_layer_image = which_layer[1]
|
191 |
+
|
192 |
+
#self.projection_matrix = torch.load(os.path.join(os.path.dirname(__file__), 'projection_matrix') )
|
193 |
+
self.projection_matrix = torch.load('projection_matrix.pth')
|
194 |
+
|
195 |
+
# Load tsv data
|
196 |
+
self.tsv_file = TSVFile(self.tsv_path)
|
197 |
+
|
198 |
+
|
199 |
+
# Load preprocessed name embedding
|
200 |
+
if which_embedder == 'bert':
|
201 |
+
self.embedding_len = 1280
|
202 |
+
elif which_embedder == 'clip':
|
203 |
+
self.embedding_len = 768
|
204 |
+
else:
|
205 |
+
assert False
|
206 |
+
|
207 |
+
def total_images(self):
|
208 |
+
return len(self)
|
209 |
+
|
210 |
+
def get_item_from_tsv(self, index):
|
211 |
+
_, item = self.tsv_file[index]
|
212 |
+
item = decode_item(item)
|
213 |
+
return item
|
214 |
+
|
215 |
+
|
216 |
+
def mapping(self, image_embedding):
|
217 |
+
if self.which_layer_image == 'after':
|
218 |
+
# both use CLIP aligned feature
|
219 |
+
return image_embedding
|
220 |
+
elif self.which_layer_image == 'after_renorm':
|
221 |
+
# text use before, but image use after projection but normalize to 28.7
|
222 |
+
return image_embedding*28.7
|
223 |
+
elif self.which_layer_image == 'after_reproject':
|
224 |
+
image_embedding = project( image_embedding.unsqueeze(0), self.projection_matrix.T )
|
225 |
+
image_embedding = image_embedding.squeeze(0)
|
226 |
+
image_embedding = image_embedding / image_embedding.norm()
|
227 |
+
image_embedding = image_embedding * 28.7
|
228 |
+
return image_embedding
|
229 |
+
|
230 |
+
|
231 |
+
|
232 |
+
def __getitem__(self, index):
|
233 |
+
if self.max_boxes_per_data > 99:
|
234 |
+
assert False, "Are you sure setting such large number of boxes?"
|
235 |
+
|
236 |
+
raw_item = self.get_item_from_tsv(index)
|
237 |
+
is_det = raw_item.get('is_det', False) # if it is from detection (such as o365), then we will make a caption
|
238 |
+
|
239 |
+
out = {}
|
240 |
+
|
241 |
+
# -------------------- id and image ------------------- #
|
242 |
+
out['id'] = raw_item['data_id']
|
243 |
+
image = raw_item['image']
|
244 |
+
image_tensor, trans_info = self.transform_image(image)
|
245 |
+
out["image"] = image_tensor
|
246 |
+
|
247 |
+
|
248 |
+
|
249 |
+
# -------------------- grounding token ------------------- #
|
250 |
+
annos = raw_item['annos']
|
251 |
+
|
252 |
+
areas = []
|
253 |
+
all_boxes = []
|
254 |
+
all_masks = []
|
255 |
+
all_text_embeddings = []
|
256 |
+
all_image_embeddings = []
|
257 |
+
if is_det:
|
258 |
+
all_category_names = []
|
259 |
+
|
260 |
+
text_embedding_name = 'text_embedding_before' if self.which_layer_text == 'before' else 'text_embedding_after'
|
261 |
+
image_embedding_name = 'image_embedding_after'
|
262 |
+
|
263 |
+
for anno in annos:
|
264 |
+
x, y, w, h = anno['bbox']
|
265 |
+
valid, (x0, y0, x1, y1) = recalculate_box_and_verify_if_valid(x, y, w, h, trans_info, self.image_size, self.min_box_size)
|
266 |
+
|
267 |
+
if valid:
|
268 |
+
areas.append( (x1-x0)*(y1-y0) )
|
269 |
+
all_boxes.append( torch.tensor([x0,y0,x1,y1]) / self.image_size ) # scale to 0-1
|
270 |
+
all_masks.append(1)
|
271 |
+
all_text_embeddings.append(anno[text_embedding_name])
|
272 |
+
all_image_embeddings.append( self.mapping(anno[image_embedding_name]) )
|
273 |
+
if is_det:
|
274 |
+
all_category_names.append(anno["category_name"])
|
275 |
+
|
276 |
+
|
277 |
+
wanted_idxs = torch.tensor(areas).sort(descending=True)[1]
|
278 |
+
wanted_idxs = wanted_idxs[0:self.max_boxes_per_data]
|
279 |
+
|
280 |
+
boxes = torch.zeros(self.max_boxes_per_data, 4)
|
281 |
+
masks = torch.zeros(self.max_boxes_per_data)
|
282 |
+
text_embeddings = torch.zeros(self.max_boxes_per_data, self.embedding_len)
|
283 |
+
image_embeddings = torch.zeros(self.max_boxes_per_data, self.embedding_len)
|
284 |
+
if is_det:
|
285 |
+
category_names = []
|
286 |
+
for i, idx in enumerate(wanted_idxs):
|
287 |
+
boxes[i] = all_boxes[idx]
|
288 |
+
masks[i] = all_masks[idx]
|
289 |
+
text_embeddings[i] = all_text_embeddings[idx]
|
290 |
+
image_embeddings[i] = all_image_embeddings[idx]
|
291 |
+
if is_det:
|
292 |
+
category_names.append(all_category_names[idx])
|
293 |
+
|
294 |
+
if self.random_drop_embedding != 'none':
|
295 |
+
image_masks, text_masks = mask_for_random_drop_text_or_image_feature(masks, self.random_drop_embedding)
|
296 |
+
else:
|
297 |
+
image_masks = masks
|
298 |
+
text_masks = masks
|
299 |
+
|
300 |
+
|
301 |
+
out["boxes"] = boxes
|
302 |
+
out["masks"] = masks
|
303 |
+
out["image_masks"] = image_masks
|
304 |
+
out["text_masks"] = text_masks
|
305 |
+
out["text_embeddings"] = text_embeddings
|
306 |
+
out["image_embeddings"] = image_embeddings
|
307 |
+
|
308 |
+
|
309 |
+
|
310 |
+
# -------------------- caption ------------------- #
|
311 |
+
if random.uniform(0, 1) < self.prob_use_caption:
|
312 |
+
if is_det:
|
313 |
+
out["caption"] = make_a_sentence(category_names)
|
314 |
+
else:
|
315 |
+
out["caption"] = raw_item["caption"]
|
316 |
+
else:
|
317 |
+
out["caption"] = ""
|
318 |
+
|
319 |
+
return out
|
320 |
+
|
321 |
+
|
322 |
+
|
323 |
+
def __len__(self):
|
324 |
+
return len(self.tsv_file)
|
325 |
+
|
326 |
+
|
dataset/utils.py
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/python
|
2 |
+
#
|
3 |
+
# Copyright 2018 Google LLC
|
4 |
+
#
|
5 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6 |
+
# you may not use this file except in compliance with the License.
|
7 |
+
# You may obtain a copy of the License at
|
8 |
+
#
|
9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10 |
+
#
|
11 |
+
# Unless required by applicable law or agreed to in writing, software
|
12 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14 |
+
# See the License for the specific language governing permissions and
|
15 |
+
# limitations under the License.
|
16 |
+
|
17 |
+
import PIL
|
18 |
+
import torch
|
19 |
+
import torchvision.transforms as T
|
20 |
+
|
21 |
+
|
22 |
+
IMAGENET_MEAN = [0.485, 0.456, 0.406]
|
23 |
+
IMAGENET_STD = [0.229, 0.224, 0.225]
|
24 |
+
|
25 |
+
INV_IMAGENET_MEAN = [-m for m in IMAGENET_MEAN]
|
26 |
+
INV_IMAGENET_STD = [1.0 / s for s in IMAGENET_STD]
|
27 |
+
|
28 |
+
|
29 |
+
def imagenet_preprocess():
|
30 |
+
return T.Normalize(mean=IMAGENET_MEAN, std=IMAGENET_STD)
|
31 |
+
|
32 |
+
|
33 |
+
def rescale(x):
|
34 |
+
lo, hi = x.min(), x.max()
|
35 |
+
return x.sub(lo).div(hi - lo)
|
36 |
+
|
37 |
+
|
38 |
+
def imagenet_deprocess(rescale_image=True):
|
39 |
+
transforms = [
|
40 |
+
T.Normalize(mean=[0, 0, 0], std=INV_IMAGENET_STD),
|
41 |
+
T.Normalize(mean=INV_IMAGENET_MEAN, std=[1.0, 1.0, 1.0]),
|
42 |
+
]
|
43 |
+
if rescale_image:
|
44 |
+
transforms.append(rescale)
|
45 |
+
return T.Compose(transforms)
|
46 |
+
|
47 |
+
|
48 |
+
def imagenet_deprocess_batch(imgs, rescale=True):
|
49 |
+
"""
|
50 |
+
Input:
|
51 |
+
- imgs: FloatTensor of shape (N, C, H, W) giving preprocessed images
|
52 |
+
|
53 |
+
Output:
|
54 |
+
- imgs_de: ByteTensor of shape (N, C, H, W) giving deprocessed images
|
55 |
+
in the range [0, 255]
|
56 |
+
"""
|
57 |
+
if isinstance(imgs, torch.autograd.Variable):
|
58 |
+
imgs = imgs.data
|
59 |
+
imgs = imgs.cpu().clone()
|
60 |
+
deprocess_fn = imagenet_deprocess(rescale_image=rescale)
|
61 |
+
imgs_de = []
|
62 |
+
for i in range(imgs.size(0)):
|
63 |
+
img_de = deprocess_fn(imgs[i])[None]
|
64 |
+
img_de = img_de.mul(255).clamp(0, 255).byte()
|
65 |
+
imgs_de.append(img_de)
|
66 |
+
imgs_de = torch.cat(imgs_de, dim=0)
|
67 |
+
return imgs_de
|
68 |
+
|
69 |
+
|
70 |
+
class Resize(object):
|
71 |
+
def __init__(self, size, interp=PIL.Image.BILINEAR):
|
72 |
+
if isinstance(size, tuple):
|
73 |
+
H, W = size
|
74 |
+
self.size = (W, H)
|
75 |
+
else:
|
76 |
+
self.size = (size, size)
|
77 |
+
self.interp = interp
|
78 |
+
|
79 |
+
def __call__(self, img):
|
80 |
+
return img.resize(self.size, self.interp)
|
81 |
+
|
82 |
+
|
83 |
+
def unpack_var(v):
|
84 |
+
if isinstance(v, torch.autograd.Variable):
|
85 |
+
return v.data
|
86 |
+
return v
|
87 |
+
|
88 |
+
|
89 |
+
def split_graph_batch(triples, obj_data, obj_to_img, triple_to_img):
|
90 |
+
triples = unpack_var(triples)
|
91 |
+
obj_data = [unpack_var(o) for o in obj_data]
|
92 |
+
obj_to_img = unpack_var(obj_to_img)
|
93 |
+
triple_to_img = unpack_var(triple_to_img)
|
94 |
+
|
95 |
+
triples_out = []
|
96 |
+
obj_data_out = [[] for _ in obj_data]
|
97 |
+
obj_offset = 0
|
98 |
+
N = obj_to_img.max() + 1
|
99 |
+
for i in range(N):
|
100 |
+
o_idxs = (obj_to_img == i).nonzero().view(-1)
|
101 |
+
t_idxs = (triple_to_img == i).nonzero().view(-1)
|
102 |
+
|
103 |
+
cur_triples = triples[t_idxs].clone()
|
104 |
+
cur_triples[:, 0] -= obj_offset
|
105 |
+
cur_triples[:, 2] -= obj_offset
|
106 |
+
triples_out.append(cur_triples)
|
107 |
+
|
108 |
+
for j, o_data in enumerate(obj_data):
|
109 |
+
cur_o_data = None
|
110 |
+
if o_data is not None:
|
111 |
+
cur_o_data = o_data[o_idxs]
|
112 |
+
obj_data_out[j].append(cur_o_data)
|
113 |
+
|
114 |
+
obj_offset += o_idxs.size(0)
|
115 |
+
|
116 |
+
return triples_out, obj_data_out
|
environment.yaml
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: gligen_demo
|
2 |
+
channels:
|
3 |
+
- xformers/label/dev
|
4 |
+
- pytorch
|
5 |
+
- defaults
|
6 |
+
dependencies:
|
7 |
+
- python=3.10.8
|
8 |
+
- pip=22.2.2
|
9 |
+
- cudatoolkit=11.3
|
10 |
+
- pytorch=1.12.1
|
11 |
+
- torchvision=0.13.1
|
12 |
+
- numpy=1.23.1
|
13 |
+
- xformers
|
14 |
+
- pip:
|
15 |
+
- omegaconf==2.1.1
|
16 |
+
- albumentations==1.3.0
|
17 |
+
- opencv-python
|
18 |
+
- imageio==2.9.0
|
19 |
+
- imageio-ffmpeg==0.4.2
|
20 |
+
- pytorch-lightning==1.4.2
|
21 |
+
- test-tube>=0.7.5
|
22 |
+
- streamlit==1.12.1
|
23 |
+
- einops==0.3.0
|
24 |
+
- git+https://github.com/openai/CLIP.git
|
25 |
+
- protobuf~=3.20.1
|
26 |
+
- torchmetrics==0.6.0
|
27 |
+
- transformers==4.19.2
|
28 |
+
- kornia==0.6.0
|
29 |
+
- gradio==3.16.0
|
example_component.py
ADDED
@@ -0,0 +1,805 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Defines helper methods useful for loading and caching Interface examples.
|
3 |
+
"""
|
4 |
+
from __future__ import annotations
|
5 |
+
|
6 |
+
import ast
|
7 |
+
import csv
|
8 |
+
import inspect
|
9 |
+
import os
|
10 |
+
import subprocess
|
11 |
+
import tempfile
|
12 |
+
import threading
|
13 |
+
import warnings
|
14 |
+
from pathlib import Path
|
15 |
+
from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Tuple
|
16 |
+
|
17 |
+
import matplotlib
|
18 |
+
import matplotlib.pyplot as plt
|
19 |
+
import numpy as np
|
20 |
+
import PIL
|
21 |
+
import PIL.Image
|
22 |
+
|
23 |
+
from gradio import components, processing_utils, routes, utils
|
24 |
+
from gradio.context import Context
|
25 |
+
from gradio.documentation import document, set_documentation_group
|
26 |
+
from gradio.flagging import CSVLogger
|
27 |
+
|
28 |
+
if TYPE_CHECKING: # Only import for type checking (to avoid circular imports).
|
29 |
+
from gradio.components import IOComponent
|
30 |
+
|
31 |
+
CACHED_FOLDER = "gradio_cached_examples"
|
32 |
+
LOG_FILE = "log.csv"
|
33 |
+
|
34 |
+
set_documentation_group("helpers")
|
35 |
+
|
36 |
+
|
37 |
+
def create_examples(
|
38 |
+
examples: List[Any] | List[List[Any]] | str,
|
39 |
+
inputs: IOComponent | List[IOComponent],
|
40 |
+
outputs: IOComponent | List[IOComponent] | None = None,
|
41 |
+
fn: Callable | None = None,
|
42 |
+
cache_examples: bool = False,
|
43 |
+
examples_per_page: int = 10,
|
44 |
+
_api_mode: bool = False,
|
45 |
+
label: str | None = None,
|
46 |
+
elem_id: str | None = None,
|
47 |
+
run_on_click: bool = False,
|
48 |
+
preprocess: bool = True,
|
49 |
+
postprocess: bool = True,
|
50 |
+
batch: bool = False,
|
51 |
+
):
|
52 |
+
"""Top-level synchronous function that creates Examples. Provided for backwards compatibility, i.e. so that gr.Examples(...) can be used to create the Examples component."""
|
53 |
+
examples_obj = Examples(
|
54 |
+
examples=examples,
|
55 |
+
inputs=inputs,
|
56 |
+
outputs=outputs,
|
57 |
+
fn=fn,
|
58 |
+
cache_examples=cache_examples,
|
59 |
+
examples_per_page=examples_per_page,
|
60 |
+
_api_mode=_api_mode,
|
61 |
+
label=label,
|
62 |
+
elem_id=elem_id,
|
63 |
+
run_on_click=run_on_click,
|
64 |
+
preprocess=preprocess,
|
65 |
+
postprocess=postprocess,
|
66 |
+
batch=batch,
|
67 |
+
_initiated_directly=False,
|
68 |
+
)
|
69 |
+
utils.synchronize_async(examples_obj.create)
|
70 |
+
return examples_obj
|
71 |
+
|
72 |
+
|
73 |
+
class Examples:
|
74 |
+
"""
|
75 |
+
This class is a wrapper over the Dataset component and can be used to create Examples
|
76 |
+
for Blocks / Interfaces. Populates the Dataset component with examples and
|
77 |
+
assigns event listener so that clicking on an example populates the input/output
|
78 |
+
components. Optionally handles example caching for fast inference.
|
79 |
+
|
80 |
+
Demos: blocks_inputs, fake_gan
|
81 |
+
Guides: more_on_examples_and_flagging, using_hugging_face_integrations, image_classification_in_pytorch, image_classification_in_tensorflow, image_classification_with_vision_transformers, create_your_own_friends_with_a_gan
|
82 |
+
"""
|
83 |
+
|
84 |
+
def __init__(
|
85 |
+
self,
|
86 |
+
examples: List[Any] | List[List[Any]] | str,
|
87 |
+
inputs: IOComponent | List[IOComponent],
|
88 |
+
outputs: IOComponent | List[IOComponent] | None = None,
|
89 |
+
fn: Callable | None = None,
|
90 |
+
cache_examples: bool = False,
|
91 |
+
examples_per_page: int = 10,
|
92 |
+
_api_mode: bool = False,
|
93 |
+
label: str | None = "Examples",
|
94 |
+
elem_id: str | None = None,
|
95 |
+
run_on_click: bool = False,
|
96 |
+
preprocess: bool = True,
|
97 |
+
postprocess: bool = True,
|
98 |
+
batch: bool = False,
|
99 |
+
_initiated_directly: bool = True,
|
100 |
+
):
|
101 |
+
"""
|
102 |
+
Parameters:
|
103 |
+
examples: example inputs that can be clicked to populate specific components. Should be nested list, in which the outer list consists of samples and each inner list consists of an input corresponding to each input component. A string path to a directory of examples can also be provided but it should be within the directory with the python file running the gradio app. If there are multiple input components and a directory is provided, a log.csv file must be present in the directory to link corresponding inputs.
|
104 |
+
inputs: the component or list of components corresponding to the examples
|
105 |
+
outputs: optionally, provide the component or list of components corresponding to the output of the examples. Required if `cache` is True.
|
106 |
+
fn: optionally, provide the function to run to generate the outputs corresponding to the examples. Required if `cache` is True.
|
107 |
+
cache_examples: if True, caches examples for fast runtime. If True, then `fn` and `outputs` need to be provided
|
108 |
+
examples_per_page: how many examples to show per page.
|
109 |
+
label: the label to use for the examples component (by default, "Examples")
|
110 |
+
elem_id: an optional string that is assigned as the id of this component in the HTML DOM.
|
111 |
+
run_on_click: if cache_examples is False, clicking on an example does not run the function when an example is clicked. Set this to True to run the function when an example is clicked. Has no effect if cache_examples is True.
|
112 |
+
preprocess: if True, preprocesses the example input before running the prediction function and caching the output. Only applies if cache_examples is True.
|
113 |
+
postprocess: if True, postprocesses the example output after running the prediction function and before caching. Only applies if cache_examples is True.
|
114 |
+
batch: If True, then the function should process a batch of inputs, meaning that it should accept a list of input values for each parameter. Used only if cache_examples is True.
|
115 |
+
"""
|
116 |
+
if _initiated_directly:
|
117 |
+
warnings.warn(
|
118 |
+
"Please use gr.Examples(...) instead of gr.examples.Examples(...) to create the Examples.",
|
119 |
+
)
|
120 |
+
|
121 |
+
if cache_examples and (fn is None or outputs is None):
|
122 |
+
raise ValueError("If caching examples, `fn` and `outputs` must be provided")
|
123 |
+
|
124 |
+
if not isinstance(inputs, list):
|
125 |
+
inputs = [inputs]
|
126 |
+
if outputs and not isinstance(outputs, list):
|
127 |
+
outputs = [outputs]
|
128 |
+
|
129 |
+
working_directory = Path().absolute()
|
130 |
+
|
131 |
+
if examples is None:
|
132 |
+
raise ValueError("The parameter `examples` cannot be None")
|
133 |
+
elif isinstance(examples, list) and (
|
134 |
+
len(examples) == 0 or isinstance(examples[0], list)
|
135 |
+
):
|
136 |
+
pass
|
137 |
+
elif (
|
138 |
+
isinstance(examples, list) and len(inputs) == 1
|
139 |
+
): # If there is only one input component, examples can be provided as a regular list instead of a list of lists
|
140 |
+
examples = [[e] for e in examples]
|
141 |
+
elif isinstance(examples, str):
|
142 |
+
if not Path(examples).exists():
|
143 |
+
raise FileNotFoundError(
|
144 |
+
"Could not find examples directory: " + examples
|
145 |
+
)
|
146 |
+
working_directory = examples
|
147 |
+
if not (Path(examples) / LOG_FILE).exists():
|
148 |
+
if len(inputs) == 1:
|
149 |
+
examples = [[e] for e in os.listdir(examples)]
|
150 |
+
else:
|
151 |
+
raise FileNotFoundError(
|
152 |
+
"Could not find log file (required for multiple inputs): "
|
153 |
+
+ LOG_FILE
|
154 |
+
)
|
155 |
+
else:
|
156 |
+
with open(Path(examples) / LOG_FILE) as logs:
|
157 |
+
examples = list(csv.reader(logs))
|
158 |
+
examples = [
|
159 |
+
examples[i][: len(inputs)] for i in range(1, len(examples))
|
160 |
+
] # remove header and unnecessary columns
|
161 |
+
|
162 |
+
else:
|
163 |
+
raise ValueError(
|
164 |
+
"The parameter `examples` must either be a string directory or a list"
|
165 |
+
"(if there is only 1 input component) or (more generally), a nested "
|
166 |
+
"list, where each sublist represents a set of inputs."
|
167 |
+
)
|
168 |
+
|
169 |
+
input_has_examples = [False] * len(inputs)
|
170 |
+
for example in examples:
|
171 |
+
for idx, example_for_input in enumerate(example):
|
172 |
+
if not (example_for_input is None):
|
173 |
+
try:
|
174 |
+
input_has_examples[idx] = True
|
175 |
+
except IndexError:
|
176 |
+
pass # If there are more example components than inputs, ignore. This can sometimes be intentional (e.g. loading from a log file where outputs and timestamps are also logged)
|
177 |
+
|
178 |
+
inputs_with_examples = [
|
179 |
+
inp for (inp, keep) in zip(inputs, input_has_examples) if keep
|
180 |
+
]
|
181 |
+
non_none_examples = [
|
182 |
+
[ex for (ex, keep) in zip(example, input_has_examples) if keep]
|
183 |
+
for example in examples
|
184 |
+
]
|
185 |
+
|
186 |
+
self.examples = examples
|
187 |
+
self.non_none_examples = non_none_examples
|
188 |
+
self.inputs = inputs
|
189 |
+
self.inputs_with_examples = inputs_with_examples
|
190 |
+
self.outputs = outputs
|
191 |
+
self.fn = fn
|
192 |
+
self.cache_examples = cache_examples
|
193 |
+
self._api_mode = _api_mode
|
194 |
+
self.preprocess = preprocess
|
195 |
+
self.postprocess = postprocess
|
196 |
+
self.batch = batch
|
197 |
+
|
198 |
+
with utils.set_directory(working_directory):
|
199 |
+
self.processed_examples = [
|
200 |
+
[
|
201 |
+
component.postprocess(sample)
|
202 |
+
for component, sample in zip(inputs, example)
|
203 |
+
]
|
204 |
+
for example in examples
|
205 |
+
]
|
206 |
+
self.non_none_processed_examples = [
|
207 |
+
[ex for (ex, keep) in zip(example, input_has_examples) if keep]
|
208 |
+
for example in self.processed_examples
|
209 |
+
]
|
210 |
+
if cache_examples:
|
211 |
+
for example in self.examples:
|
212 |
+
if len([ex for ex in example if ex is not None]) != len(self.inputs):
|
213 |
+
warnings.warn(
|
214 |
+
"Examples are being cached but not all input components have "
|
215 |
+
"example values. This may result in an exception being thrown by "
|
216 |
+
"your function. If you do get an error while caching examples, make "
|
217 |
+
"sure all of your inputs have example values for all of your examples "
|
218 |
+
"or you provide default values for those particular parameters in your function."
|
219 |
+
)
|
220 |
+
break
|
221 |
+
|
222 |
+
with utils.set_directory(working_directory):
|
223 |
+
self.dataset = components.Dataset(
|
224 |
+
components=inputs_with_examples,
|
225 |
+
samples=non_none_examples,
|
226 |
+
type="index",
|
227 |
+
label=label,
|
228 |
+
samples_per_page=examples_per_page,
|
229 |
+
elem_id=elem_id,
|
230 |
+
)
|
231 |
+
|
232 |
+
self.cached_folder = Path(CACHED_FOLDER) / str(self.dataset._id)
|
233 |
+
self.cached_file = Path(self.cached_folder) / "log.csv"
|
234 |
+
self.cache_examples = cache_examples
|
235 |
+
self.run_on_click = run_on_click
|
236 |
+
|
237 |
+
async def create(self) -> None:
|
238 |
+
"""Caches the examples if self.cache_examples is True and creates the Dataset
|
239 |
+
component to hold the examples"""
|
240 |
+
|
241 |
+
async def load_example(example_id):
|
242 |
+
# import pdb; pdb.set_trace()
|
243 |
+
if self.cache_examples:
|
244 |
+
processed_example = self.non_none_processed_examples[
|
245 |
+
example_id
|
246 |
+
] + await self.load_from_cache(example_id)
|
247 |
+
else:
|
248 |
+
processed_example = self.non_none_processed_examples[example_id]
|
249 |
+
return utils.resolve_singleton(processed_example)
|
250 |
+
|
251 |
+
if Context.root_block:
|
252 |
+
if self.cache_examples and self.outputs:
|
253 |
+
targets = self.inputs_with_examples + self.outputs
|
254 |
+
else:
|
255 |
+
targets = self.inputs_with_examples
|
256 |
+
self.dataset.click(
|
257 |
+
load_example,
|
258 |
+
inputs=[self.dataset],
|
259 |
+
outputs=targets, # type: ignore
|
260 |
+
postprocess=False,
|
261 |
+
queue=False,
|
262 |
+
)
|
263 |
+
self.dataset.click(
|
264 |
+
self.fn,
|
265 |
+
inputs=[self.dataset],
|
266 |
+
outputs=targets, # type: ignore
|
267 |
+
postprocess=False,
|
268 |
+
queue=False,
|
269 |
+
)
|
270 |
+
# if self.run_on_click and not self.cache_examples:
|
271 |
+
# if self.fn is None:
|
272 |
+
# raise ValueError("Cannot run_on_click if no function is provided")
|
273 |
+
# self.dataset.click(
|
274 |
+
# self.fn,
|
275 |
+
# inputs=self.inputs, # type: ignore
|
276 |
+
# outputs=self.outputs, # type: ignore
|
277 |
+
# )
|
278 |
+
|
279 |
+
if self.cache_examples:
|
280 |
+
await self.cache()
|
281 |
+
|
282 |
+
async def cache(self) -> None:
|
283 |
+
"""
|
284 |
+
Caches all of the examples so that their predictions can be shown immediately.
|
285 |
+
"""
|
286 |
+
if Path(self.cached_file).exists():
|
287 |
+
print(
|
288 |
+
f"Using cache from '{utils.abspath(self.cached_folder)}' directory. If method or examples have changed since last caching, delete this folder to clear cache."
|
289 |
+
)
|
290 |
+
else:
|
291 |
+
if Context.root_block is None:
|
292 |
+
raise ValueError("Cannot cache examples if not in a Blocks context")
|
293 |
+
|
294 |
+
print(f"Caching examples at: '{utils.abspath(self.cached_folder)}'")
|
295 |
+
cache_logger = CSVLogger()
|
296 |
+
|
297 |
+
# create a fake dependency to process the examples and get the predictions
|
298 |
+
dependency = Context.root_block.set_event_trigger(
|
299 |
+
event_name="fake_event",
|
300 |
+
fn=self.fn,
|
301 |
+
inputs=self.inputs_with_examples, # type: ignore
|
302 |
+
outputs=self.outputs, # type: ignore
|
303 |
+
preprocess=self.preprocess and not self._api_mode,
|
304 |
+
postprocess=self.postprocess and not self._api_mode,
|
305 |
+
batch=self.batch,
|
306 |
+
)
|
307 |
+
|
308 |
+
fn_index = Context.root_block.dependencies.index(dependency)
|
309 |
+
assert self.outputs is not None
|
310 |
+
cache_logger.setup(self.outputs, self.cached_folder)
|
311 |
+
for example_id, _ in enumerate(self.examples):
|
312 |
+
processed_input = self.processed_examples[example_id]
|
313 |
+
if self.batch:
|
314 |
+
processed_input = [[value] for value in processed_input]
|
315 |
+
prediction = await Context.root_block.process_api(
|
316 |
+
fn_index=fn_index, inputs=processed_input, request=None, state={}
|
317 |
+
)
|
318 |
+
output = prediction["data"]
|
319 |
+
if self.batch:
|
320 |
+
output = [value[0] for value in output]
|
321 |
+
cache_logger.flag(output)
|
322 |
+
# Remove the "fake_event" to prevent bugs in loading interfaces from spaces
|
323 |
+
Context.root_block.dependencies.remove(dependency)
|
324 |
+
Context.root_block.fns.pop(fn_index)
|
325 |
+
|
326 |
+
async def load_from_cache(self, example_id: int) -> List[Any]:
|
327 |
+
"""Loads a particular cached example for the interface.
|
328 |
+
Parameters:
|
329 |
+
example_id: The id of the example to process (zero-indexed).
|
330 |
+
"""
|
331 |
+
# import pdb; pdb.set_trace()
|
332 |
+
with open(self.cached_file, encoding="utf-8") as cache:
|
333 |
+
examples = list(csv.reader(cache))
|
334 |
+
example = examples[example_id + 1] # +1 to adjust for header
|
335 |
+
output = []
|
336 |
+
assert self.outputs is not None
|
337 |
+
for component, value in zip(self.outputs, example):
|
338 |
+
try:
|
339 |
+
value_as_dict = ast.literal_eval(value)
|
340 |
+
assert utils.is_update(value_as_dict)
|
341 |
+
output.append(value_as_dict)
|
342 |
+
except (ValueError, TypeError, SyntaxError, AssertionError):
|
343 |
+
output.append(component.serialize(value, self.cached_folder))
|
344 |
+
return output
|
345 |
+
|
346 |
+
|
347 |
+
class TrackedIterable:
|
348 |
+
def __init__(
|
349 |
+
self,
|
350 |
+
iterable: Iterable | None,
|
351 |
+
index: int | None,
|
352 |
+
length: int | None,
|
353 |
+
desc: str | None,
|
354 |
+
unit: str | None,
|
355 |
+
_tqdm=None,
|
356 |
+
progress: float | None = None,
|
357 |
+
) -> None:
|
358 |
+
self.iterable = iterable
|
359 |
+
self.index = index
|
360 |
+
self.length = length
|
361 |
+
self.desc = desc
|
362 |
+
self.unit = unit
|
363 |
+
self._tqdm = _tqdm
|
364 |
+
self.progress = progress
|
365 |
+
|
366 |
+
|
367 |
+
@document("__call__", "tqdm")
|
368 |
+
class Progress(Iterable):
|
369 |
+
"""
|
370 |
+
The Progress class provides a custom progress tracker that is used in a function signature.
|
371 |
+
To attach a Progress tracker to a function, simply add a parameter right after the input parameters that has a default value set to a `gradio.Progress()` instance.
|
372 |
+
The Progress tracker can then be updated in the function by calling the Progress object or using the `tqdm` method on an Iterable.
|
373 |
+
The Progress tracker is currently only available with `queue()`.
|
374 |
+
Example:
|
375 |
+
import gradio as gr
|
376 |
+
import time
|
377 |
+
def my_function(x, progress=gr.Progress()):
|
378 |
+
progress(0, desc="Starting...")
|
379 |
+
time.sleep(1)
|
380 |
+
for i in progress.tqdm(range(100)):
|
381 |
+
time.sleep(0.1)
|
382 |
+
return x
|
383 |
+
gr.Interface(my_function, gr.Textbox(), gr.Textbox()).queue().launch()
|
384 |
+
Demos: progress
|
385 |
+
"""
|
386 |
+
|
387 |
+
def __init__(
|
388 |
+
self,
|
389 |
+
track_tqdm: bool = False,
|
390 |
+
_callback: Callable | None = None, # for internal use only
|
391 |
+
_event_id: str | None = None,
|
392 |
+
):
|
393 |
+
"""
|
394 |
+
Parameters:
|
395 |
+
track_tqdm: If True, the Progress object will track any tqdm.tqdm iterations with the tqdm library in the function.
|
396 |
+
"""
|
397 |
+
self.track_tqdm = track_tqdm
|
398 |
+
self._callback = _callback
|
399 |
+
self._event_id = _event_id
|
400 |
+
self.iterables: List[TrackedIterable] = []
|
401 |
+
|
402 |
+
def __len__(self):
|
403 |
+
return self.iterables[-1].length
|
404 |
+
|
405 |
+
def __iter__(self):
|
406 |
+
return self
|
407 |
+
|
408 |
+
def __next__(self):
|
409 |
+
"""
|
410 |
+
Updates progress tracker with next item in iterable.
|
411 |
+
"""
|
412 |
+
if self._callback:
|
413 |
+
current_iterable = self.iterables[-1]
|
414 |
+
while (
|
415 |
+
not hasattr(current_iterable.iterable, "__next__")
|
416 |
+
and len(self.iterables) > 0
|
417 |
+
):
|
418 |
+
current_iterable = self.iterables.pop()
|
419 |
+
self._callback(
|
420 |
+
event_id=self._event_id,
|
421 |
+
iterables=self.iterables,
|
422 |
+
)
|
423 |
+
assert current_iterable.index is not None, "Index not set."
|
424 |
+
current_iterable.index += 1
|
425 |
+
try:
|
426 |
+
return next(current_iterable.iterable) # type: ignore
|
427 |
+
except StopIteration:
|
428 |
+
self.iterables.pop()
|
429 |
+
raise StopIteration
|
430 |
+
else:
|
431 |
+
return self
|
432 |
+
|
433 |
+
def __call__(
|
434 |
+
self,
|
435 |
+
progress: float | Tuple[int, int | None] | None,
|
436 |
+
desc: str | None = None,
|
437 |
+
total: int | None = None,
|
438 |
+
unit: str = "steps",
|
439 |
+
_tqdm=None,
|
440 |
+
):
|
441 |
+
"""
|
442 |
+
Updates progress tracker with progress and message text.
|
443 |
+
Parameters:
|
444 |
+
progress: If float, should be between 0 and 1 representing completion. If Tuple, first number represents steps completed, and second value represents total steps or None if unknown. If None, hides progress bar.
|
445 |
+
desc: description to display.
|
446 |
+
total: estimated total number of steps.
|
447 |
+
unit: unit of iterations.
|
448 |
+
"""
|
449 |
+
if self._callback:
|
450 |
+
if isinstance(progress, tuple):
|
451 |
+
index, total = progress
|
452 |
+
progress = None
|
453 |
+
else:
|
454 |
+
index = None
|
455 |
+
self._callback(
|
456 |
+
event_id=self._event_id,
|
457 |
+
iterables=self.iterables
|
458 |
+
+ [TrackedIterable(None, index, total, desc, unit, _tqdm, progress)],
|
459 |
+
)
|
460 |
+
else:
|
461 |
+
return progress
|
462 |
+
|
463 |
+
def tqdm(
|
464 |
+
self,
|
465 |
+
iterable: Iterable | None,
|
466 |
+
desc: str | None = None,
|
467 |
+
total: int | None = None,
|
468 |
+
unit: str = "steps",
|
469 |
+
_tqdm=None,
|
470 |
+
*args,
|
471 |
+
**kwargs,
|
472 |
+
):
|
473 |
+
"""
|
474 |
+
Attaches progress tracker to iterable, like tqdm.
|
475 |
+
Parameters:
|
476 |
+
iterable: iterable to attach progress tracker to.
|
477 |
+
desc: description to display.
|
478 |
+
total: estimated total number of steps.
|
479 |
+
unit: unit of iterations.
|
480 |
+
"""
|
481 |
+
if self._callback:
|
482 |
+
if iterable is None:
|
483 |
+
new_iterable = TrackedIterable(None, 0, total, desc, unit, _tqdm)
|
484 |
+
self.iterables.append(new_iterable)
|
485 |
+
self._callback(event_id=self._event_id, iterables=self.iterables)
|
486 |
+
return self
|
487 |
+
length = len(iterable) if hasattr(iterable, "__len__") else None # type: ignore
|
488 |
+
self.iterables.append(
|
489 |
+
TrackedIterable(iter(iterable), 0, length, desc, unit, _tqdm)
|
490 |
+
)
|
491 |
+
return self
|
492 |
+
|
493 |
+
def update(self, n=1):
|
494 |
+
"""
|
495 |
+
Increases latest iterable with specified number of steps.
|
496 |
+
Parameters:
|
497 |
+
n: number of steps completed.
|
498 |
+
"""
|
499 |
+
if self._callback and len(self.iterables) > 0:
|
500 |
+
current_iterable = self.iterables[-1]
|
501 |
+
assert current_iterable.index is not None, "Index not set."
|
502 |
+
current_iterable.index += n
|
503 |
+
self._callback(
|
504 |
+
event_id=self._event_id,
|
505 |
+
iterables=self.iterables,
|
506 |
+
)
|
507 |
+
else:
|
508 |
+
return
|
509 |
+
|
510 |
+
def close(self, _tqdm):
|
511 |
+
"""
|
512 |
+
Removes iterable with given _tqdm.
|
513 |
+
"""
|
514 |
+
if self._callback:
|
515 |
+
for i in range(len(self.iterables)):
|
516 |
+
if id(self.iterables[i]._tqdm) == id(_tqdm):
|
517 |
+
self.iterables.pop(i)
|
518 |
+
break
|
519 |
+
self._callback(
|
520 |
+
event_id=self._event_id,
|
521 |
+
iterables=self.iterables,
|
522 |
+
)
|
523 |
+
else:
|
524 |
+
return
|
525 |
+
|
526 |
+
|
527 |
+
def create_tracker(root_blocks, event_id, fn, track_tqdm):
|
528 |
+
|
529 |
+
progress = Progress(_callback=root_blocks._queue.set_progress, _event_id=event_id)
|
530 |
+
if not track_tqdm:
|
531 |
+
return progress, fn
|
532 |
+
|
533 |
+
try:
|
534 |
+
_tqdm = __import__("tqdm")
|
535 |
+
except ModuleNotFoundError:
|
536 |
+
return progress, fn
|
537 |
+
if not hasattr(root_blocks, "_progress_tracker_per_thread"):
|
538 |
+
root_blocks._progress_tracker_per_thread = {}
|
539 |
+
|
540 |
+
def init_tqdm(self, iterable=None, desc=None, *args, **kwargs):
|
541 |
+
self._progress = root_blocks._progress_tracker_per_thread.get(
|
542 |
+
threading.get_ident()
|
543 |
+
)
|
544 |
+
if self._progress is not None:
|
545 |
+
self._progress.event_id = event_id
|
546 |
+
self._progress.tqdm(iterable, desc, _tqdm=self, *args, **kwargs)
|
547 |
+
kwargs["file"] = open(os.devnull, "w")
|
548 |
+
self.__init__orig__(iterable, desc, *args, **kwargs)
|
549 |
+
|
550 |
+
def iter_tqdm(self):
|
551 |
+
if self._progress is not None:
|
552 |
+
return self._progress
|
553 |
+
else:
|
554 |
+
return self.__iter__orig__()
|
555 |
+
|
556 |
+
def update_tqdm(self, n=1):
|
557 |
+
if self._progress is not None:
|
558 |
+
self._progress.update(n)
|
559 |
+
return self.__update__orig__(n)
|
560 |
+
|
561 |
+
def close_tqdm(self):
|
562 |
+
if self._progress is not None:
|
563 |
+
self._progress.close(self)
|
564 |
+
return self.__close__orig__()
|
565 |
+
|
566 |
+
def exit_tqdm(self, exc_type, exc_value, traceback):
|
567 |
+
if self._progress is not None:
|
568 |
+
self._progress.close(self)
|
569 |
+
return self.__exit__orig__(exc_type, exc_value, traceback)
|
570 |
+
|
571 |
+
if not hasattr(_tqdm.tqdm, "__init__orig__"):
|
572 |
+
_tqdm.tqdm.__init__orig__ = _tqdm.tqdm.__init__
|
573 |
+
_tqdm.tqdm.__init__ = init_tqdm
|
574 |
+
if not hasattr(_tqdm.tqdm, "__update__orig__"):
|
575 |
+
_tqdm.tqdm.__update__orig__ = _tqdm.tqdm.update
|
576 |
+
_tqdm.tqdm.update = update_tqdm
|
577 |
+
if not hasattr(_tqdm.tqdm, "__close__orig__"):
|
578 |
+
_tqdm.tqdm.__close__orig__ = _tqdm.tqdm.close
|
579 |
+
_tqdm.tqdm.close = close_tqdm
|
580 |
+
if not hasattr(_tqdm.tqdm, "__exit__orig__"):
|
581 |
+
_tqdm.tqdm.__exit__orig__ = _tqdm.tqdm.__exit__
|
582 |
+
_tqdm.tqdm.__exit__ = exit_tqdm
|
583 |
+
if not hasattr(_tqdm.tqdm, "__iter__orig__"):
|
584 |
+
_tqdm.tqdm.__iter__orig__ = _tqdm.tqdm.__iter__
|
585 |
+
_tqdm.tqdm.__iter__ = iter_tqdm
|
586 |
+
if hasattr(_tqdm, "auto") and hasattr(_tqdm.auto, "tqdm"):
|
587 |
+
_tqdm.auto.tqdm = _tqdm.tqdm
|
588 |
+
|
589 |
+
def tracked_fn(*args):
|
590 |
+
thread_id = threading.get_ident()
|
591 |
+
root_blocks._progress_tracker_per_thread[thread_id] = progress
|
592 |
+
response = fn(*args)
|
593 |
+
del root_blocks._progress_tracker_per_thread[thread_id]
|
594 |
+
return response
|
595 |
+
|
596 |
+
return progress, tracked_fn
|
597 |
+
|
598 |
+
|
599 |
+
def special_args(
|
600 |
+
fn: Callable,
|
601 |
+
inputs: List[Any] | None = None,
|
602 |
+
request: routes.Request | None = None,
|
603 |
+
):
|
604 |
+
"""
|
605 |
+
Checks if function has special arguments Request (via annotation) or Progress (via default value).
|
606 |
+
If inputs is provided, these values will be loaded into the inputs array.
|
607 |
+
Parameters:
|
608 |
+
block_fn: function to check.
|
609 |
+
inputs: array to load special arguments into.
|
610 |
+
request: request to load into inputs.
|
611 |
+
Returns:
|
612 |
+
updated inputs, request index, progress index
|
613 |
+
"""
|
614 |
+
signature = inspect.signature(fn)
|
615 |
+
positional_args = []
|
616 |
+
for i, param in enumerate(signature.parameters.values()):
|
617 |
+
if param.kind not in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD):
|
618 |
+
break
|
619 |
+
positional_args.append(param)
|
620 |
+
progress_index = None
|
621 |
+
for i, param in enumerate(positional_args):
|
622 |
+
if isinstance(param.default, Progress):
|
623 |
+
progress_index = i
|
624 |
+
if inputs is not None:
|
625 |
+
inputs.insert(i, param.default)
|
626 |
+
elif param.annotation == routes.Request:
|
627 |
+
if inputs is not None:
|
628 |
+
inputs.insert(i, request)
|
629 |
+
if inputs is not None:
|
630 |
+
while len(inputs) < len(positional_args):
|
631 |
+
i = len(inputs)
|
632 |
+
param = positional_args[i]
|
633 |
+
if param.default == param.empty:
|
634 |
+
warnings.warn("Unexpected argument. Filling with None.")
|
635 |
+
inputs.append(None)
|
636 |
+
else:
|
637 |
+
inputs.append(param.default)
|
638 |
+
return inputs or [], progress_index
|
639 |
+
|
640 |
+
|
641 |
+
@document()
|
642 |
+
def update(**kwargs) -> dict:
|
643 |
+
"""
|
644 |
+
Updates component properties. When a function passed into a Gradio Interface or a Blocks events returns a typical value, it updates the value of the output component. But it is also possible to update the properties of an output component (such as the number of lines of a `Textbox` or the visibility of an `Image`) by returning the component's `update()` function, which takes as parameters any of the constructor parameters for that component.
|
645 |
+
This is a shorthand for using the update method on a component.
|
646 |
+
For example, rather than using gr.Number.update(...) you can just use gr.update(...).
|
647 |
+
Note that your editor's autocompletion will suggest proper parameters
|
648 |
+
if you use the update method on the component.
|
649 |
+
Demos: blocks_essay, blocks_update, blocks_essay_update
|
650 |
+
|
651 |
+
Parameters:
|
652 |
+
kwargs: Key-word arguments used to update the component's properties.
|
653 |
+
Example:
|
654 |
+
# Blocks Example
|
655 |
+
import gradio as gr
|
656 |
+
with gr.Blocks() as demo:
|
657 |
+
radio = gr.Radio([1, 2, 4], label="Set the value of the number")
|
658 |
+
number = gr.Number(value=2, interactive=True)
|
659 |
+
radio.change(fn=lambda value: gr.update(value=value), inputs=radio, outputs=number)
|
660 |
+
demo.launch()
|
661 |
+
|
662 |
+
# Interface example
|
663 |
+
import gradio as gr
|
664 |
+
def change_textbox(choice):
|
665 |
+
if choice == "short":
|
666 |
+
return gr.Textbox.update(lines=2, visible=True)
|
667 |
+
elif choice == "long":
|
668 |
+
return gr.Textbox.update(lines=8, visible=True)
|
669 |
+
else:
|
670 |
+
return gr.Textbox.update(visible=False)
|
671 |
+
gr.Interface(
|
672 |
+
change_textbox,
|
673 |
+
gr.Radio(
|
674 |
+
["short", "long", "none"], label="What kind of essay would you like to write?"
|
675 |
+
),
|
676 |
+
gr.Textbox(lines=2),
|
677 |
+
live=True,
|
678 |
+
).launch()
|
679 |
+
"""
|
680 |
+
kwargs["__type__"] = "generic_update"
|
681 |
+
return kwargs
|
682 |
+
|
683 |
+
|
684 |
+
def skip() -> dict:
|
685 |
+
return update()
|
686 |
+
|
687 |
+
|
688 |
+
@document()
|
689 |
+
def make_waveform(
|
690 |
+
audio: str | Tuple[int, np.ndarray],
|
691 |
+
*,
|
692 |
+
bg_color: str = "#f3f4f6",
|
693 |
+
bg_image: str | None = None,
|
694 |
+
fg_alpha: float = 0.75,
|
695 |
+
bars_color: str | Tuple[str, str] = ("#fbbf24", "#ea580c"),
|
696 |
+
bar_count: int = 50,
|
697 |
+
bar_width: float = 0.6,
|
698 |
+
):
|
699 |
+
"""
|
700 |
+
Generates a waveform video from an audio file. Useful for creating an easy to share audio visualization. The output should be passed into a `gr.Video` component.
|
701 |
+
Parameters:
|
702 |
+
audio: Audio file path or tuple of (sample_rate, audio_data)
|
703 |
+
bg_color: Background color of waveform (ignored if bg_image is provided)
|
704 |
+
bg_image: Background image of waveform
|
705 |
+
fg_alpha: Opacity of foreground waveform
|
706 |
+
bars_color: Color of waveform bars. Can be a single color or a tuple of (start_color, end_color) of gradient
|
707 |
+
bar_count: Number of bars in waveform
|
708 |
+
bar_width: Width of bars in waveform. 1 represents full width, 0.5 represents half width, etc.
|
709 |
+
Returns:
|
710 |
+
A filepath to the output video.
|
711 |
+
"""
|
712 |
+
if isinstance(audio, str):
|
713 |
+
audio_file = audio
|
714 |
+
audio = processing_utils.audio_from_file(audio)
|
715 |
+
else:
|
716 |
+
tmp_wav = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)
|
717 |
+
processing_utils.audio_to_file(audio[0], audio[1], tmp_wav.name)
|
718 |
+
audio_file = tmp_wav.name
|
719 |
+
duration = round(len(audio[1]) / audio[0], 4)
|
720 |
+
|
721 |
+
# Helper methods to create waveform
|
722 |
+
def hex_to_RGB(hex_str):
|
723 |
+
return [int(hex_str[i : i + 2], 16) for i in range(1, 6, 2)]
|
724 |
+
|
725 |
+
def get_color_gradient(c1, c2, n):
|
726 |
+
assert n > 1
|
727 |
+
c1_rgb = np.array(hex_to_RGB(c1)) / 255
|
728 |
+
c2_rgb = np.array(hex_to_RGB(c2)) / 255
|
729 |
+
mix_pcts = [x / (n - 1) for x in range(n)]
|
730 |
+
rgb_colors = [((1 - mix) * c1_rgb + (mix * c2_rgb)) for mix in mix_pcts]
|
731 |
+
return [
|
732 |
+
"#" + "".join([format(int(round(val * 255)), "02x") for val in item])
|
733 |
+
for item in rgb_colors
|
734 |
+
]
|
735 |
+
|
736 |
+
# Reshape audio to have a fixed number of bars
|
737 |
+
samples = audio[1]
|
738 |
+
if len(samples.shape) > 1:
|
739 |
+
samples = np.mean(samples, 1)
|
740 |
+
bins_to_pad = bar_count - (len(samples) % bar_count)
|
741 |
+
samples = np.pad(samples, [(0, bins_to_pad)])
|
742 |
+
samples = np.reshape(samples, (bar_count, -1))
|
743 |
+
samples = np.abs(samples)
|
744 |
+
samples = np.max(samples, 1)
|
745 |
+
|
746 |
+
matplotlib.use("Agg")
|
747 |
+
plt.clf()
|
748 |
+
# Plot waveform
|
749 |
+
color = (
|
750 |
+
bars_color
|
751 |
+
if isinstance(bars_color, str)
|
752 |
+
else get_color_gradient(bars_color[0], bars_color[1], bar_count)
|
753 |
+
)
|
754 |
+
plt.bar(
|
755 |
+
np.arange(0, bar_count),
|
756 |
+
samples * 2,
|
757 |
+
bottom=(-1 * samples),
|
758 |
+
width=bar_width,
|
759 |
+
color=color,
|
760 |
+
)
|
761 |
+
plt.axis("off")
|
762 |
+
plt.margins(x=0)
|
763 |
+
tmp_img = tempfile.NamedTemporaryFile(suffix=".png", delete=False)
|
764 |
+
savefig_kwargs: Dict[str, Any] = {"bbox_inches": "tight"}
|
765 |
+
if bg_image is not None:
|
766 |
+
savefig_kwargs["transparent"] = True
|
767 |
+
else:
|
768 |
+
savefig_kwargs["facecolor"] = bg_color
|
769 |
+
plt.savefig(tmp_img.name, **savefig_kwargs)
|
770 |
+
waveform_img = PIL.Image.open(tmp_img.name)
|
771 |
+
waveform_img = waveform_img.resize((1000, 200))
|
772 |
+
|
773 |
+
# Composite waveform with background image
|
774 |
+
if bg_image is not None:
|
775 |
+
waveform_array = np.array(waveform_img)
|
776 |
+
waveform_array[:, :, 3] = waveform_array[:, :, 3] * fg_alpha
|
777 |
+
waveform_img = PIL.Image.fromarray(waveform_array)
|
778 |
+
|
779 |
+
bg_img = PIL.Image.open(bg_image)
|
780 |
+
waveform_width, waveform_height = waveform_img.size
|
781 |
+
bg_width, bg_height = bg_img.size
|
782 |
+
if waveform_width != bg_width:
|
783 |
+
bg_img = bg_img.resize(
|
784 |
+
(waveform_width, 2 * int(bg_height * waveform_width / bg_width / 2))
|
785 |
+
)
|
786 |
+
bg_width, bg_height = bg_img.size
|
787 |
+
composite_height = max(bg_height, waveform_height)
|
788 |
+
composite = PIL.Image.new("RGBA", (waveform_width, composite_height), "#FFFFFF")
|
789 |
+
composite.paste(bg_img, (0, composite_height - bg_height))
|
790 |
+
composite.paste(
|
791 |
+
waveform_img, (0, composite_height - waveform_height), waveform_img
|
792 |
+
)
|
793 |
+
composite.save(tmp_img.name)
|
794 |
+
img_width, img_height = composite.size
|
795 |
+
else:
|
796 |
+
img_width, img_height = waveform_img.size
|
797 |
+
waveform_img.save(tmp_img.name)
|
798 |
+
|
799 |
+
# Convert waveform to video with ffmpeg
|
800 |
+
output_mp4 = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
|
801 |
+
|
802 |
+
ffmpeg_cmd = f"""ffmpeg -loop 1 -i {tmp_img.name} -i {audio_file} -vf "color=c=#FFFFFF77:s={img_width}x{img_height}[bar];[0][bar]overlay=-w+(w/{duration})*t:H-h:shortest=1" -t {duration} -y {output_mp4.name}"""
|
803 |
+
|
804 |
+
subprocess.call(ffmpeg_cmd, shell=True)
|
805 |
+
return output_mp4.name
|
gligen/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
gligen/SD_input_conv_weight_bias.pth
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:b5a0efad69747a766158304f39091c2b6a24cafb5f833d174f32bee8e864a562
|
3 |
+
size 130
|
gligen/__init__.py
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import os, sys
|
3 |
+
sys.path.append(os.path.dirname(__file__))
|
4 |
+
sys.path.append(os.path.join(os.path.dirname(__file__), "ldm"))
|
5 |
+
|
6 |
+
import gligen.evaluator as evaluator
|
7 |
+
import gligen.trainer as trainer
|
8 |
+
|
9 |
+
|
10 |
+
# import gligen.ldm as ldm
|
gligen/__pycache__/__init__.cpython-38.pyc
ADDED
Binary file (345 Bytes). View file
|
|
gligen/__pycache__/distributed.cpython-38.pyc
ADDED
Binary file (2.91 kB). View file
|
|
gligen/__pycache__/evaluator.cpython-38.pyc
ADDED
Binary file (5.9 kB). View file
|
|
gligen/__pycache__/task_grounded_generation.cpython-38.pyc
ADDED
Binary file (9.11 kB). View file
|
|
gligen/__pycache__/trainer.cpython-38.pyc
ADDED
Binary file (11.7 kB). View file
|
|
gligen/create_meta.py
ADDED
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
CKPTS = [
|
2 |
+
|
3 |
+
dict(
|
4 |
+
path="/home/chunyl/azure_mount/yuhengdb/fine_tune_ldm/version5_branch6_output/GoldG+SBU+CC3M+CC12M+O365/second_stage_drop_both/tag01/checkpoint_00450001.pth",
|
5 |
+
feature_type=['before','after_reproject'],
|
6 |
+
save_folder_name="v5b6_drop_both",
|
7 |
+
),
|
8 |
+
|
9 |
+
|
10 |
+
# dict(
|
11 |
+
# path="/home/v-yuhengli/blobfuse/output/fine_tune_ldm/version5_branch6_output/GoldG+SBU+CC3M+CC12M+O365/second_stage_drop_none/tag00/checkpoint_00165001.pth",
|
12 |
+
# feature_type=['before','after_reproject'],
|
13 |
+
# save_folder_name="v5b6_drop_none",
|
14 |
+
# ),
|
15 |
+
|
16 |
+
|
17 |
+
|
18 |
+
|
19 |
+
|
20 |
+
]
|
21 |
+
|
22 |
+
|
23 |
+
|
24 |
+
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = #
|
25 |
+
|
26 |
+
|
27 |
+
|
28 |
+
|
29 |
+
|
30 |
+
|
31 |
+
|
32 |
+
|
33 |
+
# if meta["has_image_mask"] == 0:
|
34 |
+
# image_embeddings = text_embeddings
|
35 |
+
# if meta["has_text_mask"] == 0:
|
36 |
+
# text_embeddings = image_embeddings
|
37 |
+
|
38 |
+
# out = {
|
39 |
+
# "boxes" : boxes.unsqueeze(0).repeat(batch,1,1),
|
40 |
+
# "masks" : masks.unsqueeze(0).repeat(batch,1),
|
41 |
+
# "text_masks" : masks.unsqueeze(0).repeat(batch,1),
|
42 |
+
# "image_masks" : masks.unsqueeze(0).repeat(batch,1),
|
43 |
+
# "text_embeddings" : text_embeddings.unsqueeze(0).repeat(batch,1,1),
|
44 |
+
# "image_embeddings" : image_embeddings.unsqueeze(0).repeat(batch,1,1)
|
45 |
+
# }
|
46 |
+
|
47 |
+
|
48 |
+
|
49 |
+
|
50 |
+
|
51 |
+
|
52 |
+
|
53 |
+
META = [
|
54 |
+
|
55 |
+
|
56 |
+
dict(
|
57 |
+
prompt = "a teddy bear sitting next to a red bird",
|
58 |
+
phrases = ['a teddy bear', 'a red bird'],
|
59 |
+
images = ['images/teddy.jpg', 'images/red_bird.jpg'],
|
60 |
+
locations = [ [0.0,0.09,0.33,0.76], [0.55,0.11,1.0,0.8] ],
|
61 |
+
alpha_type = [1.0, 0, 0.0],
|
62 |
+
has_text_mask = 1,
|
63 |
+
has_image_mask = 0,
|
64 |
+
save_folder_name="teddy_bird_1_1"
|
65 |
+
),
|
66 |
+
|
67 |
+
|
68 |
+
# dict(
|
69 |
+
# prompt = "a teddy bear sitting next to a bird",
|
70 |
+
# phrases = ['a teddy bear', 'a bird'],
|
71 |
+
# images = ['images/teddy.jpg', 'images/red_bird.jpg'],
|
72 |
+
# locations = [ [0.0,0.09,0.33,0.76], [0.55,0.11,1.0,0.8] ],
|
73 |
+
# alpha_type = [1.0, 0, 0.0],
|
74 |
+
# has_text_mask = 1,
|
75 |
+
# has_image_mask = 1,
|
76 |
+
# save_folder_name="teddy_bird_1_1"
|
77 |
+
# ),
|
78 |
+
|
79 |
+
|
80 |
+
# dict(
|
81 |
+
# prompt = "a teddy bear sitting next to a bird",
|
82 |
+
# phrases = ['a teddy bear', 'a bird'],
|
83 |
+
# images = ['images/teddy.jpg', 'images/red_bird.jpg'],
|
84 |
+
# locations = [ [0.0,0.09,0.33,0.76], [0.55,0.11,1.0,0.8] ],
|
85 |
+
# alpha_type = [0.5, 0, 0.5],
|
86 |
+
# has_text_mask = 1,
|
87 |
+
# has_image_mask = 0,
|
88 |
+
# save_folder_name="teddy_bird_1_0"
|
89 |
+
# ),
|
90 |
+
|
91 |
+
# dict(
|
92 |
+
# prompt = "",
|
93 |
+
# phrases = ['a teddy bear', 'an umbrella'],
|
94 |
+
# images = ['images/teddy.jpg', 'images/umbrella.png'],
|
95 |
+
# locations = [ [0.0,0.09,0.33,0.76], [0.55,0.11,1.0,0.8] ],
|
96 |
+
# alpha_type = [1.0, 0, 0.0],
|
97 |
+
# has_text_mask = 1,
|
98 |
+
# has_image_mask = 1,
|
99 |
+
# save_folder_name="empty_teddy_umbrella_1_1"
|
100 |
+
# ),
|
101 |
+
|
102 |
+
# dict(
|
103 |
+
# prompt = "hello kitty and bird hybrid",
|
104 |
+
# phrases = ['a hello kitty', 'a hello kitty'],
|
105 |
+
# images = ['images/red_bird.jpg', 'images/red_bird.jpg'],
|
106 |
+
# locations = [ [0.0,0.09,0.33,0.76], [0.55,0.11,1.0,0.8] ],
|
107 |
+
# has_text_mask = 1,
|
108 |
+
# has_image_mask = 1,
|
109 |
+
# save_folder_name="hello+bird_1_1"
|
110 |
+
# ),
|
111 |
+
|
112 |
+
# dict(
|
113 |
+
# prompt = "hello kitty and teddy bear hybrid",
|
114 |
+
# phrases = ['a hello kitty', 'a hello kitty'],
|
115 |
+
# images = ['images/teddy.jpg', 'images/teddy.jpg'],
|
116 |
+
# locations = [ [0.0,0.09,0.33,0.76], [0.55,0.11,1.0,0.8] ],
|
117 |
+
# has_text_mask = 1,
|
118 |
+
# has_image_mask = 1,
|
119 |
+
# save_folder_name="hello+teddy_1_1"
|
120 |
+
# ),
|
121 |
+
|
122 |
+
# dict(
|
123 |
+
# prompt = "bird and hello kitty hybrid",
|
124 |
+
# phrases = ['a bird', 'a bird'],
|
125 |
+
# images = ['images/hello.jpg', 'images/hello.jpg'],
|
126 |
+
# locations = [ [0.0,0.09,0.33,0.76], [0.55,0.11,1.0,0.8] ],
|
127 |
+
# alpha_type = [1.0, 0, 0.0],
|
128 |
+
# has_text_mask = 1,
|
129 |
+
# has_image_mask = 0.5,
|
130 |
+
# save_folder_name="bird+hello_1_1"
|
131 |
+
# ),
|
132 |
+
|
133 |
+
|
134 |
+
|
135 |
+
# dict(
|
136 |
+
# prompt = "a deer standing in front of a brick house in the woods, anime, oil painting, high resolution, cottagecore, ghibli inspired, 4k",
|
137 |
+
# phrases = ['a deer'],
|
138 |
+
# images = ['images/sky.jpg'],
|
139 |
+
# locations = [ [0.0,0.5,0.5,0.9] ],
|
140 |
+
# alpha_type = [1, 0, 0],
|
141 |
+
# has_text_mask = 1,
|
142 |
+
# has_image_mask = 1,
|
143 |
+
# save_folder_name="deer_sky"
|
144 |
+
# ),
|
145 |
+
|
146 |
+
|
147 |
+
# dict(
|
148 |
+
# prompt = "A woman sitting in a restaurant with a slice of pizza in front of her",
|
149 |
+
# phrases = ['dining table', 'pizza', 'person', 'wall', 'car', 'paper', 'chair', 'window', 'bottle', 'cup'],
|
150 |
+
# images = ['images/hello.jpg','images/hello.jpg','images/hello.jpg','images/hello.jpg','images/hello.jpg','images/hello.jpg','images/hello.jpg','images/hello.jpg','images/hello.jpg','images/hello.jpg'],
|
151 |
+
# locations = [ [0.0030, 0.3589, 1.0000, 1.0000],
|
152 |
+
# [0.0779, 0.6744, 0.9768, 1.0000],
|
153 |
+
# [0.2236, 0.0000, 0.7809, 0.4352],
|
154 |
+
# [0.0000, 0.0000, 0.4313, 0.4505],
|
155 |
+
# [0.6275, 0.1050, 0.9444, 0.2497],
|
156 |
+
# [0.0000, 0.3859, 0.1250, 0.6922],
|
157 |
+
# [0.7137, 0.2389, 0.8540, 0.4549],
|
158 |
+
# [0.0000, 0.0000, 0.4667, 0.0630],
|
159 |
+
# [0.3822, 0.4235, 0.4932, 0.6575],
|
160 |
+
# [0.6616, 0.3617, 0.7880, 0.5165] ],
|
161 |
+
# alpha_type = [0.0, 0, 1.0],
|
162 |
+
# has_text_mask = 1,
|
163 |
+
# has_image_mask = 0,
|
164 |
+
# save_folder_name="pizza_1_0"
|
165 |
+
# ),
|
166 |
+
|
167 |
+
|
168 |
+
|
169 |
+
|
170 |
+
]
|
gligen/distributed.py
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import math
|
2 |
+
import pickle
|
3 |
+
|
4 |
+
import torch
|
5 |
+
from torch import distributed as dist
|
6 |
+
from torch.utils.data.sampler import Sampler
|
7 |
+
|
8 |
+
|
9 |
+
def get_rank():
|
10 |
+
if not dist.is_available():
|
11 |
+
return 0
|
12 |
+
|
13 |
+
if not dist.is_initialized():
|
14 |
+
return 0
|
15 |
+
|
16 |
+
return dist.get_rank()
|
17 |
+
|
18 |
+
|
19 |
+
def synchronize():
|
20 |
+
if not dist.is_available():
|
21 |
+
return
|
22 |
+
if not dist.is_initialized():
|
23 |
+
return
|
24 |
+
|
25 |
+
world_size = dist.get_world_size()
|
26 |
+
if world_size == 1:
|
27 |
+
return
|
28 |
+
|
29 |
+
dist.barrier()
|
30 |
+
|
31 |
+
|
32 |
+
def get_world_size():
|
33 |
+
if not dist.is_available():
|
34 |
+
return 1
|
35 |
+
if not dist.is_initialized():
|
36 |
+
return 1
|
37 |
+
return dist.get_world_size()
|
38 |
+
|
39 |
+
|
40 |
+
def reduce_sum(tensor):
|
41 |
+
if not dist.is_available():
|
42 |
+
return tensor
|
43 |
+
|
44 |
+
if not dist.is_initialized():
|
45 |
+
return tensor
|
46 |
+
|
47 |
+
tensor = tensor.clone()
|
48 |
+
dist.all_reduce(tensor, op=dist.ReduceOp.SUM)
|
49 |
+
|
50 |
+
return tensor
|
51 |
+
|
52 |
+
|
53 |
+
def gather_grad(params):
|
54 |
+
world_size = get_world_size()
|
55 |
+
|
56 |
+
if world_size == 1:
|
57 |
+
return
|
58 |
+
|
59 |
+
for param in params:
|
60 |
+
if param.grad is not None:
|
61 |
+
dist.all_reduce(param.grad.data, op=dist.ReduceOp.SUM)
|
62 |
+
param.grad.data.div_(world_size)
|
63 |
+
|
64 |
+
|
65 |
+
def all_gather(data):
|
66 |
+
world_size = get_world_size()
|
67 |
+
|
68 |
+
if world_size == 1:
|
69 |
+
return [data]
|
70 |
+
|
71 |
+
buffer = pickle.dumps(data)
|
72 |
+
storage = torch.ByteStorage.from_buffer(buffer)
|
73 |
+
tensor = torch.ByteTensor(storage).to('cuda')
|
74 |
+
|
75 |
+
local_size = torch.IntTensor([tensor.numel()]).to('cuda')
|
76 |
+
size_list = [torch.IntTensor([0]).to('cuda') for _ in range(world_size)]
|
77 |
+
dist.all_gather(size_list, local_size)
|
78 |
+
size_list = [int(size.item()) for size in size_list]
|
79 |
+
max_size = max(size_list)
|
80 |
+
|
81 |
+
tensor_list = []
|
82 |
+
for _ in size_list:
|
83 |
+
tensor_list.append(torch.ByteTensor(size=(max_size,)).to('cuda'))
|
84 |
+
|
85 |
+
if local_size != max_size:
|
86 |
+
padding = torch.ByteTensor(size=(max_size - local_size,)).to('cuda')
|
87 |
+
tensor = torch.cat((tensor, padding), 0)
|
88 |
+
|
89 |
+
dist.all_gather(tensor_list, tensor)
|
90 |
+
|
91 |
+
data_list = []
|
92 |
+
|
93 |
+
for size, tensor in zip(size_list, tensor_list):
|
94 |
+
buffer = tensor.cpu().numpy().tobytes()[:size]
|
95 |
+
data_list.append(pickle.loads(buffer))
|
96 |
+
|
97 |
+
return data_list
|
98 |
+
|
99 |
+
|
100 |
+
def reduce_loss_dict(loss_dict):
|
101 |
+
world_size = get_world_size()
|
102 |
+
|
103 |
+
if world_size < 2:
|
104 |
+
return loss_dict
|
105 |
+
|
106 |
+
with torch.no_grad():
|
107 |
+
keys = []
|
108 |
+
losses = []
|
109 |
+
|
110 |
+
for k in sorted(loss_dict.keys()):
|
111 |
+
keys.append(k)
|
112 |
+
losses.append(loss_dict[k])
|
113 |
+
|
114 |
+
losses = torch.stack(losses, 0)
|
115 |
+
dist.reduce(losses, dst=0)
|
116 |
+
|
117 |
+
if dist.get_rank() == 0:
|
118 |
+
losses /= world_size
|
119 |
+
|
120 |
+
reduced_losses = {k: v for k, v in zip(keys, losses)}
|
121 |
+
|
122 |
+
return reduced_losses
|
gligen/evaluator.py
ADDED
@@ -0,0 +1,225 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from ldm.models.diffusion.ddim import DDIMSampler
|
3 |
+
from ldm.models.diffusion.plms import PLMSSampler
|
4 |
+
from ldm.util import instantiate_from_config
|
5 |
+
import numpy as np
|
6 |
+
import random
|
7 |
+
from dataset.concat_dataset import ConCatDataset #, collate_fn
|
8 |
+
from torch.utils.data import DataLoader
|
9 |
+
from torch.utils.data.distributed import DistributedSampler
|
10 |
+
import os
|
11 |
+
from tqdm import tqdm
|
12 |
+
from distributed import get_rank, synchronize, get_world_size
|
13 |
+
from trainer import read_official_ckpt, batch_to_device, ImageCaptionSaver, wrap_loader #, get_padded_boxes
|
14 |
+
from PIL import Image
|
15 |
+
import math
|
16 |
+
import json
|
17 |
+
#hello
|
18 |
+
|
19 |
+
def draw_masks_from_boxes(boxes,size):
|
20 |
+
|
21 |
+
image_masks = []
|
22 |
+
for box in boxes:
|
23 |
+
image_mask = torch.ones(size[0],size[1])
|
24 |
+
for bx in box:
|
25 |
+
x0, x1 = bx[0]*size[0], bx[2]*size[0]
|
26 |
+
y0, y1 = bx[1]*size[1], bx[3]*size[1]
|
27 |
+
image_mask[int(y0):int(y1), int(x0):int(x1)] = 0
|
28 |
+
image_masks.append(image_mask)
|
29 |
+
return torch.stack(image_masks).unsqueeze(1)
|
30 |
+
|
31 |
+
|
32 |
+
|
33 |
+
def set_alpha_scale(model, alpha_scale):
|
34 |
+
from ldm.modules.attention import GatedCrossAttentionDense, GatedSelfAttentionDense
|
35 |
+
for module in model.modules():
|
36 |
+
if type(module) == GatedCrossAttentionDense or type(module) == GatedSelfAttentionDense:
|
37 |
+
module.scale = alpha_scale
|
38 |
+
# print("scale: ", alpha_scale)
|
39 |
+
# print("attn: ", module.alpha_attn)
|
40 |
+
# print("dense: ", module.alpha_dense)
|
41 |
+
# print(' ')
|
42 |
+
# print(' ')
|
43 |
+
|
44 |
+
|
45 |
+
def save_images(samples, image_ids, folder, to256):
|
46 |
+
for sample, image_id in zip(samples, image_ids):
|
47 |
+
sample = torch.clamp(sample, min=-1, max=1) * 0.5 + 0.5
|
48 |
+
sample = sample.cpu().numpy().transpose(1,2,0) * 255
|
49 |
+
img_name = str(int(image_id))+'.png'
|
50 |
+
img = Image.fromarray(sample.astype(np.uint8))
|
51 |
+
if to256:
|
52 |
+
img = img.resize( (256,256), Image.BICUBIC)
|
53 |
+
img.save(os.path.join(folder,img_name))
|
54 |
+
|
55 |
+
|
56 |
+
def ckpt_to_folder_name(basename):
|
57 |
+
name=""
|
58 |
+
for s in basename:
|
59 |
+
if s.isdigit():
|
60 |
+
name+=s
|
61 |
+
seen = round( int(name)/1000, 1 )
|
62 |
+
return str(seen).ljust(4,'0')+'k'
|
63 |
+
|
64 |
+
|
65 |
+
class Evaluator:
|
66 |
+
def __init__(self, config):
|
67 |
+
|
68 |
+
self.config = config
|
69 |
+
self.device = torch.device("cuda")
|
70 |
+
|
71 |
+
|
72 |
+
# = = = = = create model and diffusion = = = = = #
|
73 |
+
if self.config.ckpt != "real":
|
74 |
+
|
75 |
+
self.model = instantiate_from_config(config.model).to(self.device)
|
76 |
+
self.autoencoder = instantiate_from_config(config.autoencoder).to(self.device)
|
77 |
+
self.text_encoder = instantiate_from_config(config.text_encoder).to(self.device)
|
78 |
+
self.diffusion = instantiate_from_config(config.diffusion).to(self.device)
|
79 |
+
|
80 |
+
# donot need to load official_ckpt for self.model here, since we will load from our ckpt
|
81 |
+
state_dict = read_official_ckpt( os.path.join(config.DATA_ROOT, config.official_ckpt_name) )
|
82 |
+
self.autoencoder.load_state_dict( state_dict["autoencoder"] )
|
83 |
+
self.text_encoder.load_state_dict( state_dict["text_encoder"] )
|
84 |
+
self.diffusion.load_state_dict( state_dict["diffusion"] )
|
85 |
+
|
86 |
+
|
87 |
+
# = = = = = load from our ckpt = = = = = #
|
88 |
+
if self.config.ckpt == "real":
|
89 |
+
print("Saving all real images...")
|
90 |
+
self.just_save_real = True
|
91 |
+
else:
|
92 |
+
checkpoint = torch.load(self.config.ckpt, map_location="cpu")
|
93 |
+
which_state = 'ema' if 'ema' in checkpoint else "model"
|
94 |
+
which_state = which_state if config.which_state is None else config.which_state
|
95 |
+
self.model.load_state_dict(checkpoint[which_state])
|
96 |
+
print("ckpt is loaded")
|
97 |
+
self.just_save_real = False
|
98 |
+
set_alpha_scale(self.model, self.config.alpha_scale)
|
99 |
+
|
100 |
+
self.autoencoder.eval()
|
101 |
+
self.model.eval()
|
102 |
+
self.text_encoder.eval()
|
103 |
+
|
104 |
+
|
105 |
+
# = = = = = create data = = = = = #
|
106 |
+
self.dataset_eval = ConCatDataset(config.val_dataset_names, config.DATA_ROOT, config.which_embedder, train=False)
|
107 |
+
print("total eval images: ", len(self.dataset_eval))
|
108 |
+
sampler = DistributedSampler(self.dataset_eval,shuffle=False) if config.distributed else None
|
109 |
+
loader_eval = DataLoader( self.dataset_eval,batch_size=config.batch_size,
|
110 |
+
num_workers=config.workers,
|
111 |
+
pin_memory=True,
|
112 |
+
sampler=sampler,
|
113 |
+
drop_last=False) # shuffle default is False
|
114 |
+
self.loader_eval = loader_eval
|
115 |
+
|
116 |
+
|
117 |
+
# = = = = = create output folder = = = = = #
|
118 |
+
folder_name = ckpt_to_folder_name(os.path.basename(config.ckpt))
|
119 |
+
self.outdir = os.path.join(config.OUTPUT_ROOT, folder_name)
|
120 |
+
self.outdir_real = os.path.join(self.outdir,'real')
|
121 |
+
self.outdir_fake = os.path.join(self.outdir,'fake')
|
122 |
+
if config.to256:
|
123 |
+
self.outdir_real256 = os.path.join(self.outdir,'real256')
|
124 |
+
self.outdir_fake256 = os.path.join(self.outdir,'fake256')
|
125 |
+
synchronize() # if rank0 is faster, it may mkdir before the other rank call os.listdir()
|
126 |
+
if get_rank() == 0:
|
127 |
+
os.makedirs(self.outdir, exist_ok=True)
|
128 |
+
os.makedirs(self.outdir_real, exist_ok=True)
|
129 |
+
os.makedirs(self.outdir_fake, exist_ok=True)
|
130 |
+
if config.to256:
|
131 |
+
os.makedirs(self.outdir_real256, exist_ok=True)
|
132 |
+
os.makedirs(self.outdir_fake256, exist_ok=True)
|
133 |
+
print(self.outdir) # double check
|
134 |
+
|
135 |
+
self.evaluation_finished = False
|
136 |
+
if os.path.exists( os.path.join(self.outdir,'score.txt') ):
|
137 |
+
self.evaluation_finished = True
|
138 |
+
|
139 |
+
|
140 |
+
def alread_saved_this_batch(self, batch):
|
141 |
+
existing_real_files = os.listdir( self.outdir_real )
|
142 |
+
existing_fake_files = os.listdir( self.outdir_fake )
|
143 |
+
status = []
|
144 |
+
for image_id in batch["id"]:
|
145 |
+
img_name = str(int(image_id))+'.png'
|
146 |
+
status.append(img_name in existing_real_files)
|
147 |
+
status.append(img_name in existing_fake_files)
|
148 |
+
return all(status)
|
149 |
+
|
150 |
+
|
151 |
+
@torch.no_grad()
|
152 |
+
def start_evaluating(self):
|
153 |
+
|
154 |
+
iterator = tqdm( self.loader_eval, desc='Evaluating progress')
|
155 |
+
for batch in iterator:
|
156 |
+
|
157 |
+
#if not self.alread_saved_this_batch(batch):
|
158 |
+
if True:
|
159 |
+
|
160 |
+
batch_to_device(batch, self.device)
|
161 |
+
batch_size = batch["image"].shape[0]
|
162 |
+
samples_real = batch["image"]
|
163 |
+
|
164 |
+
if self.just_save_real:
|
165 |
+
samples_fake = None
|
166 |
+
else:
|
167 |
+
uc = self.text_encoder.encode( batch_size*[""] )
|
168 |
+
context = self.text_encoder.encode( batch["caption"] )
|
169 |
+
|
170 |
+
image_mask = x0 = None
|
171 |
+
if self.config.inpaint:
|
172 |
+
image_mask = draw_masks_from_boxes( batch['boxes'], self.model.image_size ).cuda()
|
173 |
+
x0 = self.autoencoder.encode( batch["image"] )
|
174 |
+
|
175 |
+
shape = (batch_size, self.model.in_channels, self.model.image_size, self.model.image_size)
|
176 |
+
if self.config.no_plms:
|
177 |
+
sampler = DDIMSampler(self.diffusion, self.model)
|
178 |
+
steps = 250
|
179 |
+
else:
|
180 |
+
sampler = PLMSSampler(self.diffusion, self.model)
|
181 |
+
steps = 50
|
182 |
+
|
183 |
+
input = dict( x=None, timesteps=None, context=context, boxes=batch['boxes'], masks=batch['masks'], positive_embeddings=batch["positive_embeddings"] )
|
184 |
+
samples_fake = sampler.sample(S=steps, shape=shape, input=input, uc=uc, guidance_scale=self.config.guidance_scale, mask=image_mask, x0=x0)
|
185 |
+
samples_fake = self.autoencoder.decode(samples_fake)
|
186 |
+
|
187 |
+
|
188 |
+
save_images(samples_real, batch['id'], self.outdir_real, to256=False )
|
189 |
+
if self.config.to256:
|
190 |
+
save_images(samples_real, batch['id'], self.outdir_real256, to256=True )
|
191 |
+
|
192 |
+
if samples_fake is not None:
|
193 |
+
save_images(samples_fake, batch['id'], self.outdir_fake, to256=False )
|
194 |
+
if self.config.to256:
|
195 |
+
save_images(samples_fake, batch['id'], self.outdir_fake256, to256=True )
|
196 |
+
|
197 |
+
|
198 |
+
def fire_fid(self):
|
199 |
+
paths = [self.outdir_real, self.outdir_fake]
|
200 |
+
if self.config.to256:
|
201 |
+
paths = [self.outdir_real256, self.outdir_fake256]
|
202 |
+
|
203 |
+
|
204 |
+
|
205 |
+
|
206 |
+
|
207 |
+
|
208 |
+
|
209 |
+
|
210 |
+
|
211 |
+
|
212 |
+
|
213 |
+
|
214 |
+
|
215 |
+
|
216 |
+
|
217 |
+
|
218 |
+
|
219 |
+
|
220 |
+
|
221 |
+
|
222 |
+
|
223 |
+
|
224 |
+
|
225 |
+
|
gligen/ldm/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
gligen/ldm/__pycache__/util.cpython-38.pyc
ADDED
Binary file (3.2 kB). View file
|
|
gligen/ldm/data/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
gligen/ldm/data/__init__.py
ADDED
File without changes
|
gligen/ldm/data/base.py
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from abc import abstractmethod
|
2 |
+
from torch.utils.data import Dataset, ConcatDataset, ChainDataset, IterableDataset
|
3 |
+
|
4 |
+
|
5 |
+
class Txt2ImgIterableBaseDataset(IterableDataset):
|
6 |
+
'''
|
7 |
+
Define an interface to make the IterableDatasets for text2img data chainable
|
8 |
+
'''
|
9 |
+
def __init__(self, num_records=0, valid_ids=None, size=256):
|
10 |
+
super().__init__()
|
11 |
+
self.num_records = num_records
|
12 |
+
self.valid_ids = valid_ids
|
13 |
+
self.sample_ids = valid_ids
|
14 |
+
self.size = size
|
15 |
+
|
16 |
+
print(f'{self.__class__.__name__} dataset contains {self.__len__()} examples.')
|
17 |
+
|
18 |
+
def __len__(self):
|
19 |
+
return self.num_records
|
20 |
+
|
21 |
+
@abstractmethod
|
22 |
+
def __iter__(self):
|
23 |
+
pass
|
gligen/ldm/data/imagenet.py
ADDED
@@ -0,0 +1,394 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os, yaml, pickle, shutil, tarfile, glob
|
2 |
+
import cv2
|
3 |
+
import albumentations
|
4 |
+
import PIL
|
5 |
+
import numpy as np
|
6 |
+
import torchvision.transforms.functional as TF
|
7 |
+
from omegaconf import OmegaConf
|
8 |
+
from functools import partial
|
9 |
+
from PIL import Image
|
10 |
+
from tqdm import tqdm
|
11 |
+
from torch.utils.data import Dataset, Subset
|
12 |
+
|
13 |
+
import taming.data.utils as tdu
|
14 |
+
from taming.data.imagenet import str_to_indices, give_synsets_from_indices, download, retrieve
|
15 |
+
from taming.data.imagenet import ImagePaths
|
16 |
+
|
17 |
+
from ldm.modules.image_degradation import degradation_fn_bsr, degradation_fn_bsr_light
|
18 |
+
|
19 |
+
|
20 |
+
def synset2idx(path_to_yaml="ldm/data/index_synset.yaml"):
|
21 |
+
with open(path_to_yaml) as f:
|
22 |
+
di2s = yaml.load(f)
|
23 |
+
return dict((v,k) for k,v in di2s.items())
|
24 |
+
|
25 |
+
|
26 |
+
class ImageNetBase(Dataset):
|
27 |
+
def __init__(self, config=None):
|
28 |
+
self.config = config or OmegaConf.create()
|
29 |
+
if not type(self.config)==dict:
|
30 |
+
self.config = OmegaConf.to_container(self.config)
|
31 |
+
self.keep_orig_class_label = self.config.get("keep_orig_class_label", False)
|
32 |
+
self.process_images = True # if False we skip loading & processing images and self.data contains filepaths
|
33 |
+
self._prepare()
|
34 |
+
self._prepare_synset_to_human()
|
35 |
+
self._prepare_idx_to_synset()
|
36 |
+
self._prepare_human_to_integer_label()
|
37 |
+
self._load()
|
38 |
+
|
39 |
+
def __len__(self):
|
40 |
+
return len(self.data)
|
41 |
+
|
42 |
+
def __getitem__(self, i):
|
43 |
+
return self.data[i]
|
44 |
+
|
45 |
+
def _prepare(self):
|
46 |
+
raise NotImplementedError()
|
47 |
+
|
48 |
+
def _filter_relpaths(self, relpaths):
|
49 |
+
ignore = set([
|
50 |
+
"n06596364_9591.JPEG",
|
51 |
+
])
|
52 |
+
relpaths = [rpath for rpath in relpaths if not rpath.split("/")[-1] in ignore]
|
53 |
+
if "sub_indices" in self.config:
|
54 |
+
indices = str_to_indices(self.config["sub_indices"])
|
55 |
+
synsets = give_synsets_from_indices(indices, path_to_yaml=self.idx2syn) # returns a list of strings
|
56 |
+
self.synset2idx = synset2idx(path_to_yaml=self.idx2syn)
|
57 |
+
files = []
|
58 |
+
for rpath in relpaths:
|
59 |
+
syn = rpath.split("/")[0]
|
60 |
+
if syn in synsets:
|
61 |
+
files.append(rpath)
|
62 |
+
return files
|
63 |
+
else:
|
64 |
+
return relpaths
|
65 |
+
|
66 |
+
def _prepare_synset_to_human(self):
|
67 |
+
SIZE = 2655750
|
68 |
+
URL = "https://heibox.uni-heidelberg.de/f/9f28e956cd304264bb82/?dl=1"
|
69 |
+
self.human_dict = os.path.join(self.root, "synset_human.txt")
|
70 |
+
if (not os.path.exists(self.human_dict) or
|
71 |
+
not os.path.getsize(self.human_dict)==SIZE):
|
72 |
+
download(URL, self.human_dict)
|
73 |
+
|
74 |
+
def _prepare_idx_to_synset(self):
|
75 |
+
URL = "https://heibox.uni-heidelberg.de/f/d835d5b6ceda4d3aa910/?dl=1"
|
76 |
+
self.idx2syn = os.path.join(self.root, "index_synset.yaml")
|
77 |
+
if (not os.path.exists(self.idx2syn)):
|
78 |
+
download(URL, self.idx2syn)
|
79 |
+
|
80 |
+
def _prepare_human_to_integer_label(self):
|
81 |
+
URL = "https://heibox.uni-heidelberg.de/f/2362b797d5be43b883f6/?dl=1"
|
82 |
+
self.human2integer = os.path.join(self.root, "imagenet1000_clsidx_to_labels.txt")
|
83 |
+
if (not os.path.exists(self.human2integer)):
|
84 |
+
download(URL, self.human2integer)
|
85 |
+
with open(self.human2integer, "r") as f:
|
86 |
+
lines = f.read().splitlines()
|
87 |
+
assert len(lines) == 1000
|
88 |
+
self.human2integer_dict = dict()
|
89 |
+
for line in lines:
|
90 |
+
value, key = line.split(":")
|
91 |
+
self.human2integer_dict[key] = int(value)
|
92 |
+
|
93 |
+
def _load(self):
|
94 |
+
with open(self.txt_filelist, "r") as f:
|
95 |
+
self.relpaths = f.read().splitlines()
|
96 |
+
l1 = len(self.relpaths)
|
97 |
+
self.relpaths = self._filter_relpaths(self.relpaths)
|
98 |
+
print("Removed {} files from filelist during filtering.".format(l1 - len(self.relpaths)))
|
99 |
+
|
100 |
+
self.synsets = [p.split("/")[0] for p in self.relpaths]
|
101 |
+
self.abspaths = [os.path.join(self.datadir, p) for p in self.relpaths]
|
102 |
+
|
103 |
+
unique_synsets = np.unique(self.synsets)
|
104 |
+
class_dict = dict((synset, i) for i, synset in enumerate(unique_synsets))
|
105 |
+
if not self.keep_orig_class_label:
|
106 |
+
self.class_labels = [class_dict[s] for s in self.synsets]
|
107 |
+
else:
|
108 |
+
self.class_labels = [self.synset2idx[s] for s in self.synsets]
|
109 |
+
|
110 |
+
with open(self.human_dict, "r") as f:
|
111 |
+
human_dict = f.read().splitlines()
|
112 |
+
human_dict = dict(line.split(maxsplit=1) for line in human_dict)
|
113 |
+
|
114 |
+
self.human_labels = [human_dict[s] for s in self.synsets]
|
115 |
+
|
116 |
+
labels = {
|
117 |
+
"relpath": np.array(self.relpaths),
|
118 |
+
"synsets": np.array(self.synsets),
|
119 |
+
"class_label": np.array(self.class_labels),
|
120 |
+
"human_label": np.array(self.human_labels),
|
121 |
+
}
|
122 |
+
|
123 |
+
if self.process_images:
|
124 |
+
self.size = retrieve(self.config, "size", default=256)
|
125 |
+
self.data = ImagePaths(self.abspaths,
|
126 |
+
labels=labels,
|
127 |
+
size=self.size,
|
128 |
+
random_crop=self.random_crop,
|
129 |
+
)
|
130 |
+
else:
|
131 |
+
self.data = self.abspaths
|
132 |
+
|
133 |
+
|
134 |
+
class ImageNetTrain(ImageNetBase):
|
135 |
+
NAME = "ILSVRC2012_train"
|
136 |
+
URL = "http://www.image-net.org/challenges/LSVRC/2012/"
|
137 |
+
AT_HASH = "a306397ccf9c2ead27155983c254227c0fd938e2"
|
138 |
+
FILES = [
|
139 |
+
"ILSVRC2012_img_train.tar",
|
140 |
+
]
|
141 |
+
SIZES = [
|
142 |
+
147897477120,
|
143 |
+
]
|
144 |
+
|
145 |
+
def __init__(self, process_images=True, data_root=None, **kwargs):
|
146 |
+
self.process_images = process_images
|
147 |
+
self.data_root = data_root
|
148 |
+
super().__init__(**kwargs)
|
149 |
+
|
150 |
+
def _prepare(self):
|
151 |
+
if self.data_root:
|
152 |
+
self.root = os.path.join(self.data_root, self.NAME)
|
153 |
+
else:
|
154 |
+
cachedir = os.environ.get("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
|
155 |
+
self.root = os.path.join(cachedir, "autoencoders/data", self.NAME)
|
156 |
+
|
157 |
+
self.datadir = os.path.join(self.root, "data")
|
158 |
+
self.txt_filelist = os.path.join(self.root, "filelist.txt")
|
159 |
+
self.expected_length = 1281167
|
160 |
+
self.random_crop = retrieve(self.config, "ImageNetTrain/random_crop",
|
161 |
+
default=True)
|
162 |
+
if not tdu.is_prepared(self.root):
|
163 |
+
# prep
|
164 |
+
print("Preparing dataset {} in {}".format(self.NAME, self.root))
|
165 |
+
|
166 |
+
datadir = self.datadir
|
167 |
+
if not os.path.exists(datadir):
|
168 |
+
path = os.path.join(self.root, self.FILES[0])
|
169 |
+
if not os.path.exists(path) or not os.path.getsize(path)==self.SIZES[0]:
|
170 |
+
import academictorrents as at
|
171 |
+
atpath = at.get(self.AT_HASH, datastore=self.root)
|
172 |
+
assert atpath == path
|
173 |
+
|
174 |
+
print("Extracting {} to {}".format(path, datadir))
|
175 |
+
os.makedirs(datadir, exist_ok=True)
|
176 |
+
with tarfile.open(path, "r:") as tar:
|
177 |
+
tar.extractall(path=datadir)
|
178 |
+
|
179 |
+
print("Extracting sub-tars.")
|
180 |
+
subpaths = sorted(glob.glob(os.path.join(datadir, "*.tar")))
|
181 |
+
for subpath in tqdm(subpaths):
|
182 |
+
subdir = subpath[:-len(".tar")]
|
183 |
+
os.makedirs(subdir, exist_ok=True)
|
184 |
+
with tarfile.open(subpath, "r:") as tar:
|
185 |
+
tar.extractall(path=subdir)
|
186 |
+
|
187 |
+
filelist = glob.glob(os.path.join(datadir, "**", "*.JPEG"))
|
188 |
+
filelist = [os.path.relpath(p, start=datadir) for p in filelist]
|
189 |
+
filelist = sorted(filelist)
|
190 |
+
filelist = "\n".join(filelist)+"\n"
|
191 |
+
with open(self.txt_filelist, "w") as f:
|
192 |
+
f.write(filelist)
|
193 |
+
|
194 |
+
tdu.mark_prepared(self.root)
|
195 |
+
|
196 |
+
|
197 |
+
class ImageNetValidation(ImageNetBase):
|
198 |
+
NAME = "ILSVRC2012_validation"
|
199 |
+
URL = "http://www.image-net.org/challenges/LSVRC/2012/"
|
200 |
+
AT_HASH = "5d6d0df7ed81efd49ca99ea4737e0ae5e3a5f2e5"
|
201 |
+
VS_URL = "https://heibox.uni-heidelberg.de/f/3e0f6e9c624e45f2bd73/?dl=1"
|
202 |
+
FILES = [
|
203 |
+
"ILSVRC2012_img_val.tar",
|
204 |
+
"validation_synset.txt",
|
205 |
+
]
|
206 |
+
SIZES = [
|
207 |
+
6744924160,
|
208 |
+
1950000,
|
209 |
+
]
|
210 |
+
|
211 |
+
def __init__(self, process_images=True, data_root=None, **kwargs):
|
212 |
+
self.data_root = data_root
|
213 |
+
self.process_images = process_images
|
214 |
+
super().__init__(**kwargs)
|
215 |
+
|
216 |
+
def _prepare(self):
|
217 |
+
if self.data_root:
|
218 |
+
self.root = os.path.join(self.data_root, self.NAME)
|
219 |
+
else:
|
220 |
+
cachedir = os.environ.get("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
|
221 |
+
self.root = os.path.join(cachedir, "autoencoders/data", self.NAME)
|
222 |
+
self.datadir = os.path.join(self.root, "data")
|
223 |
+
self.txt_filelist = os.path.join(self.root, "filelist.txt")
|
224 |
+
self.expected_length = 50000
|
225 |
+
self.random_crop = retrieve(self.config, "ImageNetValidation/random_crop",
|
226 |
+
default=False)
|
227 |
+
if not tdu.is_prepared(self.root):
|
228 |
+
# prep
|
229 |
+
print("Preparing dataset {} in {}".format(self.NAME, self.root))
|
230 |
+
|
231 |
+
datadir = self.datadir
|
232 |
+
if not os.path.exists(datadir):
|
233 |
+
path = os.path.join(self.root, self.FILES[0])
|
234 |
+
if not os.path.exists(path) or not os.path.getsize(path)==self.SIZES[0]:
|
235 |
+
import academictorrents as at
|
236 |
+
atpath = at.get(self.AT_HASH, datastore=self.root)
|
237 |
+
assert atpath == path
|
238 |
+
|
239 |
+
print("Extracting {} to {}".format(path, datadir))
|
240 |
+
os.makedirs(datadir, exist_ok=True)
|
241 |
+
with tarfile.open(path, "r:") as tar:
|
242 |
+
tar.extractall(path=datadir)
|
243 |
+
|
244 |
+
vspath = os.path.join(self.root, self.FILES[1])
|
245 |
+
if not os.path.exists(vspath) or not os.path.getsize(vspath)==self.SIZES[1]:
|
246 |
+
download(self.VS_URL, vspath)
|
247 |
+
|
248 |
+
with open(vspath, "r") as f:
|
249 |
+
synset_dict = f.read().splitlines()
|
250 |
+
synset_dict = dict(line.split() for line in synset_dict)
|
251 |
+
|
252 |
+
print("Reorganizing into synset folders")
|
253 |
+
synsets = np.unique(list(synset_dict.values()))
|
254 |
+
for s in synsets:
|
255 |
+
os.makedirs(os.path.join(datadir, s), exist_ok=True)
|
256 |
+
for k, v in synset_dict.items():
|
257 |
+
src = os.path.join(datadir, k)
|
258 |
+
dst = os.path.join(datadir, v)
|
259 |
+
shutil.move(src, dst)
|
260 |
+
|
261 |
+
filelist = glob.glob(os.path.join(datadir, "**", "*.JPEG"))
|
262 |
+
filelist = [os.path.relpath(p, start=datadir) for p in filelist]
|
263 |
+
filelist = sorted(filelist)
|
264 |
+
filelist = "\n".join(filelist)+"\n"
|
265 |
+
with open(self.txt_filelist, "w") as f:
|
266 |
+
f.write(filelist)
|
267 |
+
|
268 |
+
tdu.mark_prepared(self.root)
|
269 |
+
|
270 |
+
|
271 |
+
|
272 |
+
class ImageNetSR(Dataset):
|
273 |
+
def __init__(self, size=None,
|
274 |
+
degradation=None, downscale_f=4, min_crop_f=0.5, max_crop_f=1.,
|
275 |
+
random_crop=True):
|
276 |
+
"""
|
277 |
+
Imagenet Superresolution Dataloader
|
278 |
+
Performs following ops in order:
|
279 |
+
1. crops a crop of size s from image either as random or center crop
|
280 |
+
2. resizes crop to size with cv2.area_interpolation
|
281 |
+
3. degrades resized crop with degradation_fn
|
282 |
+
|
283 |
+
:param size: resizing to size after cropping
|
284 |
+
:param degradation: degradation_fn, e.g. cv_bicubic or bsrgan_light
|
285 |
+
:param downscale_f: Low Resolution Downsample factor
|
286 |
+
:param min_crop_f: determines crop size s,
|
287 |
+
where s = c * min_img_side_len with c sampled from interval (min_crop_f, max_crop_f)
|
288 |
+
:param max_crop_f: ""
|
289 |
+
:param data_root:
|
290 |
+
:param random_crop:
|
291 |
+
"""
|
292 |
+
self.base = self.get_base()
|
293 |
+
assert size
|
294 |
+
assert (size / downscale_f).is_integer()
|
295 |
+
self.size = size
|
296 |
+
self.LR_size = int(size / downscale_f)
|
297 |
+
self.min_crop_f = min_crop_f
|
298 |
+
self.max_crop_f = max_crop_f
|
299 |
+
assert(max_crop_f <= 1.)
|
300 |
+
self.center_crop = not random_crop
|
301 |
+
|
302 |
+
self.image_rescaler = albumentations.SmallestMaxSize(max_size=size, interpolation=cv2.INTER_AREA)
|
303 |
+
|
304 |
+
self.pil_interpolation = False # gets reset later if incase interp_op is from pillow
|
305 |
+
|
306 |
+
if degradation == "bsrgan":
|
307 |
+
self.degradation_process = partial(degradation_fn_bsr, sf=downscale_f)
|
308 |
+
|
309 |
+
elif degradation == "bsrgan_light":
|
310 |
+
self.degradation_process = partial(degradation_fn_bsr_light, sf=downscale_f)
|
311 |
+
|
312 |
+
else:
|
313 |
+
interpolation_fn = {
|
314 |
+
"cv_nearest": cv2.INTER_NEAREST,
|
315 |
+
"cv_bilinear": cv2.INTER_LINEAR,
|
316 |
+
"cv_bicubic": cv2.INTER_CUBIC,
|
317 |
+
"cv_area": cv2.INTER_AREA,
|
318 |
+
"cv_lanczos": cv2.INTER_LANCZOS4,
|
319 |
+
"pil_nearest": PIL.Image.NEAREST,
|
320 |
+
"pil_bilinear": PIL.Image.BILINEAR,
|
321 |
+
"pil_bicubic": PIL.Image.BICUBIC,
|
322 |
+
"pil_box": PIL.Image.BOX,
|
323 |
+
"pil_hamming": PIL.Image.HAMMING,
|
324 |
+
"pil_lanczos": PIL.Image.LANCZOS,
|
325 |
+
}[degradation]
|
326 |
+
|
327 |
+
self.pil_interpolation = degradation.startswith("pil_")
|
328 |
+
|
329 |
+
if self.pil_interpolation:
|
330 |
+
self.degradation_process = partial(TF.resize, size=self.LR_size, interpolation=interpolation_fn)
|
331 |
+
|
332 |
+
else:
|
333 |
+
self.degradation_process = albumentations.SmallestMaxSize(max_size=self.LR_size,
|
334 |
+
interpolation=interpolation_fn)
|
335 |
+
|
336 |
+
def __len__(self):
|
337 |
+
return len(self.base)
|
338 |
+
|
339 |
+
def __getitem__(self, i):
|
340 |
+
example = self.base[i]
|
341 |
+
image = Image.open(example["file_path_"])
|
342 |
+
|
343 |
+
if not image.mode == "RGB":
|
344 |
+
image = image.convert("RGB")
|
345 |
+
|
346 |
+
image = np.array(image).astype(np.uint8)
|
347 |
+
|
348 |
+
min_side_len = min(image.shape[:2])
|
349 |
+
crop_side_len = min_side_len * np.random.uniform(self.min_crop_f, self.max_crop_f, size=None)
|
350 |
+
crop_side_len = int(crop_side_len)
|
351 |
+
|
352 |
+
if self.center_crop:
|
353 |
+
self.cropper = albumentations.CenterCrop(height=crop_side_len, width=crop_side_len)
|
354 |
+
|
355 |
+
else:
|
356 |
+
self.cropper = albumentations.RandomCrop(height=crop_side_len, width=crop_side_len)
|
357 |
+
|
358 |
+
image = self.cropper(image=image)["image"]
|
359 |
+
image = self.image_rescaler(image=image)["image"]
|
360 |
+
|
361 |
+
if self.pil_interpolation:
|
362 |
+
image_pil = PIL.Image.fromarray(image)
|
363 |
+
LR_image = self.degradation_process(image_pil)
|
364 |
+
LR_image = np.array(LR_image).astype(np.uint8)
|
365 |
+
|
366 |
+
else:
|
367 |
+
LR_image = self.degradation_process(image=image)["image"]
|
368 |
+
|
369 |
+
example["image"] = (image/127.5 - 1.0).astype(np.float32)
|
370 |
+
example["LR_image"] = (LR_image/127.5 - 1.0).astype(np.float32)
|
371 |
+
|
372 |
+
return example
|
373 |
+
|
374 |
+
|
375 |
+
class ImageNetSRTrain(ImageNetSR):
|
376 |
+
def __init__(self, **kwargs):
|
377 |
+
super().__init__(**kwargs)
|
378 |
+
|
379 |
+
def get_base(self):
|
380 |
+
with open("ldm/data/imagenet_train_hr_indices.p", "rb") as f:
|
381 |
+
indices = pickle.load(f)
|
382 |
+
dset = ImageNetTrain(process_images=False,)
|
383 |
+
return Subset(dset, indices)
|
384 |
+
|
385 |
+
|
386 |
+
class ImageNetSRValidation(ImageNetSR):
|
387 |
+
def __init__(self, **kwargs):
|
388 |
+
super().__init__(**kwargs)
|
389 |
+
|
390 |
+
def get_base(self):
|
391 |
+
with open("ldm/data/imagenet_val_hr_indices.p", "rb") as f:
|
392 |
+
indices = pickle.load(f)
|
393 |
+
dset = ImageNetValidation(process_images=False,)
|
394 |
+
return Subset(dset, indices)
|
gligen/ldm/data/imagenet_clsidx_to_label.txt
ADDED
@@ -0,0 +1,1000 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
0: 'tench, Tinca tinca',
|
2 |
+
1: 'goldfish, Carassius auratus',
|
3 |
+
2: 'great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias',
|
4 |
+
3: 'tiger shark, Galeocerdo cuvieri',
|
5 |
+
4: 'hammerhead, hammerhead shark',
|
6 |
+
5: 'electric ray, crampfish, numbfish, torpedo',
|
7 |
+
6: 'stingray',
|
8 |
+
7: 'cock',
|
9 |
+
8: 'hen',
|
10 |
+
9: 'ostrich, Struthio camelus',
|
11 |
+
10: 'brambling, Fringilla montifringilla',
|
12 |
+
11: 'goldfinch, Carduelis carduelis',
|
13 |
+
12: 'house finch, linnet, Carpodacus mexicanus',
|
14 |
+
13: 'junco, snowbird',
|
15 |
+
14: 'indigo bunting, indigo finch, indigo bird, Passerina cyanea',
|
16 |
+
15: 'robin, American robin, Turdus migratorius',
|
17 |
+
16: 'bulbul',
|
18 |
+
17: 'jay',
|
19 |
+
18: 'magpie',
|
20 |
+
19: 'chickadee',
|
21 |
+
20: 'water ouzel, dipper',
|
22 |
+
21: 'kite',
|
23 |
+
22: 'bald eagle, American eagle, Haliaeetus leucocephalus',
|
24 |
+
23: 'vulture',
|
25 |
+
24: 'great grey owl, great gray owl, Strix nebulosa',
|
26 |
+
25: 'European fire salamander, Salamandra salamandra',
|
27 |
+
26: 'common newt, Triturus vulgaris',
|
28 |
+
27: 'eft',
|
29 |
+
28: 'spotted salamander, Ambystoma maculatum',
|
30 |
+
29: 'axolotl, mud puppy, Ambystoma mexicanum',
|
31 |
+
30: 'bullfrog, Rana catesbeiana',
|
32 |
+
31: 'tree frog, tree-frog',
|
33 |
+
32: 'tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui',
|
34 |
+
33: 'loggerhead, loggerhead turtle, Caretta caretta',
|
35 |
+
34: 'leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea',
|
36 |
+
35: 'mud turtle',
|
37 |
+
36: 'terrapin',
|
38 |
+
37: 'box turtle, box tortoise',
|
39 |
+
38: 'banded gecko',
|
40 |
+
39: 'common iguana, iguana, Iguana iguana',
|
41 |
+
40: 'American chameleon, anole, Anolis carolinensis',
|
42 |
+
41: 'whiptail, whiptail lizard',
|
43 |
+
42: 'agama',
|
44 |
+
43: 'frilled lizard, Chlamydosaurus kingi',
|
45 |
+
44: 'alligator lizard',
|
46 |
+
45: 'Gila monster, Heloderma suspectum',
|
47 |
+
46: 'green lizard, Lacerta viridis',
|
48 |
+
47: 'African chameleon, Chamaeleo chamaeleon',
|
49 |
+
48: 'Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis',
|
50 |
+
49: 'African crocodile, Nile crocodile, Crocodylus niloticus',
|
51 |
+
50: 'American alligator, Alligator mississipiensis',
|
52 |
+
51: 'triceratops',
|
53 |
+
52: 'thunder snake, worm snake, Carphophis amoenus',
|
54 |
+
53: 'ringneck snake, ring-necked snake, ring snake',
|
55 |
+
54: 'hognose snake, puff adder, sand viper',
|
56 |
+
55: 'green snake, grass snake',
|
57 |
+
56: 'king snake, kingsnake',
|
58 |
+
57: 'garter snake, grass snake',
|
59 |
+
58: 'water snake',
|
60 |
+
59: 'vine snake',
|
61 |
+
60: 'night snake, Hypsiglena torquata',
|
62 |
+
61: 'boa constrictor, Constrictor constrictor',
|
63 |
+
62: 'rock python, rock snake, Python sebae',
|
64 |
+
63: 'Indian cobra, Naja naja',
|
65 |
+
64: 'green mamba',
|
66 |
+
65: 'sea snake',
|
67 |
+
66: 'horned viper, cerastes, sand viper, horned asp, Cerastes cornutus',
|
68 |
+
67: 'diamondback, diamondback rattlesnake, Crotalus adamanteus',
|
69 |
+
68: 'sidewinder, horned rattlesnake, Crotalus cerastes',
|
70 |
+
69: 'trilobite',
|
71 |
+
70: 'harvestman, daddy longlegs, Phalangium opilio',
|
72 |
+
71: 'scorpion',
|
73 |
+
72: 'black and gold garden spider, Argiope aurantia',
|
74 |
+
73: 'barn spider, Araneus cavaticus',
|
75 |
+
74: 'garden spider, Aranea diademata',
|
76 |
+
75: 'black widow, Latrodectus mactans',
|
77 |
+
76: 'tarantula',
|
78 |
+
77: 'wolf spider, hunting spider',
|
79 |
+
78: 'tick',
|
80 |
+
79: 'centipede',
|
81 |
+
80: 'black grouse',
|
82 |
+
81: 'ptarmigan',
|
83 |
+
82: 'ruffed grouse, partridge, Bonasa umbellus',
|
84 |
+
83: 'prairie chicken, prairie grouse, prairie fowl',
|
85 |
+
84: 'peacock',
|
86 |
+
85: 'quail',
|
87 |
+
86: 'partridge',
|
88 |
+
87: 'African grey, African gray, Psittacus erithacus',
|
89 |
+
88: 'macaw',
|
90 |
+
89: 'sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita',
|
91 |
+
90: 'lorikeet',
|
92 |
+
91: 'coucal',
|
93 |
+
92: 'bee eater',
|
94 |
+
93: 'hornbill',
|
95 |
+
94: 'hummingbird',
|
96 |
+
95: 'jacamar',
|
97 |
+
96: 'toucan',
|
98 |
+
97: 'drake',
|
99 |
+
98: 'red-breasted merganser, Mergus serrator',
|
100 |
+
99: 'goose',
|
101 |
+
100: 'black swan, Cygnus atratus',
|
102 |
+
101: 'tusker',
|
103 |
+
102: 'echidna, spiny anteater, anteater',
|
104 |
+
103: 'platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus',
|
105 |
+
104: 'wallaby, brush kangaroo',
|
106 |
+
105: 'koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus',
|
107 |
+
106: 'wombat',
|
108 |
+
107: 'jellyfish',
|
109 |
+
108: 'sea anemone, anemone',
|
110 |
+
109: 'brain coral',
|
111 |
+
110: 'flatworm, platyhelminth',
|
112 |
+
111: 'nematode, nematode worm, roundworm',
|
113 |
+
112: 'conch',
|
114 |
+
113: 'snail',
|
115 |
+
114: 'slug',
|
116 |
+
115: 'sea slug, nudibranch',
|
117 |
+
116: 'chiton, coat-of-mail shell, sea cradle, polyplacophore',
|
118 |
+
117: 'chambered nautilus, pearly nautilus, nautilus',
|
119 |
+
118: 'Dungeness crab, Cancer magister',
|
120 |
+
119: 'rock crab, Cancer irroratus',
|
121 |
+
120: 'fiddler crab',
|
122 |
+
121: 'king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica',
|
123 |
+
122: 'American lobster, Northern lobster, Maine lobster, Homarus americanus',
|
124 |
+
123: 'spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish',
|
125 |
+
124: 'crayfish, crawfish, crawdad, crawdaddy',
|
126 |
+
125: 'hermit crab',
|
127 |
+
126: 'isopod',
|
128 |
+
127: 'white stork, Ciconia ciconia',
|
129 |
+
128: 'black stork, Ciconia nigra',
|
130 |
+
129: 'spoonbill',
|
131 |
+
130: 'flamingo',
|
132 |
+
131: 'little blue heron, Egretta caerulea',
|
133 |
+
132: 'American egret, great white heron, Egretta albus',
|
134 |
+
133: 'bittern',
|
135 |
+
134: 'crane',
|
136 |
+
135: 'limpkin, Aramus pictus',
|
137 |
+
136: 'European gallinule, Porphyrio porphyrio',
|
138 |
+
137: 'American coot, marsh hen, mud hen, water hen, Fulica americana',
|
139 |
+
138: 'bustard',
|
140 |
+
139: 'ruddy turnstone, Arenaria interpres',
|
141 |
+
140: 'red-backed sandpiper, dunlin, Erolia alpina',
|
142 |
+
141: 'redshank, Tringa totanus',
|
143 |
+
142: 'dowitcher',
|
144 |
+
143: 'oystercatcher, oyster catcher',
|
145 |
+
144: 'pelican',
|
146 |
+
145: 'king penguin, Aptenodytes patagonica',
|
147 |
+
146: 'albatross, mollymawk',
|
148 |
+
147: 'grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus',
|
149 |
+
148: 'killer whale, killer, orca, grampus, sea wolf, Orcinus orca',
|
150 |
+
149: 'dugong, Dugong dugon',
|
151 |
+
150: 'sea lion',
|
152 |
+
151: 'Chihuahua',
|
153 |
+
152: 'Japanese spaniel',
|
154 |
+
153: 'Maltese dog, Maltese terrier, Maltese',
|
155 |
+
154: 'Pekinese, Pekingese, Peke',
|
156 |
+
155: 'Shih-Tzu',
|
157 |
+
156: 'Blenheim spaniel',
|
158 |
+
157: 'papillon',
|
159 |
+
158: 'toy terrier',
|
160 |
+
159: 'Rhodesian ridgeback',
|
161 |
+
160: 'Afghan hound, Afghan',
|
162 |
+
161: 'basset, basset hound',
|
163 |
+
162: 'beagle',
|
164 |
+
163: 'bloodhound, sleuthhound',
|
165 |
+
164: 'bluetick',
|
166 |
+
165: 'black-and-tan coonhound',
|
167 |
+
166: 'Walker hound, Walker foxhound',
|
168 |
+
167: 'English foxhound',
|
169 |
+
168: 'redbone',
|
170 |
+
169: 'borzoi, Russian wolfhound',
|
171 |
+
170: 'Irish wolfhound',
|
172 |
+
171: 'Italian greyhound',
|
173 |
+
172: 'whippet',
|
174 |
+
173: 'Ibizan hound, Ibizan Podenco',
|
175 |
+
174: 'Norwegian elkhound, elkhound',
|
176 |
+
175: 'otterhound, otter hound',
|
177 |
+
176: 'Saluki, gazelle hound',
|
178 |
+
177: 'Scottish deerhound, deerhound',
|
179 |
+
178: 'Weimaraner',
|
180 |
+
179: 'Staffordshire bullterrier, Staffordshire bull terrier',
|
181 |
+
180: 'American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier',
|
182 |
+
181: 'Bedlington terrier',
|
183 |
+
182: 'Border terrier',
|
184 |
+
183: 'Kerry blue terrier',
|
185 |
+
184: 'Irish terrier',
|
186 |
+
185: 'Norfolk terrier',
|
187 |
+
186: 'Norwich terrier',
|
188 |
+
187: 'Yorkshire terrier',
|
189 |
+
188: 'wire-haired fox terrier',
|
190 |
+
189: 'Lakeland terrier',
|
191 |
+
190: 'Sealyham terrier, Sealyham',
|
192 |
+
191: 'Airedale, Airedale terrier',
|
193 |
+
192: 'cairn, cairn terrier',
|
194 |
+
193: 'Australian terrier',
|
195 |
+
194: 'Dandie Dinmont, Dandie Dinmont terrier',
|
196 |
+
195: 'Boston bull, Boston terrier',
|
197 |
+
196: 'miniature schnauzer',
|
198 |
+
197: 'giant schnauzer',
|
199 |
+
198: 'standard schnauzer',
|
200 |
+
199: 'Scotch terrier, Scottish terrier, Scottie',
|
201 |
+
200: 'Tibetan terrier, chrysanthemum dog',
|
202 |
+
201: 'silky terrier, Sydney silky',
|
203 |
+
202: 'soft-coated wheaten terrier',
|
204 |
+
203: 'West Highland white terrier',
|
205 |
+
204: 'Lhasa, Lhasa apso',
|
206 |
+
205: 'flat-coated retriever',
|
207 |
+
206: 'curly-coated retriever',
|
208 |
+
207: 'golden retriever',
|
209 |
+
208: 'Labrador retriever',
|
210 |
+
209: 'Chesapeake Bay retriever',
|
211 |
+
210: 'German short-haired pointer',
|
212 |
+
211: 'vizsla, Hungarian pointer',
|
213 |
+
212: 'English setter',
|
214 |
+
213: 'Irish setter, red setter',
|
215 |
+
214: 'Gordon setter',
|
216 |
+
215: 'Brittany spaniel',
|
217 |
+
216: 'clumber, clumber spaniel',
|
218 |
+
217: 'English springer, English springer spaniel',
|
219 |
+
218: 'Welsh springer spaniel',
|
220 |
+
219: 'cocker spaniel, English cocker spaniel, cocker',
|
221 |
+
220: 'Sussex spaniel',
|
222 |
+
221: 'Irish water spaniel',
|
223 |
+
222: 'kuvasz',
|
224 |
+
223: 'schipperke',
|
225 |
+
224: 'groenendael',
|
226 |
+
225: 'malinois',
|
227 |
+
226: 'briard',
|
228 |
+
227: 'kelpie',
|
229 |
+
228: 'komondor',
|
230 |
+
229: 'Old English sheepdog, bobtail',
|
231 |
+
230: 'Shetland sheepdog, Shetland sheep dog, Shetland',
|
232 |
+
231: 'collie',
|
233 |
+
232: 'Border collie',
|
234 |
+
233: 'Bouvier des Flandres, Bouviers des Flandres',
|
235 |
+
234: 'Rottweiler',
|
236 |
+
235: 'German shepherd, German shepherd dog, German police dog, alsatian',
|
237 |
+
236: 'Doberman, Doberman pinscher',
|
238 |
+
237: 'miniature pinscher',
|
239 |
+
238: 'Greater Swiss Mountain dog',
|
240 |
+
239: 'Bernese mountain dog',
|
241 |
+
240: 'Appenzeller',
|
242 |
+
241: 'EntleBucher',
|
243 |
+
242: 'boxer',
|
244 |
+
243: 'bull mastiff',
|
245 |
+
244: 'Tibetan mastiff',
|
246 |
+
245: 'French bulldog',
|
247 |
+
246: 'Great Dane',
|
248 |
+
247: 'Saint Bernard, St Bernard',
|
249 |
+
248: 'Eskimo dog, husky',
|
250 |
+
249: 'malamute, malemute, Alaskan malamute',
|
251 |
+
250: 'Siberian husky',
|
252 |
+
251: 'dalmatian, coach dog, carriage dog',
|
253 |
+
252: 'affenpinscher, monkey pinscher, monkey dog',
|
254 |
+
253: 'basenji',
|
255 |
+
254: 'pug, pug-dog',
|
256 |
+
255: 'Leonberg',
|
257 |
+
256: 'Newfoundland, Newfoundland dog',
|
258 |
+
257: 'Great Pyrenees',
|
259 |
+
258: 'Samoyed, Samoyede',
|
260 |
+
259: 'Pomeranian',
|
261 |
+
260: 'chow, chow chow',
|
262 |
+
261: 'keeshond',
|
263 |
+
262: 'Brabancon griffon',
|
264 |
+
263: 'Pembroke, Pembroke Welsh corgi',
|
265 |
+
264: 'Cardigan, Cardigan Welsh corgi',
|
266 |
+
265: 'toy poodle',
|
267 |
+
266: 'miniature poodle',
|
268 |
+
267: 'standard poodle',
|
269 |
+
268: 'Mexican hairless',
|
270 |
+
269: 'timber wolf, grey wolf, gray wolf, Canis lupus',
|
271 |
+
270: 'white wolf, Arctic wolf, Canis lupus tundrarum',
|
272 |
+
271: 'red wolf, maned wolf, Canis rufus, Canis niger',
|
273 |
+
272: 'coyote, prairie wolf, brush wolf, Canis latrans',
|
274 |
+
273: 'dingo, warrigal, warragal, Canis dingo',
|
275 |
+
274: 'dhole, Cuon alpinus',
|
276 |
+
275: 'African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus',
|
277 |
+
276: 'hyena, hyaena',
|
278 |
+
277: 'red fox, Vulpes vulpes',
|
279 |
+
278: 'kit fox, Vulpes macrotis',
|
280 |
+
279: 'Arctic fox, white fox, Alopex lagopus',
|
281 |
+
280: 'grey fox, gray fox, Urocyon cinereoargenteus',
|
282 |
+
281: 'tabby, tabby cat',
|
283 |
+
282: 'tiger cat',
|
284 |
+
283: 'Persian cat',
|
285 |
+
284: 'Siamese cat, Siamese',
|
286 |
+
285: 'Egyptian cat',
|
287 |
+
286: 'cougar, puma, catamount, mountain lion, painter, panther, Felis concolor',
|
288 |
+
287: 'lynx, catamount',
|
289 |
+
288: 'leopard, Panthera pardus',
|
290 |
+
289: 'snow leopard, ounce, Panthera uncia',
|
291 |
+
290: 'jaguar, panther, Panthera onca, Felis onca',
|
292 |
+
291: 'lion, king of beasts, Panthera leo',
|
293 |
+
292: 'tiger, Panthera tigris',
|
294 |
+
293: 'cheetah, chetah, Acinonyx jubatus',
|
295 |
+
294: 'brown bear, bruin, Ursus arctos',
|
296 |
+
295: 'American black bear, black bear, Ursus americanus, Euarctos americanus',
|
297 |
+
296: 'ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus',
|
298 |
+
297: 'sloth bear, Melursus ursinus, Ursus ursinus',
|
299 |
+
298: 'mongoose',
|
300 |
+
299: 'meerkat, mierkat',
|
301 |
+
300: 'tiger beetle',
|
302 |
+
301: 'ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle',
|
303 |
+
302: 'ground beetle, carabid beetle',
|
304 |
+
303: 'long-horned beetle, longicorn, longicorn beetle',
|
305 |
+
304: 'leaf beetle, chrysomelid',
|
306 |
+
305: 'dung beetle',
|
307 |
+
306: 'rhinoceros beetle',
|
308 |
+
307: 'weevil',
|
309 |
+
308: 'fly',
|
310 |
+
309: 'bee',
|
311 |
+
310: 'ant, emmet, pismire',
|
312 |
+
311: 'grasshopper, hopper',
|
313 |
+
312: 'cricket',
|
314 |
+
313: 'walking stick, walkingstick, stick insect',
|
315 |
+
314: 'cockroach, roach',
|
316 |
+
315: 'mantis, mantid',
|
317 |
+
316: 'cicada, cicala',
|
318 |
+
317: 'leafhopper',
|
319 |
+
318: 'lacewing, lacewing fly',
|
320 |
+
319: "dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk",
|
321 |
+
320: 'damselfly',
|
322 |
+
321: 'admiral',
|
323 |
+
322: 'ringlet, ringlet butterfly',
|
324 |
+
323: 'monarch, monarch butterfly, milkweed butterfly, Danaus plexippus',
|
325 |
+
324: 'cabbage butterfly',
|
326 |
+
325: 'sulphur butterfly, sulfur butterfly',
|
327 |
+
326: 'lycaenid, lycaenid butterfly',
|
328 |
+
327: 'starfish, sea star',
|
329 |
+
328: 'sea urchin',
|
330 |
+
329: 'sea cucumber, holothurian',
|
331 |
+
330: 'wood rabbit, cottontail, cottontail rabbit',
|
332 |
+
331: 'hare',
|
333 |
+
332: 'Angora, Angora rabbit',
|
334 |
+
333: 'hamster',
|
335 |
+
334: 'porcupine, hedgehog',
|
336 |
+
335: 'fox squirrel, eastern fox squirrel, Sciurus niger',
|
337 |
+
336: 'marmot',
|
338 |
+
337: 'beaver',
|
339 |
+
338: 'guinea pig, Cavia cobaya',
|
340 |
+
339: 'sorrel',
|
341 |
+
340: 'zebra',
|
342 |
+
341: 'hog, pig, grunter, squealer, Sus scrofa',
|
343 |
+
342: 'wild boar, boar, Sus scrofa',
|
344 |
+
343: 'warthog',
|
345 |
+
344: 'hippopotamus, hippo, river horse, Hippopotamus amphibius',
|
346 |
+
345: 'ox',
|
347 |
+
346: 'water buffalo, water ox, Asiatic buffalo, Bubalus bubalis',
|
348 |
+
347: 'bison',
|
349 |
+
348: 'ram, tup',
|
350 |
+
349: 'bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis',
|
351 |
+
350: 'ibex, Capra ibex',
|
352 |
+
351: 'hartebeest',
|
353 |
+
352: 'impala, Aepyceros melampus',
|
354 |
+
353: 'gazelle',
|
355 |
+
354: 'Arabian camel, dromedary, Camelus dromedarius',
|
356 |
+
355: 'llama',
|
357 |
+
356: 'weasel',
|
358 |
+
357: 'mink',
|
359 |
+
358: 'polecat, fitch, foulmart, foumart, Mustela putorius',
|
360 |
+
359: 'black-footed ferret, ferret, Mustela nigripes',
|
361 |
+
360: 'otter',
|
362 |
+
361: 'skunk, polecat, wood pussy',
|
363 |
+
362: 'badger',
|
364 |
+
363: 'armadillo',
|
365 |
+
364: 'three-toed sloth, ai, Bradypus tridactylus',
|
366 |
+
365: 'orangutan, orang, orangutang, Pongo pygmaeus',
|
367 |
+
366: 'gorilla, Gorilla gorilla',
|
368 |
+
367: 'chimpanzee, chimp, Pan troglodytes',
|
369 |
+
368: 'gibbon, Hylobates lar',
|
370 |
+
369: 'siamang, Hylobates syndactylus, Symphalangus syndactylus',
|
371 |
+
370: 'guenon, guenon monkey',
|
372 |
+
371: 'patas, hussar monkey, Erythrocebus patas',
|
373 |
+
372: 'baboon',
|
374 |
+
373: 'macaque',
|
375 |
+
374: 'langur',
|
376 |
+
375: 'colobus, colobus monkey',
|
377 |
+
376: 'proboscis monkey, Nasalis larvatus',
|
378 |
+
377: 'marmoset',
|
379 |
+
378: 'capuchin, ringtail, Cebus capucinus',
|
380 |
+
379: 'howler monkey, howler',
|
381 |
+
380: 'titi, titi monkey',
|
382 |
+
381: 'spider monkey, Ateles geoffroyi',
|
383 |
+
382: 'squirrel monkey, Saimiri sciureus',
|
384 |
+
383: 'Madagascar cat, ring-tailed lemur, Lemur catta',
|
385 |
+
384: 'indri, indris, Indri indri, Indri brevicaudatus',
|
386 |
+
385: 'Indian elephant, Elephas maximus',
|
387 |
+
386: 'African elephant, Loxodonta africana',
|
388 |
+
387: 'lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens',
|
389 |
+
388: 'giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca',
|
390 |
+
389: 'barracouta, snoek',
|
391 |
+
390: 'eel',
|
392 |
+
391: 'coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch',
|
393 |
+
392: 'rock beauty, Holocanthus tricolor',
|
394 |
+
393: 'anemone fish',
|
395 |
+
394: 'sturgeon',
|
396 |
+
395: 'gar, garfish, garpike, billfish, Lepisosteus osseus',
|
397 |
+
396: 'lionfish',
|
398 |
+
397: 'puffer, pufferfish, blowfish, globefish',
|
399 |
+
398: 'abacus',
|
400 |
+
399: 'abaya',
|
401 |
+
400: "academic gown, academic robe, judge's robe",
|
402 |
+
401: 'accordion, piano accordion, squeeze box',
|
403 |
+
402: 'acoustic guitar',
|
404 |
+
403: 'aircraft carrier, carrier, flattop, attack aircraft carrier',
|
405 |
+
404: 'airliner',
|
406 |
+
405: 'airship, dirigible',
|
407 |
+
406: 'altar',
|
408 |
+
407: 'ambulance',
|
409 |
+
408: 'amphibian, amphibious vehicle',
|
410 |
+
409: 'analog clock',
|
411 |
+
410: 'apiary, bee house',
|
412 |
+
411: 'apron',
|
413 |
+
412: 'ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin',
|
414 |
+
413: 'assault rifle, assault gun',
|
415 |
+
414: 'backpack, back pack, knapsack, packsack, rucksack, haversack',
|
416 |
+
415: 'bakery, bakeshop, bakehouse',
|
417 |
+
416: 'balance beam, beam',
|
418 |
+
417: 'balloon',
|
419 |
+
418: 'ballpoint, ballpoint pen, ballpen, Biro',
|
420 |
+
419: 'Band Aid',
|
421 |
+
420: 'banjo',
|
422 |
+
421: 'bannister, banister, balustrade, balusters, handrail',
|
423 |
+
422: 'barbell',
|
424 |
+
423: 'barber chair',
|
425 |
+
424: 'barbershop',
|
426 |
+
425: 'barn',
|
427 |
+
426: 'barometer',
|
428 |
+
427: 'barrel, cask',
|
429 |
+
428: 'barrow, garden cart, lawn cart, wheelbarrow',
|
430 |
+
429: 'baseball',
|
431 |
+
430: 'basketball',
|
432 |
+
431: 'bassinet',
|
433 |
+
432: 'bassoon',
|
434 |
+
433: 'bathing cap, swimming cap',
|
435 |
+
434: 'bath towel',
|
436 |
+
435: 'bathtub, bathing tub, bath, tub',
|
437 |
+
436: 'beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon',
|
438 |
+
437: 'beacon, lighthouse, beacon light, pharos',
|
439 |
+
438: 'beaker',
|
440 |
+
439: 'bearskin, busby, shako',
|
441 |
+
440: 'beer bottle',
|
442 |
+
441: 'beer glass',
|
443 |
+
442: 'bell cote, bell cot',
|
444 |
+
443: 'bib',
|
445 |
+
444: 'bicycle-built-for-two, tandem bicycle, tandem',
|
446 |
+
445: 'bikini, two-piece',
|
447 |
+
446: 'binder, ring-binder',
|
448 |
+
447: 'binoculars, field glasses, opera glasses',
|
449 |
+
448: 'birdhouse',
|
450 |
+
449: 'boathouse',
|
451 |
+
450: 'bobsled, bobsleigh, bob',
|
452 |
+
451: 'bolo tie, bolo, bola tie, bola',
|
453 |
+
452: 'bonnet, poke bonnet',
|
454 |
+
453: 'bookcase',
|
455 |
+
454: 'bookshop, bookstore, bookstall',
|
456 |
+
455: 'bottlecap',
|
457 |
+
456: 'bow',
|
458 |
+
457: 'bow tie, bow-tie, bowtie',
|
459 |
+
458: 'brass, memorial tablet, plaque',
|
460 |
+
459: 'brassiere, bra, bandeau',
|
461 |
+
460: 'breakwater, groin, groyne, mole, bulwark, seawall, jetty',
|
462 |
+
461: 'breastplate, aegis, egis',
|
463 |
+
462: 'broom',
|
464 |
+
463: 'bucket, pail',
|
465 |
+
464: 'buckle',
|
466 |
+
465: 'bulletproof vest',
|
467 |
+
466: 'bullet train, bullet',
|
468 |
+
467: 'butcher shop, meat market',
|
469 |
+
468: 'cab, hack, taxi, taxicab',
|
470 |
+
469: 'caldron, cauldron',
|
471 |
+
470: 'candle, taper, wax light',
|
472 |
+
471: 'cannon',
|
473 |
+
472: 'canoe',
|
474 |
+
473: 'can opener, tin opener',
|
475 |
+
474: 'cardigan',
|
476 |
+
475: 'car mirror',
|
477 |
+
476: 'carousel, carrousel, merry-go-round, roundabout, whirligig',
|
478 |
+
477: "carpenter's kit, tool kit",
|
479 |
+
478: 'carton',
|
480 |
+
479: 'car wheel',
|
481 |
+
480: 'cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM',
|
482 |
+
481: 'cassette',
|
483 |
+
482: 'cassette player',
|
484 |
+
483: 'castle',
|
485 |
+
484: 'catamaran',
|
486 |
+
485: 'CD player',
|
487 |
+
486: 'cello, violoncello',
|
488 |
+
487: 'cellular telephone, cellular phone, cellphone, cell, mobile phone',
|
489 |
+
488: 'chain',
|
490 |
+
489: 'chainlink fence',
|
491 |
+
490: 'chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour',
|
492 |
+
491: 'chain saw, chainsaw',
|
493 |
+
492: 'chest',
|
494 |
+
493: 'chiffonier, commode',
|
495 |
+
494: 'chime, bell, gong',
|
496 |
+
495: 'china cabinet, china closet',
|
497 |
+
496: 'Christmas stocking',
|
498 |
+
497: 'church, church building',
|
499 |
+
498: 'cinema, movie theater, movie theatre, movie house, picture palace',
|
500 |
+
499: 'cleaver, meat cleaver, chopper',
|
501 |
+
500: 'cliff dwelling',
|
502 |
+
501: 'cloak',
|
503 |
+
502: 'clog, geta, patten, sabot',
|
504 |
+
503: 'cocktail shaker',
|
505 |
+
504: 'coffee mug',
|
506 |
+
505: 'coffeepot',
|
507 |
+
506: 'coil, spiral, volute, whorl, helix',
|
508 |
+
507: 'combination lock',
|
509 |
+
508: 'computer keyboard, keypad',
|
510 |
+
509: 'confectionery, confectionary, candy store',
|
511 |
+
510: 'container ship, containership, container vessel',
|
512 |
+
511: 'convertible',
|
513 |
+
512: 'corkscrew, bottle screw',
|
514 |
+
513: 'cornet, horn, trumpet, trump',
|
515 |
+
514: 'cowboy boot',
|
516 |
+
515: 'cowboy hat, ten-gallon hat',
|
517 |
+
516: 'cradle',
|
518 |
+
517: 'crane',
|
519 |
+
518: 'crash helmet',
|
520 |
+
519: 'crate',
|
521 |
+
520: 'crib, cot',
|
522 |
+
521: 'Crock Pot',
|
523 |
+
522: 'croquet ball',
|
524 |
+
523: 'crutch',
|
525 |
+
524: 'cuirass',
|
526 |
+
525: 'dam, dike, dyke',
|
527 |
+
526: 'desk',
|
528 |
+
527: 'desktop computer',
|
529 |
+
528: 'dial telephone, dial phone',
|
530 |
+
529: 'diaper, nappy, napkin',
|
531 |
+
530: 'digital clock',
|
532 |
+
531: 'digital watch',
|
533 |
+
532: 'dining table, board',
|
534 |
+
533: 'dishrag, dishcloth',
|
535 |
+
534: 'dishwasher, dish washer, dishwashing machine',
|
536 |
+
535: 'disk brake, disc brake',
|
537 |
+
536: 'dock, dockage, docking facility',
|
538 |
+
537: 'dogsled, dog sled, dog sleigh',
|
539 |
+
538: 'dome',
|
540 |
+
539: 'doormat, welcome mat',
|
541 |
+
540: 'drilling platform, offshore rig',
|
542 |
+
541: 'drum, membranophone, tympan',
|
543 |
+
542: 'drumstick',
|
544 |
+
543: 'dumbbell',
|
545 |
+
544: 'Dutch oven',
|
546 |
+
545: 'electric fan, blower',
|
547 |
+
546: 'electric guitar',
|
548 |
+
547: 'electric locomotive',
|
549 |
+
548: 'entertainment center',
|
550 |
+
549: 'envelope',
|
551 |
+
550: 'espresso maker',
|
552 |
+
551: 'face powder',
|
553 |
+
552: 'feather boa, boa',
|
554 |
+
553: 'file, file cabinet, filing cabinet',
|
555 |
+
554: 'fireboat',
|
556 |
+
555: 'fire engine, fire truck',
|
557 |
+
556: 'fire screen, fireguard',
|
558 |
+
557: 'flagpole, flagstaff',
|
559 |
+
558: 'flute, transverse flute',
|
560 |
+
559: 'folding chair',
|
561 |
+
560: 'football helmet',
|
562 |
+
561: 'forklift',
|
563 |
+
562: 'fountain',
|
564 |
+
563: 'fountain pen',
|
565 |
+
564: 'four-poster',
|
566 |
+
565: 'freight car',
|
567 |
+
566: 'French horn, horn',
|
568 |
+
567: 'frying pan, frypan, skillet',
|
569 |
+
568: 'fur coat',
|
570 |
+
569: 'garbage truck, dustcart',
|
571 |
+
570: 'gasmask, respirator, gas helmet',
|
572 |
+
571: 'gas pump, gasoline pump, petrol pump, island dispenser',
|
573 |
+
572: 'goblet',
|
574 |
+
573: 'go-kart',
|
575 |
+
574: 'golf ball',
|
576 |
+
575: 'golfcart, golf cart',
|
577 |
+
576: 'gondola',
|
578 |
+
577: 'gong, tam-tam',
|
579 |
+
578: 'gown',
|
580 |
+
579: 'grand piano, grand',
|
581 |
+
580: 'greenhouse, nursery, glasshouse',
|
582 |
+
581: 'grille, radiator grille',
|
583 |
+
582: 'grocery store, grocery, food market, market',
|
584 |
+
583: 'guillotine',
|
585 |
+
584: 'hair slide',
|
586 |
+
585: 'hair spray',
|
587 |
+
586: 'half track',
|
588 |
+
587: 'hammer',
|
589 |
+
588: 'hamper',
|
590 |
+
589: 'hand blower, blow dryer, blow drier, hair dryer, hair drier',
|
591 |
+
590: 'hand-held computer, hand-held microcomputer',
|
592 |
+
591: 'handkerchief, hankie, hanky, hankey',
|
593 |
+
592: 'hard disc, hard disk, fixed disk',
|
594 |
+
593: 'harmonica, mouth organ, harp, mouth harp',
|
595 |
+
594: 'harp',
|
596 |
+
595: 'harvester, reaper',
|
597 |
+
596: 'hatchet',
|
598 |
+
597: 'holster',
|
599 |
+
598: 'home theater, home theatre',
|
600 |
+
599: 'honeycomb',
|
601 |
+
600: 'hook, claw',
|
602 |
+
601: 'hoopskirt, crinoline',
|
603 |
+
602: 'horizontal bar, high bar',
|
604 |
+
603: 'horse cart, horse-cart',
|
605 |
+
604: 'hourglass',
|
606 |
+
605: 'iPod',
|
607 |
+
606: 'iron, smoothing iron',
|
608 |
+
607: "jack-o'-lantern",
|
609 |
+
608: 'jean, blue jean, denim',
|
610 |
+
609: 'jeep, landrover',
|
611 |
+
610: 'jersey, T-shirt, tee shirt',
|
612 |
+
611: 'jigsaw puzzle',
|
613 |
+
612: 'jinrikisha, ricksha, rickshaw',
|
614 |
+
613: 'joystick',
|
615 |
+
614: 'kimono',
|
616 |
+
615: 'knee pad',
|
617 |
+
616: 'knot',
|
618 |
+
617: 'lab coat, laboratory coat',
|
619 |
+
618: 'ladle',
|
620 |
+
619: 'lampshade, lamp shade',
|
621 |
+
620: 'laptop, laptop computer',
|
622 |
+
621: 'lawn mower, mower',
|
623 |
+
622: 'lens cap, lens cover',
|
624 |
+
623: 'letter opener, paper knife, paperknife',
|
625 |
+
624: 'library',
|
626 |
+
625: 'lifeboat',
|
627 |
+
626: 'lighter, light, igniter, ignitor',
|
628 |
+
627: 'limousine, limo',
|
629 |
+
628: 'liner, ocean liner',
|
630 |
+
629: 'lipstick, lip rouge',
|
631 |
+
630: 'Loafer',
|
632 |
+
631: 'lotion',
|
633 |
+
632: 'loudspeaker, speaker, speaker unit, loudspeaker system, speaker system',
|
634 |
+
633: "loupe, jeweler's loupe",
|
635 |
+
634: 'lumbermill, sawmill',
|
636 |
+
635: 'magnetic compass',
|
637 |
+
636: 'mailbag, postbag',
|
638 |
+
637: 'mailbox, letter box',
|
639 |
+
638: 'maillot',
|
640 |
+
639: 'maillot, tank suit',
|
641 |
+
640: 'manhole cover',
|
642 |
+
641: 'maraca',
|
643 |
+
642: 'marimba, xylophone',
|
644 |
+
643: 'mask',
|
645 |
+
644: 'matchstick',
|
646 |
+
645: 'maypole',
|
647 |
+
646: 'maze, labyrinth',
|
648 |
+
647: 'measuring cup',
|
649 |
+
648: 'medicine chest, medicine cabinet',
|
650 |
+
649: 'megalith, megalithic structure',
|
651 |
+
650: 'microphone, mike',
|
652 |
+
651: 'microwave, microwave oven',
|
653 |
+
652: 'military uniform',
|
654 |
+
653: 'milk can',
|
655 |
+
654: 'minibus',
|
656 |
+
655: 'miniskirt, mini',
|
657 |
+
656: 'minivan',
|
658 |
+
657: 'missile',
|
659 |
+
658: 'mitten',
|
660 |
+
659: 'mixing bowl',
|
661 |
+
660: 'mobile home, manufactured home',
|
662 |
+
661: 'Model T',
|
663 |
+
662: 'modem',
|
664 |
+
663: 'monastery',
|
665 |
+
664: 'monitor',
|
666 |
+
665: 'moped',
|
667 |
+
666: 'mortar',
|
668 |
+
667: 'mortarboard',
|
669 |
+
668: 'mosque',
|
670 |
+
669: 'mosquito net',
|
671 |
+
670: 'motor scooter, scooter',
|
672 |
+
671: 'mountain bike, all-terrain bike, off-roader',
|
673 |
+
672: 'mountain tent',
|
674 |
+
673: 'mouse, computer mouse',
|
675 |
+
674: 'mousetrap',
|
676 |
+
675: 'moving van',
|
677 |
+
676: 'muzzle',
|
678 |
+
677: 'nail',
|
679 |
+
678: 'neck brace',
|
680 |
+
679: 'necklace',
|
681 |
+
680: 'nipple',
|
682 |
+
681: 'notebook, notebook computer',
|
683 |
+
682: 'obelisk',
|
684 |
+
683: 'oboe, hautboy, hautbois',
|
685 |
+
684: 'ocarina, sweet potato',
|
686 |
+
685: 'odometer, hodometer, mileometer, milometer',
|
687 |
+
686: 'oil filter',
|
688 |
+
687: 'organ, pipe organ',
|
689 |
+
688: 'oscilloscope, scope, cathode-ray oscilloscope, CRO',
|
690 |
+
689: 'overskirt',
|
691 |
+
690: 'oxcart',
|
692 |
+
691: 'oxygen mask',
|
693 |
+
692: 'packet',
|
694 |
+
693: 'paddle, boat paddle',
|
695 |
+
694: 'paddlewheel, paddle wheel',
|
696 |
+
695: 'padlock',
|
697 |
+
696: 'paintbrush',
|
698 |
+
697: "pajama, pyjama, pj's, jammies",
|
699 |
+
698: 'palace',
|
700 |
+
699: 'panpipe, pandean pipe, syrinx',
|
701 |
+
700: 'paper towel',
|
702 |
+
701: 'parachute, chute',
|
703 |
+
702: 'parallel bars, bars',
|
704 |
+
703: 'park bench',
|
705 |
+
704: 'parking meter',
|
706 |
+
705: 'passenger car, coach, carriage',
|
707 |
+
706: 'patio, terrace',
|
708 |
+
707: 'pay-phone, pay-station',
|
709 |
+
708: 'pedestal, plinth, footstall',
|
710 |
+
709: 'pencil box, pencil case',
|
711 |
+
710: 'pencil sharpener',
|
712 |
+
711: 'perfume, essence',
|
713 |
+
712: 'Petri dish',
|
714 |
+
713: 'photocopier',
|
715 |
+
714: 'pick, plectrum, plectron',
|
716 |
+
715: 'pickelhaube',
|
717 |
+
716: 'picket fence, paling',
|
718 |
+
717: 'pickup, pickup truck',
|
719 |
+
718: 'pier',
|
720 |
+
719: 'piggy bank, penny bank',
|
721 |
+
720: 'pill bottle',
|
722 |
+
721: 'pillow',
|
723 |
+
722: 'ping-pong ball',
|
724 |
+
723: 'pinwheel',
|
725 |
+
724: 'pirate, pirate ship',
|
726 |
+
725: 'pitcher, ewer',
|
727 |
+
726: "plane, carpenter's plane, woodworking plane",
|
728 |
+
727: 'planetarium',
|
729 |
+
728: 'plastic bag',
|
730 |
+
729: 'plate rack',
|
731 |
+
730: 'plow, plough',
|
732 |
+
731: "plunger, plumber's helper",
|
733 |
+
732: 'Polaroid camera, Polaroid Land camera',
|
734 |
+
733: 'pole',
|
735 |
+
734: 'police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria',
|
736 |
+
735: 'poncho',
|
737 |
+
736: 'pool table, billiard table, snooker table',
|
738 |
+
737: 'pop bottle, soda bottle',
|
739 |
+
738: 'pot, flowerpot',
|
740 |
+
739: "potter's wheel",
|
741 |
+
740: 'power drill',
|
742 |
+
741: 'prayer rug, prayer mat',
|
743 |
+
742: 'printer',
|
744 |
+
743: 'prison, prison house',
|
745 |
+
744: 'projectile, missile',
|
746 |
+
745: 'projector',
|
747 |
+
746: 'puck, hockey puck',
|
748 |
+
747: 'punching bag, punch bag, punching ball, punchball',
|
749 |
+
748: 'purse',
|
750 |
+
749: 'quill, quill pen',
|
751 |
+
750: 'quilt, comforter, comfort, puff',
|
752 |
+
751: 'racer, race car, racing car',
|
753 |
+
752: 'racket, racquet',
|
754 |
+
753: 'radiator',
|
755 |
+
754: 'radio, wireless',
|
756 |
+
755: 'radio telescope, radio reflector',
|
757 |
+
756: 'rain barrel',
|
758 |
+
757: 'recreational vehicle, RV, R.V.',
|
759 |
+
758: 'reel',
|
760 |
+
759: 'reflex camera',
|
761 |
+
760: 'refrigerator, icebox',
|
762 |
+
761: 'remote control, remote',
|
763 |
+
762: 'restaurant, eating house, eating place, eatery',
|
764 |
+
763: 'revolver, six-gun, six-shooter',
|
765 |
+
764: 'rifle',
|
766 |
+
765: 'rocking chair, rocker',
|
767 |
+
766: 'rotisserie',
|
768 |
+
767: 'rubber eraser, rubber, pencil eraser',
|
769 |
+
768: 'rugby ball',
|
770 |
+
769: 'rule, ruler',
|
771 |
+
770: 'running shoe',
|
772 |
+
771: 'safe',
|
773 |
+
772: 'safety pin',
|
774 |
+
773: 'saltshaker, salt shaker',
|
775 |
+
774: 'sandal',
|
776 |
+
775: 'sarong',
|
777 |
+
776: 'sax, saxophone',
|
778 |
+
777: 'scabbard',
|
779 |
+
778: 'scale, weighing machine',
|
780 |
+
779: 'school bus',
|
781 |
+
780: 'schooner',
|
782 |
+
781: 'scoreboard',
|
783 |
+
782: 'screen, CRT screen',
|
784 |
+
783: 'screw',
|
785 |
+
784: 'screwdriver',
|
786 |
+
785: 'seat belt, seatbelt',
|
787 |
+
786: 'sewing machine',
|
788 |
+
787: 'shield, buckler',
|
789 |
+
788: 'shoe shop, shoe-shop, shoe store',
|
790 |
+
789: 'shoji',
|
791 |
+
790: 'shopping basket',
|
792 |
+
791: 'shopping cart',
|
793 |
+
792: 'shovel',
|
794 |
+
793: 'shower cap',
|
795 |
+
794: 'shower curtain',
|
796 |
+
795: 'ski',
|
797 |
+
796: 'ski mask',
|
798 |
+
797: 'sleeping bag',
|
799 |
+
798: 'slide rule, slipstick',
|
800 |
+
799: 'sliding door',
|
801 |
+
800: 'slot, one-armed bandit',
|
802 |
+
801: 'snorkel',
|
803 |
+
802: 'snowmobile',
|
804 |
+
803: 'snowplow, snowplough',
|
805 |
+
804: 'soap dispenser',
|
806 |
+
805: 'soccer ball',
|
807 |
+
806: 'sock',
|
808 |
+
807: 'solar dish, solar collector, solar furnace',
|
809 |
+
808: 'sombrero',
|
810 |
+
809: 'soup bowl',
|
811 |
+
810: 'space bar',
|
812 |
+
811: 'space heater',
|
813 |
+
812: 'space shuttle',
|
814 |
+
813: 'spatula',
|
815 |
+
814: 'speedboat',
|
816 |
+
815: "spider web, spider's web",
|
817 |
+
816: 'spindle',
|
818 |
+
817: 'sports car, sport car',
|
819 |
+
818: 'spotlight, spot',
|
820 |
+
819: 'stage',
|
821 |
+
820: 'steam locomotive',
|
822 |
+
821: 'steel arch bridge',
|
823 |
+
822: 'steel drum',
|
824 |
+
823: 'stethoscope',
|
825 |
+
824: 'stole',
|
826 |
+
825: 'stone wall',
|
827 |
+
826: 'stopwatch, stop watch',
|
828 |
+
827: 'stove',
|
829 |
+
828: 'strainer',
|
830 |
+
829: 'streetcar, tram, tramcar, trolley, trolley car',
|
831 |
+
830: 'stretcher',
|
832 |
+
831: 'studio couch, day bed',
|
833 |
+
832: 'stupa, tope',
|
834 |
+
833: 'submarine, pigboat, sub, U-boat',
|
835 |
+
834: 'suit, suit of clothes',
|
836 |
+
835: 'sundial',
|
837 |
+
836: 'sunglass',
|
838 |
+
837: 'sunglasses, dark glasses, shades',
|
839 |
+
838: 'sunscreen, sunblock, sun blocker',
|
840 |
+
839: 'suspension bridge',
|
841 |
+
840: 'swab, swob, mop',
|
842 |
+
841: 'sweatshirt',
|
843 |
+
842: 'swimming trunks, bathing trunks',
|
844 |
+
843: 'swing',
|
845 |
+
844: 'switch, electric switch, electrical switch',
|
846 |
+
845: 'syringe',
|
847 |
+
846: 'table lamp',
|
848 |
+
847: 'tank, army tank, armored combat vehicle, armoured combat vehicle',
|
849 |
+
848: 'tape player',
|
850 |
+
849: 'teapot',
|
851 |
+
850: 'teddy, teddy bear',
|
852 |
+
851: 'television, television system',
|
853 |
+
852: 'tennis ball',
|
854 |
+
853: 'thatch, thatched roof',
|
855 |
+
854: 'theater curtain, theatre curtain',
|
856 |
+
855: 'thimble',
|
857 |
+
856: 'thresher, thrasher, threshing machine',
|
858 |
+
857: 'throne',
|
859 |
+
858: 'tile roof',
|
860 |
+
859: 'toaster',
|
861 |
+
860: 'tobacco shop, tobacconist shop, tobacconist',
|
862 |
+
861: 'toilet seat',
|
863 |
+
862: 'torch',
|
864 |
+
863: 'totem pole',
|
865 |
+
864: 'tow truck, tow car, wrecker',
|
866 |
+
865: 'toyshop',
|
867 |
+
866: 'tractor',
|
868 |
+
867: 'trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi',
|
869 |
+
868: 'tray',
|
870 |
+
869: 'trench coat',
|
871 |
+
870: 'tricycle, trike, velocipede',
|
872 |
+
871: 'trimaran',
|
873 |
+
872: 'tripod',
|
874 |
+
873: 'triumphal arch',
|
875 |
+
874: 'trolleybus, trolley coach, trackless trolley',
|
876 |
+
875: 'trombone',
|
877 |
+
876: 'tub, vat',
|
878 |
+
877: 'turnstile',
|
879 |
+
878: 'typewriter keyboard',
|
880 |
+
879: 'umbrella',
|
881 |
+
880: 'unicycle, monocycle',
|
882 |
+
881: 'upright, upright piano',
|
883 |
+
882: 'vacuum, vacuum cleaner',
|
884 |
+
883: 'vase',
|
885 |
+
884: 'vault',
|
886 |
+
885: 'velvet',
|
887 |
+
886: 'vending machine',
|
888 |
+
887: 'vestment',
|
889 |
+
888: 'viaduct',
|
890 |
+
889: 'violin, fiddle',
|
891 |
+
890: 'volleyball',
|
892 |
+
891: 'waffle iron',
|
893 |
+
892: 'wall clock',
|
894 |
+
893: 'wallet, billfold, notecase, pocketbook',
|
895 |
+
894: 'wardrobe, closet, press',
|
896 |
+
895: 'warplane, military plane',
|
897 |
+
896: 'washbasin, handbasin, washbowl, lavabo, wash-hand basin',
|
898 |
+
897: 'washer, automatic washer, washing machine',
|
899 |
+
898: 'water bottle',
|
900 |
+
899: 'water jug',
|
901 |
+
900: 'water tower',
|
902 |
+
901: 'whiskey jug',
|
903 |
+
902: 'whistle',
|
904 |
+
903: 'wig',
|
905 |
+
904: 'window screen',
|
906 |
+
905: 'window shade',
|
907 |
+
906: 'Windsor tie',
|
908 |
+
907: 'wine bottle',
|
909 |
+
908: 'wing',
|
910 |
+
909: 'wok',
|
911 |
+
910: 'wooden spoon',
|
912 |
+
911: 'wool, woolen, woollen',
|
913 |
+
912: 'worm fence, snake fence, snake-rail fence, Virginia fence',
|
914 |
+
913: 'wreck',
|
915 |
+
914: 'yawl',
|
916 |
+
915: 'yurt',
|
917 |
+
916: 'web site, website, internet site, site',
|
918 |
+
917: 'comic book',
|
919 |
+
918: 'crossword puzzle, crossword',
|
920 |
+
919: 'street sign',
|
921 |
+
920: 'traffic light, traffic signal, stoplight',
|
922 |
+
921: 'book jacket, dust cover, dust jacket, dust wrapper',
|
923 |
+
922: 'menu',
|
924 |
+
923: 'plate',
|
925 |
+
924: 'guacamole',
|
926 |
+
925: 'consomme',
|
927 |
+
926: 'hot pot, hotpot',
|
928 |
+
927: 'trifle',
|
929 |
+
928: 'ice cream, icecream',
|
930 |
+
929: 'ice lolly, lolly, lollipop, popsicle',
|
931 |
+
930: 'French loaf',
|
932 |
+
931: 'bagel, beigel',
|
933 |
+
932: 'pretzel',
|
934 |
+
933: 'cheeseburger',
|
935 |
+
934: 'hotdog, hot dog, red hot',
|
936 |
+
935: 'mashed potato',
|
937 |
+
936: 'head cabbage',
|
938 |
+
937: 'broccoli',
|
939 |
+
938: 'cauliflower',
|
940 |
+
939: 'zucchini, courgette',
|
941 |
+
940: 'spaghetti squash',
|
942 |
+
941: 'acorn squash',
|
943 |
+
942: 'butternut squash',
|
944 |
+
943: 'cucumber, cuke',
|
945 |
+
944: 'artichoke, globe artichoke',
|
946 |
+
945: 'bell pepper',
|
947 |
+
946: 'cardoon',
|
948 |
+
947: 'mushroom',
|
949 |
+
948: 'Granny Smith',
|
950 |
+
949: 'strawberry',
|
951 |
+
950: 'orange',
|
952 |
+
951: 'lemon',
|
953 |
+
952: 'fig',
|
954 |
+
953: 'pineapple, ananas',
|
955 |
+
954: 'banana',
|
956 |
+
955: 'jackfruit, jak, jack',
|
957 |
+
956: 'custard apple',
|
958 |
+
957: 'pomegranate',
|
959 |
+
958: 'hay',
|
960 |
+
959: 'carbonara',
|
961 |
+
960: 'chocolate sauce, chocolate syrup',
|
962 |
+
961: 'dough',
|
963 |
+
962: 'meat loaf, meatloaf',
|
964 |
+
963: 'pizza, pizza pie',
|
965 |
+
964: 'potpie',
|
966 |
+
965: 'burrito',
|
967 |
+
966: 'red wine',
|
968 |
+
967: 'espresso',
|
969 |
+
968: 'cup',
|
970 |
+
969: 'eggnog',
|
971 |
+
970: 'alp',
|
972 |
+
971: 'bubble',
|
973 |
+
972: 'cliff, drop, drop-off',
|
974 |
+
973: 'coral reef',
|
975 |
+
974: 'geyser',
|
976 |
+
975: 'lakeside, lakeshore',
|
977 |
+
976: 'promontory, headland, head, foreland',
|
978 |
+
977: 'sandbar, sand bar',
|
979 |
+
978: 'seashore, coast, seacoast, sea-coast',
|
980 |
+
979: 'valley, vale',
|
981 |
+
980: 'volcano',
|
982 |
+
981: 'ballplayer, baseball player',
|
983 |
+
982: 'groom, bridegroom',
|
984 |
+
983: 'scuba diver',
|
985 |
+
984: 'rapeseed',
|
986 |
+
985: 'daisy',
|
987 |
+
986: "yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum",
|
988 |
+
987: 'corn',
|
989 |
+
988: 'acorn',
|
990 |
+
989: 'hip, rose hip, rosehip',
|
991 |
+
990: 'buckeye, horse chestnut, conker',
|
992 |
+
991: 'coral fungus',
|
993 |
+
992: 'agaric',
|
994 |
+
993: 'gyromitra',
|
995 |
+
994: 'stinkhorn, carrion fungus',
|
996 |
+
995: 'earthstar',
|
997 |
+
996: 'hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa',
|
998 |
+
997: 'bolete',
|
999 |
+
998: 'ear, spike, capitulum',
|
1000 |
+
999: 'toilet tissue, toilet paper, bathroom tissue'
|
gligen/ldm/data/imagenet_train_hr_indices.p
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:f86ea1924a1522b20bc0f709a069cc65f09d5fc617a7a31af7aaa3839a5a4d73
|
3 |
+
size 132
|
gligen/ldm/data/imagenet_val_hr_indices.p
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:ff1f5eb275a93c0fb53e227679f323ea1d024c87db296453296cebeef86fc0f4
|
3 |
+
size 131
|
gligen/ldm/data/index_synset.yaml
ADDED
@@ -0,0 +1,1000 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
0: n01440764
|
2 |
+
1: n01443537
|
3 |
+
2: n01484850
|
4 |
+
3: n01491361
|
5 |
+
4: n01494475
|
6 |
+
5: n01496331
|
7 |
+
6: n01498041
|
8 |
+
7: n01514668
|
9 |
+
8: n07646067
|
10 |
+
9: n01518878
|
11 |
+
10: n01530575
|
12 |
+
11: n01531178
|
13 |
+
12: n01532829
|
14 |
+
13: n01534433
|
15 |
+
14: n01537544
|
16 |
+
15: n01558993
|
17 |
+
16: n01560419
|
18 |
+
17: n01580077
|
19 |
+
18: n01582220
|
20 |
+
19: n01592084
|
21 |
+
20: n01601694
|
22 |
+
21: n13382471
|
23 |
+
22: n01614925
|
24 |
+
23: n01616318
|
25 |
+
24: n01622779
|
26 |
+
25: n01629819
|
27 |
+
26: n01630670
|
28 |
+
27: n01631663
|
29 |
+
28: n01632458
|
30 |
+
29: n01632777
|
31 |
+
30: n01641577
|
32 |
+
31: n01644373
|
33 |
+
32: n01644900
|
34 |
+
33: n01664065
|
35 |
+
34: n01665541
|
36 |
+
35: n01667114
|
37 |
+
36: n01667778
|
38 |
+
37: n01669191
|
39 |
+
38: n01675722
|
40 |
+
39: n01677366
|
41 |
+
40: n01682714
|
42 |
+
41: n01685808
|
43 |
+
42: n01687978
|
44 |
+
43: n01688243
|
45 |
+
44: n01689811
|
46 |
+
45: n01692333
|
47 |
+
46: n01693334
|
48 |
+
47: n01694178
|
49 |
+
48: n01695060
|
50 |
+
49: n01697457
|
51 |
+
50: n01698640
|
52 |
+
51: n01704323
|
53 |
+
52: n01728572
|
54 |
+
53: n01728920
|
55 |
+
54: n01729322
|
56 |
+
55: n01729977
|
57 |
+
56: n01734418
|
58 |
+
57: n01735189
|
59 |
+
58: n01737021
|
60 |
+
59: n01739381
|
61 |
+
60: n01740131
|
62 |
+
61: n01742172
|
63 |
+
62: n01744401
|
64 |
+
63: n01748264
|
65 |
+
64: n01749939
|
66 |
+
65: n01751748
|
67 |
+
66: n01753488
|
68 |
+
67: n01755581
|
69 |
+
68: n01756291
|
70 |
+
69: n01768244
|
71 |
+
70: n01770081
|
72 |
+
71: n01770393
|
73 |
+
72: n01773157
|
74 |
+
73: n01773549
|
75 |
+
74: n01773797
|
76 |
+
75: n01774384
|
77 |
+
76: n01774750
|
78 |
+
77: n01775062
|
79 |
+
78: n04432308
|
80 |
+
79: n01784675
|
81 |
+
80: n01795545
|
82 |
+
81: n01796340
|
83 |
+
82: n01797886
|
84 |
+
83: n01798484
|
85 |
+
84: n01806143
|
86 |
+
85: n07647321
|
87 |
+
86: n07647496
|
88 |
+
87: n01817953
|
89 |
+
88: n01818515
|
90 |
+
89: n01819313
|
91 |
+
90: n01820546
|
92 |
+
91: n01824575
|
93 |
+
92: n01828970
|
94 |
+
93: n01829413
|
95 |
+
94: n01833805
|
96 |
+
95: n01843065
|
97 |
+
96: n01843383
|
98 |
+
97: n01847000
|
99 |
+
98: n01855032
|
100 |
+
99: n07646821
|
101 |
+
100: n01860187
|
102 |
+
101: n01871265
|
103 |
+
102: n01872772
|
104 |
+
103: n01873310
|
105 |
+
104: n01877812
|
106 |
+
105: n01882714
|
107 |
+
106: n01883070
|
108 |
+
107: n01910747
|
109 |
+
108: n01914609
|
110 |
+
109: n01917289
|
111 |
+
110: n01924916
|
112 |
+
111: n01930112
|
113 |
+
112: n01943899
|
114 |
+
113: n01944390
|
115 |
+
114: n13719102
|
116 |
+
115: n01950731
|
117 |
+
116: n01955084
|
118 |
+
117: n01968897
|
119 |
+
118: n01978287
|
120 |
+
119: n01978455
|
121 |
+
120: n01980166
|
122 |
+
121: n01981276
|
123 |
+
122: n01983481
|
124 |
+
123: n01984695
|
125 |
+
124: n01985128
|
126 |
+
125: n01986214
|
127 |
+
126: n01990800
|
128 |
+
127: n02002556
|
129 |
+
128: n02002724
|
130 |
+
129: n02006656
|
131 |
+
130: n02007558
|
132 |
+
131: n02009229
|
133 |
+
132: n02009912
|
134 |
+
133: n02011460
|
135 |
+
134: n03126707
|
136 |
+
135: n02013706
|
137 |
+
136: n02017213
|
138 |
+
137: n02018207
|
139 |
+
138: n02018795
|
140 |
+
139: n02025239
|
141 |
+
140: n02027492
|
142 |
+
141: n02028035
|
143 |
+
142: n02033041
|
144 |
+
143: n02037110
|
145 |
+
144: n02051845
|
146 |
+
145: n02056570
|
147 |
+
146: n02058221
|
148 |
+
147: n02066245
|
149 |
+
148: n02071294
|
150 |
+
149: n02074367
|
151 |
+
150: n02077923
|
152 |
+
151: n08742578
|
153 |
+
152: n02085782
|
154 |
+
153: n02085936
|
155 |
+
154: n02086079
|
156 |
+
155: n02086240
|
157 |
+
156: n02086646
|
158 |
+
157: n02086910
|
159 |
+
158: n02087046
|
160 |
+
159: n02087394
|
161 |
+
160: n02088094
|
162 |
+
161: n02088238
|
163 |
+
162: n02088364
|
164 |
+
163: n02088466
|
165 |
+
164: n02088632
|
166 |
+
165: n02089078
|
167 |
+
166: n02089867
|
168 |
+
167: n02089973
|
169 |
+
168: n02090379
|
170 |
+
169: n02090622
|
171 |
+
170: n02090721
|
172 |
+
171: n02091032
|
173 |
+
172: n02091134
|
174 |
+
173: n02091244
|
175 |
+
174: n02091467
|
176 |
+
175: n02091635
|
177 |
+
176: n02091831
|
178 |
+
177: n02092002
|
179 |
+
178: n02092339
|
180 |
+
179: n02093256
|
181 |
+
180: n02093428
|
182 |
+
181: n02093647
|
183 |
+
182: n02093754
|
184 |
+
183: n02093859
|
185 |
+
184: n02093991
|
186 |
+
185: n02094114
|
187 |
+
186: n02094258
|
188 |
+
187: n02094433
|
189 |
+
188: n02095314
|
190 |
+
189: n02095570
|
191 |
+
190: n02095889
|
192 |
+
191: n02096051
|
193 |
+
192: n02096177
|
194 |
+
193: n02096294
|
195 |
+
194: n02096437
|
196 |
+
195: n02096585
|
197 |
+
196: n02097047
|
198 |
+
197: n02097130
|
199 |
+
198: n02097209
|
200 |
+
199: n02097298
|
201 |
+
200: n02097474
|
202 |
+
201: n02097658
|
203 |
+
202: n02098105
|
204 |
+
203: n02098286
|
205 |
+
204: n02098413
|
206 |
+
205: n02099267
|
207 |
+
206: n02099429
|
208 |
+
207: n02099601
|
209 |
+
208: n02099712
|
210 |
+
209: n02099849
|
211 |
+
210: n02100236
|
212 |
+
211: n02100583
|
213 |
+
212: n02100735
|
214 |
+
213: n02100877
|
215 |
+
214: n02101006
|
216 |
+
215: n02101388
|
217 |
+
216: n02101556
|
218 |
+
217: n02102040
|
219 |
+
218: n02102177
|
220 |
+
219: n02102318
|
221 |
+
220: n02102480
|
222 |
+
221: n02102973
|
223 |
+
222: n02104029
|
224 |
+
223: n02104365
|
225 |
+
224: n02105056
|
226 |
+
225: n02105162
|
227 |
+
226: n02105251
|
228 |
+
227: n02105412
|
229 |
+
228: n02105505
|
230 |
+
229: n02105641
|
231 |
+
230: n02105855
|
232 |
+
231: n02106030
|
233 |
+
232: n02106166
|
234 |
+
233: n02106382
|
235 |
+
234: n02106550
|
236 |
+
235: n02106662
|
237 |
+
236: n02107142
|
238 |
+
237: n02107312
|
239 |
+
238: n02107574
|
240 |
+
239: n02107683
|
241 |
+
240: n02107908
|
242 |
+
241: n02108000
|
243 |
+
242: n02108089
|
244 |
+
243: n02108422
|
245 |
+
244: n02108551
|
246 |
+
245: n02108915
|
247 |
+
246: n02109047
|
248 |
+
247: n02109525
|
249 |
+
248: n02109961
|
250 |
+
249: n02110063
|
251 |
+
250: n02110185
|
252 |
+
251: n02110341
|
253 |
+
252: n02110627
|
254 |
+
253: n02110806
|
255 |
+
254: n02110958
|
256 |
+
255: n02111129
|
257 |
+
256: n02111277
|
258 |
+
257: n02111500
|
259 |
+
258: n02111889
|
260 |
+
259: n02112018
|
261 |
+
260: n02112137
|
262 |
+
261: n02112350
|
263 |
+
262: n02112706
|
264 |
+
263: n02113023
|
265 |
+
264: n02113186
|
266 |
+
265: n02113624
|
267 |
+
266: n02113712
|
268 |
+
267: n02113799
|
269 |
+
268: n02113978
|
270 |
+
269: n02114367
|
271 |
+
270: n02114548
|
272 |
+
271: n02114712
|
273 |
+
272: n02114855
|
274 |
+
273: n02115641
|
275 |
+
274: n02115913
|
276 |
+
275: n02116738
|
277 |
+
276: n02117135
|
278 |
+
277: n02119022
|
279 |
+
278: n02119789
|
280 |
+
279: n02120079
|
281 |
+
280: n02120505
|
282 |
+
281: n02123045
|
283 |
+
282: n02123159
|
284 |
+
283: n02123394
|
285 |
+
284: n02123597
|
286 |
+
285: n02124075
|
287 |
+
286: n02125311
|
288 |
+
287: n02127052
|
289 |
+
288: n02128385
|
290 |
+
289: n02128757
|
291 |
+
290: n02128925
|
292 |
+
291: n02129165
|
293 |
+
292: n02129604
|
294 |
+
293: n02130308
|
295 |
+
294: n02132136
|
296 |
+
295: n02133161
|
297 |
+
296: n02134084
|
298 |
+
297: n02134418
|
299 |
+
298: n02137549
|
300 |
+
299: n02138441
|
301 |
+
300: n02165105
|
302 |
+
301: n02165456
|
303 |
+
302: n02167151
|
304 |
+
303: n02168699
|
305 |
+
304: n02169497
|
306 |
+
305: n02172182
|
307 |
+
306: n02174001
|
308 |
+
307: n02177972
|
309 |
+
308: n03373237
|
310 |
+
309: n07975909
|
311 |
+
310: n02219486
|
312 |
+
311: n02226429
|
313 |
+
312: n02229544
|
314 |
+
313: n02231487
|
315 |
+
314: n02233338
|
316 |
+
315: n02236044
|
317 |
+
316: n02256656
|
318 |
+
317: n02259212
|
319 |
+
318: n02264363
|
320 |
+
319: n02268443
|
321 |
+
320: n02268853
|
322 |
+
321: n02276258
|
323 |
+
322: n02277742
|
324 |
+
323: n02279972
|
325 |
+
324: n02280649
|
326 |
+
325: n02281406
|
327 |
+
326: n02281787
|
328 |
+
327: n02317335
|
329 |
+
328: n02319095
|
330 |
+
329: n02321529
|
331 |
+
330: n02325366
|
332 |
+
331: n02326432
|
333 |
+
332: n02328150
|
334 |
+
333: n02342885
|
335 |
+
334: n02346627
|
336 |
+
335: n02356798
|
337 |
+
336: n02361337
|
338 |
+
337: n05262120
|
339 |
+
338: n02364673
|
340 |
+
339: n02389026
|
341 |
+
340: n02391049
|
342 |
+
341: n02395406
|
343 |
+
342: n02396427
|
344 |
+
343: n02397096
|
345 |
+
344: n02398521
|
346 |
+
345: n02403003
|
347 |
+
346: n02408429
|
348 |
+
347: n02410509
|
349 |
+
348: n02412080
|
350 |
+
349: n02415577
|
351 |
+
350: n02417914
|
352 |
+
351: n02422106
|
353 |
+
352: n02422699
|
354 |
+
353: n02423022
|
355 |
+
354: n02437312
|
356 |
+
355: n02437616
|
357 |
+
356: n10771990
|
358 |
+
357: n14765497
|
359 |
+
358: n02443114
|
360 |
+
359: n02443484
|
361 |
+
360: n14765785
|
362 |
+
361: n02445715
|
363 |
+
362: n02447366
|
364 |
+
363: n02454379
|
365 |
+
364: n02457408
|
366 |
+
365: n02480495
|
367 |
+
366: n02480855
|
368 |
+
367: n02481823
|
369 |
+
368: n02483362
|
370 |
+
369: n02483708
|
371 |
+
370: n02484975
|
372 |
+
371: n02486261
|
373 |
+
372: n02486410
|
374 |
+
373: n02487347
|
375 |
+
374: n02488291
|
376 |
+
375: n02488702
|
377 |
+
376: n02489166
|
378 |
+
377: n02490219
|
379 |
+
378: n02492035
|
380 |
+
379: n02492660
|
381 |
+
380: n02493509
|
382 |
+
381: n02493793
|
383 |
+
382: n02494079
|
384 |
+
383: n02497673
|
385 |
+
384: n02500267
|
386 |
+
385: n02504013
|
387 |
+
386: n02504458
|
388 |
+
387: n02509815
|
389 |
+
388: n02510455
|
390 |
+
389: n02514041
|
391 |
+
390: n07783967
|
392 |
+
391: n02536864
|
393 |
+
392: n02606052
|
394 |
+
393: n02607072
|
395 |
+
394: n02640242
|
396 |
+
395: n02641379
|
397 |
+
396: n02643566
|
398 |
+
397: n02655020
|
399 |
+
398: n02666347
|
400 |
+
399: n02667093
|
401 |
+
400: n02669723
|
402 |
+
401: n02672831
|
403 |
+
402: n02676566
|
404 |
+
403: n02687172
|
405 |
+
404: n02690373
|
406 |
+
405: n02692877
|
407 |
+
406: n02699494
|
408 |
+
407: n02701002
|
409 |
+
408: n02704792
|
410 |
+
409: n02708093
|
411 |
+
410: n02727426
|
412 |
+
411: n08496334
|
413 |
+
412: n02747177
|
414 |
+
413: n02749479
|
415 |
+
414: n02769748
|
416 |
+
415: n02776631
|
417 |
+
416: n02777292
|
418 |
+
417: n02782329
|
419 |
+
418: n02783161
|
420 |
+
419: n02786058
|
421 |
+
420: n02787622
|
422 |
+
421: n02788148
|
423 |
+
422: n02790996
|
424 |
+
423: n02791124
|
425 |
+
424: n02791270
|
426 |
+
425: n02793495
|
427 |
+
426: n02794156
|
428 |
+
427: n02795169
|
429 |
+
428: n02797295
|
430 |
+
429: n02799071
|
431 |
+
430: n02802426
|
432 |
+
431: n02804515
|
433 |
+
432: n02804610
|
434 |
+
433: n02807133
|
435 |
+
434: n02808304
|
436 |
+
435: n02808440
|
437 |
+
436: n02814533
|
438 |
+
437: n02814860
|
439 |
+
438: n02815834
|
440 |
+
439: n02817516
|
441 |
+
440: n02823428
|
442 |
+
441: n02823750
|
443 |
+
442: n02825657
|
444 |
+
443: n02834397
|
445 |
+
444: n02835271
|
446 |
+
445: n02837789
|
447 |
+
446: n02840245
|
448 |
+
447: n02841315
|
449 |
+
448: n02843684
|
450 |
+
449: n02859443
|
451 |
+
450: n02860847
|
452 |
+
451: n02865351
|
453 |
+
452: n02869837
|
454 |
+
453: n02870880
|
455 |
+
454: n02871525
|
456 |
+
455: n02877765
|
457 |
+
456: n02880308
|
458 |
+
457: n02883205
|
459 |
+
458: n02892201
|
460 |
+
459: n02892767
|
461 |
+
460: n02894605
|
462 |
+
461: n02895154
|
463 |
+
462: n12520864
|
464 |
+
463: n02909870
|
465 |
+
464: n02910353
|
466 |
+
465: n02916936
|
467 |
+
466: n02917067
|
468 |
+
467: n02927161
|
469 |
+
468: n02930766
|
470 |
+
469: n02939185
|
471 |
+
470: n02948072
|
472 |
+
471: n02950826
|
473 |
+
472: n02951358
|
474 |
+
473: n02951585
|
475 |
+
474: n02963159
|
476 |
+
475: n02965783
|
477 |
+
476: n02966193
|
478 |
+
477: n02966687
|
479 |
+
478: n02971356
|
480 |
+
479: n02974003
|
481 |
+
480: n02977058
|
482 |
+
481: n02978881
|
483 |
+
482: n02979186
|
484 |
+
483: n02980441
|
485 |
+
484: n02981792
|
486 |
+
485: n02988304
|
487 |
+
486: n02992211
|
488 |
+
487: n02992529
|
489 |
+
488: n13652994
|
490 |
+
489: n03000134
|
491 |
+
490: n03000247
|
492 |
+
491: n03000684
|
493 |
+
492: n03014705
|
494 |
+
493: n03016953
|
495 |
+
494: n03017168
|
496 |
+
495: n03018349
|
497 |
+
496: n03026506
|
498 |
+
497: n03028079
|
499 |
+
498: n03032252
|
500 |
+
499: n03041632
|
501 |
+
500: n03042490
|
502 |
+
501: n03045698
|
503 |
+
502: n03047690
|
504 |
+
503: n03062245
|
505 |
+
504: n03063599
|
506 |
+
505: n03063689
|
507 |
+
506: n03065424
|
508 |
+
507: n03075370
|
509 |
+
508: n03085013
|
510 |
+
509: n03089624
|
511 |
+
510: n03095699
|
512 |
+
511: n03100240
|
513 |
+
512: n03109150
|
514 |
+
513: n03110669
|
515 |
+
514: n03124043
|
516 |
+
515: n03124170
|
517 |
+
516: n15142452
|
518 |
+
517: n03126707
|
519 |
+
518: n03127747
|
520 |
+
519: n03127925
|
521 |
+
520: n03131574
|
522 |
+
521: n03133878
|
523 |
+
522: n03134739
|
524 |
+
523: n03141823
|
525 |
+
524: n03146219
|
526 |
+
525: n03160309
|
527 |
+
526: n03179701
|
528 |
+
527: n03180011
|
529 |
+
528: n03187595
|
530 |
+
529: n03188531
|
531 |
+
530: n03196217
|
532 |
+
531: n03197337
|
533 |
+
532: n03201208
|
534 |
+
533: n03207743
|
535 |
+
534: n03207941
|
536 |
+
535: n03208938
|
537 |
+
536: n03216828
|
538 |
+
537: n03218198
|
539 |
+
538: n13872072
|
540 |
+
539: n03223299
|
541 |
+
540: n03240683
|
542 |
+
541: n03249569
|
543 |
+
542: n07647870
|
544 |
+
543: n03255030
|
545 |
+
544: n03259401
|
546 |
+
545: n03271574
|
547 |
+
546: n03272010
|
548 |
+
547: n03272562
|
549 |
+
548: n03290653
|
550 |
+
549: n13869788
|
551 |
+
550: n03297495
|
552 |
+
551: n03314780
|
553 |
+
552: n03325584
|
554 |
+
553: n03337140
|
555 |
+
554: n03344393
|
556 |
+
555: n03345487
|
557 |
+
556: n03347037
|
558 |
+
557: n03355925
|
559 |
+
558: n03372029
|
560 |
+
559: n03376595
|
561 |
+
560: n03379051
|
562 |
+
561: n03384352
|
563 |
+
562: n03388043
|
564 |
+
563: n03388183
|
565 |
+
564: n03388549
|
566 |
+
565: n03393912
|
567 |
+
566: n03394916
|
568 |
+
567: n03400231
|
569 |
+
568: n03404251
|
570 |
+
569: n03417042
|
571 |
+
570: n03424325
|
572 |
+
571: n03425413
|
573 |
+
572: n03443371
|
574 |
+
573: n03444034
|
575 |
+
574: n03445777
|
576 |
+
575: n03445924
|
577 |
+
576: n03447447
|
578 |
+
577: n03447721
|
579 |
+
578: n08286342
|
580 |
+
579: n03452741
|
581 |
+
580: n03457902
|
582 |
+
581: n03459775
|
583 |
+
582: n03461385
|
584 |
+
583: n03467068
|
585 |
+
584: n03476684
|
586 |
+
585: n03476991
|
587 |
+
586: n03478589
|
588 |
+
587: n03482001
|
589 |
+
588: n03482405
|
590 |
+
589: n03483316
|
591 |
+
590: n03485407
|
592 |
+
591: n03485794
|
593 |
+
592: n03492542
|
594 |
+
593: n03494278
|
595 |
+
594: n03495570
|
596 |
+
595: n10161363
|
597 |
+
596: n03498962
|
598 |
+
597: n03527565
|
599 |
+
598: n03529860
|
600 |
+
599: n09218315
|
601 |
+
600: n03532672
|
602 |
+
601: n03534580
|
603 |
+
602: n03535780
|
604 |
+
603: n03538406
|
605 |
+
604: n03544143
|
606 |
+
605: n03584254
|
607 |
+
606: n03584829
|
608 |
+
607: n03590841
|
609 |
+
608: n03594734
|
610 |
+
609: n03594945
|
611 |
+
610: n03595614
|
612 |
+
611: n03598930
|
613 |
+
612: n03599486
|
614 |
+
613: n03602883
|
615 |
+
614: n03617480
|
616 |
+
615: n03623198
|
617 |
+
616: n15102712
|
618 |
+
617: n03630383
|
619 |
+
618: n03633091
|
620 |
+
619: n03637318
|
621 |
+
620: n03642806
|
622 |
+
621: n03649909
|
623 |
+
622: n03657121
|
624 |
+
623: n03658185
|
625 |
+
624: n07977870
|
626 |
+
625: n03662601
|
627 |
+
626: n03666591
|
628 |
+
627: n03670208
|
629 |
+
628: n03673027
|
630 |
+
629: n03676483
|
631 |
+
630: n03680355
|
632 |
+
631: n03690938
|
633 |
+
632: n03691459
|
634 |
+
633: n03692522
|
635 |
+
634: n03697007
|
636 |
+
635: n03706229
|
637 |
+
636: n03709823
|
638 |
+
637: n03710193
|
639 |
+
638: n03710637
|
640 |
+
639: n03710721
|
641 |
+
640: n03717622
|
642 |
+
641: n03720891
|
643 |
+
642: n03721384
|
644 |
+
643: n03725035
|
645 |
+
644: n03729826
|
646 |
+
645: n03733131
|
647 |
+
646: n03733281
|
648 |
+
647: n03733805
|
649 |
+
648: n03742115
|
650 |
+
649: n03743016
|
651 |
+
650: n03759954
|
652 |
+
651: n03761084
|
653 |
+
652: n03763968
|
654 |
+
653: n03764736
|
655 |
+
654: n03769881
|
656 |
+
655: n03770439
|
657 |
+
656: n03770679
|
658 |
+
657: n03773504
|
659 |
+
658: n03775071
|
660 |
+
659: n03775546
|
661 |
+
660: n03776460
|
662 |
+
661: n03777568
|
663 |
+
662: n03777754
|
664 |
+
663: n03781244
|
665 |
+
664: n03782006
|
666 |
+
665: n03785016
|
667 |
+
666: n14955889
|
668 |
+
667: n03787032
|
669 |
+
668: n03788195
|
670 |
+
669: n03788365
|
671 |
+
670: n03791053
|
672 |
+
671: n03792782
|
673 |
+
672: n03792972
|
674 |
+
673: n03793489
|
675 |
+
674: n03794056
|
676 |
+
675: n03796401
|
677 |
+
676: n03803284
|
678 |
+
677: n13652335
|
679 |
+
678: n03814639
|
680 |
+
679: n03814906
|
681 |
+
680: n03825788
|
682 |
+
681: n03832673
|
683 |
+
682: n03837869
|
684 |
+
683: n03838899
|
685 |
+
684: n03840681
|
686 |
+
685: n03841143
|
687 |
+
686: n03843555
|
688 |
+
687: n03854065
|
689 |
+
688: n03857828
|
690 |
+
689: n03866082
|
691 |
+
690: n03868242
|
692 |
+
691: n03868863
|
693 |
+
692: n07281099
|
694 |
+
693: n03873416
|
695 |
+
694: n03874293
|
696 |
+
695: n03874599
|
697 |
+
696: n03876231
|
698 |
+
697: n03877472
|
699 |
+
698: n08053121
|
700 |
+
699: n03884397
|
701 |
+
700: n03887697
|
702 |
+
701: n03888257
|
703 |
+
702: n03888605
|
704 |
+
703: n03891251
|
705 |
+
704: n03891332
|
706 |
+
705: n03895866
|
707 |
+
706: n03899768
|
708 |
+
707: n03902125
|
709 |
+
708: n03903868
|
710 |
+
709: n03908618
|
711 |
+
710: n03908714
|
712 |
+
711: n03916031
|
713 |
+
712: n03920288
|
714 |
+
713: n03924679
|
715 |
+
714: n03929660
|
716 |
+
715: n03929855
|
717 |
+
716: n03930313
|
718 |
+
717: n03930630
|
719 |
+
718: n03934042
|
720 |
+
719: n03935335
|
721 |
+
720: n03937543
|
722 |
+
721: n03938244
|
723 |
+
722: n03942813
|
724 |
+
723: n03944341
|
725 |
+
724: n03947888
|
726 |
+
725: n03950228
|
727 |
+
726: n03954731
|
728 |
+
727: n03956157
|
729 |
+
728: n03958227
|
730 |
+
729: n03961711
|
731 |
+
730: n03967562
|
732 |
+
731: n03970156
|
733 |
+
732: n03976467
|
734 |
+
733: n08620881
|
735 |
+
734: n03977966
|
736 |
+
735: n03980874
|
737 |
+
736: n03982430
|
738 |
+
737: n03983396
|
739 |
+
738: n03991062
|
740 |
+
739: n03992509
|
741 |
+
740: n03995372
|
742 |
+
741: n03998194
|
743 |
+
742: n04004767
|
744 |
+
743: n13937284
|
745 |
+
744: n04008634
|
746 |
+
745: n04009801
|
747 |
+
746: n04019541
|
748 |
+
747: n04023962
|
749 |
+
748: n13413294
|
750 |
+
749: n04033901
|
751 |
+
750: n04033995
|
752 |
+
751: n04037443
|
753 |
+
752: n04039381
|
754 |
+
753: n09403211
|
755 |
+
754: n04041544
|
756 |
+
755: n04044716
|
757 |
+
756: n04049303
|
758 |
+
757: n04065272
|
759 |
+
758: n07056680
|
760 |
+
759: n04069434
|
761 |
+
760: n04070727
|
762 |
+
761: n04074963
|
763 |
+
762: n04081281
|
764 |
+
763: n04086273
|
765 |
+
764: n04090263
|
766 |
+
765: n04099969
|
767 |
+
766: n04111531
|
768 |
+
767: n04116512
|
769 |
+
768: n04118538
|
770 |
+
769: n04118776
|
771 |
+
770: n04120489
|
772 |
+
771: n04125116
|
773 |
+
772: n04127249
|
774 |
+
773: n04131690
|
775 |
+
774: n04133789
|
776 |
+
775: n04136333
|
777 |
+
776: n04141076
|
778 |
+
777: n04141327
|
779 |
+
778: n04141975
|
780 |
+
779: n04146614
|
781 |
+
780: n04147291
|
782 |
+
781: n04149813
|
783 |
+
782: n04152593
|
784 |
+
783: n04154340
|
785 |
+
784: n07917272
|
786 |
+
785: n04162706
|
787 |
+
786: n04179913
|
788 |
+
787: n04192698
|
789 |
+
788: n04200800
|
790 |
+
789: n04201297
|
791 |
+
790: n04204238
|
792 |
+
791: n04204347
|
793 |
+
792: n04208427
|
794 |
+
793: n04209133
|
795 |
+
794: n04209239
|
796 |
+
795: n04228054
|
797 |
+
796: n04229816
|
798 |
+
797: n04235860
|
799 |
+
798: n04238763
|
800 |
+
799: n04239074
|
801 |
+
800: n04243546
|
802 |
+
801: n04251144
|
803 |
+
802: n04252077
|
804 |
+
803: n04252225
|
805 |
+
804: n04254120
|
806 |
+
805: n04254680
|
807 |
+
806: n04254777
|
808 |
+
807: n04258138
|
809 |
+
808: n04259630
|
810 |
+
809: n04263257
|
811 |
+
810: n04264628
|
812 |
+
811: n04265275
|
813 |
+
812: n04266014
|
814 |
+
813: n04270147
|
815 |
+
814: n04273569
|
816 |
+
815: n04275363
|
817 |
+
816: n05605498
|
818 |
+
817: n04285008
|
819 |
+
818: n04286575
|
820 |
+
819: n08646566
|
821 |
+
820: n04310018
|
822 |
+
821: n04311004
|
823 |
+
822: n04311174
|
824 |
+
823: n04317175
|
825 |
+
824: n04325704
|
826 |
+
825: n04326547
|
827 |
+
826: n04328186
|
828 |
+
827: n04330267
|
829 |
+
828: n04332243
|
830 |
+
829: n04335435
|
831 |
+
830: n04337157
|
832 |
+
831: n04344873
|
833 |
+
832: n04346328
|
834 |
+
833: n04347754
|
835 |
+
834: n04350905
|
836 |
+
835: n04355338
|
837 |
+
836: n04355933
|
838 |
+
837: n04356056
|
839 |
+
838: n04357314
|
840 |
+
839: n04366367
|
841 |
+
840: n04367480
|
842 |
+
841: n04370456
|
843 |
+
842: n04371430
|
844 |
+
843: n14009946
|
845 |
+
844: n04372370
|
846 |
+
845: n04376876
|
847 |
+
846: n04380533
|
848 |
+
847: n04389033
|
849 |
+
848: n04392985
|
850 |
+
849: n04398044
|
851 |
+
850: n04399382
|
852 |
+
851: n04404412
|
853 |
+
852: n04409515
|
854 |
+
853: n04417672
|
855 |
+
854: n04418357
|
856 |
+
855: n04423845
|
857 |
+
856: n04428191
|
858 |
+
857: n04429376
|
859 |
+
858: n04435653
|
860 |
+
859: n04442312
|
861 |
+
860: n04443257
|
862 |
+
861: n04447861
|
863 |
+
862: n04456115
|
864 |
+
863: n04458633
|
865 |
+
864: n04461696
|
866 |
+
865: n04462240
|
867 |
+
866: n04465666
|
868 |
+
867: n04467665
|
869 |
+
868: n04476259
|
870 |
+
869: n04479046
|
871 |
+
870: n04482393
|
872 |
+
871: n04483307
|
873 |
+
872: n04485082
|
874 |
+
873: n04486054
|
875 |
+
874: n04487081
|
876 |
+
875: n04487394
|
877 |
+
876: n04493381
|
878 |
+
877: n04501370
|
879 |
+
878: n04505470
|
880 |
+
879: n04507155
|
881 |
+
880: n04509417
|
882 |
+
881: n04515003
|
883 |
+
882: n04517823
|
884 |
+
883: n04522168
|
885 |
+
884: n04523525
|
886 |
+
885: n04525038
|
887 |
+
886: n04525305
|
888 |
+
887: n04532106
|
889 |
+
888: n04532670
|
890 |
+
889: n04536866
|
891 |
+
890: n04540053
|
892 |
+
891: n04542943
|
893 |
+
892: n04548280
|
894 |
+
893: n04548362
|
895 |
+
894: n04550184
|
896 |
+
895: n04552348
|
897 |
+
896: n04553703
|
898 |
+
897: n04554684
|
899 |
+
898: n04557648
|
900 |
+
899: n04560804
|
901 |
+
900: n04562935
|
902 |
+
901: n04579145
|
903 |
+
902: n04579667
|
904 |
+
903: n04584207
|
905 |
+
904: n04589890
|
906 |
+
905: n04590129
|
907 |
+
906: n04591157
|
908 |
+
907: n04591713
|
909 |
+
908: n10782135
|
910 |
+
909: n04596742
|
911 |
+
910: n04598010
|
912 |
+
911: n04599235
|
913 |
+
912: n04604644
|
914 |
+
913: n14423870
|
915 |
+
914: n04612504
|
916 |
+
915: n04613696
|
917 |
+
916: n06359193
|
918 |
+
917: n06596364
|
919 |
+
918: n06785654
|
920 |
+
919: n06794110
|
921 |
+
920: n06874185
|
922 |
+
921: n07248320
|
923 |
+
922: n07565083
|
924 |
+
923: n07657664
|
925 |
+
924: n07583066
|
926 |
+
925: n07584110
|
927 |
+
926: n07590611
|
928 |
+
927: n07613480
|
929 |
+
928: n07614500
|
930 |
+
929: n07615774
|
931 |
+
930: n07684084
|
932 |
+
931: n07693725
|
933 |
+
932: n07695742
|
934 |
+
933: n07697313
|
935 |
+
934: n07697537
|
936 |
+
935: n07711569
|
937 |
+
936: n07714571
|
938 |
+
937: n07714990
|
939 |
+
938: n07715103
|
940 |
+
939: n12159804
|
941 |
+
940: n12160303
|
942 |
+
941: n12160857
|
943 |
+
942: n07717556
|
944 |
+
943: n07718472
|
945 |
+
944: n07718747
|
946 |
+
945: n07720875
|
947 |
+
946: n07730033
|
948 |
+
947: n13001041
|
949 |
+
948: n07742313
|
950 |
+
949: n12630144
|
951 |
+
950: n14991210
|
952 |
+
951: n07749582
|
953 |
+
952: n07753113
|
954 |
+
953: n07753275
|
955 |
+
954: n07753592
|
956 |
+
955: n07754684
|
957 |
+
956: n07760859
|
958 |
+
957: n07768694
|
959 |
+
958: n07802026
|
960 |
+
959: n07831146
|
961 |
+
960: n07836838
|
962 |
+
961: n07860988
|
963 |
+
962: n07871810
|
964 |
+
963: n07873807
|
965 |
+
964: n07875152
|
966 |
+
965: n07880968
|
967 |
+
966: n07892512
|
968 |
+
967: n07920052
|
969 |
+
968: n13904665
|
970 |
+
969: n07932039
|
971 |
+
970: n09193705
|
972 |
+
971: n09229709
|
973 |
+
972: n09246464
|
974 |
+
973: n09256479
|
975 |
+
974: n09288635
|
976 |
+
975: n09332890
|
977 |
+
976: n09399592
|
978 |
+
977: n09421951
|
979 |
+
978: n09428293
|
980 |
+
979: n09468604
|
981 |
+
980: n09472597
|
982 |
+
981: n09835506
|
983 |
+
982: n10148035
|
984 |
+
983: n10565667
|
985 |
+
984: n11879895
|
986 |
+
985: n11939491
|
987 |
+
986: n12057211
|
988 |
+
987: n12144580
|
989 |
+
988: n12267677
|
990 |
+
989: n12620546
|
991 |
+
990: n12768682
|
992 |
+
991: n12985857
|
993 |
+
992: n12998815
|
994 |
+
993: n13037406
|
995 |
+
994: n13040303
|
996 |
+
995: n13044778
|
997 |
+
996: n13052670
|
998 |
+
997: n13054560
|
999 |
+
998: n13133613
|
1000 |
+
999: n15075141
|
gligen/ldm/data/lsun.py
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import numpy as np
|
3 |
+
import PIL
|
4 |
+
from PIL import Image
|
5 |
+
from torch.utils.data import Dataset
|
6 |
+
from torchvision import transforms
|
7 |
+
|
8 |
+
|
9 |
+
class LSUNBase(Dataset):
|
10 |
+
def __init__(self,
|
11 |
+
txt_file,
|
12 |
+
data_root,
|
13 |
+
size=None,
|
14 |
+
interpolation="bicubic",
|
15 |
+
flip_p=0.5
|
16 |
+
):
|
17 |
+
self.data_paths = txt_file
|
18 |
+
self.data_root = data_root
|
19 |
+
with open(self.data_paths, "r") as f:
|
20 |
+
self.image_paths = f.read().splitlines()
|
21 |
+
self._length = len(self.image_paths)
|
22 |
+
self.labels = {
|
23 |
+
"relative_file_path_": [l for l in self.image_paths],
|
24 |
+
"file_path_": [os.path.join(self.data_root, l)
|
25 |
+
for l in self.image_paths],
|
26 |
+
}
|
27 |
+
|
28 |
+
self.size = size
|
29 |
+
self.interpolation = {"linear": PIL.Image.LINEAR,
|
30 |
+
"bilinear": PIL.Image.BILINEAR,
|
31 |
+
"bicubic": PIL.Image.BICUBIC,
|
32 |
+
"lanczos": PIL.Image.LANCZOS,
|
33 |
+
}[interpolation]
|
34 |
+
self.flip = transforms.RandomHorizontalFlip(p=flip_p)
|
35 |
+
|
36 |
+
def __len__(self):
|
37 |
+
return self._length
|
38 |
+
|
39 |
+
def __getitem__(self, i):
|
40 |
+
example = dict((k, self.labels[k][i]) for k in self.labels)
|
41 |
+
image = Image.open(example["file_path_"])
|
42 |
+
if not image.mode == "RGB":
|
43 |
+
image = image.convert("RGB")
|
44 |
+
|
45 |
+
# default to score-sde preprocessing
|
46 |
+
img = np.array(image).astype(np.uint8)
|
47 |
+
crop = min(img.shape[0], img.shape[1])
|
48 |
+
h, w, = img.shape[0], img.shape[1]
|
49 |
+
img = img[(h - crop) // 2:(h + crop) // 2,
|
50 |
+
(w - crop) // 2:(w + crop) // 2]
|
51 |
+
|
52 |
+
image = Image.fromarray(img)
|
53 |
+
if self.size is not None:
|
54 |
+
image = image.resize((self.size, self.size), resample=self.interpolation)
|
55 |
+
|
56 |
+
image = self.flip(image)
|
57 |
+
image = np.array(image).astype(np.uint8)
|
58 |
+
example["image"] = (image / 127.5 - 1.0).astype(np.float32)
|
59 |
+
return example
|
60 |
+
|
61 |
+
|
62 |
+
class LSUNChurchesTrain(LSUNBase):
|
63 |
+
def __init__(self, **kwargs):
|
64 |
+
super().__init__(txt_file="data/lsun/church_outdoor_train.txt", data_root="data/lsun/churches", **kwargs)
|
65 |
+
|
66 |
+
|
67 |
+
class LSUNChurchesValidation(LSUNBase):
|
68 |
+
def __init__(self, flip_p=0., **kwargs):
|
69 |
+
super().__init__(txt_file="data/lsun/church_outdoor_val.txt", data_root="data/lsun/churches",
|
70 |
+
flip_p=flip_p, **kwargs)
|
71 |
+
|
72 |
+
|
73 |
+
class LSUNBedroomsTrain(LSUNBase):
|
74 |
+
def __init__(self, **kwargs):
|
75 |
+
super().__init__(txt_file="data/lsun/bedrooms_train.txt", data_root="data/lsun/bedrooms", **kwargs)
|
76 |
+
|
77 |
+
|
78 |
+
class LSUNBedroomsValidation(LSUNBase):
|
79 |
+
def __init__(self, flip_p=0.0, **kwargs):
|
80 |
+
super().__init__(txt_file="data/lsun/bedrooms_val.txt", data_root="data/lsun/bedrooms",
|
81 |
+
flip_p=flip_p, **kwargs)
|
82 |
+
|
83 |
+
|
84 |
+
class LSUNCatsTrain(LSUNBase):
|
85 |
+
def __init__(self, **kwargs):
|
86 |
+
super().__init__(txt_file="data/lsun/cat_train.txt", data_root="data/lsun/cats", **kwargs)
|
87 |
+
|
88 |
+
|
89 |
+
class LSUNCatsValidation(LSUNBase):
|
90 |
+
def __init__(self, flip_p=0., **kwargs):
|
91 |
+
super().__init__(txt_file="data/lsun/cat_val.txt", data_root="data/lsun/cats",
|
92 |
+
flip_p=flip_p, **kwargs)
|
gligen/ldm/lr_scheduler.py
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
|
3 |
+
|
4 |
+
class LambdaWarmUpCosineScheduler:
|
5 |
+
"""
|
6 |
+
note: use with a base_lr of 1.0
|
7 |
+
"""
|
8 |
+
def __init__(self, warm_up_steps, lr_min, lr_max, lr_start, max_decay_steps, verbosity_interval=0):
|
9 |
+
self.lr_warm_up_steps = warm_up_steps
|
10 |
+
self.lr_start = lr_start
|
11 |
+
self.lr_min = lr_min
|
12 |
+
self.lr_max = lr_max
|
13 |
+
self.lr_max_decay_steps = max_decay_steps
|
14 |
+
self.last_lr = 0.
|
15 |
+
self.verbosity_interval = verbosity_interval
|
16 |
+
|
17 |
+
def schedule(self, n, **kwargs):
|
18 |
+
if self.verbosity_interval > 0:
|
19 |
+
if n % self.verbosity_interval == 0: print(f"current step: {n}, recent lr-multiplier: {self.last_lr}")
|
20 |
+
if n < self.lr_warm_up_steps:
|
21 |
+
lr = (self.lr_max - self.lr_start) / self.lr_warm_up_steps * n + self.lr_start
|
22 |
+
self.last_lr = lr
|
23 |
+
return lr
|
24 |
+
else:
|
25 |
+
t = (n - self.lr_warm_up_steps) / (self.lr_max_decay_steps - self.lr_warm_up_steps)
|
26 |
+
t = min(t, 1.0)
|
27 |
+
lr = self.lr_min + 0.5 * (self.lr_max - self.lr_min) * (
|
28 |
+
1 + np.cos(t * np.pi))
|
29 |
+
self.last_lr = lr
|
30 |
+
return lr
|
31 |
+
|
32 |
+
def __call__(self, n, **kwargs):
|
33 |
+
return self.schedule(n,**kwargs)
|
34 |
+
|
35 |
+
|
36 |
+
class LambdaWarmUpCosineScheduler2:
|
37 |
+
"""
|
38 |
+
supports repeated iterations, configurable via lists
|
39 |
+
note: use with a base_lr of 1.0.
|
40 |
+
"""
|
41 |
+
def __init__(self, warm_up_steps, f_min, f_max, f_start, cycle_lengths, verbosity_interval=0):
|
42 |
+
assert len(warm_up_steps) == len(f_min) == len(f_max) == len(f_start) == len(cycle_lengths)
|
43 |
+
self.lr_warm_up_steps = warm_up_steps
|
44 |
+
self.f_start = f_start
|
45 |
+
self.f_min = f_min
|
46 |
+
self.f_max = f_max
|
47 |
+
self.cycle_lengths = cycle_lengths
|
48 |
+
self.cum_cycles = np.cumsum([0] + list(self.cycle_lengths))
|
49 |
+
self.last_f = 0.
|
50 |
+
self.verbosity_interval = verbosity_interval
|
51 |
+
|
52 |
+
def find_in_interval(self, n):
|
53 |
+
interval = 0
|
54 |
+
for cl in self.cum_cycles[1:]:
|
55 |
+
if n <= cl:
|
56 |
+
return interval
|
57 |
+
interval += 1
|
58 |
+
|
59 |
+
def schedule(self, n, **kwargs):
|
60 |
+
cycle = self.find_in_interval(n)
|
61 |
+
n = n - self.cum_cycles[cycle]
|
62 |
+
if self.verbosity_interval > 0:
|
63 |
+
if n % self.verbosity_interval == 0: print(f"current step: {n}, recent lr-multiplier: {self.last_f}, "
|
64 |
+
f"current cycle {cycle}")
|
65 |
+
if n < self.lr_warm_up_steps[cycle]:
|
66 |
+
f = (self.f_max[cycle] - self.f_start[cycle]) / self.lr_warm_up_steps[cycle] * n + self.f_start[cycle]
|
67 |
+
self.last_f = f
|
68 |
+
return f
|
69 |
+
else:
|
70 |
+
t = (n - self.lr_warm_up_steps[cycle]) / (self.cycle_lengths[cycle] - self.lr_warm_up_steps[cycle])
|
71 |
+
t = min(t, 1.0)
|
72 |
+
f = self.f_min[cycle] + 0.5 * (self.f_max[cycle] - self.f_min[cycle]) * (
|
73 |
+
1 + np.cos(t * np.pi))
|
74 |
+
self.last_f = f
|
75 |
+
return f
|
76 |
+
|
77 |
+
def __call__(self, n, **kwargs):
|
78 |
+
return self.schedule(n, **kwargs)
|
79 |
+
|
80 |
+
|
81 |
+
class LambdaLinearScheduler(LambdaWarmUpCosineScheduler2):
|
82 |
+
|
83 |
+
def schedule(self, n, **kwargs):
|
84 |
+
cycle = self.find_in_interval(n)
|
85 |
+
n = n - self.cum_cycles[cycle]
|
86 |
+
if self.verbosity_interval > 0:
|
87 |
+
if n % self.verbosity_interval == 0: print(f"current step: {n}, recent lr-multiplier: {self.last_f}, "
|
88 |
+
f"current cycle {cycle}")
|
89 |
+
|
90 |
+
if n < self.lr_warm_up_steps[cycle]:
|
91 |
+
f = (self.f_max[cycle] - self.f_start[cycle]) / self.lr_warm_up_steps[cycle] * n + self.f_start[cycle]
|
92 |
+
self.last_f = f
|
93 |
+
return f
|
94 |
+
else:
|
95 |
+
f = self.f_min[cycle] + (self.f_max[cycle] - self.f_min[cycle]) * (self.cycle_lengths[cycle] - n) / (self.cycle_lengths[cycle])
|
96 |
+
self.last_f = f
|
97 |
+
return f
|
98 |
+
|
gligen/ldm/models/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
gligen/ldm/models/__pycache__/autoencoder.cpython-38.pyc
ADDED
Binary file (1.58 kB). View file
|
|
gligen/ldm/models/autoencoder.py
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
import torch.nn as nn
|
3 |
+
#import pytorch_lightning as pl
|
4 |
+
import torch.nn.functional as F
|
5 |
+
from contextlib import contextmanager
|
6 |
+
|
7 |
+
# from taming.modules.vqvae.quantize import VectorQuantizer2 as VectorQuantizer
|
8 |
+
|
9 |
+
from ldm.modules.diffusionmodules.model import Encoder, Decoder
|
10 |
+
from ldm.modules.distributions.distributions import DiagonalGaussianDistribution
|
11 |
+
|
12 |
+
from ldm.util import instantiate_from_config
|
13 |
+
|
14 |
+
|
15 |
+
|
16 |
+
|
17 |
+
class AutoencoderKL(nn.Module):
|
18 |
+
def __init__(self,
|
19 |
+
ddconfig,
|
20 |
+
embed_dim,
|
21 |
+
scale_factor=1
|
22 |
+
):
|
23 |
+
super().__init__()
|
24 |
+
self.encoder = Encoder(**ddconfig)
|
25 |
+
self.decoder = Decoder(**ddconfig)
|
26 |
+
assert ddconfig["double_z"]
|
27 |
+
self.quant_conv = torch.nn.Conv2d(2*ddconfig["z_channels"], 2*embed_dim, 1)
|
28 |
+
self.post_quant_conv = torch.nn.Conv2d(embed_dim, ddconfig["z_channels"], 1)
|
29 |
+
self.embed_dim = embed_dim
|
30 |
+
self.scale_factor = scale_factor
|
31 |
+
|
32 |
+
|
33 |
+
|
34 |
+
def encode(self, x):
|
35 |
+
h = self.encoder(x)
|
36 |
+
moments = self.quant_conv(h)
|
37 |
+
posterior = DiagonalGaussianDistribution(moments)
|
38 |
+
return posterior.sample() * self.scale_factor
|
39 |
+
|
40 |
+
def decode(self, z):
|
41 |
+
z = 1. / self.scale_factor * z
|
42 |
+
z = self.post_quant_conv(z)
|
43 |
+
dec = self.decoder(z)
|
44 |
+
return dec
|
45 |
+
|
46 |
+
|
47 |
+
|
48 |
+
|
49 |
+
|
50 |
+
|
51 |
+
|
52 |
+
|
gligen/ldm/models/diffusion/__init__.py
ADDED
File without changes
|
gligen/ldm/models/diffusion/__pycache__/__init__.cpython-38.pyc
ADDED
Binary file (159 Bytes). View file
|
|
gligen/ldm/models/diffusion/__pycache__/ddim.cpython-38.pyc
ADDED
Binary file (4.57 kB). View file
|
|
gligen/ldm/models/diffusion/__pycache__/ddpm.cpython-38.pyc
ADDED
Binary file (2.12 kB). View file
|
|
gligen/ldm/models/diffusion/__pycache__/gaussian_smoothing.cpython-38.pyc
ADDED
Binary file (4.11 kB). View file
|
|
gligen/ldm/models/diffusion/__pycache__/ldm.cpython-38.pyc
ADDED
Binary file (1.21 kB). View file
|
|
gligen/ldm/models/diffusion/__pycache__/loss.cpython-38.pyc
ADDED
Binary file (4.23 kB). View file
|
|