nikunjkdtechnoland
commited on
Commit
•
e041d7d
1
Parent(s):
89c278d
init commit some more add files
Browse files- iopaint/file_manager/storage_backends.py +46 -0
- iopaint/model/anytext/cldm/recognizer.py +300 -0
- iopaint/model/anytext/ldm/models/diffusion/dpm_solver/sampler.py +87 -0
- iopaint/model/anytext/ldm/models/diffusion/plms.py +244 -0
- iopaint/model/anytext/ldm/models/diffusion/sampling_util.py +22 -0
- iopaint/model/anytext/ocr_recog/RNN.py +210 -0
- iopaint/model/anytext/ocr_recog/RecCTCHead.py +48 -0
- iopaint/model/anytext/ocr_recog/RecModel.py +45 -0
- iopaint/model/anytext/ocr_recog/RecMv1_enhance.py +232 -0
- iopaint/model/anytext/ocr_recog/RecSVTR.py +591 -0
- iopaint/model/anytext/ocr_recog/ppocr_keys_v1.txt +6623 -0
- iopaint/model/original_sd_configs/sd_xl_base.yaml +93 -0
- iopaint/model/original_sd_configs/sd_xl_refiner.yaml +86 -0
- iopaint/model/paint_by_example.py +68 -0
- iopaint/model/plms_sampler.py +225 -0
- iopaint/model/power_paint/pipeline_powerpaint.py +1243 -0
- iopaint/model/power_paint/pipeline_powerpaint_controlnet.py +1775 -0
- iopaint/model/power_paint/power_paint.py +101 -0
- iopaint/model/sd.py +129 -0
- iopaint/model/sdxl.py +110 -0
- iopaint/plugins/realesrgan.py +109 -0
- iopaint/plugins/remove_bg.py +71 -0
- iopaint/plugins/restoreformer.py +57 -0
- iopaint/plugins/segment_anything/modeling/prompt_encoder.py +214 -0
- iopaint/plugins/segment_anything/modeling/sam.py +174 -0
- iopaint/plugins/segment_anything/predictor.py +285 -0
- iopaint/runtime.py +88 -0
- iopaint/schema.py +458 -0
- iopaint/single_processing.py +180 -0
- requirements.txt +26 -0
iopaint/file_manager/storage_backends.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copy from https://github.com/silentsokolov/flask-thumbnails/blob/master/flask_thumbnails/storage_backends.py
|
2 |
+
import errno
|
3 |
+
import os
|
4 |
+
from abc import ABC, abstractmethod
|
5 |
+
|
6 |
+
|
7 |
+
class BaseStorageBackend(ABC):
|
8 |
+
def __init__(self, app=None):
|
9 |
+
self.app = app
|
10 |
+
|
11 |
+
@abstractmethod
|
12 |
+
def read(self, filepath, mode="rb", **kwargs):
|
13 |
+
raise NotImplementedError
|
14 |
+
|
15 |
+
@abstractmethod
|
16 |
+
def exists(self, filepath):
|
17 |
+
raise NotImplementedError
|
18 |
+
|
19 |
+
@abstractmethod
|
20 |
+
def save(self, filepath, data):
|
21 |
+
raise NotImplementedError
|
22 |
+
|
23 |
+
|
24 |
+
class FilesystemStorageBackend(BaseStorageBackend):
|
25 |
+
def read(self, filepath, mode="rb", **kwargs):
|
26 |
+
with open(filepath, mode) as f: # pylint: disable=unspecified-encoding
|
27 |
+
return f.read()
|
28 |
+
|
29 |
+
def exists(self, filepath):
|
30 |
+
return os.path.exists(filepath)
|
31 |
+
|
32 |
+
def save(self, filepath, data):
|
33 |
+
directory = os.path.dirname(filepath)
|
34 |
+
|
35 |
+
if not os.path.exists(directory):
|
36 |
+
try:
|
37 |
+
os.makedirs(directory)
|
38 |
+
except OSError as e:
|
39 |
+
if e.errno != errno.EEXIST:
|
40 |
+
raise
|
41 |
+
|
42 |
+
if not os.path.isdir(directory):
|
43 |
+
raise IOError("{} is not a directory".format(directory))
|
44 |
+
|
45 |
+
with open(filepath, "wb") as f:
|
46 |
+
f.write(data)
|
iopaint/model/anytext/cldm/recognizer.py
ADDED
@@ -0,0 +1,300 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Copyright (c) Alibaba, Inc. and its affiliates.
|
3 |
+
"""
|
4 |
+
import os
|
5 |
+
import cv2
|
6 |
+
import numpy as np
|
7 |
+
import math
|
8 |
+
import traceback
|
9 |
+
from easydict import EasyDict as edict
|
10 |
+
import time
|
11 |
+
from iopaint.model.anytext.ocr_recog.RecModel import RecModel
|
12 |
+
import torch
|
13 |
+
import torch.nn.functional as F
|
14 |
+
|
15 |
+
|
16 |
+
def min_bounding_rect(img):
|
17 |
+
ret, thresh = cv2.threshold(img, 127, 255, 0)
|
18 |
+
contours, hierarchy = cv2.findContours(
|
19 |
+
thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
|
20 |
+
)
|
21 |
+
if len(contours) == 0:
|
22 |
+
print("Bad contours, using fake bbox...")
|
23 |
+
return np.array([[0, 0], [100, 0], [100, 100], [0, 100]])
|
24 |
+
max_contour = max(contours, key=cv2.contourArea)
|
25 |
+
rect = cv2.minAreaRect(max_contour)
|
26 |
+
box = cv2.boxPoints(rect)
|
27 |
+
box = np.int0(box)
|
28 |
+
# sort
|
29 |
+
x_sorted = sorted(box, key=lambda x: x[0])
|
30 |
+
left = x_sorted[:2]
|
31 |
+
right = x_sorted[2:]
|
32 |
+
left = sorted(left, key=lambda x: x[1])
|
33 |
+
(tl, bl) = left
|
34 |
+
right = sorted(right, key=lambda x: x[1])
|
35 |
+
(tr, br) = right
|
36 |
+
if tl[1] > bl[1]:
|
37 |
+
(tl, bl) = (bl, tl)
|
38 |
+
if tr[1] > br[1]:
|
39 |
+
(tr, br) = (br, tr)
|
40 |
+
return np.array([tl, tr, br, bl])
|
41 |
+
|
42 |
+
|
43 |
+
def create_predictor(model_dir=None, model_lang="ch", is_onnx=False):
|
44 |
+
model_file_path = model_dir
|
45 |
+
if model_file_path is not None and not os.path.exists(model_file_path):
|
46 |
+
raise ValueError("not find model file path {}".format(model_file_path))
|
47 |
+
|
48 |
+
if is_onnx:
|
49 |
+
import onnxruntime as ort
|
50 |
+
|
51 |
+
sess = ort.InferenceSession(
|
52 |
+
model_file_path, providers=["CPUExecutionProvider"]
|
53 |
+
) # 'TensorrtExecutionProvider', 'CUDAExecutionProvider', 'CPUExecutionProvider'
|
54 |
+
return sess
|
55 |
+
else:
|
56 |
+
if model_lang == "ch":
|
57 |
+
n_class = 6625
|
58 |
+
elif model_lang == "en":
|
59 |
+
n_class = 97
|
60 |
+
else:
|
61 |
+
raise ValueError(f"Unsupported OCR recog model_lang: {model_lang}")
|
62 |
+
rec_config = edict(
|
63 |
+
in_channels=3,
|
64 |
+
backbone=edict(
|
65 |
+
type="MobileNetV1Enhance",
|
66 |
+
scale=0.5,
|
67 |
+
last_conv_stride=[1, 2],
|
68 |
+
last_pool_type="avg",
|
69 |
+
),
|
70 |
+
neck=edict(
|
71 |
+
type="SequenceEncoder",
|
72 |
+
encoder_type="svtr",
|
73 |
+
dims=64,
|
74 |
+
depth=2,
|
75 |
+
hidden_dims=120,
|
76 |
+
use_guide=True,
|
77 |
+
),
|
78 |
+
head=edict(
|
79 |
+
type="CTCHead",
|
80 |
+
fc_decay=0.00001,
|
81 |
+
out_channels=n_class,
|
82 |
+
return_feats=True,
|
83 |
+
),
|
84 |
+
)
|
85 |
+
|
86 |
+
rec_model = RecModel(rec_config)
|
87 |
+
if model_file_path is not None:
|
88 |
+
rec_model.load_state_dict(torch.load(model_file_path, map_location="cpu"))
|
89 |
+
rec_model.eval()
|
90 |
+
return rec_model.eval()
|
91 |
+
|
92 |
+
|
93 |
+
def _check_image_file(path):
|
94 |
+
img_end = {"jpg", "bmp", "png", "jpeg", "rgb", "tif", "tiff"}
|
95 |
+
return any([path.lower().endswith(e) for e in img_end])
|
96 |
+
|
97 |
+
|
98 |
+
def get_image_file_list(img_file):
|
99 |
+
imgs_lists = []
|
100 |
+
if img_file is None or not os.path.exists(img_file):
|
101 |
+
raise Exception("not found any img file in {}".format(img_file))
|
102 |
+
if os.path.isfile(img_file) and _check_image_file(img_file):
|
103 |
+
imgs_lists.append(img_file)
|
104 |
+
elif os.path.isdir(img_file):
|
105 |
+
for single_file in os.listdir(img_file):
|
106 |
+
file_path = os.path.join(img_file, single_file)
|
107 |
+
if os.path.isfile(file_path) and _check_image_file(file_path):
|
108 |
+
imgs_lists.append(file_path)
|
109 |
+
if len(imgs_lists) == 0:
|
110 |
+
raise Exception("not found any img file in {}".format(img_file))
|
111 |
+
imgs_lists = sorted(imgs_lists)
|
112 |
+
return imgs_lists
|
113 |
+
|
114 |
+
|
115 |
+
class TextRecognizer(object):
|
116 |
+
def __init__(self, args, predictor):
|
117 |
+
self.rec_image_shape = [int(v) for v in args.rec_image_shape.split(",")]
|
118 |
+
self.rec_batch_num = args.rec_batch_num
|
119 |
+
self.predictor = predictor
|
120 |
+
self.chars = self.get_char_dict(args.rec_char_dict_path)
|
121 |
+
self.char2id = {x: i for i, x in enumerate(self.chars)}
|
122 |
+
self.is_onnx = not isinstance(self.predictor, torch.nn.Module)
|
123 |
+
self.use_fp16 = args.use_fp16
|
124 |
+
|
125 |
+
# img: CHW
|
126 |
+
def resize_norm_img(self, img, max_wh_ratio):
|
127 |
+
imgC, imgH, imgW = self.rec_image_shape
|
128 |
+
assert imgC == img.shape[0]
|
129 |
+
imgW = int((imgH * max_wh_ratio))
|
130 |
+
|
131 |
+
h, w = img.shape[1:]
|
132 |
+
ratio = w / float(h)
|
133 |
+
if math.ceil(imgH * ratio) > imgW:
|
134 |
+
resized_w = imgW
|
135 |
+
else:
|
136 |
+
resized_w = int(math.ceil(imgH * ratio))
|
137 |
+
resized_image = torch.nn.functional.interpolate(
|
138 |
+
img.unsqueeze(0),
|
139 |
+
size=(imgH, resized_w),
|
140 |
+
mode="bilinear",
|
141 |
+
align_corners=True,
|
142 |
+
)
|
143 |
+
resized_image /= 255.0
|
144 |
+
resized_image -= 0.5
|
145 |
+
resized_image /= 0.5
|
146 |
+
padding_im = torch.zeros((imgC, imgH, imgW), dtype=torch.float32).to(img.device)
|
147 |
+
padding_im[:, :, 0:resized_w] = resized_image[0]
|
148 |
+
return padding_im
|
149 |
+
|
150 |
+
# img_list: list of tensors with shape chw 0-255
|
151 |
+
def pred_imglist(self, img_list, show_debug=False, is_ori=False):
|
152 |
+
img_num = len(img_list)
|
153 |
+
assert img_num > 0
|
154 |
+
# Calculate the aspect ratio of all text bars
|
155 |
+
width_list = []
|
156 |
+
for img in img_list:
|
157 |
+
width_list.append(img.shape[2] / float(img.shape[1]))
|
158 |
+
# Sorting can speed up the recognition process
|
159 |
+
indices = torch.from_numpy(np.argsort(np.array(width_list)))
|
160 |
+
batch_num = self.rec_batch_num
|
161 |
+
preds_all = [None] * img_num
|
162 |
+
preds_neck_all = [None] * img_num
|
163 |
+
for beg_img_no in range(0, img_num, batch_num):
|
164 |
+
end_img_no = min(img_num, beg_img_no + batch_num)
|
165 |
+
norm_img_batch = []
|
166 |
+
|
167 |
+
imgC, imgH, imgW = self.rec_image_shape[:3]
|
168 |
+
max_wh_ratio = imgW / imgH
|
169 |
+
for ino in range(beg_img_no, end_img_no):
|
170 |
+
h, w = img_list[indices[ino]].shape[1:]
|
171 |
+
if h > w * 1.2:
|
172 |
+
img = img_list[indices[ino]]
|
173 |
+
img = torch.transpose(img, 1, 2).flip(dims=[1])
|
174 |
+
img_list[indices[ino]] = img
|
175 |
+
h, w = img.shape[1:]
|
176 |
+
# wh_ratio = w * 1.0 / h
|
177 |
+
# max_wh_ratio = max(max_wh_ratio, wh_ratio) # comment to not use different ratio
|
178 |
+
for ino in range(beg_img_no, end_img_no):
|
179 |
+
norm_img = self.resize_norm_img(img_list[indices[ino]], max_wh_ratio)
|
180 |
+
if self.use_fp16:
|
181 |
+
norm_img = norm_img.half()
|
182 |
+
norm_img = norm_img.unsqueeze(0)
|
183 |
+
norm_img_batch.append(norm_img)
|
184 |
+
norm_img_batch = torch.cat(norm_img_batch, dim=0)
|
185 |
+
if show_debug:
|
186 |
+
for i in range(len(norm_img_batch)):
|
187 |
+
_img = norm_img_batch[i].permute(1, 2, 0).detach().cpu().numpy()
|
188 |
+
_img = (_img + 0.5) * 255
|
189 |
+
_img = _img[:, :, ::-1]
|
190 |
+
file_name = f"{indices[beg_img_no + i]}"
|
191 |
+
file_name = file_name + "_ori" if is_ori else file_name
|
192 |
+
cv2.imwrite(file_name + ".jpg", _img)
|
193 |
+
if self.is_onnx:
|
194 |
+
input_dict = {}
|
195 |
+
input_dict[self.predictor.get_inputs()[0].name] = (
|
196 |
+
norm_img_batch.detach().cpu().numpy()
|
197 |
+
)
|
198 |
+
outputs = self.predictor.run(None, input_dict)
|
199 |
+
preds = {}
|
200 |
+
preds["ctc"] = torch.from_numpy(outputs[0])
|
201 |
+
preds["ctc_neck"] = [torch.zeros(1)] * img_num
|
202 |
+
else:
|
203 |
+
preds = self.predictor(norm_img_batch)
|
204 |
+
for rno in range(preds["ctc"].shape[0]):
|
205 |
+
preds_all[indices[beg_img_no + rno]] = preds["ctc"][rno]
|
206 |
+
preds_neck_all[indices[beg_img_no + rno]] = preds["ctc_neck"][rno]
|
207 |
+
|
208 |
+
return torch.stack(preds_all, dim=0), torch.stack(preds_neck_all, dim=0)
|
209 |
+
|
210 |
+
def get_char_dict(self, character_dict_path):
|
211 |
+
character_str = []
|
212 |
+
with open(character_dict_path, "rb") as fin:
|
213 |
+
lines = fin.readlines()
|
214 |
+
for line in lines:
|
215 |
+
line = line.decode("utf-8").strip("\n").strip("\r\n")
|
216 |
+
character_str.append(line)
|
217 |
+
dict_character = list(character_str)
|
218 |
+
dict_character = ["sos"] + dict_character + [" "] # eos is space
|
219 |
+
return dict_character
|
220 |
+
|
221 |
+
def get_text(self, order):
|
222 |
+
char_list = [self.chars[text_id] for text_id in order]
|
223 |
+
return "".join(char_list)
|
224 |
+
|
225 |
+
def decode(self, mat):
|
226 |
+
text_index = mat.detach().cpu().numpy().argmax(axis=1)
|
227 |
+
ignored_tokens = [0]
|
228 |
+
selection = np.ones(len(text_index), dtype=bool)
|
229 |
+
selection[1:] = text_index[1:] != text_index[:-1]
|
230 |
+
for ignored_token in ignored_tokens:
|
231 |
+
selection &= text_index != ignored_token
|
232 |
+
return text_index[selection], np.where(selection)[0]
|
233 |
+
|
234 |
+
def get_ctcloss(self, preds, gt_text, weight):
|
235 |
+
if not isinstance(weight, torch.Tensor):
|
236 |
+
weight = torch.tensor(weight).to(preds.device)
|
237 |
+
ctc_loss = torch.nn.CTCLoss(reduction="none")
|
238 |
+
log_probs = preds.log_softmax(dim=2).permute(1, 0, 2) # NTC-->TNC
|
239 |
+
targets = []
|
240 |
+
target_lengths = []
|
241 |
+
for t in gt_text:
|
242 |
+
targets += [self.char2id.get(i, len(self.chars) - 1) for i in t]
|
243 |
+
target_lengths += [len(t)]
|
244 |
+
targets = torch.tensor(targets).to(preds.device)
|
245 |
+
target_lengths = torch.tensor(target_lengths).to(preds.device)
|
246 |
+
input_lengths = torch.tensor([log_probs.shape[0]] * (log_probs.shape[1])).to(
|
247 |
+
preds.device
|
248 |
+
)
|
249 |
+
loss = ctc_loss(log_probs, targets, input_lengths, target_lengths)
|
250 |
+
loss = loss / input_lengths * weight
|
251 |
+
return loss
|
252 |
+
|
253 |
+
|
254 |
+
def main():
|
255 |
+
rec_model_dir = "./ocr_weights/ppv3_rec.pth"
|
256 |
+
predictor = create_predictor(rec_model_dir)
|
257 |
+
args = edict()
|
258 |
+
args.rec_image_shape = "3, 48, 320"
|
259 |
+
args.rec_char_dict_path = "./ocr_weights/ppocr_keys_v1.txt"
|
260 |
+
args.rec_batch_num = 6
|
261 |
+
text_recognizer = TextRecognizer(args, predictor)
|
262 |
+
image_dir = "./test_imgs_cn"
|
263 |
+
gt_text = ["韩国小馆"] * 14
|
264 |
+
|
265 |
+
image_file_list = get_image_file_list(image_dir)
|
266 |
+
valid_image_file_list = []
|
267 |
+
img_list = []
|
268 |
+
|
269 |
+
for image_file in image_file_list:
|
270 |
+
img = cv2.imread(image_file)
|
271 |
+
if img is None:
|
272 |
+
print("error in loading image:{}".format(image_file))
|
273 |
+
continue
|
274 |
+
valid_image_file_list.append(image_file)
|
275 |
+
img_list.append(torch.from_numpy(img).permute(2, 0, 1).float())
|
276 |
+
try:
|
277 |
+
tic = time.time()
|
278 |
+
times = []
|
279 |
+
for i in range(10):
|
280 |
+
preds, _ = text_recognizer.pred_imglist(img_list) # get text
|
281 |
+
preds_all = preds.softmax(dim=2)
|
282 |
+
times += [(time.time() - tic) * 1000.0]
|
283 |
+
tic = time.time()
|
284 |
+
print(times)
|
285 |
+
print(np.mean(times[1:]) / len(preds_all))
|
286 |
+
weight = np.ones(len(gt_text))
|
287 |
+
loss = text_recognizer.get_ctcloss(preds, gt_text, weight)
|
288 |
+
for i in range(len(valid_image_file_list)):
|
289 |
+
pred = preds_all[i]
|
290 |
+
order, idx = text_recognizer.decode(pred)
|
291 |
+
text = text_recognizer.get_text(order)
|
292 |
+
print(
|
293 |
+
f'{valid_image_file_list[i]}: pred/gt="{text}"/"{gt_text[i]}", loss={loss[i]:.2f}'
|
294 |
+
)
|
295 |
+
except Exception as E:
|
296 |
+
print(traceback.format_exc(), E)
|
297 |
+
|
298 |
+
|
299 |
+
if __name__ == "__main__":
|
300 |
+
main()
|
iopaint/model/anytext/ldm/models/diffusion/dpm_solver/sampler.py
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""SAMPLING ONLY."""
|
2 |
+
import torch
|
3 |
+
|
4 |
+
from .dpm_solver import NoiseScheduleVP, model_wrapper, DPM_Solver
|
5 |
+
|
6 |
+
|
7 |
+
MODEL_TYPES = {
|
8 |
+
"eps": "noise",
|
9 |
+
"v": "v"
|
10 |
+
}
|
11 |
+
|
12 |
+
|
13 |
+
class DPMSolverSampler(object):
|
14 |
+
def __init__(self, model, **kwargs):
|
15 |
+
super().__init__()
|
16 |
+
self.model = model
|
17 |
+
to_torch = lambda x: x.clone().detach().to(torch.float32).to(model.device)
|
18 |
+
self.register_buffer('alphas_cumprod', to_torch(model.alphas_cumprod))
|
19 |
+
|
20 |
+
def register_buffer(self, name, attr):
|
21 |
+
if type(attr) == torch.Tensor:
|
22 |
+
if attr.device != torch.device("cuda"):
|
23 |
+
attr = attr.to(torch.device("cuda"))
|
24 |
+
setattr(self, name, attr)
|
25 |
+
|
26 |
+
@torch.no_grad()
|
27 |
+
def sample(self,
|
28 |
+
S,
|
29 |
+
batch_size,
|
30 |
+
shape,
|
31 |
+
conditioning=None,
|
32 |
+
callback=None,
|
33 |
+
normals_sequence=None,
|
34 |
+
img_callback=None,
|
35 |
+
quantize_x0=False,
|
36 |
+
eta=0.,
|
37 |
+
mask=None,
|
38 |
+
x0=None,
|
39 |
+
temperature=1.,
|
40 |
+
noise_dropout=0.,
|
41 |
+
score_corrector=None,
|
42 |
+
corrector_kwargs=None,
|
43 |
+
verbose=True,
|
44 |
+
x_T=None,
|
45 |
+
log_every_t=100,
|
46 |
+
unconditional_guidance_scale=1.,
|
47 |
+
unconditional_conditioning=None,
|
48 |
+
# this has to come in the same format as the conditioning, # e.g. as encoded tokens, ...
|
49 |
+
**kwargs
|
50 |
+
):
|
51 |
+
if conditioning is not None:
|
52 |
+
if isinstance(conditioning, dict):
|
53 |
+
cbs = conditioning[list(conditioning.keys())[0]].shape[0]
|
54 |
+
if cbs != batch_size:
|
55 |
+
print(f"Warning: Got {cbs} conditionings but batch-size is {batch_size}")
|
56 |
+
else:
|
57 |
+
if conditioning.shape[0] != batch_size:
|
58 |
+
print(f"Warning: Got {conditioning.shape[0]} conditionings but batch-size is {batch_size}")
|
59 |
+
|
60 |
+
# sampling
|
61 |
+
C, H, W = shape
|
62 |
+
size = (batch_size, C, H, W)
|
63 |
+
|
64 |
+
print(f'Data shape for DPM-Solver sampling is {size}, sampling steps {S}')
|
65 |
+
|
66 |
+
device = self.model.betas.device
|
67 |
+
if x_T is None:
|
68 |
+
img = torch.randn(size, device=device)
|
69 |
+
else:
|
70 |
+
img = x_T
|
71 |
+
|
72 |
+
ns = NoiseScheduleVP('discrete', alphas_cumprod=self.alphas_cumprod)
|
73 |
+
|
74 |
+
model_fn = model_wrapper(
|
75 |
+
lambda x, t, c: self.model.apply_model(x, t, c),
|
76 |
+
ns,
|
77 |
+
model_type=MODEL_TYPES[self.model.parameterization],
|
78 |
+
guidance_type="classifier-free",
|
79 |
+
condition=conditioning,
|
80 |
+
unconditional_condition=unconditional_conditioning,
|
81 |
+
guidance_scale=unconditional_guidance_scale,
|
82 |
+
)
|
83 |
+
|
84 |
+
dpm_solver = DPM_Solver(model_fn, ns, predict_x0=True, thresholding=False)
|
85 |
+
x = dpm_solver.sample(img, steps=S, skip_type="time_uniform", method="multistep", order=2, lower_order_final=True)
|
86 |
+
|
87 |
+
return x.to(device), None
|
iopaint/model/anytext/ldm/models/diffusion/plms.py
ADDED
@@ -0,0 +1,244 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""SAMPLING ONLY."""
|
2 |
+
|
3 |
+
import torch
|
4 |
+
import numpy as np
|
5 |
+
from tqdm import tqdm
|
6 |
+
from functools import partial
|
7 |
+
|
8 |
+
from iopaint.model.anytext.ldm.modules.diffusionmodules.util import make_ddim_sampling_parameters, make_ddim_timesteps, noise_like
|
9 |
+
from iopaint.model.anytext.ldm.models.diffusion.sampling_util import norm_thresholding
|
10 |
+
|
11 |
+
|
12 |
+
class PLMSSampler(object):
|
13 |
+
def __init__(self, model, schedule="linear", **kwargs):
|
14 |
+
super().__init__()
|
15 |
+
self.model = model
|
16 |
+
self.ddpm_num_timesteps = model.num_timesteps
|
17 |
+
self.schedule = schedule
|
18 |
+
|
19 |
+
def register_buffer(self, name, attr):
|
20 |
+
if type(attr) == torch.Tensor:
|
21 |
+
if attr.device != torch.device("cuda"):
|
22 |
+
attr = attr.to(torch.device("cuda"))
|
23 |
+
setattr(self, name, attr)
|
24 |
+
|
25 |
+
def make_schedule(self, ddim_num_steps, ddim_discretize="uniform", ddim_eta=0., verbose=True):
|
26 |
+
if ddim_eta != 0:
|
27 |
+
raise ValueError('ddim_eta must be 0 for PLMS')
|
28 |
+
self.ddim_timesteps = make_ddim_timesteps(ddim_discr_method=ddim_discretize, num_ddim_timesteps=ddim_num_steps,
|
29 |
+
num_ddpm_timesteps=self.ddpm_num_timesteps,verbose=verbose)
|
30 |
+
alphas_cumprod = self.model.alphas_cumprod
|
31 |
+
assert alphas_cumprod.shape[0] == self.ddpm_num_timesteps, 'alphas have to be defined for each timestep'
|
32 |
+
to_torch = lambda x: x.clone().detach().to(torch.float32).to(self.model.device)
|
33 |
+
|
34 |
+
self.register_buffer('betas', to_torch(self.model.betas))
|
35 |
+
self.register_buffer('alphas_cumprod', to_torch(alphas_cumprod))
|
36 |
+
self.register_buffer('alphas_cumprod_prev', to_torch(self.model.alphas_cumprod_prev))
|
37 |
+
|
38 |
+
# calculations for diffusion q(x_t | x_{t-1}) and others
|
39 |
+
self.register_buffer('sqrt_alphas_cumprod', to_torch(np.sqrt(alphas_cumprod.cpu())))
|
40 |
+
self.register_buffer('sqrt_one_minus_alphas_cumprod', to_torch(np.sqrt(1. - alphas_cumprod.cpu())))
|
41 |
+
self.register_buffer('log_one_minus_alphas_cumprod', to_torch(np.log(1. - alphas_cumprod.cpu())))
|
42 |
+
self.register_buffer('sqrt_recip_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod.cpu())))
|
43 |
+
self.register_buffer('sqrt_recipm1_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod.cpu() - 1)))
|
44 |
+
|
45 |
+
# ddim sampling parameters
|
46 |
+
ddim_sigmas, ddim_alphas, ddim_alphas_prev = make_ddim_sampling_parameters(alphacums=alphas_cumprod.cpu(),
|
47 |
+
ddim_timesteps=self.ddim_timesteps,
|
48 |
+
eta=ddim_eta,verbose=verbose)
|
49 |
+
self.register_buffer('ddim_sigmas', ddim_sigmas)
|
50 |
+
self.register_buffer('ddim_alphas', ddim_alphas)
|
51 |
+
self.register_buffer('ddim_alphas_prev', ddim_alphas_prev)
|
52 |
+
self.register_buffer('ddim_sqrt_one_minus_alphas', np.sqrt(1. - ddim_alphas))
|
53 |
+
sigmas_for_original_sampling_steps = ddim_eta * torch.sqrt(
|
54 |
+
(1 - self.alphas_cumprod_prev) / (1 - self.alphas_cumprod) * (
|
55 |
+
1 - self.alphas_cumprod / self.alphas_cumprod_prev))
|
56 |
+
self.register_buffer('ddim_sigmas_for_original_num_steps', sigmas_for_original_sampling_steps)
|
57 |
+
|
58 |
+
@torch.no_grad()
|
59 |
+
def sample(self,
|
60 |
+
S,
|
61 |
+
batch_size,
|
62 |
+
shape,
|
63 |
+
conditioning=None,
|
64 |
+
callback=None,
|
65 |
+
normals_sequence=None,
|
66 |
+
img_callback=None,
|
67 |
+
quantize_x0=False,
|
68 |
+
eta=0.,
|
69 |
+
mask=None,
|
70 |
+
x0=None,
|
71 |
+
temperature=1.,
|
72 |
+
noise_dropout=0.,
|
73 |
+
score_corrector=None,
|
74 |
+
corrector_kwargs=None,
|
75 |
+
verbose=True,
|
76 |
+
x_T=None,
|
77 |
+
log_every_t=100,
|
78 |
+
unconditional_guidance_scale=1.,
|
79 |
+
unconditional_conditioning=None,
|
80 |
+
# this has to come in the same format as the conditioning, # e.g. as encoded tokens, ...
|
81 |
+
dynamic_threshold=None,
|
82 |
+
**kwargs
|
83 |
+
):
|
84 |
+
if conditioning is not None:
|
85 |
+
if isinstance(conditioning, dict):
|
86 |
+
cbs = conditioning[list(conditioning.keys())[0]].shape[0]
|
87 |
+
if cbs != batch_size:
|
88 |
+
print(f"Warning: Got {cbs} conditionings but batch-size is {batch_size}")
|
89 |
+
else:
|
90 |
+
if conditioning.shape[0] != batch_size:
|
91 |
+
print(f"Warning: Got {conditioning.shape[0]} conditionings but batch-size is {batch_size}")
|
92 |
+
|
93 |
+
self.make_schedule(ddim_num_steps=S, ddim_eta=eta, verbose=verbose)
|
94 |
+
# sampling
|
95 |
+
C, H, W = shape
|
96 |
+
size = (batch_size, C, H, W)
|
97 |
+
print(f'Data shape for PLMS sampling is {size}')
|
98 |
+
|
99 |
+
samples, intermediates = self.plms_sampling(conditioning, size,
|
100 |
+
callback=callback,
|
101 |
+
img_callback=img_callback,
|
102 |
+
quantize_denoised=quantize_x0,
|
103 |
+
mask=mask, x0=x0,
|
104 |
+
ddim_use_original_steps=False,
|
105 |
+
noise_dropout=noise_dropout,
|
106 |
+
temperature=temperature,
|
107 |
+
score_corrector=score_corrector,
|
108 |
+
corrector_kwargs=corrector_kwargs,
|
109 |
+
x_T=x_T,
|
110 |
+
log_every_t=log_every_t,
|
111 |
+
unconditional_guidance_scale=unconditional_guidance_scale,
|
112 |
+
unconditional_conditioning=unconditional_conditioning,
|
113 |
+
dynamic_threshold=dynamic_threshold,
|
114 |
+
)
|
115 |
+
return samples, intermediates
|
116 |
+
|
117 |
+
@torch.no_grad()
|
118 |
+
def plms_sampling(self, cond, shape,
|
119 |
+
x_T=None, ddim_use_original_steps=False,
|
120 |
+
callback=None, timesteps=None, quantize_denoised=False,
|
121 |
+
mask=None, x0=None, img_callback=None, log_every_t=100,
|
122 |
+
temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
|
123 |
+
unconditional_guidance_scale=1., unconditional_conditioning=None,
|
124 |
+
dynamic_threshold=None):
|
125 |
+
device = self.model.betas.device
|
126 |
+
b = shape[0]
|
127 |
+
if x_T is None:
|
128 |
+
img = torch.randn(shape, device=device)
|
129 |
+
else:
|
130 |
+
img = x_T
|
131 |
+
|
132 |
+
if timesteps is None:
|
133 |
+
timesteps = self.ddpm_num_timesteps if ddim_use_original_steps else self.ddim_timesteps
|
134 |
+
elif timesteps is not None and not ddim_use_original_steps:
|
135 |
+
subset_end = int(min(timesteps / self.ddim_timesteps.shape[0], 1) * self.ddim_timesteps.shape[0]) - 1
|
136 |
+
timesteps = self.ddim_timesteps[:subset_end]
|
137 |
+
|
138 |
+
intermediates = {'x_inter': [img], 'pred_x0': [img]}
|
139 |
+
time_range = list(reversed(range(0,timesteps))) if ddim_use_original_steps else np.flip(timesteps)
|
140 |
+
total_steps = timesteps if ddim_use_original_steps else timesteps.shape[0]
|
141 |
+
print(f"Running PLMS Sampling with {total_steps} timesteps")
|
142 |
+
|
143 |
+
iterator = tqdm(time_range, desc='PLMS Sampler', total=total_steps)
|
144 |
+
old_eps = []
|
145 |
+
|
146 |
+
for i, step in enumerate(iterator):
|
147 |
+
index = total_steps - i - 1
|
148 |
+
ts = torch.full((b,), step, device=device, dtype=torch.long)
|
149 |
+
ts_next = torch.full((b,), time_range[min(i + 1, len(time_range) - 1)], device=device, dtype=torch.long)
|
150 |
+
|
151 |
+
if mask is not None:
|
152 |
+
assert x0 is not None
|
153 |
+
img_orig = self.model.q_sample(x0, ts) # TODO: deterministic forward pass?
|
154 |
+
img = img_orig * mask + (1. - mask) * img
|
155 |
+
|
156 |
+
outs = self.p_sample_plms(img, cond, ts, index=index, use_original_steps=ddim_use_original_steps,
|
157 |
+
quantize_denoised=quantize_denoised, temperature=temperature,
|
158 |
+
noise_dropout=noise_dropout, score_corrector=score_corrector,
|
159 |
+
corrector_kwargs=corrector_kwargs,
|
160 |
+
unconditional_guidance_scale=unconditional_guidance_scale,
|
161 |
+
unconditional_conditioning=unconditional_conditioning,
|
162 |
+
old_eps=old_eps, t_next=ts_next,
|
163 |
+
dynamic_threshold=dynamic_threshold)
|
164 |
+
img, pred_x0, e_t = outs
|
165 |
+
old_eps.append(e_t)
|
166 |
+
if len(old_eps) >= 4:
|
167 |
+
old_eps.pop(0)
|
168 |
+
if callback: callback(i)
|
169 |
+
if img_callback: img_callback(pred_x0, i)
|
170 |
+
|
171 |
+
if index % log_every_t == 0 or index == total_steps - 1:
|
172 |
+
intermediates['x_inter'].append(img)
|
173 |
+
intermediates['pred_x0'].append(pred_x0)
|
174 |
+
|
175 |
+
return img, intermediates
|
176 |
+
|
177 |
+
@torch.no_grad()
|
178 |
+
def p_sample_plms(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False,
|
179 |
+
temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
|
180 |
+
unconditional_guidance_scale=1., unconditional_conditioning=None, old_eps=None, t_next=None,
|
181 |
+
dynamic_threshold=None):
|
182 |
+
b, *_, device = *x.shape, x.device
|
183 |
+
|
184 |
+
def get_model_output(x, t):
|
185 |
+
if unconditional_conditioning is None or unconditional_guidance_scale == 1.:
|
186 |
+
e_t = self.model.apply_model(x, t, c)
|
187 |
+
else:
|
188 |
+
x_in = torch.cat([x] * 2)
|
189 |
+
t_in = torch.cat([t] * 2)
|
190 |
+
c_in = torch.cat([unconditional_conditioning, c])
|
191 |
+
e_t_uncond, e_t = self.model.apply_model(x_in, t_in, c_in).chunk(2)
|
192 |
+
e_t = e_t_uncond + unconditional_guidance_scale * (e_t - e_t_uncond)
|
193 |
+
|
194 |
+
if score_corrector is not None:
|
195 |
+
assert self.model.parameterization == "eps"
|
196 |
+
e_t = score_corrector.modify_score(self.model, e_t, x, t, c, **corrector_kwargs)
|
197 |
+
|
198 |
+
return e_t
|
199 |
+
|
200 |
+
alphas = self.model.alphas_cumprod if use_original_steps else self.ddim_alphas
|
201 |
+
alphas_prev = self.model.alphas_cumprod_prev if use_original_steps else self.ddim_alphas_prev
|
202 |
+
sqrt_one_minus_alphas = self.model.sqrt_one_minus_alphas_cumprod if use_original_steps else self.ddim_sqrt_one_minus_alphas
|
203 |
+
sigmas = self.model.ddim_sigmas_for_original_num_steps if use_original_steps else self.ddim_sigmas
|
204 |
+
|
205 |
+
def get_x_prev_and_pred_x0(e_t, index):
|
206 |
+
# select parameters corresponding to the currently considered timestep
|
207 |
+
a_t = torch.full((b, 1, 1, 1), alphas[index], device=device)
|
208 |
+
a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device)
|
209 |
+
sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device)
|
210 |
+
sqrt_one_minus_at = torch.full((b, 1, 1, 1), sqrt_one_minus_alphas[index],device=device)
|
211 |
+
|
212 |
+
# current prediction for x_0
|
213 |
+
pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt()
|
214 |
+
if quantize_denoised:
|
215 |
+
pred_x0, _, *_ = self.model.first_stage_model.quantize(pred_x0)
|
216 |
+
if dynamic_threshold is not None:
|
217 |
+
pred_x0 = norm_thresholding(pred_x0, dynamic_threshold)
|
218 |
+
# direction pointing to x_t
|
219 |
+
dir_xt = (1. - a_prev - sigma_t**2).sqrt() * e_t
|
220 |
+
noise = sigma_t * noise_like(x.shape, device, repeat_noise) * temperature
|
221 |
+
if noise_dropout > 0.:
|
222 |
+
noise = torch.nn.functional.dropout(noise, p=noise_dropout)
|
223 |
+
x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise
|
224 |
+
return x_prev, pred_x0
|
225 |
+
|
226 |
+
e_t = get_model_output(x, t)
|
227 |
+
if len(old_eps) == 0:
|
228 |
+
# Pseudo Improved Euler (2nd order)
|
229 |
+
x_prev, pred_x0 = get_x_prev_and_pred_x0(e_t, index)
|
230 |
+
e_t_next = get_model_output(x_prev, t_next)
|
231 |
+
e_t_prime = (e_t + e_t_next) / 2
|
232 |
+
elif len(old_eps) == 1:
|
233 |
+
# 2nd order Pseudo Linear Multistep (Adams-Bashforth)
|
234 |
+
e_t_prime = (3 * e_t - old_eps[-1]) / 2
|
235 |
+
elif len(old_eps) == 2:
|
236 |
+
# 3nd order Pseudo Linear Multistep (Adams-Bashforth)
|
237 |
+
e_t_prime = (23 * e_t - 16 * old_eps[-1] + 5 * old_eps[-2]) / 12
|
238 |
+
elif len(old_eps) >= 3:
|
239 |
+
# 4nd order Pseudo Linear Multistep (Adams-Bashforth)
|
240 |
+
e_t_prime = (55 * e_t - 59 * old_eps[-1] + 37 * old_eps[-2] - 9 * old_eps[-3]) / 24
|
241 |
+
|
242 |
+
x_prev, pred_x0 = get_x_prev_and_pred_x0(e_t_prime, index)
|
243 |
+
|
244 |
+
return x_prev, pred_x0, e_t
|
iopaint/model/anytext/ldm/models/diffusion/sampling_util.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
import numpy as np
|
3 |
+
|
4 |
+
|
5 |
+
def append_dims(x, target_dims):
|
6 |
+
"""Appends dimensions to the end of a tensor until it has target_dims dimensions.
|
7 |
+
From https://github.com/crowsonkb/k-diffusion/blob/master/k_diffusion/utils.py"""
|
8 |
+
dims_to_append = target_dims - x.ndim
|
9 |
+
if dims_to_append < 0:
|
10 |
+
raise ValueError(f'input has {x.ndim} dims but target_dims is {target_dims}, which is less')
|
11 |
+
return x[(...,) + (None,) * dims_to_append]
|
12 |
+
|
13 |
+
|
14 |
+
def norm_thresholding(x0, value):
|
15 |
+
s = append_dims(x0.pow(2).flatten(1).mean(1).sqrt().clamp(min=value), x0.ndim)
|
16 |
+
return x0 * (value / s)
|
17 |
+
|
18 |
+
|
19 |
+
def spatial_norm_thresholding(x0, value):
|
20 |
+
# b c h w
|
21 |
+
s = x0.pow(2).mean(1, keepdim=True).sqrt().clamp(min=value)
|
22 |
+
return x0 * (value / s)
|
iopaint/model/anytext/ocr_recog/RNN.py
ADDED
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from torch import nn
|
2 |
+
import torch
|
3 |
+
from .RecSVTR import Block
|
4 |
+
|
5 |
+
class Swish(nn.Module):
|
6 |
+
def __int__(self):
|
7 |
+
super(Swish, self).__int__()
|
8 |
+
|
9 |
+
def forward(self,x):
|
10 |
+
return x*torch.sigmoid(x)
|
11 |
+
|
12 |
+
class Im2Im(nn.Module):
|
13 |
+
def __init__(self, in_channels, **kwargs):
|
14 |
+
super().__init__()
|
15 |
+
self.out_channels = in_channels
|
16 |
+
|
17 |
+
def forward(self, x):
|
18 |
+
return x
|
19 |
+
|
20 |
+
class Im2Seq(nn.Module):
|
21 |
+
def __init__(self, in_channels, **kwargs):
|
22 |
+
super().__init__()
|
23 |
+
self.out_channels = in_channels
|
24 |
+
|
25 |
+
def forward(self, x):
|
26 |
+
B, C, H, W = x.shape
|
27 |
+
# assert H == 1
|
28 |
+
x = x.reshape(B, C, H * W)
|
29 |
+
x = x.permute((0, 2, 1))
|
30 |
+
return x
|
31 |
+
|
32 |
+
class EncoderWithRNN(nn.Module):
|
33 |
+
def __init__(self, in_channels,**kwargs):
|
34 |
+
super(EncoderWithRNN, self).__init__()
|
35 |
+
hidden_size = kwargs.get('hidden_size', 256)
|
36 |
+
self.out_channels = hidden_size * 2
|
37 |
+
self.lstm = nn.LSTM(in_channels, hidden_size, bidirectional=True, num_layers=2,batch_first=True)
|
38 |
+
|
39 |
+
def forward(self, x):
|
40 |
+
self.lstm.flatten_parameters()
|
41 |
+
x, _ = self.lstm(x)
|
42 |
+
return x
|
43 |
+
|
44 |
+
class SequenceEncoder(nn.Module):
|
45 |
+
def __init__(self, in_channels, encoder_type='rnn', **kwargs):
|
46 |
+
super(SequenceEncoder, self).__init__()
|
47 |
+
self.encoder_reshape = Im2Seq(in_channels)
|
48 |
+
self.out_channels = self.encoder_reshape.out_channels
|
49 |
+
self.encoder_type = encoder_type
|
50 |
+
if encoder_type == 'reshape':
|
51 |
+
self.only_reshape = True
|
52 |
+
else:
|
53 |
+
support_encoder_dict = {
|
54 |
+
'reshape': Im2Seq,
|
55 |
+
'rnn': EncoderWithRNN,
|
56 |
+
'svtr': EncoderWithSVTR
|
57 |
+
}
|
58 |
+
assert encoder_type in support_encoder_dict, '{} must in {}'.format(
|
59 |
+
encoder_type, support_encoder_dict.keys())
|
60 |
+
|
61 |
+
self.encoder = support_encoder_dict[encoder_type](
|
62 |
+
self.encoder_reshape.out_channels,**kwargs)
|
63 |
+
self.out_channels = self.encoder.out_channels
|
64 |
+
self.only_reshape = False
|
65 |
+
|
66 |
+
def forward(self, x):
|
67 |
+
if self.encoder_type != 'svtr':
|
68 |
+
x = self.encoder_reshape(x)
|
69 |
+
if not self.only_reshape:
|
70 |
+
x = self.encoder(x)
|
71 |
+
return x
|
72 |
+
else:
|
73 |
+
x = self.encoder(x)
|
74 |
+
x = self.encoder_reshape(x)
|
75 |
+
return x
|
76 |
+
|
77 |
+
class ConvBNLayer(nn.Module):
|
78 |
+
def __init__(self,
|
79 |
+
in_channels,
|
80 |
+
out_channels,
|
81 |
+
kernel_size=3,
|
82 |
+
stride=1,
|
83 |
+
padding=0,
|
84 |
+
bias_attr=False,
|
85 |
+
groups=1,
|
86 |
+
act=nn.GELU):
|
87 |
+
super().__init__()
|
88 |
+
self.conv = nn.Conv2d(
|
89 |
+
in_channels=in_channels,
|
90 |
+
out_channels=out_channels,
|
91 |
+
kernel_size=kernel_size,
|
92 |
+
stride=stride,
|
93 |
+
padding=padding,
|
94 |
+
groups=groups,
|
95 |
+
# weight_attr=paddle.ParamAttr(initializer=nn.initializer.KaimingUniform()),
|
96 |
+
bias=bias_attr)
|
97 |
+
self.norm = nn.BatchNorm2d(out_channels)
|
98 |
+
self.act = Swish()
|
99 |
+
|
100 |
+
def forward(self, inputs):
|
101 |
+
out = self.conv(inputs)
|
102 |
+
out = self.norm(out)
|
103 |
+
out = self.act(out)
|
104 |
+
return out
|
105 |
+
|
106 |
+
|
107 |
+
class EncoderWithSVTR(nn.Module):
|
108 |
+
def __init__(
|
109 |
+
self,
|
110 |
+
in_channels,
|
111 |
+
dims=64, # XS
|
112 |
+
depth=2,
|
113 |
+
hidden_dims=120,
|
114 |
+
use_guide=False,
|
115 |
+
num_heads=8,
|
116 |
+
qkv_bias=True,
|
117 |
+
mlp_ratio=2.0,
|
118 |
+
drop_rate=0.1,
|
119 |
+
attn_drop_rate=0.1,
|
120 |
+
drop_path=0.,
|
121 |
+
qk_scale=None):
|
122 |
+
super(EncoderWithSVTR, self).__init__()
|
123 |
+
self.depth = depth
|
124 |
+
self.use_guide = use_guide
|
125 |
+
self.conv1 = ConvBNLayer(
|
126 |
+
in_channels, in_channels // 8, padding=1, act='swish')
|
127 |
+
self.conv2 = ConvBNLayer(
|
128 |
+
in_channels // 8, hidden_dims, kernel_size=1, act='swish')
|
129 |
+
|
130 |
+
self.svtr_block = nn.ModuleList([
|
131 |
+
Block(
|
132 |
+
dim=hidden_dims,
|
133 |
+
num_heads=num_heads,
|
134 |
+
mixer='Global',
|
135 |
+
HW=None,
|
136 |
+
mlp_ratio=mlp_ratio,
|
137 |
+
qkv_bias=qkv_bias,
|
138 |
+
qk_scale=qk_scale,
|
139 |
+
drop=drop_rate,
|
140 |
+
act_layer='swish',
|
141 |
+
attn_drop=attn_drop_rate,
|
142 |
+
drop_path=drop_path,
|
143 |
+
norm_layer='nn.LayerNorm',
|
144 |
+
epsilon=1e-05,
|
145 |
+
prenorm=False) for i in range(depth)
|
146 |
+
])
|
147 |
+
self.norm = nn.LayerNorm(hidden_dims, eps=1e-6)
|
148 |
+
self.conv3 = ConvBNLayer(
|
149 |
+
hidden_dims, in_channels, kernel_size=1, act='swish')
|
150 |
+
# last conv-nxn, the input is concat of input tensor and conv3 output tensor
|
151 |
+
self.conv4 = ConvBNLayer(
|
152 |
+
2 * in_channels, in_channels // 8, padding=1, act='swish')
|
153 |
+
|
154 |
+
self.conv1x1 = ConvBNLayer(
|
155 |
+
in_channels // 8, dims, kernel_size=1, act='swish')
|
156 |
+
self.out_channels = dims
|
157 |
+
self.apply(self._init_weights)
|
158 |
+
|
159 |
+
def _init_weights(self, m):
|
160 |
+
# weight initialization
|
161 |
+
if isinstance(m, nn.Conv2d):
|
162 |
+
nn.init.kaiming_normal_(m.weight, mode='fan_out')
|
163 |
+
if m.bias is not None:
|
164 |
+
nn.init.zeros_(m.bias)
|
165 |
+
elif isinstance(m, nn.BatchNorm2d):
|
166 |
+
nn.init.ones_(m.weight)
|
167 |
+
nn.init.zeros_(m.bias)
|
168 |
+
elif isinstance(m, nn.Linear):
|
169 |
+
nn.init.normal_(m.weight, 0, 0.01)
|
170 |
+
if m.bias is not None:
|
171 |
+
nn.init.zeros_(m.bias)
|
172 |
+
elif isinstance(m, nn.ConvTranspose2d):
|
173 |
+
nn.init.kaiming_normal_(m.weight, mode='fan_out')
|
174 |
+
if m.bias is not None:
|
175 |
+
nn.init.zeros_(m.bias)
|
176 |
+
elif isinstance(m, nn.LayerNorm):
|
177 |
+
nn.init.ones_(m.weight)
|
178 |
+
nn.init.zeros_(m.bias)
|
179 |
+
|
180 |
+
def forward(self, x):
|
181 |
+
# for use guide
|
182 |
+
if self.use_guide:
|
183 |
+
z = x.clone()
|
184 |
+
z.stop_gradient = True
|
185 |
+
else:
|
186 |
+
z = x
|
187 |
+
# for short cut
|
188 |
+
h = z
|
189 |
+
# reduce dim
|
190 |
+
z = self.conv1(z)
|
191 |
+
z = self.conv2(z)
|
192 |
+
# SVTR global block
|
193 |
+
B, C, H, W = z.shape
|
194 |
+
z = z.flatten(2).permute(0, 2, 1)
|
195 |
+
|
196 |
+
for blk in self.svtr_block:
|
197 |
+
z = blk(z)
|
198 |
+
|
199 |
+
z = self.norm(z)
|
200 |
+
# last stage
|
201 |
+
z = z.reshape([-1, H, W, C]).permute(0, 3, 1, 2)
|
202 |
+
z = self.conv3(z)
|
203 |
+
z = torch.cat((h, z), dim=1)
|
204 |
+
z = self.conv1x1(self.conv4(z))
|
205 |
+
|
206 |
+
return z
|
207 |
+
|
208 |
+
if __name__=="__main__":
|
209 |
+
svtrRNN = EncoderWithSVTR(56)
|
210 |
+
print(svtrRNN)
|
iopaint/model/anytext/ocr_recog/RecCTCHead.py
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from torch import nn
|
2 |
+
|
3 |
+
|
4 |
+
class CTCHead(nn.Module):
|
5 |
+
def __init__(self,
|
6 |
+
in_channels,
|
7 |
+
out_channels=6625,
|
8 |
+
fc_decay=0.0004,
|
9 |
+
mid_channels=None,
|
10 |
+
return_feats=False,
|
11 |
+
**kwargs):
|
12 |
+
super(CTCHead, self).__init__()
|
13 |
+
if mid_channels is None:
|
14 |
+
self.fc = nn.Linear(
|
15 |
+
in_channels,
|
16 |
+
out_channels,
|
17 |
+
bias=True,)
|
18 |
+
else:
|
19 |
+
self.fc1 = nn.Linear(
|
20 |
+
in_channels,
|
21 |
+
mid_channels,
|
22 |
+
bias=True,
|
23 |
+
)
|
24 |
+
self.fc2 = nn.Linear(
|
25 |
+
mid_channels,
|
26 |
+
out_channels,
|
27 |
+
bias=True,
|
28 |
+
)
|
29 |
+
|
30 |
+
self.out_channels = out_channels
|
31 |
+
self.mid_channels = mid_channels
|
32 |
+
self.return_feats = return_feats
|
33 |
+
|
34 |
+
def forward(self, x, labels=None):
|
35 |
+
if self.mid_channels is None:
|
36 |
+
predicts = self.fc(x)
|
37 |
+
else:
|
38 |
+
x = self.fc1(x)
|
39 |
+
predicts = self.fc2(x)
|
40 |
+
|
41 |
+
if self.return_feats:
|
42 |
+
result = dict()
|
43 |
+
result['ctc'] = predicts
|
44 |
+
result['ctc_neck'] = x
|
45 |
+
else:
|
46 |
+
result = predicts
|
47 |
+
|
48 |
+
return result
|
iopaint/model/anytext/ocr_recog/RecModel.py
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from torch import nn
|
2 |
+
from .RNN import SequenceEncoder, Im2Seq, Im2Im
|
3 |
+
from .RecMv1_enhance import MobileNetV1Enhance
|
4 |
+
|
5 |
+
from .RecCTCHead import CTCHead
|
6 |
+
|
7 |
+
backbone_dict = {"MobileNetV1Enhance":MobileNetV1Enhance}
|
8 |
+
neck_dict = {'SequenceEncoder': SequenceEncoder, 'Im2Seq': Im2Seq,'None':Im2Im}
|
9 |
+
head_dict = {'CTCHead':CTCHead}
|
10 |
+
|
11 |
+
|
12 |
+
class RecModel(nn.Module):
|
13 |
+
def __init__(self, config):
|
14 |
+
super().__init__()
|
15 |
+
assert 'in_channels' in config, 'in_channels must in model config'
|
16 |
+
backbone_type = config.backbone.pop('type')
|
17 |
+
assert backbone_type in backbone_dict, f'backbone.type must in {backbone_dict}'
|
18 |
+
self.backbone = backbone_dict[backbone_type](config.in_channels, **config.backbone)
|
19 |
+
|
20 |
+
neck_type = config.neck.pop('type')
|
21 |
+
assert neck_type in neck_dict, f'neck.type must in {neck_dict}'
|
22 |
+
self.neck = neck_dict[neck_type](self.backbone.out_channels, **config.neck)
|
23 |
+
|
24 |
+
head_type = config.head.pop('type')
|
25 |
+
assert head_type in head_dict, f'head.type must in {head_dict}'
|
26 |
+
self.head = head_dict[head_type](self.neck.out_channels, **config.head)
|
27 |
+
|
28 |
+
self.name = f'RecModel_{backbone_type}_{neck_type}_{head_type}'
|
29 |
+
|
30 |
+
def load_3rd_state_dict(self, _3rd_name, _state):
|
31 |
+
self.backbone.load_3rd_state_dict(_3rd_name, _state)
|
32 |
+
self.neck.load_3rd_state_dict(_3rd_name, _state)
|
33 |
+
self.head.load_3rd_state_dict(_3rd_name, _state)
|
34 |
+
|
35 |
+
def forward(self, x):
|
36 |
+
x = self.backbone(x)
|
37 |
+
x = self.neck(x)
|
38 |
+
x = self.head(x)
|
39 |
+
return x
|
40 |
+
|
41 |
+
def encode(self, x):
|
42 |
+
x = self.backbone(x)
|
43 |
+
x = self.neck(x)
|
44 |
+
x = self.head.ctc_encoder(x)
|
45 |
+
return x
|
iopaint/model/anytext/ocr_recog/RecMv1_enhance.py
ADDED
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
import torch.nn as nn
|
3 |
+
import torch.nn.functional as F
|
4 |
+
from .common import Activation
|
5 |
+
|
6 |
+
|
7 |
+
class ConvBNLayer(nn.Module):
|
8 |
+
def __init__(self,
|
9 |
+
num_channels,
|
10 |
+
filter_size,
|
11 |
+
num_filters,
|
12 |
+
stride,
|
13 |
+
padding,
|
14 |
+
channels=None,
|
15 |
+
num_groups=1,
|
16 |
+
act='hard_swish'):
|
17 |
+
super(ConvBNLayer, self).__init__()
|
18 |
+
self.act = act
|
19 |
+
self._conv = nn.Conv2d(
|
20 |
+
in_channels=num_channels,
|
21 |
+
out_channels=num_filters,
|
22 |
+
kernel_size=filter_size,
|
23 |
+
stride=stride,
|
24 |
+
padding=padding,
|
25 |
+
groups=num_groups,
|
26 |
+
bias=False)
|
27 |
+
|
28 |
+
self._batch_norm = nn.BatchNorm2d(
|
29 |
+
num_filters,
|
30 |
+
)
|
31 |
+
if self.act is not None:
|
32 |
+
self._act = Activation(act_type=act, inplace=True)
|
33 |
+
|
34 |
+
def forward(self, inputs):
|
35 |
+
y = self._conv(inputs)
|
36 |
+
y = self._batch_norm(y)
|
37 |
+
if self.act is not None:
|
38 |
+
y = self._act(y)
|
39 |
+
return y
|
40 |
+
|
41 |
+
|
42 |
+
class DepthwiseSeparable(nn.Module):
|
43 |
+
def __init__(self,
|
44 |
+
num_channels,
|
45 |
+
num_filters1,
|
46 |
+
num_filters2,
|
47 |
+
num_groups,
|
48 |
+
stride,
|
49 |
+
scale,
|
50 |
+
dw_size=3,
|
51 |
+
padding=1,
|
52 |
+
use_se=False):
|
53 |
+
super(DepthwiseSeparable, self).__init__()
|
54 |
+
self.use_se = use_se
|
55 |
+
self._depthwise_conv = ConvBNLayer(
|
56 |
+
num_channels=num_channels,
|
57 |
+
num_filters=int(num_filters1 * scale),
|
58 |
+
filter_size=dw_size,
|
59 |
+
stride=stride,
|
60 |
+
padding=padding,
|
61 |
+
num_groups=int(num_groups * scale))
|
62 |
+
if use_se:
|
63 |
+
self._se = SEModule(int(num_filters1 * scale))
|
64 |
+
self._pointwise_conv = ConvBNLayer(
|
65 |
+
num_channels=int(num_filters1 * scale),
|
66 |
+
filter_size=1,
|
67 |
+
num_filters=int(num_filters2 * scale),
|
68 |
+
stride=1,
|
69 |
+
padding=0)
|
70 |
+
|
71 |
+
def forward(self, inputs):
|
72 |
+
y = self._depthwise_conv(inputs)
|
73 |
+
if self.use_se:
|
74 |
+
y = self._se(y)
|
75 |
+
y = self._pointwise_conv(y)
|
76 |
+
return y
|
77 |
+
|
78 |
+
|
79 |
+
class MobileNetV1Enhance(nn.Module):
|
80 |
+
def __init__(self,
|
81 |
+
in_channels=3,
|
82 |
+
scale=0.5,
|
83 |
+
last_conv_stride=1,
|
84 |
+
last_pool_type='max',
|
85 |
+
**kwargs):
|
86 |
+
super().__init__()
|
87 |
+
self.scale = scale
|
88 |
+
self.block_list = []
|
89 |
+
|
90 |
+
self.conv1 = ConvBNLayer(
|
91 |
+
num_channels=in_channels,
|
92 |
+
filter_size=3,
|
93 |
+
channels=3,
|
94 |
+
num_filters=int(32 * scale),
|
95 |
+
stride=2,
|
96 |
+
padding=1)
|
97 |
+
|
98 |
+
conv2_1 = DepthwiseSeparable(
|
99 |
+
num_channels=int(32 * scale),
|
100 |
+
num_filters1=32,
|
101 |
+
num_filters2=64,
|
102 |
+
num_groups=32,
|
103 |
+
stride=1,
|
104 |
+
scale=scale)
|
105 |
+
self.block_list.append(conv2_1)
|
106 |
+
|
107 |
+
conv2_2 = DepthwiseSeparable(
|
108 |
+
num_channels=int(64 * scale),
|
109 |
+
num_filters1=64,
|
110 |
+
num_filters2=128,
|
111 |
+
num_groups=64,
|
112 |
+
stride=1,
|
113 |
+
scale=scale)
|
114 |
+
self.block_list.append(conv2_2)
|
115 |
+
|
116 |
+
conv3_1 = DepthwiseSeparable(
|
117 |
+
num_channels=int(128 * scale),
|
118 |
+
num_filters1=128,
|
119 |
+
num_filters2=128,
|
120 |
+
num_groups=128,
|
121 |
+
stride=1,
|
122 |
+
scale=scale)
|
123 |
+
self.block_list.append(conv3_1)
|
124 |
+
|
125 |
+
conv3_2 = DepthwiseSeparable(
|
126 |
+
num_channels=int(128 * scale),
|
127 |
+
num_filters1=128,
|
128 |
+
num_filters2=256,
|
129 |
+
num_groups=128,
|
130 |
+
stride=(2, 1),
|
131 |
+
scale=scale)
|
132 |
+
self.block_list.append(conv3_2)
|
133 |
+
|
134 |
+
conv4_1 = DepthwiseSeparable(
|
135 |
+
num_channels=int(256 * scale),
|
136 |
+
num_filters1=256,
|
137 |
+
num_filters2=256,
|
138 |
+
num_groups=256,
|
139 |
+
stride=1,
|
140 |
+
scale=scale)
|
141 |
+
self.block_list.append(conv4_1)
|
142 |
+
|
143 |
+
conv4_2 = DepthwiseSeparable(
|
144 |
+
num_channels=int(256 * scale),
|
145 |
+
num_filters1=256,
|
146 |
+
num_filters2=512,
|
147 |
+
num_groups=256,
|
148 |
+
stride=(2, 1),
|
149 |
+
scale=scale)
|
150 |
+
self.block_list.append(conv4_2)
|
151 |
+
|
152 |
+
for _ in range(5):
|
153 |
+
conv5 = DepthwiseSeparable(
|
154 |
+
num_channels=int(512 * scale),
|
155 |
+
num_filters1=512,
|
156 |
+
num_filters2=512,
|
157 |
+
num_groups=512,
|
158 |
+
stride=1,
|
159 |
+
dw_size=5,
|
160 |
+
padding=2,
|
161 |
+
scale=scale,
|
162 |
+
use_se=False)
|
163 |
+
self.block_list.append(conv5)
|
164 |
+
|
165 |
+
conv5_6 = DepthwiseSeparable(
|
166 |
+
num_channels=int(512 * scale),
|
167 |
+
num_filters1=512,
|
168 |
+
num_filters2=1024,
|
169 |
+
num_groups=512,
|
170 |
+
stride=(2, 1),
|
171 |
+
dw_size=5,
|
172 |
+
padding=2,
|
173 |
+
scale=scale,
|
174 |
+
use_se=True)
|
175 |
+
self.block_list.append(conv5_6)
|
176 |
+
|
177 |
+
conv6 = DepthwiseSeparable(
|
178 |
+
num_channels=int(1024 * scale),
|
179 |
+
num_filters1=1024,
|
180 |
+
num_filters2=1024,
|
181 |
+
num_groups=1024,
|
182 |
+
stride=last_conv_stride,
|
183 |
+
dw_size=5,
|
184 |
+
padding=2,
|
185 |
+
use_se=True,
|
186 |
+
scale=scale)
|
187 |
+
self.block_list.append(conv6)
|
188 |
+
|
189 |
+
self.block_list = nn.Sequential(*self.block_list)
|
190 |
+
if last_pool_type == 'avg':
|
191 |
+
self.pool = nn.AvgPool2d(kernel_size=2, stride=2, padding=0)
|
192 |
+
else:
|
193 |
+
self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
|
194 |
+
self.out_channels = int(1024 * scale)
|
195 |
+
|
196 |
+
def forward(self, inputs):
|
197 |
+
y = self.conv1(inputs)
|
198 |
+
y = self.block_list(y)
|
199 |
+
y = self.pool(y)
|
200 |
+
return y
|
201 |
+
|
202 |
+
def hardsigmoid(x):
|
203 |
+
return F.relu6(x + 3., inplace=True) / 6.
|
204 |
+
|
205 |
+
class SEModule(nn.Module):
|
206 |
+
def __init__(self, channel, reduction=4):
|
207 |
+
super(SEModule, self).__init__()
|
208 |
+
self.avg_pool = nn.AdaptiveAvgPool2d(1)
|
209 |
+
self.conv1 = nn.Conv2d(
|
210 |
+
in_channels=channel,
|
211 |
+
out_channels=channel // reduction,
|
212 |
+
kernel_size=1,
|
213 |
+
stride=1,
|
214 |
+
padding=0,
|
215 |
+
bias=True)
|
216 |
+
self.conv2 = nn.Conv2d(
|
217 |
+
in_channels=channel // reduction,
|
218 |
+
out_channels=channel,
|
219 |
+
kernel_size=1,
|
220 |
+
stride=1,
|
221 |
+
padding=0,
|
222 |
+
bias=True)
|
223 |
+
|
224 |
+
def forward(self, inputs):
|
225 |
+
outputs = self.avg_pool(inputs)
|
226 |
+
outputs = self.conv1(outputs)
|
227 |
+
outputs = F.relu(outputs)
|
228 |
+
outputs = self.conv2(outputs)
|
229 |
+
outputs = hardsigmoid(outputs)
|
230 |
+
x = torch.mul(inputs, outputs)
|
231 |
+
|
232 |
+
return x
|
iopaint/model/anytext/ocr_recog/RecSVTR.py
ADDED
@@ -0,0 +1,591 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
import torch.nn as nn
|
3 |
+
import numpy as np
|
4 |
+
from torch.nn.init import trunc_normal_, zeros_, ones_
|
5 |
+
from torch.nn import functional
|
6 |
+
|
7 |
+
|
8 |
+
def drop_path(x, drop_prob=0., training=False):
|
9 |
+
"""Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
|
10 |
+
the original name is misleading as 'Drop Connect' is a different form of dropout in a separate paper...
|
11 |
+
See discussion: https://github.com/tensorflow/tpu/issues/494#issuecomment-532968956 ...
|
12 |
+
"""
|
13 |
+
if drop_prob == 0. or not training:
|
14 |
+
return x
|
15 |
+
keep_prob = torch.tensor(1 - drop_prob)
|
16 |
+
shape = (x.size()[0], ) + (1, ) * (x.ndim - 1)
|
17 |
+
random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype)
|
18 |
+
random_tensor = torch.floor(random_tensor) # binarize
|
19 |
+
output = x.divide(keep_prob) * random_tensor
|
20 |
+
return output
|
21 |
+
|
22 |
+
|
23 |
+
class Swish(nn.Module):
|
24 |
+
def __int__(self):
|
25 |
+
super(Swish, self).__int__()
|
26 |
+
|
27 |
+
def forward(self,x):
|
28 |
+
return x*torch.sigmoid(x)
|
29 |
+
|
30 |
+
|
31 |
+
class ConvBNLayer(nn.Module):
|
32 |
+
def __init__(self,
|
33 |
+
in_channels,
|
34 |
+
out_channels,
|
35 |
+
kernel_size=3,
|
36 |
+
stride=1,
|
37 |
+
padding=0,
|
38 |
+
bias_attr=False,
|
39 |
+
groups=1,
|
40 |
+
act=nn.GELU):
|
41 |
+
super().__init__()
|
42 |
+
self.conv = nn.Conv2d(
|
43 |
+
in_channels=in_channels,
|
44 |
+
out_channels=out_channels,
|
45 |
+
kernel_size=kernel_size,
|
46 |
+
stride=stride,
|
47 |
+
padding=padding,
|
48 |
+
groups=groups,
|
49 |
+
# weight_attr=paddle.ParamAttr(initializer=nn.initializer.KaimingUniform()),
|
50 |
+
bias=bias_attr)
|
51 |
+
self.norm = nn.BatchNorm2d(out_channels)
|
52 |
+
self.act = act()
|
53 |
+
|
54 |
+
def forward(self, inputs):
|
55 |
+
out = self.conv(inputs)
|
56 |
+
out = self.norm(out)
|
57 |
+
out = self.act(out)
|
58 |
+
return out
|
59 |
+
|
60 |
+
|
61 |
+
class DropPath(nn.Module):
|
62 |
+
"""Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
|
63 |
+
"""
|
64 |
+
|
65 |
+
def __init__(self, drop_prob=None):
|
66 |
+
super(DropPath, self).__init__()
|
67 |
+
self.drop_prob = drop_prob
|
68 |
+
|
69 |
+
def forward(self, x):
|
70 |
+
return drop_path(x, self.drop_prob, self.training)
|
71 |
+
|
72 |
+
|
73 |
+
class Identity(nn.Module):
|
74 |
+
def __init__(self):
|
75 |
+
super(Identity, self).__init__()
|
76 |
+
|
77 |
+
def forward(self, input):
|
78 |
+
return input
|
79 |
+
|
80 |
+
|
81 |
+
class Mlp(nn.Module):
|
82 |
+
def __init__(self,
|
83 |
+
in_features,
|
84 |
+
hidden_features=None,
|
85 |
+
out_features=None,
|
86 |
+
act_layer=nn.GELU,
|
87 |
+
drop=0.):
|
88 |
+
super().__init__()
|
89 |
+
out_features = out_features or in_features
|
90 |
+
hidden_features = hidden_features or in_features
|
91 |
+
self.fc1 = nn.Linear(in_features, hidden_features)
|
92 |
+
if isinstance(act_layer, str):
|
93 |
+
self.act = Swish()
|
94 |
+
else:
|
95 |
+
self.act = act_layer()
|
96 |
+
self.fc2 = nn.Linear(hidden_features, out_features)
|
97 |
+
self.drop = nn.Dropout(drop)
|
98 |
+
|
99 |
+
def forward(self, x):
|
100 |
+
x = self.fc1(x)
|
101 |
+
x = self.act(x)
|
102 |
+
x = self.drop(x)
|
103 |
+
x = self.fc2(x)
|
104 |
+
x = self.drop(x)
|
105 |
+
return x
|
106 |
+
|
107 |
+
|
108 |
+
class ConvMixer(nn.Module):
|
109 |
+
def __init__(
|
110 |
+
self,
|
111 |
+
dim,
|
112 |
+
num_heads=8,
|
113 |
+
HW=(8, 25),
|
114 |
+
local_k=(3, 3), ):
|
115 |
+
super().__init__()
|
116 |
+
self.HW = HW
|
117 |
+
self.dim = dim
|
118 |
+
self.local_mixer = nn.Conv2d(
|
119 |
+
dim,
|
120 |
+
dim,
|
121 |
+
local_k,
|
122 |
+
1, (local_k[0] // 2, local_k[1] // 2),
|
123 |
+
groups=num_heads,
|
124 |
+
# weight_attr=ParamAttr(initializer=KaimingNormal())
|
125 |
+
)
|
126 |
+
|
127 |
+
def forward(self, x):
|
128 |
+
h = self.HW[0]
|
129 |
+
w = self.HW[1]
|
130 |
+
x = x.transpose([0, 2, 1]).reshape([0, self.dim, h, w])
|
131 |
+
x = self.local_mixer(x)
|
132 |
+
x = x.flatten(2).transpose([0, 2, 1])
|
133 |
+
return x
|
134 |
+
|
135 |
+
|
136 |
+
class Attention(nn.Module):
|
137 |
+
def __init__(self,
|
138 |
+
dim,
|
139 |
+
num_heads=8,
|
140 |
+
mixer='Global',
|
141 |
+
HW=(8, 25),
|
142 |
+
local_k=(7, 11),
|
143 |
+
qkv_bias=False,
|
144 |
+
qk_scale=None,
|
145 |
+
attn_drop=0.,
|
146 |
+
proj_drop=0.):
|
147 |
+
super().__init__()
|
148 |
+
self.num_heads = num_heads
|
149 |
+
head_dim = dim // num_heads
|
150 |
+
self.scale = qk_scale or head_dim**-0.5
|
151 |
+
|
152 |
+
self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
|
153 |
+
self.attn_drop = nn.Dropout(attn_drop)
|
154 |
+
self.proj = nn.Linear(dim, dim)
|
155 |
+
self.proj_drop = nn.Dropout(proj_drop)
|
156 |
+
self.HW = HW
|
157 |
+
if HW is not None:
|
158 |
+
H = HW[0]
|
159 |
+
W = HW[1]
|
160 |
+
self.N = H * W
|
161 |
+
self.C = dim
|
162 |
+
if mixer == 'Local' and HW is not None:
|
163 |
+
hk = local_k[0]
|
164 |
+
wk = local_k[1]
|
165 |
+
mask = torch.ones([H * W, H + hk - 1, W + wk - 1])
|
166 |
+
for h in range(0, H):
|
167 |
+
for w in range(0, W):
|
168 |
+
mask[h * W + w, h:h + hk, w:w + wk] = 0.
|
169 |
+
mask_paddle = mask[:, hk // 2:H + hk // 2, wk // 2:W + wk //
|
170 |
+
2].flatten(1)
|
171 |
+
mask_inf = torch.full([H * W, H * W],fill_value=float('-inf'))
|
172 |
+
mask = torch.where(mask_paddle < 1, mask_paddle, mask_inf)
|
173 |
+
self.mask = mask[None,None,:]
|
174 |
+
# self.mask = mask.unsqueeze([0, 1])
|
175 |
+
self.mixer = mixer
|
176 |
+
|
177 |
+
def forward(self, x):
|
178 |
+
if self.HW is not None:
|
179 |
+
N = self.N
|
180 |
+
C = self.C
|
181 |
+
else:
|
182 |
+
_, N, C = x.shape
|
183 |
+
qkv = self.qkv(x).reshape((-1, N, 3, self.num_heads, C //self.num_heads)).permute((2, 0, 3, 1, 4))
|
184 |
+
q, k, v = qkv[0] * self.scale, qkv[1], qkv[2]
|
185 |
+
|
186 |
+
attn = (q.matmul(k.permute((0, 1, 3, 2))))
|
187 |
+
if self.mixer == 'Local':
|
188 |
+
attn += self.mask
|
189 |
+
attn = functional.softmax(attn, dim=-1)
|
190 |
+
attn = self.attn_drop(attn)
|
191 |
+
|
192 |
+
x = (attn.matmul(v)).permute((0, 2, 1, 3)).reshape((-1, N, C))
|
193 |
+
x = self.proj(x)
|
194 |
+
x = self.proj_drop(x)
|
195 |
+
return x
|
196 |
+
|
197 |
+
|
198 |
+
class Block(nn.Module):
|
199 |
+
def __init__(self,
|
200 |
+
dim,
|
201 |
+
num_heads,
|
202 |
+
mixer='Global',
|
203 |
+
local_mixer=(7, 11),
|
204 |
+
HW=(8, 25),
|
205 |
+
mlp_ratio=4.,
|
206 |
+
qkv_bias=False,
|
207 |
+
qk_scale=None,
|
208 |
+
drop=0.,
|
209 |
+
attn_drop=0.,
|
210 |
+
drop_path=0.,
|
211 |
+
act_layer=nn.GELU,
|
212 |
+
norm_layer='nn.LayerNorm',
|
213 |
+
epsilon=1e-6,
|
214 |
+
prenorm=True):
|
215 |
+
super().__init__()
|
216 |
+
if isinstance(norm_layer, str):
|
217 |
+
self.norm1 = eval(norm_layer)(dim, eps=epsilon)
|
218 |
+
else:
|
219 |
+
self.norm1 = norm_layer(dim)
|
220 |
+
if mixer == 'Global' or mixer == 'Local':
|
221 |
+
|
222 |
+
self.mixer = Attention(
|
223 |
+
dim,
|
224 |
+
num_heads=num_heads,
|
225 |
+
mixer=mixer,
|
226 |
+
HW=HW,
|
227 |
+
local_k=local_mixer,
|
228 |
+
qkv_bias=qkv_bias,
|
229 |
+
qk_scale=qk_scale,
|
230 |
+
attn_drop=attn_drop,
|
231 |
+
proj_drop=drop)
|
232 |
+
elif mixer == 'Conv':
|
233 |
+
self.mixer = ConvMixer(
|
234 |
+
dim, num_heads=num_heads, HW=HW, local_k=local_mixer)
|
235 |
+
else:
|
236 |
+
raise TypeError("The mixer must be one of [Global, Local, Conv]")
|
237 |
+
|
238 |
+
self.drop_path = DropPath(drop_path) if drop_path > 0. else Identity()
|
239 |
+
if isinstance(norm_layer, str):
|
240 |
+
self.norm2 = eval(norm_layer)(dim, eps=epsilon)
|
241 |
+
else:
|
242 |
+
self.norm2 = norm_layer(dim)
|
243 |
+
mlp_hidden_dim = int(dim * mlp_ratio)
|
244 |
+
self.mlp_ratio = mlp_ratio
|
245 |
+
self.mlp = Mlp(in_features=dim,
|
246 |
+
hidden_features=mlp_hidden_dim,
|
247 |
+
act_layer=act_layer,
|
248 |
+
drop=drop)
|
249 |
+
self.prenorm = prenorm
|
250 |
+
|
251 |
+
def forward(self, x):
|
252 |
+
if self.prenorm:
|
253 |
+
x = self.norm1(x + self.drop_path(self.mixer(x)))
|
254 |
+
x = self.norm2(x + self.drop_path(self.mlp(x)))
|
255 |
+
else:
|
256 |
+
x = x + self.drop_path(self.mixer(self.norm1(x)))
|
257 |
+
x = x + self.drop_path(self.mlp(self.norm2(x)))
|
258 |
+
return x
|
259 |
+
|
260 |
+
|
261 |
+
class PatchEmbed(nn.Module):
|
262 |
+
""" Image to Patch Embedding
|
263 |
+
"""
|
264 |
+
|
265 |
+
def __init__(self,
|
266 |
+
img_size=(32, 100),
|
267 |
+
in_channels=3,
|
268 |
+
embed_dim=768,
|
269 |
+
sub_num=2):
|
270 |
+
super().__init__()
|
271 |
+
num_patches = (img_size[1] // (2 ** sub_num)) * \
|
272 |
+
(img_size[0] // (2 ** sub_num))
|
273 |
+
self.img_size = img_size
|
274 |
+
self.num_patches = num_patches
|
275 |
+
self.embed_dim = embed_dim
|
276 |
+
self.norm = None
|
277 |
+
if sub_num == 2:
|
278 |
+
self.proj = nn.Sequential(
|
279 |
+
ConvBNLayer(
|
280 |
+
in_channels=in_channels,
|
281 |
+
out_channels=embed_dim // 2,
|
282 |
+
kernel_size=3,
|
283 |
+
stride=2,
|
284 |
+
padding=1,
|
285 |
+
act=nn.GELU,
|
286 |
+
bias_attr=False),
|
287 |
+
ConvBNLayer(
|
288 |
+
in_channels=embed_dim // 2,
|
289 |
+
out_channels=embed_dim,
|
290 |
+
kernel_size=3,
|
291 |
+
stride=2,
|
292 |
+
padding=1,
|
293 |
+
act=nn.GELU,
|
294 |
+
bias_attr=False))
|
295 |
+
if sub_num == 3:
|
296 |
+
self.proj = nn.Sequential(
|
297 |
+
ConvBNLayer(
|
298 |
+
in_channels=in_channels,
|
299 |
+
out_channels=embed_dim // 4,
|
300 |
+
kernel_size=3,
|
301 |
+
stride=2,
|
302 |
+
padding=1,
|
303 |
+
act=nn.GELU,
|
304 |
+
bias_attr=False),
|
305 |
+
ConvBNLayer(
|
306 |
+
in_channels=embed_dim // 4,
|
307 |
+
out_channels=embed_dim // 2,
|
308 |
+
kernel_size=3,
|
309 |
+
stride=2,
|
310 |
+
padding=1,
|
311 |
+
act=nn.GELU,
|
312 |
+
bias_attr=False),
|
313 |
+
ConvBNLayer(
|
314 |
+
in_channels=embed_dim // 2,
|
315 |
+
out_channels=embed_dim,
|
316 |
+
kernel_size=3,
|
317 |
+
stride=2,
|
318 |
+
padding=1,
|
319 |
+
act=nn.GELU,
|
320 |
+
bias_attr=False))
|
321 |
+
|
322 |
+
def forward(self, x):
|
323 |
+
B, C, H, W = x.shape
|
324 |
+
assert H == self.img_size[0] and W == self.img_size[1], \
|
325 |
+
f"Input image size ({H}*{W}) doesn't match model ({self.img_size[0]}*{self.img_size[1]})."
|
326 |
+
x = self.proj(x).flatten(2).permute(0, 2, 1)
|
327 |
+
return x
|
328 |
+
|
329 |
+
|
330 |
+
class SubSample(nn.Module):
|
331 |
+
def __init__(self,
|
332 |
+
in_channels,
|
333 |
+
out_channels,
|
334 |
+
types='Pool',
|
335 |
+
stride=(2, 1),
|
336 |
+
sub_norm='nn.LayerNorm',
|
337 |
+
act=None):
|
338 |
+
super().__init__()
|
339 |
+
self.types = types
|
340 |
+
if types == 'Pool':
|
341 |
+
self.avgpool = nn.AvgPool2d(
|
342 |
+
kernel_size=(3, 5), stride=stride, padding=(1, 2))
|
343 |
+
self.maxpool = nn.MaxPool2d(
|
344 |
+
kernel_size=(3, 5), stride=stride, padding=(1, 2))
|
345 |
+
self.proj = nn.Linear(in_channels, out_channels)
|
346 |
+
else:
|
347 |
+
self.conv = nn.Conv2d(
|
348 |
+
in_channels,
|
349 |
+
out_channels,
|
350 |
+
kernel_size=3,
|
351 |
+
stride=stride,
|
352 |
+
padding=1,
|
353 |
+
# weight_attr=ParamAttr(initializer=KaimingNormal())
|
354 |
+
)
|
355 |
+
self.norm = eval(sub_norm)(out_channels)
|
356 |
+
if act is not None:
|
357 |
+
self.act = act()
|
358 |
+
else:
|
359 |
+
self.act = None
|
360 |
+
|
361 |
+
def forward(self, x):
|
362 |
+
|
363 |
+
if self.types == 'Pool':
|
364 |
+
x1 = self.avgpool(x)
|
365 |
+
x2 = self.maxpool(x)
|
366 |
+
x = (x1 + x2) * 0.5
|
367 |
+
out = self.proj(x.flatten(2).permute((0, 2, 1)))
|
368 |
+
else:
|
369 |
+
x = self.conv(x)
|
370 |
+
out = x.flatten(2).permute((0, 2, 1))
|
371 |
+
out = self.norm(out)
|
372 |
+
if self.act is not None:
|
373 |
+
out = self.act(out)
|
374 |
+
|
375 |
+
return out
|
376 |
+
|
377 |
+
|
378 |
+
class SVTRNet(nn.Module):
|
379 |
+
def __init__(
|
380 |
+
self,
|
381 |
+
img_size=[48, 100],
|
382 |
+
in_channels=3,
|
383 |
+
embed_dim=[64, 128, 256],
|
384 |
+
depth=[3, 6, 3],
|
385 |
+
num_heads=[2, 4, 8],
|
386 |
+
mixer=['Local'] * 6 + ['Global'] *
|
387 |
+
6, # Local atten, Global atten, Conv
|
388 |
+
local_mixer=[[7, 11], [7, 11], [7, 11]],
|
389 |
+
patch_merging='Conv', # Conv, Pool, None
|
390 |
+
mlp_ratio=4,
|
391 |
+
qkv_bias=True,
|
392 |
+
qk_scale=None,
|
393 |
+
drop_rate=0.,
|
394 |
+
last_drop=0.1,
|
395 |
+
attn_drop_rate=0.,
|
396 |
+
drop_path_rate=0.1,
|
397 |
+
norm_layer='nn.LayerNorm',
|
398 |
+
sub_norm='nn.LayerNorm',
|
399 |
+
epsilon=1e-6,
|
400 |
+
out_channels=192,
|
401 |
+
out_char_num=25,
|
402 |
+
block_unit='Block',
|
403 |
+
act='nn.GELU',
|
404 |
+
last_stage=True,
|
405 |
+
sub_num=2,
|
406 |
+
prenorm=True,
|
407 |
+
use_lenhead=False,
|
408 |
+
**kwargs):
|
409 |
+
super().__init__()
|
410 |
+
self.img_size = img_size
|
411 |
+
self.embed_dim = embed_dim
|
412 |
+
self.out_channels = out_channels
|
413 |
+
self.prenorm = prenorm
|
414 |
+
patch_merging = None if patch_merging != 'Conv' and patch_merging != 'Pool' else patch_merging
|
415 |
+
self.patch_embed = PatchEmbed(
|
416 |
+
img_size=img_size,
|
417 |
+
in_channels=in_channels,
|
418 |
+
embed_dim=embed_dim[0],
|
419 |
+
sub_num=sub_num)
|
420 |
+
num_patches = self.patch_embed.num_patches
|
421 |
+
self.HW = [img_size[0] // (2**sub_num), img_size[1] // (2**sub_num)]
|
422 |
+
self.pos_embed = nn.Parameter(torch.zeros(1, num_patches, embed_dim[0]))
|
423 |
+
# self.pos_embed = self.create_parameter(
|
424 |
+
# shape=[1, num_patches, embed_dim[0]], default_initializer=zeros_)
|
425 |
+
|
426 |
+
# self.add_parameter("pos_embed", self.pos_embed)
|
427 |
+
|
428 |
+
self.pos_drop = nn.Dropout(p=drop_rate)
|
429 |
+
Block_unit = eval(block_unit)
|
430 |
+
|
431 |
+
dpr = np.linspace(0, drop_path_rate, sum(depth))
|
432 |
+
self.blocks1 = nn.ModuleList(
|
433 |
+
[
|
434 |
+
Block_unit(
|
435 |
+
dim=embed_dim[0],
|
436 |
+
num_heads=num_heads[0],
|
437 |
+
mixer=mixer[0:depth[0]][i],
|
438 |
+
HW=self.HW,
|
439 |
+
local_mixer=local_mixer[0],
|
440 |
+
mlp_ratio=mlp_ratio,
|
441 |
+
qkv_bias=qkv_bias,
|
442 |
+
qk_scale=qk_scale,
|
443 |
+
drop=drop_rate,
|
444 |
+
act_layer=eval(act),
|
445 |
+
attn_drop=attn_drop_rate,
|
446 |
+
drop_path=dpr[0:depth[0]][i],
|
447 |
+
norm_layer=norm_layer,
|
448 |
+
epsilon=epsilon,
|
449 |
+
prenorm=prenorm) for i in range(depth[0])
|
450 |
+
]
|
451 |
+
)
|
452 |
+
if patch_merging is not None:
|
453 |
+
self.sub_sample1 = SubSample(
|
454 |
+
embed_dim[0],
|
455 |
+
embed_dim[1],
|
456 |
+
sub_norm=sub_norm,
|
457 |
+
stride=[2, 1],
|
458 |
+
types=patch_merging)
|
459 |
+
HW = [self.HW[0] // 2, self.HW[1]]
|
460 |
+
else:
|
461 |
+
HW = self.HW
|
462 |
+
self.patch_merging = patch_merging
|
463 |
+
self.blocks2 = nn.ModuleList([
|
464 |
+
Block_unit(
|
465 |
+
dim=embed_dim[1],
|
466 |
+
num_heads=num_heads[1],
|
467 |
+
mixer=mixer[depth[0]:depth[0] + depth[1]][i],
|
468 |
+
HW=HW,
|
469 |
+
local_mixer=local_mixer[1],
|
470 |
+
mlp_ratio=mlp_ratio,
|
471 |
+
qkv_bias=qkv_bias,
|
472 |
+
qk_scale=qk_scale,
|
473 |
+
drop=drop_rate,
|
474 |
+
act_layer=eval(act),
|
475 |
+
attn_drop=attn_drop_rate,
|
476 |
+
drop_path=dpr[depth[0]:depth[0] + depth[1]][i],
|
477 |
+
norm_layer=norm_layer,
|
478 |
+
epsilon=epsilon,
|
479 |
+
prenorm=prenorm) for i in range(depth[1])
|
480 |
+
])
|
481 |
+
if patch_merging is not None:
|
482 |
+
self.sub_sample2 = SubSample(
|
483 |
+
embed_dim[1],
|
484 |
+
embed_dim[2],
|
485 |
+
sub_norm=sub_norm,
|
486 |
+
stride=[2, 1],
|
487 |
+
types=patch_merging)
|
488 |
+
HW = [self.HW[0] // 4, self.HW[1]]
|
489 |
+
else:
|
490 |
+
HW = self.HW
|
491 |
+
self.blocks3 = nn.ModuleList([
|
492 |
+
Block_unit(
|
493 |
+
dim=embed_dim[2],
|
494 |
+
num_heads=num_heads[2],
|
495 |
+
mixer=mixer[depth[0] + depth[1]:][i],
|
496 |
+
HW=HW,
|
497 |
+
local_mixer=local_mixer[2],
|
498 |
+
mlp_ratio=mlp_ratio,
|
499 |
+
qkv_bias=qkv_bias,
|
500 |
+
qk_scale=qk_scale,
|
501 |
+
drop=drop_rate,
|
502 |
+
act_layer=eval(act),
|
503 |
+
attn_drop=attn_drop_rate,
|
504 |
+
drop_path=dpr[depth[0] + depth[1]:][i],
|
505 |
+
norm_layer=norm_layer,
|
506 |
+
epsilon=epsilon,
|
507 |
+
prenorm=prenorm) for i in range(depth[2])
|
508 |
+
])
|
509 |
+
self.last_stage = last_stage
|
510 |
+
if last_stage:
|
511 |
+
self.avg_pool = nn.AdaptiveAvgPool2d((1, out_char_num))
|
512 |
+
self.last_conv = nn.Conv2d(
|
513 |
+
in_channels=embed_dim[2],
|
514 |
+
out_channels=self.out_channels,
|
515 |
+
kernel_size=1,
|
516 |
+
stride=1,
|
517 |
+
padding=0,
|
518 |
+
bias=False)
|
519 |
+
self.hardswish = nn.Hardswish()
|
520 |
+
self.dropout = nn.Dropout(p=last_drop)
|
521 |
+
if not prenorm:
|
522 |
+
self.norm = eval(norm_layer)(embed_dim[-1], epsilon=epsilon)
|
523 |
+
self.use_lenhead = use_lenhead
|
524 |
+
if use_lenhead:
|
525 |
+
self.len_conv = nn.Linear(embed_dim[2], self.out_channels)
|
526 |
+
self.hardswish_len = nn.Hardswish()
|
527 |
+
self.dropout_len = nn.Dropout(
|
528 |
+
p=last_drop)
|
529 |
+
|
530 |
+
trunc_normal_(self.pos_embed,std=.02)
|
531 |
+
self.apply(self._init_weights)
|
532 |
+
|
533 |
+
def _init_weights(self, m):
|
534 |
+
if isinstance(m, nn.Linear):
|
535 |
+
trunc_normal_(m.weight,std=.02)
|
536 |
+
if isinstance(m, nn.Linear) and m.bias is not None:
|
537 |
+
zeros_(m.bias)
|
538 |
+
elif isinstance(m, nn.LayerNorm):
|
539 |
+
zeros_(m.bias)
|
540 |
+
ones_(m.weight)
|
541 |
+
|
542 |
+
def forward_features(self, x):
|
543 |
+
x = self.patch_embed(x)
|
544 |
+
x = x + self.pos_embed
|
545 |
+
x = self.pos_drop(x)
|
546 |
+
for blk in self.blocks1:
|
547 |
+
x = blk(x)
|
548 |
+
if self.patch_merging is not None:
|
549 |
+
x = self.sub_sample1(
|
550 |
+
x.permute([0, 2, 1]).reshape(
|
551 |
+
[-1, self.embed_dim[0], self.HW[0], self.HW[1]]))
|
552 |
+
for blk in self.blocks2:
|
553 |
+
x = blk(x)
|
554 |
+
if self.patch_merging is not None:
|
555 |
+
x = self.sub_sample2(
|
556 |
+
x.permute([0, 2, 1]).reshape(
|
557 |
+
[-1, self.embed_dim[1], self.HW[0] // 2, self.HW[1]]))
|
558 |
+
for blk in self.blocks3:
|
559 |
+
x = blk(x)
|
560 |
+
if not self.prenorm:
|
561 |
+
x = self.norm(x)
|
562 |
+
return x
|
563 |
+
|
564 |
+
def forward(self, x):
|
565 |
+
x = self.forward_features(x)
|
566 |
+
if self.use_lenhead:
|
567 |
+
len_x = self.len_conv(x.mean(1))
|
568 |
+
len_x = self.dropout_len(self.hardswish_len(len_x))
|
569 |
+
if self.last_stage:
|
570 |
+
if self.patch_merging is not None:
|
571 |
+
h = self.HW[0] // 4
|
572 |
+
else:
|
573 |
+
h = self.HW[0]
|
574 |
+
x = self.avg_pool(
|
575 |
+
x.permute([0, 2, 1]).reshape(
|
576 |
+
[-1, self.embed_dim[2], h, self.HW[1]]))
|
577 |
+
x = self.last_conv(x)
|
578 |
+
x = self.hardswish(x)
|
579 |
+
x = self.dropout(x)
|
580 |
+
if self.use_lenhead:
|
581 |
+
return x, len_x
|
582 |
+
return x
|
583 |
+
|
584 |
+
|
585 |
+
if __name__=="__main__":
|
586 |
+
a = torch.rand(1,3,48,100)
|
587 |
+
svtr = SVTRNet()
|
588 |
+
|
589 |
+
out = svtr(a)
|
590 |
+
print(svtr)
|
591 |
+
print(out.size())
|
iopaint/model/anytext/ocr_recog/ppocr_keys_v1.txt
ADDED
@@ -0,0 +1,6623 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'
|
2 |
+
疗
|
3 |
+
绚
|
4 |
+
诚
|
5 |
+
娇
|
6 |
+
溜
|
7 |
+
题
|
8 |
+
贿
|
9 |
+
者
|
10 |
+
廖
|
11 |
+
更
|
12 |
+
纳
|
13 |
+
加
|
14 |
+
奉
|
15 |
+
公
|
16 |
+
一
|
17 |
+
就
|
18 |
+
汴
|
19 |
+
计
|
20 |
+
与
|
21 |
+
路
|
22 |
+
房
|
23 |
+
原
|
24 |
+
妇
|
25 |
+
2
|
26 |
+
0
|
27 |
+
8
|
28 |
+
-
|
29 |
+
7
|
30 |
+
其
|
31 |
+
>
|
32 |
+
:
|
33 |
+
]
|
34 |
+
,
|
35 |
+
,
|
36 |
+
骑
|
37 |
+
刈
|
38 |
+
全
|
39 |
+
消
|
40 |
+
昏
|
41 |
+
傈
|
42 |
+
安
|
43 |
+
久
|
44 |
+
钟
|
45 |
+
嗅
|
46 |
+
不
|
47 |
+
影
|
48 |
+
处
|
49 |
+
驽
|
50 |
+
蜿
|
51 |
+
资
|
52 |
+
关
|
53 |
+
椤
|
54 |
+
地
|
55 |
+
瘸
|
56 |
+
专
|
57 |
+
问
|
58 |
+
忖
|
59 |
+
票
|
60 |
+
嫉
|
61 |
+
炎
|
62 |
+
韵
|
63 |
+
要
|
64 |
+
月
|
65 |
+
田
|
66 |
+
节
|
67 |
+
陂
|
68 |
+
鄙
|
69 |
+
捌
|
70 |
+
备
|
71 |
+
拳
|
72 |
+
伺
|
73 |
+
眼
|
74 |
+
网
|
75 |
+
盎
|
76 |
+
大
|
77 |
+
傍
|
78 |
+
心
|
79 |
+
东
|
80 |
+
愉
|
81 |
+
汇
|
82 |
+
蹿
|
83 |
+
科
|
84 |
+
每
|
85 |
+
业
|
86 |
+
里
|
87 |
+
航
|
88 |
+
晏
|
89 |
+
字
|
90 |
+
平
|
91 |
+
录
|
92 |
+
先
|
93 |
+
1
|
94 |
+
3
|
95 |
+
彤
|
96 |
+
鲶
|
97 |
+
产
|
98 |
+
稍
|
99 |
+
督
|
100 |
+
腴
|
101 |
+
有
|
102 |
+
象
|
103 |
+
岳
|
104 |
+
注
|
105 |
+
绍
|
106 |
+
在
|
107 |
+
泺
|
108 |
+
文
|
109 |
+
定
|
110 |
+
核
|
111 |
+
名
|
112 |
+
水
|
113 |
+
过
|
114 |
+
理
|
115 |
+
让
|
116 |
+
偷
|
117 |
+
率
|
118 |
+
等
|
119 |
+
这
|
120 |
+
发
|
121 |
+
”
|
122 |
+
为
|
123 |
+
含
|
124 |
+
肥
|
125 |
+
酉
|
126 |
+
相
|
127 |
+
鄱
|
128 |
+
七
|
129 |
+
编
|
130 |
+
猥
|
131 |
+
锛
|
132 |
+
日
|
133 |
+
镀
|
134 |
+
蒂
|
135 |
+
掰
|
136 |
+
倒
|
137 |
+
辆
|
138 |
+
栾
|
139 |
+
栗
|
140 |
+
综
|
141 |
+
涩
|
142 |
+
州
|
143 |
+
雌
|
144 |
+
滑
|
145 |
+
馀
|
146 |
+
了
|
147 |
+
机
|
148 |
+
块
|
149 |
+
司
|
150 |
+
宰
|
151 |
+
甙
|
152 |
+
兴
|
153 |
+
矽
|
154 |
+
抚
|
155 |
+
保
|
156 |
+
用
|
157 |
+
沧
|
158 |
+
秩
|
159 |
+
如
|
160 |
+
收
|
161 |
+
息
|
162 |
+
滥
|
163 |
+
页
|
164 |
+
疑
|
165 |
+
埠
|
166 |
+
!
|
167 |
+
!
|
168 |
+
姥
|
169 |
+
异
|
170 |
+
橹
|
171 |
+
钇
|
172 |
+
向
|
173 |
+
下
|
174 |
+
跄
|
175 |
+
的
|
176 |
+
椴
|
177 |
+
沫
|
178 |
+
国
|
179 |
+
绥
|
180 |
+
獠
|
181 |
+
报
|
182 |
+
开
|
183 |
+
民
|
184 |
+
蜇
|
185 |
+
何
|
186 |
+
分
|
187 |
+
凇
|
188 |
+
长
|
189 |
+
讥
|
190 |
+
藏
|
191 |
+
掏
|
192 |
+
施
|
193 |
+
羽
|
194 |
+
中
|
195 |
+
讲
|
196 |
+
派
|
197 |
+
嘟
|
198 |
+
人
|
199 |
+
提
|
200 |
+
浼
|
201 |
+
间
|
202 |
+
世
|
203 |
+
而
|
204 |
+
古
|
205 |
+
多
|
206 |
+
倪
|
207 |
+
唇
|
208 |
+
饯
|
209 |
+
控
|
210 |
+
庚
|
211 |
+
首
|
212 |
+
赛
|
213 |
+
蜓
|
214 |
+
味
|
215 |
+
断
|
216 |
+
制
|
217 |
+
觉
|
218 |
+
技
|
219 |
+
替
|
220 |
+
艰
|
221 |
+
溢
|
222 |
+
潮
|
223 |
+
夕
|
224 |
+
钺
|
225 |
+
外
|
226 |
+
摘
|
227 |
+
枋
|
228 |
+
动
|
229 |
+
双
|
230 |
+
单
|
231 |
+
啮
|
232 |
+
户
|
233 |
+
枇
|
234 |
+
确
|
235 |
+
锦
|
236 |
+
曜
|
237 |
+
杜
|
238 |
+
或
|
239 |
+
能
|
240 |
+
效
|
241 |
+
霜
|
242 |
+
盒
|
243 |
+
然
|
244 |
+
侗
|
245 |
+
电
|
246 |
+
晁
|
247 |
+
放
|
248 |
+
步
|
249 |
+
鹃
|
250 |
+
新
|
251 |
+
杖
|
252 |
+
蜂
|
253 |
+
吒
|
254 |
+
濂
|
255 |
+
瞬
|
256 |
+
评
|
257 |
+
总
|
258 |
+
隍
|
259 |
+
对
|
260 |
+
独
|
261 |
+
合
|
262 |
+
也
|
263 |
+
是
|
264 |
+
府
|
265 |
+
青
|
266 |
+
天
|
267 |
+
诲
|
268 |
+
墙
|
269 |
+
组
|
270 |
+
滴
|
271 |
+
级
|
272 |
+
邀
|
273 |
+
帘
|
274 |
+
示
|
275 |
+
已
|
276 |
+
时
|
277 |
+
骸
|
278 |
+
仄
|
279 |
+
泅
|
280 |
+
和
|
281 |
+
遨
|
282 |
+
店
|
283 |
+
雇
|
284 |
+
疫
|
285 |
+
持
|
286 |
+
巍
|
287 |
+
踮
|
288 |
+
境
|
289 |
+
只
|
290 |
+
亨
|
291 |
+
目
|
292 |
+
鉴
|
293 |
+
崤
|
294 |
+
闲
|
295 |
+
体
|
296 |
+
泄
|
297 |
+
杂
|
298 |
+
作
|
299 |
+
般
|
300 |
+
轰
|
301 |
+
化
|
302 |
+
解
|
303 |
+
迂
|
304 |
+
诿
|
305 |
+
蛭
|
306 |
+
璀
|
307 |
+
腾
|
308 |
+
告
|
309 |
+
版
|
310 |
+
服
|
311 |
+
省
|
312 |
+
师
|
313 |
+
小
|
314 |
+
规
|
315 |
+
程
|
316 |
+
线
|
317 |
+
海
|
318 |
+
办
|
319 |
+
引
|
320 |
+
二
|
321 |
+
桧
|
322 |
+
牌
|
323 |
+
砺
|
324 |
+
洄
|
325 |
+
裴
|
326 |
+
修
|
327 |
+
图
|
328 |
+
痫
|
329 |
+
胡
|
330 |
+
许
|
331 |
+
犊
|
332 |
+
事
|
333 |
+
郛
|
334 |
+
基
|
335 |
+
柴
|
336 |
+
呼
|
337 |
+
食
|
338 |
+
研
|
339 |
+
奶
|
340 |
+
律
|
341 |
+
蛋
|
342 |
+
因
|
343 |
+
葆
|
344 |
+
察
|
345 |
+
戏
|
346 |
+
褒
|
347 |
+
戒
|
348 |
+
再
|
349 |
+
李
|
350 |
+
骁
|
351 |
+
工
|
352 |
+
貂
|
353 |
+
油
|
354 |
+
鹅
|
355 |
+
章
|
356 |
+
啄
|
357 |
+
休
|
358 |
+
场
|
359 |
+
给
|
360 |
+
睡
|
361 |
+
纷
|
362 |
+
豆
|
363 |
+
器
|
364 |
+
捎
|
365 |
+
说
|
366 |
+
敏
|
367 |
+
学
|
368 |
+
会
|
369 |
+
浒
|
370 |
+
设
|
371 |
+
诊
|
372 |
+
格
|
373 |
+
廓
|
374 |
+
查
|
375 |
+
来
|
376 |
+
霓
|
377 |
+
室
|
378 |
+
溆
|
379 |
+
¢
|
380 |
+
诡
|
381 |
+
寥
|
382 |
+
焕
|
383 |
+
舜
|
384 |
+
柒
|
385 |
+
狐
|
386 |
+
回
|
387 |
+
戟
|
388 |
+
砾
|
389 |
+
厄
|
390 |
+
实
|
391 |
+
翩
|
392 |
+
尿
|
393 |
+
五
|
394 |
+
入
|
395 |
+
径
|
396 |
+
惭
|
397 |
+
喹
|
398 |
+
股
|
399 |
+
宇
|
400 |
+
篝
|
401 |
+
|
|
402 |
+
;
|
403 |
+
美
|
404 |
+
期
|
405 |
+
云
|
406 |
+
九
|
407 |
+
祺
|
408 |
+
扮
|
409 |
+
靠
|
410 |
+
锝
|
411 |
+
槌
|
412 |
+
系
|
413 |
+
企
|
414 |
+
酰
|
415 |
+
阊
|
416 |
+
暂
|
417 |
+
蚕
|
418 |
+
忻
|
419 |
+
豁
|
420 |
+
本
|
421 |
+
羹
|
422 |
+
执
|
423 |
+
条
|
424 |
+
钦
|
425 |
+
H
|
426 |
+
獒
|
427 |
+
限
|
428 |
+
进
|
429 |
+
季
|
430 |
+
楦
|
431 |
+
于
|
432 |
+
芘
|
433 |
+
玖
|
434 |
+
铋
|
435 |
+
茯
|
436 |
+
未
|
437 |
+
答
|
438 |
+
粘
|
439 |
+
括
|
440 |
+
样
|
441 |
+
精
|
442 |
+
欠
|
443 |
+
矢
|
444 |
+
甥
|
445 |
+
帷
|
446 |
+
嵩
|
447 |
+
扣
|
448 |
+
令
|
449 |
+
仔
|
450 |
+
风
|
451 |
+
皈
|
452 |
+
行
|
453 |
+
支
|
454 |
+
部
|
455 |
+
蓉
|
456 |
+
刮
|
457 |
+
站
|
458 |
+
蜡
|
459 |
+
救
|
460 |
+
钊
|
461 |
+
汗
|
462 |
+
松
|
463 |
+
嫌
|
464 |
+
成
|
465 |
+
可
|
466 |
+
.
|
467 |
+
鹤
|
468 |
+
院
|
469 |
+
从
|
470 |
+
交
|
471 |
+
政
|
472 |
+
怕
|
473 |
+
活
|
474 |
+
调
|
475 |
+
球
|
476 |
+
局
|
477 |
+
验
|
478 |
+
髌
|
479 |
+
第
|
480 |
+
韫
|
481 |
+
谗
|
482 |
+
串
|
483 |
+
到
|
484 |
+
圆
|
485 |
+
年
|
486 |
+
米
|
487 |
+
/
|
488 |
+
*
|
489 |
+
友
|
490 |
+
忿
|
491 |
+
检
|
492 |
+
区
|
493 |
+
看
|
494 |
+
自
|
495 |
+
敢
|
496 |
+
刃
|
497 |
+
个
|
498 |
+
兹
|
499 |
+
弄
|
500 |
+
流
|
501 |
+
留
|
502 |
+
同
|
503 |
+
没
|
504 |
+
齿
|
505 |
+
星
|
506 |
+
聆
|
507 |
+
轼
|
508 |
+
湖
|
509 |
+
什
|
510 |
+
三
|
511 |
+
建
|
512 |
+
蛔
|
513 |
+
儿
|
514 |
+
椋
|
515 |
+
汕
|
516 |
+
震
|
517 |
+
颧
|
518 |
+
鲤
|
519 |
+
跟
|
520 |
+
力
|
521 |
+
情
|
522 |
+
璺
|
523 |
+
铨
|
524 |
+
陪
|
525 |
+
务
|
526 |
+
指
|
527 |
+
族
|
528 |
+
训
|
529 |
+
滦
|
530 |
+
鄣
|
531 |
+
濮
|
532 |
+
扒
|
533 |
+
商
|
534 |
+
箱
|
535 |
+
十
|
536 |
+
召
|
537 |
+
慷
|
538 |
+
辗
|
539 |
+
所
|
540 |
+
莞
|
541 |
+
管
|
542 |
+
护
|
543 |
+
臭
|
544 |
+
横
|
545 |
+
硒
|
546 |
+
嗓
|
547 |
+
接
|
548 |
+
侦
|
549 |
+
六
|
550 |
+
露
|
551 |
+
党
|
552 |
+
馋
|
553 |
+
驾
|
554 |
+
剖
|
555 |
+
高
|
556 |
+
侬
|
557 |
+
妪
|
558 |
+
幂
|
559 |
+
猗
|
560 |
+
绺
|
561 |
+
骐
|
562 |
+
央
|
563 |
+
酐
|
564 |
+
孝
|
565 |
+
筝
|
566 |
+
课
|
567 |
+
徇
|
568 |
+
缰
|
569 |
+
门
|
570 |
+
男
|
571 |
+
西
|
572 |
+
项
|
573 |
+
句
|
574 |
+
谙
|
575 |
+
瞒
|
576 |
+
秃
|
577 |
+
篇
|
578 |
+
教
|
579 |
+
碲
|
580 |
+
罚
|
581 |
+
声
|
582 |
+
呐
|
583 |
+
景
|
584 |
+
前
|
585 |
+
富
|
586 |
+
嘴
|
587 |
+
鳌
|
588 |
+
稀
|
589 |
+
免
|
590 |
+
朋
|
591 |
+
啬
|
592 |
+
睐
|
593 |
+
去
|
594 |
+
赈
|
595 |
+
鱼
|
596 |
+
住
|
597 |
+
肩
|
598 |
+
愕
|
599 |
+
速
|
600 |
+
旁
|
601 |
+
波
|
602 |
+
厅
|
603 |
+
健
|
604 |
+
茼
|
605 |
+
厥
|
606 |
+
鲟
|
607 |
+
谅
|
608 |
+
投
|
609 |
+
攸
|
610 |
+
炔
|
611 |
+
数
|
612 |
+
方
|
613 |
+
击
|
614 |
+
呋
|
615 |
+
谈
|
616 |
+
绩
|
617 |
+
别
|
618 |
+
愫
|
619 |
+
僚
|
620 |
+
躬
|
621 |
+
鹧
|
622 |
+
胪
|
623 |
+
炳
|
624 |
+
招
|
625 |
+
喇
|
626 |
+
膨
|
627 |
+
泵
|
628 |
+
蹦
|
629 |
+
毛
|
630 |
+
结
|
631 |
+
5
|
632 |
+
4
|
633 |
+
谱
|
634 |
+
识
|
635 |
+
陕
|
636 |
+
粽
|
637 |
+
婚
|
638 |
+
拟
|
639 |
+
构
|
640 |
+
且
|
641 |
+
搜
|
642 |
+
任
|
643 |
+
潘
|
644 |
+
比
|
645 |
+
郢
|
646 |
+
妨
|
647 |
+
醪
|
648 |
+
陀
|
649 |
+
桔
|
650 |
+
碘
|
651 |
+
扎
|
652 |
+
选
|
653 |
+
哈
|
654 |
+
骷
|
655 |
+
楷
|
656 |
+
亿
|
657 |
+
明
|
658 |
+
缆
|
659 |
+
脯
|
660 |
+
监
|
661 |
+
睫
|
662 |
+
逻
|
663 |
+
婵
|
664 |
+
共
|
665 |
+
赴
|
666 |
+
淝
|
667 |
+
凡
|
668 |
+
惦
|
669 |
+
及
|
670 |
+
达
|
671 |
+
揖
|
672 |
+
谩
|
673 |
+
澹
|
674 |
+
减
|
675 |
+
焰
|
676 |
+
蛹
|
677 |
+
番
|
678 |
+
祁
|
679 |
+
柏
|
680 |
+
员
|
681 |
+
禄
|
682 |
+
怡
|
683 |
+
峤
|
684 |
+
龙
|
685 |
+
白
|
686 |
+
叽
|
687 |
+
生
|
688 |
+
闯
|
689 |
+
起
|
690 |
+
细
|
691 |
+
装
|
692 |
+
谕
|
693 |
+
竟
|
694 |
+
聚
|
695 |
+
钙
|
696 |
+
上
|
697 |
+
导
|
698 |
+
渊
|
699 |
+
按
|
700 |
+
艾
|
701 |
+
辘
|
702 |
+
挡
|
703 |
+
耒
|
704 |
+
盹
|
705 |
+
饪
|
706 |
+
臀
|
707 |
+
记
|
708 |
+
邮
|
709 |
+
蕙
|
710 |
+
受
|
711 |
+
各
|
712 |
+
医
|
713 |
+
搂
|
714 |
+
普
|
715 |
+
滇
|
716 |
+
朗
|
717 |
+
茸
|
718 |
+
带
|
719 |
+
翻
|
720 |
+
酚
|
721 |
+
(
|
722 |
+
光
|
723 |
+
堤
|
724 |
+
墟
|
725 |
+
蔷
|
726 |
+
万
|
727 |
+
幻
|
728 |
+
〓
|
729 |
+
瑙
|
730 |
+
辈
|
731 |
+
昧
|
732 |
+
盏
|
733 |
+
亘
|
734 |
+
蛀
|
735 |
+
吉
|
736 |
+
铰
|
737 |
+
请
|
738 |
+
子
|
739 |
+
假
|
740 |
+
闻
|
741 |
+
税
|
742 |
+
井
|
743 |
+
诩
|
744 |
+
哨
|
745 |
+
嫂
|
746 |
+
好
|
747 |
+
面
|
748 |
+
琐
|
749 |
+
校
|
750 |
+
馊
|
751 |
+
鬣
|
752 |
+
缂
|
753 |
+
营
|
754 |
+
访
|
755 |
+
炖
|
756 |
+
占
|
757 |
+
农
|
758 |
+
缀
|
759 |
+
否
|
760 |
+
经
|
761 |
+
钚
|
762 |
+
棵
|
763 |
+
趟
|
764 |
+
张
|
765 |
+
亟
|
766 |
+
吏
|
767 |
+
茶
|
768 |
+
谨
|
769 |
+
捻
|
770 |
+
论
|
771 |
+
迸
|
772 |
+
堂
|
773 |
+
玉
|
774 |
+
信
|
775 |
+
吧
|
776 |
+
瞠
|
777 |
+
乡
|
778 |
+
姬
|
779 |
+
寺
|
780 |
+
咬
|
781 |
+
溏
|
782 |
+
苄
|
783 |
+
皿
|
784 |
+
意
|
785 |
+
赉
|
786 |
+
宝
|
787 |
+
尔
|
788 |
+
钰
|
789 |
+
艺
|
790 |
+
特
|
791 |
+
唳
|
792 |
+
踉
|
793 |
+
都
|
794 |
+
荣
|
795 |
+
倚
|
796 |
+
登
|
797 |
+
荐
|
798 |
+
丧
|
799 |
+
奇
|
800 |
+
涵
|
801 |
+
批
|
802 |
+
炭
|
803 |
+
近
|
804 |
+
符
|
805 |
+
傩
|
806 |
+
感
|
807 |
+
道
|
808 |
+
着
|
809 |
+
菊
|
810 |
+
虹
|
811 |
+
仲
|
812 |
+
众
|
813 |
+
懈
|
814 |
+
濯
|
815 |
+
颞
|
816 |
+
眺
|
817 |
+
南
|
818 |
+
释
|
819 |
+
北
|
820 |
+
缝
|
821 |
+
标
|
822 |
+
既
|
823 |
+
茗
|
824 |
+
整
|
825 |
+
撼
|
826 |
+
迤
|
827 |
+
贲
|
828 |
+
挎
|
829 |
+
耱
|
830 |
+
拒
|
831 |
+
某
|
832 |
+
妍
|
833 |
+
卫
|
834 |
+
哇
|
835 |
+
英
|
836 |
+
矶
|
837 |
+
藩
|
838 |
+
治
|
839 |
+
他
|
840 |
+
元
|
841 |
+
领
|
842 |
+
膜
|
843 |
+
遮
|
844 |
+
穗
|
845 |
+
蛾
|
846 |
+
飞
|
847 |
+
荒
|
848 |
+
棺
|
849 |
+
劫
|
850 |
+
么
|
851 |
+
市
|
852 |
+
火
|
853 |
+
温
|
854 |
+
拈
|
855 |
+
棚
|
856 |
+
洼
|
857 |
+
转
|
858 |
+
果
|
859 |
+
奕
|
860 |
+
卸
|
861 |
+
迪
|
862 |
+
伸
|
863 |
+
泳
|
864 |
+
斗
|
865 |
+
邡
|
866 |
+
侄
|
867 |
+
涨
|
868 |
+
屯
|
869 |
+
萋
|
870 |
+
胭
|
871 |
+
氡
|
872 |
+
崮
|
873 |
+
枞
|
874 |
+
惧
|
875 |
+
冒
|
876 |
+
彩
|
877 |
+
斜
|
878 |
+
手
|
879 |
+
豚
|
880 |
+
随
|
881 |
+
旭
|
882 |
+
淑
|
883 |
+
妞
|
884 |
+
形
|
885 |
+
菌
|
886 |
+
吲
|
887 |
+
沱
|
888 |
+
争
|
889 |
+
驯
|
890 |
+
歹
|
891 |
+
挟
|
892 |
+
兆
|
893 |
+
柱
|
894 |
+
传
|
895 |
+
至
|
896 |
+
包
|
897 |
+
内
|
898 |
+
响
|
899 |
+
临
|
900 |
+
红
|
901 |
+
功
|
902 |
+
弩
|
903 |
+
衡
|
904 |
+
寂
|
905 |
+
禁
|
906 |
+
老
|
907 |
+
棍
|
908 |
+
耆
|
909 |
+
渍
|
910 |
+
织
|
911 |
+
害
|
912 |
+
氵
|
913 |
+
渑
|
914 |
+
布
|
915 |
+
载
|
916 |
+
靥
|
917 |
+
嗬
|
918 |
+
虽
|
919 |
+
苹
|
920 |
+
咨
|
921 |
+
娄
|
922 |
+
库
|
923 |
+
雉
|
924 |
+
榜
|
925 |
+
帜
|
926 |
+
嘲
|
927 |
+
套
|
928 |
+
瑚
|
929 |
+
亲
|
930 |
+
簸
|
931 |
+
欧
|
932 |
+
边
|
933 |
+
6
|
934 |
+
腿
|
935 |
+
旮
|
936 |
+
抛
|
937 |
+
吹
|
938 |
+
瞳
|
939 |
+
得
|
940 |
+
镓
|
941 |
+
梗
|
942 |
+
厨
|
943 |
+
继
|
944 |
+
漾
|
945 |
+
愣
|
946 |
+
憨
|
947 |
+
士
|
948 |
+
策
|
949 |
+
窑
|
950 |
+
抑
|
951 |
+
躯
|
952 |
+
襟
|
953 |
+
脏
|
954 |
+
参
|
955 |
+
贸
|
956 |
+
言
|
957 |
+
干
|
958 |
+
绸
|
959 |
+
鳄
|
960 |
+
穷
|
961 |
+
藜
|
962 |
+
音
|
963 |
+
折
|
964 |
+
详
|
965 |
+
)
|
966 |
+
举
|
967 |
+
悍
|
968 |
+
甸
|
969 |
+
癌
|
970 |
+
黎
|
971 |
+
谴
|
972 |
+
死
|
973 |
+
罩
|
974 |
+
迁
|
975 |
+
寒
|
976 |
+
驷
|
977 |
+
袖
|
978 |
+
媒
|
979 |
+
蒋
|
980 |
+
掘
|
981 |
+
模
|
982 |
+
纠
|
983 |
+
恣
|
984 |
+
观
|
985 |
+
祖
|
986 |
+
蛆
|
987 |
+
碍
|
988 |
+
位
|
989 |
+
稿
|
990 |
+
主
|
991 |
+
澧
|
992 |
+
跌
|
993 |
+
筏
|
994 |
+
京
|
995 |
+
锏
|
996 |
+
帝
|
997 |
+
贴
|
998 |
+
证
|
999 |
+
糠
|
1000 |
+
才
|
1001 |
+
黄
|
1002 |
+
鲸
|
1003 |
+
略
|
1004 |
+
炯
|
1005 |
+
饱
|
1006 |
+
四
|
1007 |
+
出
|
1008 |
+
园
|
1009 |
+
犀
|
1010 |
+
牧
|
1011 |
+
容
|
1012 |
+
汉
|
1013 |
+
杆
|
1014 |
+
浈
|
1015 |
+
汰
|
1016 |
+
瑷
|
1017 |
+
造
|
1018 |
+
虫
|
1019 |
+
瘩
|
1020 |
+
怪
|
1021 |
+
驴
|
1022 |
+
济
|
1023 |
+
应
|
1024 |
+
花
|
1025 |
+
沣
|
1026 |
+
谔
|
1027 |
+
夙
|
1028 |
+
旅
|
1029 |
+
价
|
1030 |
+
矿
|
1031 |
+
以
|
1032 |
+
考
|
1033 |
+
s
|
1034 |
+
u
|
1035 |
+
呦
|
1036 |
+
晒
|
1037 |
+
巡
|
1038 |
+
茅
|
1039 |
+
准
|
1040 |
+
肟
|
1041 |
+
瓴
|
1042 |
+
詹
|
1043 |
+
仟
|
1044 |
+
褂
|
1045 |
+
译
|
1046 |
+
桌
|
1047 |
+
混
|
1048 |
+
宁
|
1049 |
+
怦
|
1050 |
+
郑
|
1051 |
+
抿
|
1052 |
+
些
|
1053 |
+
余
|
1054 |
+
鄂
|
1055 |
+
饴
|
1056 |
+
攒
|
1057 |
+
珑
|
1058 |
+
群
|
1059 |
+
阖
|
1060 |
+
岔
|
1061 |
+
琨
|
1062 |
+
藓
|
1063 |
+
预
|
1064 |
+
环
|
1065 |
+
洮
|
1066 |
+
岌
|
1067 |
+
宀
|
1068 |
+
杲
|
1069 |
+
瀵
|
1070 |
+
最
|
1071 |
+
常
|
1072 |
+
囡
|
1073 |
+
周
|
1074 |
+
踊
|
1075 |
+
女
|
1076 |
+
鼓
|
1077 |
+
袭
|
1078 |
+
喉
|
1079 |
+
简
|
1080 |
+
范
|
1081 |
+
薯
|
1082 |
+
遐
|
1083 |
+
疏
|
1084 |
+
粱
|
1085 |
+
黜
|
1086 |
+
禧
|
1087 |
+
法
|
1088 |
+
箔
|
1089 |
+
斤
|
1090 |
+
遥
|
1091 |
+
汝
|
1092 |
+
奥
|
1093 |
+
直
|
1094 |
+
贞
|
1095 |
+
撑
|
1096 |
+
置
|
1097 |
+
绱
|
1098 |
+
集
|
1099 |
+
她
|
1100 |
+
馅
|
1101 |
+
逗
|
1102 |
+
钧
|
1103 |
+
橱
|
1104 |
+
魉
|
1105 |
+
[
|
1106 |
+
恙
|
1107 |
+
躁
|
1108 |
+
唤
|
1109 |
+
9
|
1110 |
+
旺
|
1111 |
+
膘
|
1112 |
+
待
|
1113 |
+
脾
|
1114 |
+
惫
|
1115 |
+
购
|
1116 |
+
吗
|
1117 |
+
依
|
1118 |
+
盲
|
1119 |
+
度
|
1120 |
+
瘿
|
1121 |
+
蠖
|
1122 |
+
俾
|
1123 |
+
之
|
1124 |
+
镗
|
1125 |
+
拇
|
1126 |
+
鲵
|
1127 |
+
厝
|
1128 |
+
簧
|
1129 |
+
续
|
1130 |
+
款
|
1131 |
+
展
|
1132 |
+
啃
|
1133 |
+
表
|
1134 |
+
剔
|
1135 |
+
品
|
1136 |
+
钻
|
1137 |
+
腭
|
1138 |
+
损
|
1139 |
+
清
|
1140 |
+
锶
|
1141 |
+
统
|
1142 |
+
涌
|
1143 |
+
寸
|
1144 |
+
滨
|
1145 |
+
贪
|
1146 |
+
链
|
1147 |
+
吠
|
1148 |
+
冈
|
1149 |
+
伎
|
1150 |
+
迥
|
1151 |
+
咏
|
1152 |
+
吁
|
1153 |
+
览
|
1154 |
+
防
|
1155 |
+
迅
|
1156 |
+
失
|
1157 |
+
汾
|
1158 |
+
阔
|
1159 |
+
逵
|
1160 |
+
绀
|
1161 |
+
蔑
|
1162 |
+
列
|
1163 |
+
川
|
1164 |
+
凭
|
1165 |
+
努
|
1166 |
+
熨
|
1167 |
+
揪
|
1168 |
+
利
|
1169 |
+
俱
|
1170 |
+
绉
|
1171 |
+
抢
|
1172 |
+
鸨
|
1173 |
+
我
|
1174 |
+
即
|
1175 |
+
责
|
1176 |
+
膦
|
1177 |
+
易
|
1178 |
+
毓
|
1179 |
+
鹊
|
1180 |
+
刹
|
1181 |
+
玷
|
1182 |
+
岿
|
1183 |
+
空
|
1184 |
+
嘞
|
1185 |
+
绊
|
1186 |
+
排
|
1187 |
+
术
|
1188 |
+
估
|
1189 |
+
锷
|
1190 |
+
违
|
1191 |
+
们
|
1192 |
+
苟
|
1193 |
+
铜
|
1194 |
+
播
|
1195 |
+
肘
|
1196 |
+
件
|
1197 |
+
烫
|
1198 |
+
审
|
1199 |
+
鲂
|
1200 |
+
广
|
1201 |
+
像
|
1202 |
+
铌
|
1203 |
+
惰
|
1204 |
+
铟
|
1205 |
+
巳
|
1206 |
+
胍
|
1207 |
+
鲍
|
1208 |
+
康
|
1209 |
+
憧
|
1210 |
+
色
|
1211 |
+
恢
|
1212 |
+
想
|
1213 |
+
拷
|
1214 |
+
尤
|
1215 |
+
疳
|
1216 |
+
知
|
1217 |
+
S
|
1218 |
+
Y
|
1219 |
+
F
|
1220 |
+
D
|
1221 |
+
A
|
1222 |
+
峄
|
1223 |
+
裕
|
1224 |
+
帮
|
1225 |
+
握
|
1226 |
+
搔
|
1227 |
+
氐
|
1228 |
+
氘
|
1229 |
+
难
|
1230 |
+
墒
|
1231 |
+
沮
|
1232 |
+
雨
|
1233 |
+
叁
|
1234 |
+
缥
|
1235 |
+
悴
|
1236 |
+
藐
|
1237 |
+
湫
|
1238 |
+
娟
|
1239 |
+
苑
|
1240 |
+
稠
|
1241 |
+
颛
|
1242 |
+
簇
|
1243 |
+
后
|
1244 |
+
阕
|
1245 |
+
闭
|
1246 |
+
蕤
|
1247 |
+
缚
|
1248 |
+
怎
|
1249 |
+
佞
|
1250 |
+
码
|
1251 |
+
嘤
|
1252 |
+
蔡
|
1253 |
+
痊
|
1254 |
+
舱
|
1255 |
+
螯
|
1256 |
+
帕
|
1257 |
+
赫
|
1258 |
+
昵
|
1259 |
+
升
|
1260 |
+
烬
|
1261 |
+
岫
|
1262 |
+
、
|
1263 |
+
疵
|
1264 |
+
蜻
|
1265 |
+
髁
|
1266 |
+
蕨
|
1267 |
+
隶
|
1268 |
+
烛
|
1269 |
+
械
|
1270 |
+
丑
|
1271 |
+
盂
|
1272 |
+
梁
|
1273 |
+
强
|
1274 |
+
鲛
|
1275 |
+
由
|
1276 |
+
拘
|
1277 |
+
揉
|
1278 |
+
劭
|
1279 |
+
龟
|
1280 |
+
撤
|
1281 |
+
钩
|
1282 |
+
呕
|
1283 |
+
孛
|
1284 |
+
费
|
1285 |
+
妻
|
1286 |
+
漂
|
1287 |
+
求
|
1288 |
+
阑
|
1289 |
+
崖
|
1290 |
+
秤
|
1291 |
+
甘
|
1292 |
+
通
|
1293 |
+
深
|
1294 |
+
补
|
1295 |
+
赃
|
1296 |
+
坎
|
1297 |
+
床
|
1298 |
+
啪
|
1299 |
+
承
|
1300 |
+
吼
|
1301 |
+
量
|
1302 |
+
暇
|
1303 |
+
钼
|
1304 |
+
烨
|
1305 |
+
阂
|
1306 |
+
擎
|
1307 |
+
脱
|
1308 |
+
逮
|
1309 |
+
称
|
1310 |
+
P
|
1311 |
+
神
|
1312 |
+
属
|
1313 |
+
矗
|
1314 |
+
华
|
1315 |
+
届
|
1316 |
+
狍
|
1317 |
+
葑
|
1318 |
+
汹
|
1319 |
+
育
|
1320 |
+
患
|
1321 |
+
窒
|
1322 |
+
蛰
|
1323 |
+
佼
|
1324 |
+
静
|
1325 |
+
槎
|
1326 |
+
运
|
1327 |
+
鳗
|
1328 |
+
庆
|
1329 |
+
逝
|
1330 |
+
曼
|
1331 |
+
疱
|
1332 |
+
克
|
1333 |
+
代
|
1334 |
+
官
|
1335 |
+
此
|
1336 |
+
麸
|
1337 |
+
耧
|
1338 |
+
蚌
|
1339 |
+
晟
|
1340 |
+
例
|
1341 |
+
础
|
1342 |
+
榛
|
1343 |
+
副
|
1344 |
+
测
|
1345 |
+
唰
|
1346 |
+
缢
|
1347 |
+
迹
|
1348 |
+
灬
|
1349 |
+
霁
|
1350 |
+
身
|
1351 |
+
岁
|
1352 |
+
赭
|
1353 |
+
扛
|
1354 |
+
又
|
1355 |
+
菡
|
1356 |
+
乜
|
1357 |
+
雾
|
1358 |
+
板
|
1359 |
+
读
|
1360 |
+
陷
|
1361 |
+
徉
|
1362 |
+
贯
|
1363 |
+
郁
|
1364 |
+
虑
|
1365 |
+
变
|
1366 |
+
钓
|
1367 |
+
菜
|
1368 |
+
圾
|
1369 |
+
现
|
1370 |
+
琢
|
1371 |
+
式
|
1372 |
+
乐
|
1373 |
+
维
|
1374 |
+
渔
|
1375 |
+
浜
|
1376 |
+
左
|
1377 |
+
吾
|
1378 |
+
脑
|
1379 |
+
钡
|
1380 |
+
警
|
1381 |
+
T
|
1382 |
+
啵
|
1383 |
+
拴
|
1384 |
+
偌
|
1385 |
+
漱
|
1386 |
+
湿
|
1387 |
+
硕
|
1388 |
+
止
|
1389 |
+
骼
|
1390 |
+
魄
|
1391 |
+
积
|
1392 |
+
燥
|
1393 |
+
联
|
1394 |
+
踢
|
1395 |
+
玛
|
1396 |
+
则
|
1397 |
+
窿
|
1398 |
+
见
|
1399 |
+
振
|
1400 |
+
畿
|
1401 |
+
送
|
1402 |
+
班
|
1403 |
+
钽
|
1404 |
+
您
|
1405 |
+
赵
|
1406 |
+
刨
|
1407 |
+
印
|
1408 |
+
讨
|
1409 |
+
踝
|
1410 |
+
籍
|
1411 |
+
谡
|
1412 |
+
舌
|
1413 |
+
崧
|
1414 |
+
汽
|
1415 |
+
蔽
|
1416 |
+
沪
|
1417 |
+
酥
|
1418 |
+
绒
|
1419 |
+
怖
|
1420 |
+
财
|
1421 |
+
帖
|
1422 |
+
肱
|
1423 |
+
私
|
1424 |
+
莎
|
1425 |
+
勋
|
1426 |
+
羔
|
1427 |
+
霸
|
1428 |
+
励
|
1429 |
+
哼
|
1430 |
+
帐
|
1431 |
+
将
|
1432 |
+
帅
|
1433 |
+
渠
|
1434 |
+
纪
|
1435 |
+
婴
|
1436 |
+
娩
|
1437 |
+
岭
|
1438 |
+
厘
|
1439 |
+
滕
|
1440 |
+
吻
|
1441 |
+
伤
|
1442 |
+
坝
|
1443 |
+
冠
|
1444 |
+
戊
|
1445 |
+
隆
|
1446 |
+
瘁
|
1447 |
+
介
|
1448 |
+
涧
|
1449 |
+
物
|
1450 |
+
黍
|
1451 |
+
并
|
1452 |
+
姗
|
1453 |
+
奢
|
1454 |
+
蹑
|
1455 |
+
掣
|
1456 |
+
垸
|
1457 |
+
锴
|
1458 |
+
命
|
1459 |
+
箍
|
1460 |
+
捉
|
1461 |
+
病
|
1462 |
+
辖
|
1463 |
+
琰
|
1464 |
+
眭
|
1465 |
+
迩
|
1466 |
+
艘
|
1467 |
+
绌
|
1468 |
+
繁
|
1469 |
+
寅
|
1470 |
+
若
|
1471 |
+
毋
|
1472 |
+
思
|
1473 |
+
诉
|
1474 |
+
类
|
1475 |
+
诈
|
1476 |
+
燮
|
1477 |
+
轲
|
1478 |
+
酮
|
1479 |
+
狂
|
1480 |
+
重
|
1481 |
+
反
|
1482 |
+
职
|
1483 |
+
筱
|
1484 |
+
县
|
1485 |
+
委
|
1486 |
+
磕
|
1487 |
+
绣
|
1488 |
+
奖
|
1489 |
+
晋
|
1490 |
+
濉
|
1491 |
+
志
|
1492 |
+
徽
|
1493 |
+
肠
|
1494 |
+
呈
|
1495 |
+
獐
|
1496 |
+
坻
|
1497 |
+
口
|
1498 |
+
片
|
1499 |
+
碰
|
1500 |
+
几
|
1501 |
+
村
|
1502 |
+
柿
|
1503 |
+
劳
|
1504 |
+
料
|
1505 |
+
获
|
1506 |
+
亩
|
1507 |
+
惕
|
1508 |
+
晕
|
1509 |
+
厌
|
1510 |
+
号
|
1511 |
+
罢
|
1512 |
+
池
|
1513 |
+
正
|
1514 |
+
鏖
|
1515 |
+
煨
|
1516 |
+
家
|
1517 |
+
棕
|
1518 |
+
复
|
1519 |
+
尝
|
1520 |
+
懋
|
1521 |
+
蜥
|
1522 |
+
锅
|
1523 |
+
岛
|
1524 |
+
扰
|
1525 |
+
队
|
1526 |
+
坠
|
1527 |
+
瘾
|
1528 |
+
钬
|
1529 |
+
@
|
1530 |
+
卧
|
1531 |
+
疣
|
1532 |
+
镇
|
1533 |
+
譬
|
1534 |
+
冰
|
1535 |
+
彷
|
1536 |
+
频
|
1537 |
+
黯
|
1538 |
+
据
|
1539 |
+
垄
|
1540 |
+
采
|
1541 |
+
八
|
1542 |
+
缪
|
1543 |
+
瘫
|
1544 |
+
型
|
1545 |
+
熹
|
1546 |
+
砰
|
1547 |
+
楠
|
1548 |
+
襁
|
1549 |
+
箐
|
1550 |
+
但
|
1551 |
+
嘶
|
1552 |
+
绳
|
1553 |
+
啤
|
1554 |
+
拍
|
1555 |
+
盥
|
1556 |
+
穆
|
1557 |
+
傲
|
1558 |
+
洗
|
1559 |
+
盯
|
1560 |
+
塘
|
1561 |
+
怔
|
1562 |
+
筛
|
1563 |
+
丿
|
1564 |
+
台
|
1565 |
+
恒
|
1566 |
+
喂
|
1567 |
+
葛
|
1568 |
+
永
|
1569 |
+
¥
|
1570 |
+
烟
|
1571 |
+
酒
|
1572 |
+
桦
|
1573 |
+
书
|
1574 |
+
砂
|
1575 |
+
蚝
|
1576 |
+
缉
|
1577 |
+
态
|
1578 |
+
瀚
|
1579 |
+
袄
|
1580 |
+
圳
|
1581 |
+
轻
|
1582 |
+
蛛
|
1583 |
+
超
|
1584 |
+
榧
|
1585 |
+
遛
|
1586 |
+
姒
|
1587 |
+
奘
|
1588 |
+
铮
|
1589 |
+
右
|
1590 |
+
荽
|
1591 |
+
望
|
1592 |
+
偻
|
1593 |
+
卡
|
1594 |
+
丶
|
1595 |
+
氰
|
1596 |
+
附
|
1597 |
+
做
|
1598 |
+
革
|
1599 |
+
索
|
1600 |
+
戚
|
1601 |
+
坨
|
1602 |
+
桷
|
1603 |
+
唁
|
1604 |
+
垅
|
1605 |
+
榻
|
1606 |
+
岐
|
1607 |
+
偎
|
1608 |
+
坛
|
1609 |
+
莨
|
1610 |
+
山
|
1611 |
+
殊
|
1612 |
+
微
|
1613 |
+
骇
|
1614 |
+
陈
|
1615 |
+
爨
|
1616 |
+
推
|
1617 |
+
嗝
|
1618 |
+
驹
|
1619 |
+
澡
|
1620 |
+
藁
|
1621 |
+
呤
|
1622 |
+
卤
|
1623 |
+
嘻
|
1624 |
+
糅
|
1625 |
+
逛
|
1626 |
+
侵
|
1627 |
+
郓
|
1628 |
+
酌
|
1629 |
+
德
|
1630 |
+
摇
|
1631 |
+
※
|
1632 |
+
鬃
|
1633 |
+
被
|
1634 |
+
慨
|
1635 |
+
殡
|
1636 |
+
羸
|
1637 |
+
昌
|
1638 |
+
泡
|
1639 |
+
戛
|
1640 |
+
鞋
|
1641 |
+
河
|
1642 |
+
宪
|
1643 |
+
沿
|
1644 |
+
玲
|
1645 |
+
鲨
|
1646 |
+
翅
|
1647 |
+
哽
|
1648 |
+
源
|
1649 |
+
铅
|
1650 |
+
语
|
1651 |
+
照
|
1652 |
+
邯
|
1653 |
+
址
|
1654 |
+
荃
|
1655 |
+
佬
|
1656 |
+
顺
|
1657 |
+
鸳
|
1658 |
+
町
|
1659 |
+
霭
|
1660 |
+
睾
|
1661 |
+
瓢
|
1662 |
+
夸
|
1663 |
+
椁
|
1664 |
+
晓
|
1665 |
+
酿
|
1666 |
+
痈
|
1667 |
+
咔
|
1668 |
+
侏
|
1669 |
+
券
|
1670 |
+
噎
|
1671 |
+
湍
|
1672 |
+
签
|
1673 |
+
嚷
|
1674 |
+
离
|
1675 |
+
午
|
1676 |
+
尚
|
1677 |
+
社
|
1678 |
+
锤
|
1679 |
+
背
|
1680 |
+
孟
|
1681 |
+
使
|
1682 |
+
浪
|
1683 |
+
缦
|
1684 |
+
潍
|
1685 |
+
鞅
|
1686 |
+
军
|
1687 |
+
姹
|
1688 |
+
驶
|
1689 |
+
笑
|
1690 |
+
鳟
|
1691 |
+
鲁
|
1692 |
+
》
|
1693 |
+
孽
|
1694 |
+
钜
|
1695 |
+
绿
|
1696 |
+
洱
|
1697 |
+
礴
|
1698 |
+
焯
|
1699 |
+
椰
|
1700 |
+
颖
|
1701 |
+
囔
|
1702 |
+
乌
|
1703 |
+
孔
|
1704 |
+
巴
|
1705 |
+
互
|
1706 |
+
性
|
1707 |
+
椽
|
1708 |
+
哞
|
1709 |
+
聘
|
1710 |
+
昨
|
1711 |
+
早
|
1712 |
+
暮
|
1713 |
+
胶
|
1714 |
+
炀
|
1715 |
+
隧
|
1716 |
+
低
|
1717 |
+
彗
|
1718 |
+
昝
|
1719 |
+
铁
|
1720 |
+
呓
|
1721 |
+
氽
|
1722 |
+
藉
|
1723 |
+
喔
|
1724 |
+
癖
|
1725 |
+
瑗
|
1726 |
+
姨
|
1727 |
+
权
|
1728 |
+
胱
|
1729 |
+
韦
|
1730 |
+
堑
|
1731 |
+
蜜
|
1732 |
+
酋
|
1733 |
+
楝
|
1734 |
+
砝
|
1735 |
+
毁
|
1736 |
+
靓
|
1737 |
+
歙
|
1738 |
+
锲
|
1739 |
+
究
|
1740 |
+
屋
|
1741 |
+
喳
|
1742 |
+
骨
|
1743 |
+
辨
|
1744 |
+
碑
|
1745 |
+
武
|
1746 |
+
鸠
|
1747 |
+
宫
|
1748 |
+
辜
|
1749 |
+
烊
|
1750 |
+
适
|
1751 |
+
坡
|
1752 |
+
殃
|
1753 |
+
培
|
1754 |
+
佩
|
1755 |
+
供
|
1756 |
+
走
|
1757 |
+
蜈
|
1758 |
+
迟
|
1759 |
+
翼
|
1760 |
+
况
|
1761 |
+
姣
|
1762 |
+
凛
|
1763 |
+
浔
|
1764 |
+
吃
|
1765 |
+
飘
|
1766 |
+
债
|
1767 |
+
犟
|
1768 |
+
金
|
1769 |
+
促
|
1770 |
+
苛
|
1771 |
+
崇
|
1772 |
+
坂
|
1773 |
+
莳
|
1774 |
+
畔
|
1775 |
+
绂
|
1776 |
+
兵
|
1777 |
+
蠕
|
1778 |
+
斋
|
1779 |
+
根
|
1780 |
+
砍
|
1781 |
+
亢
|
1782 |
+
欢
|
1783 |
+
恬
|
1784 |
+
崔
|
1785 |
+
剁
|
1786 |
+
餐
|
1787 |
+
榫
|
1788 |
+
快
|
1789 |
+
扶
|
1790 |
+
‖
|
1791 |
+
濒
|
1792 |
+
缠
|
1793 |
+
鳜
|
1794 |
+
当
|
1795 |
+
彭
|
1796 |
+
驭
|
1797 |
+
浦
|
1798 |
+
篮
|
1799 |
+
昀
|
1800 |
+
锆
|
1801 |
+
秸
|
1802 |
+
钳
|
1803 |
+
弋
|
1804 |
+
娣
|
1805 |
+
瞑
|
1806 |
+
夷
|
1807 |
+
龛
|
1808 |
+
苫
|
1809 |
+
拱
|
1810 |
+
致
|
1811 |
+
%
|
1812 |
+
嵊
|
1813 |
+
障
|
1814 |
+
隐
|
1815 |
+
弑
|
1816 |
+
初
|
1817 |
+
娓
|
1818 |
+
抉
|
1819 |
+
汩
|
1820 |
+
累
|
1821 |
+
蓖
|
1822 |
+
"
|
1823 |
+
唬
|
1824 |
+
助
|
1825 |
+
苓
|
1826 |
+
昙
|
1827 |
+
押
|
1828 |
+
毙
|
1829 |
+
破
|
1830 |
+
城
|
1831 |
+
郧
|
1832 |
+
逢
|
1833 |
+
嚏
|
1834 |
+
獭
|
1835 |
+
瞻
|
1836 |
+
溱
|
1837 |
+
婿
|
1838 |
+
赊
|
1839 |
+
跨
|
1840 |
+
恼
|
1841 |
+
璧
|
1842 |
+
萃
|
1843 |
+
姻
|
1844 |
+
貉
|
1845 |
+
灵
|
1846 |
+
炉
|
1847 |
+
密
|
1848 |
+
氛
|
1849 |
+
陶
|
1850 |
+
砸
|
1851 |
+
谬
|
1852 |
+
衔
|
1853 |
+
点
|
1854 |
+
琛
|
1855 |
+
沛
|
1856 |
+
枳
|
1857 |
+
层
|
1858 |
+
岱
|
1859 |
+
诺
|
1860 |
+
脍
|
1861 |
+
榈
|
1862 |
+
埂
|
1863 |
+
征
|
1864 |
+
冷
|
1865 |
+
裁
|
1866 |
+
打
|
1867 |
+
蹴
|
1868 |
+
素
|
1869 |
+
瘘
|
1870 |
+
逞
|
1871 |
+
蛐
|
1872 |
+
聊
|
1873 |
+
激
|
1874 |
+
腱
|
1875 |
+
萘
|
1876 |
+
踵
|
1877 |
+
飒
|
1878 |
+
蓟
|
1879 |
+
吆
|
1880 |
+
取
|
1881 |
+
咙
|
1882 |
+
簋
|
1883 |
+
涓
|
1884 |
+
矩
|
1885 |
+
曝
|
1886 |
+
挺
|
1887 |
+
揣
|
1888 |
+
座
|
1889 |
+
你
|
1890 |
+
史
|
1891 |
+
舵
|
1892 |
+
焱
|
1893 |
+
尘
|
1894 |
+
苏
|
1895 |
+
笈
|
1896 |
+
脚
|
1897 |
+
溉
|
1898 |
+
榨
|
1899 |
+
诵
|
1900 |
+
樊
|
1901 |
+
邓
|
1902 |
+
焊
|
1903 |
+
义
|
1904 |
+
庶
|
1905 |
+
儋
|
1906 |
+
蟋
|
1907 |
+
蒲
|
1908 |
+
赦
|
1909 |
+
呷
|
1910 |
+
杞
|
1911 |
+
诠
|
1912 |
+
豪
|
1913 |
+
还
|
1914 |
+
试
|
1915 |
+
颓
|
1916 |
+
茉
|
1917 |
+
太
|
1918 |
+
除
|
1919 |
+
紫
|
1920 |
+
逃
|
1921 |
+
痴
|
1922 |
+
草
|
1923 |
+
充
|
1924 |
+
鳕
|
1925 |
+
珉
|
1926 |
+
祗
|
1927 |
+
墨
|
1928 |
+
渭
|
1929 |
+
烩
|
1930 |
+
蘸
|
1931 |
+
慕
|
1932 |
+
璇
|
1933 |
+
镶
|
1934 |
+
穴
|
1935 |
+
嵘
|
1936 |
+
恶
|
1937 |
+
骂
|
1938 |
+
险
|
1939 |
+
绋
|
1940 |
+
幕
|
1941 |
+
碉
|
1942 |
+
肺
|
1943 |
+
戳
|
1944 |
+
刘
|
1945 |
+
潞
|
1946 |
+
秣
|
1947 |
+
纾
|
1948 |
+
潜
|
1949 |
+
銮
|
1950 |
+
洛
|
1951 |
+
须
|
1952 |
+
罘
|
1953 |
+
销
|
1954 |
+
瘪
|
1955 |
+
汞
|
1956 |
+
兮
|
1957 |
+
屉
|
1958 |
+
r
|
1959 |
+
林
|
1960 |
+
厕
|
1961 |
+
质
|
1962 |
+
探
|
1963 |
+
划
|
1964 |
+
狸
|
1965 |
+
殚
|
1966 |
+
善
|
1967 |
+
煊
|
1968 |
+
烹
|
1969 |
+
〒
|
1970 |
+
锈
|
1971 |
+
逯
|
1972 |
+
宸
|
1973 |
+
辍
|
1974 |
+
泱
|
1975 |
+
柚
|
1976 |
+
袍
|
1977 |
+
远
|
1978 |
+
蹋
|
1979 |
+
嶙
|
1980 |
+
绝
|
1981 |
+
峥
|
1982 |
+
娥
|
1983 |
+
缍
|
1984 |
+
雀
|
1985 |
+
徵
|
1986 |
+
认
|
1987 |
+
镱
|
1988 |
+
谷
|
1989 |
+
=
|
1990 |
+
贩
|
1991 |
+
勉
|
1992 |
+
撩
|
1993 |
+
鄯
|
1994 |
+
斐
|
1995 |
+
洋
|
1996 |
+
非
|
1997 |
+
祚
|
1998 |
+
泾
|
1999 |
+
诒
|
2000 |
+
饿
|
2001 |
+
撬
|
2002 |
+
威
|
2003 |
+
晷
|
2004 |
+
搭
|
2005 |
+
芍
|
2006 |
+
锥
|
2007 |
+
笺
|
2008 |
+
蓦
|
2009 |
+
候
|
2010 |
+
琊
|
2011 |
+
档
|
2012 |
+
礁
|
2013 |
+
沼
|
2014 |
+
卵
|
2015 |
+
荠
|
2016 |
+
忑
|
2017 |
+
朝
|
2018 |
+
凹
|
2019 |
+
瑞
|
2020 |
+
头
|
2021 |
+
仪
|
2022 |
+
弧
|
2023 |
+
孵
|
2024 |
+
畏
|
2025 |
+
铆
|
2026 |
+
突
|
2027 |
+
衲
|
2028 |
+
车
|
2029 |
+
浩
|
2030 |
+
气
|
2031 |
+
茂
|
2032 |
+
悖
|
2033 |
+
厢
|
2034 |
+
枕
|
2035 |
+
酝
|
2036 |
+
戴
|
2037 |
+
湾
|
2038 |
+
邹
|
2039 |
+
飚
|
2040 |
+
攘
|
2041 |
+
锂
|
2042 |
+
写
|
2043 |
+
宵
|
2044 |
+
翁
|
2045 |
+
岷
|
2046 |
+
无
|
2047 |
+
喜
|
2048 |
+
丈
|
2049 |
+
挑
|
2050 |
+
嗟
|
2051 |
+
绛
|
2052 |
+
殉
|
2053 |
+
议
|
2054 |
+
槽
|
2055 |
+
具
|
2056 |
+
醇
|
2057 |
+
淞
|
2058 |
+
笃
|
2059 |
+
郴
|
2060 |
+
阅
|
2061 |
+
饼
|
2062 |
+
底
|
2063 |
+
壕
|
2064 |
+
砚
|
2065 |
+
弈
|
2066 |
+
询
|
2067 |
+
缕
|
2068 |
+
庹
|
2069 |
+
翟
|
2070 |
+
零
|
2071 |
+
筷
|
2072 |
+
暨
|
2073 |
+
舟
|
2074 |
+
闺
|
2075 |
+
甯
|
2076 |
+
撞
|
2077 |
+
麂
|
2078 |
+
茌
|
2079 |
+
蔼
|
2080 |
+
很
|
2081 |
+
珲
|
2082 |
+
捕
|
2083 |
+
棠
|
2084 |
+
角
|
2085 |
+
阉
|
2086 |
+
媛
|
2087 |
+
娲
|
2088 |
+
诽
|
2089 |
+
剿
|
2090 |
+
尉
|
2091 |
+
爵
|
2092 |
+
睬
|
2093 |
+
韩
|
2094 |
+
诰
|
2095 |
+
匣
|
2096 |
+
危
|
2097 |
+
糍
|
2098 |
+
镯
|
2099 |
+
立
|
2100 |
+
浏
|
2101 |
+
阳
|
2102 |
+
少
|
2103 |
+
盆
|
2104 |
+
舔
|
2105 |
+
擘
|
2106 |
+
匪
|
2107 |
+
申
|
2108 |
+
尬
|
2109 |
+
铣
|
2110 |
+
旯
|
2111 |
+
抖
|
2112 |
+
赘
|
2113 |
+
瓯
|
2114 |
+
居
|
2115 |
+
ˇ
|
2116 |
+
哮
|
2117 |
+
游
|
2118 |
+
锭
|
2119 |
+
茏
|
2120 |
+
歌
|
2121 |
+
坏
|
2122 |
+
甚
|
2123 |
+
秒
|
2124 |
+
舞
|
2125 |
+
沙
|
2126 |
+
仗
|
2127 |
+
劲
|
2128 |
+
潺
|
2129 |
+
阿
|
2130 |
+
燧
|
2131 |
+
郭
|
2132 |
+
嗖
|
2133 |
+
霏
|
2134 |
+
忠
|
2135 |
+
材
|
2136 |
+
奂
|
2137 |
+
耐
|
2138 |
+
跺
|
2139 |
+
砀
|
2140 |
+
输
|
2141 |
+
岖
|
2142 |
+
媳
|
2143 |
+
氟
|
2144 |
+
极
|
2145 |
+
摆
|
2146 |
+
灿
|
2147 |
+
今
|
2148 |
+
扔
|
2149 |
+
腻
|
2150 |
+
枝
|
2151 |
+
奎
|
2152 |
+
药
|
2153 |
+
熄
|
2154 |
+
吨
|
2155 |
+
话
|
2156 |
+
q
|
2157 |
+
额
|
2158 |
+
慑
|
2159 |
+
嘌
|
2160 |
+
协
|
2161 |
+
喀
|
2162 |
+
壳
|
2163 |
+
埭
|
2164 |
+
视
|
2165 |
+
著
|
2166 |
+
於
|
2167 |
+
愧
|
2168 |
+
陲
|
2169 |
+
翌
|
2170 |
+
峁
|
2171 |
+
颅
|
2172 |
+
佛
|
2173 |
+
腹
|
2174 |
+
聋
|
2175 |
+
侯
|
2176 |
+
咎
|
2177 |
+
叟
|
2178 |
+
秀
|
2179 |
+
颇
|
2180 |
+
存
|
2181 |
+
较
|
2182 |
+
罪
|
2183 |
+
哄
|
2184 |
+
岗
|
2185 |
+
扫
|
2186 |
+
栏
|
2187 |
+
钾
|
2188 |
+
羌
|
2189 |
+
己
|
2190 |
+
璨
|
2191 |
+
枭
|
2192 |
+
霉
|
2193 |
+
煌
|
2194 |
+
涸
|
2195 |
+
衿
|
2196 |
+
键
|
2197 |
+
镝
|
2198 |
+
益
|
2199 |
+
岢
|
2200 |
+
奏
|
2201 |
+
连
|
2202 |
+
夯
|
2203 |
+
睿
|
2204 |
+
冥
|
2205 |
+
均
|
2206 |
+
糖
|
2207 |
+
狞
|
2208 |
+
蹊
|
2209 |
+
稻
|
2210 |
+
爸
|
2211 |
+
刿
|
2212 |
+
胥
|
2213 |
+
煜
|
2214 |
+
丽
|
2215 |
+
肿
|
2216 |
+
璃
|
2217 |
+
掸
|
2218 |
+
跚
|
2219 |
+
灾
|
2220 |
+
垂
|
2221 |
+
樾
|
2222 |
+
濑
|
2223 |
+
乎
|
2224 |
+
莲
|
2225 |
+
窄
|
2226 |
+
犹
|
2227 |
+
撮
|
2228 |
+
战
|
2229 |
+
馄
|
2230 |
+
软
|
2231 |
+
络
|
2232 |
+
显
|
2233 |
+
鸢
|
2234 |
+
胸
|
2235 |
+
宾
|
2236 |
+
妲
|
2237 |
+
恕
|
2238 |
+
埔
|
2239 |
+
蝌
|
2240 |
+
份
|
2241 |
+
遇
|
2242 |
+
巧
|
2243 |
+
瞟
|
2244 |
+
粒
|
2245 |
+
恰
|
2246 |
+
剥
|
2247 |
+
桡
|
2248 |
+
博
|
2249 |
+
讯
|
2250 |
+
凯
|
2251 |
+
堇
|
2252 |
+
阶
|
2253 |
+
滤
|
2254 |
+
卖
|
2255 |
+
斌
|
2256 |
+
骚
|
2257 |
+
彬
|
2258 |
+
兑
|
2259 |
+
磺
|
2260 |
+
樱
|
2261 |
+
舷
|
2262 |
+
两
|
2263 |
+
娱
|
2264 |
+
福
|
2265 |
+
仃
|
2266 |
+
差
|
2267 |
+
找
|
2268 |
+
桁
|
2269 |
+
÷
|
2270 |
+
净
|
2271 |
+
把
|
2272 |
+
阴
|
2273 |
+
污
|
2274 |
+
戬
|
2275 |
+
雷
|
2276 |
+
碓
|
2277 |
+
蕲
|
2278 |
+
楚
|
2279 |
+
罡
|
2280 |
+
焖
|
2281 |
+
抽
|
2282 |
+
妫
|
2283 |
+
咒
|
2284 |
+
仑
|
2285 |
+
闱
|
2286 |
+
尽
|
2287 |
+
邑
|
2288 |
+
菁
|
2289 |
+
爱
|
2290 |
+
贷
|
2291 |
+
沥
|
2292 |
+
鞑
|
2293 |
+
牡
|
2294 |
+
嗉
|
2295 |
+
崴
|
2296 |
+
骤
|
2297 |
+
塌
|
2298 |
+
嗦
|
2299 |
+
订
|
2300 |
+
拮
|
2301 |
+
滓
|
2302 |
+
捡
|
2303 |
+
锻
|
2304 |
+
次
|
2305 |
+
坪
|
2306 |
+
杩
|
2307 |
+
臃
|
2308 |
+
箬
|
2309 |
+
融
|
2310 |
+
珂
|
2311 |
+
鹗
|
2312 |
+
宗
|
2313 |
+
枚
|
2314 |
+
降
|
2315 |
+
鸬
|
2316 |
+
妯
|
2317 |
+
阄
|
2318 |
+
堰
|
2319 |
+
盐
|
2320 |
+
毅
|
2321 |
+
必
|
2322 |
+
杨
|
2323 |
+
崃
|
2324 |
+
俺
|
2325 |
+
甬
|
2326 |
+
状
|
2327 |
+
莘
|
2328 |
+
货
|
2329 |
+
耸
|
2330 |
+
菱
|
2331 |
+
腼
|
2332 |
+
铸
|
2333 |
+
唏
|
2334 |
+
痤
|
2335 |
+
孚
|
2336 |
+
澳
|
2337 |
+
懒
|
2338 |
+
溅
|
2339 |
+
翘
|
2340 |
+
疙
|
2341 |
+
杷
|
2342 |
+
淼
|
2343 |
+
缙
|
2344 |
+
骰
|
2345 |
+
喊
|
2346 |
+
悉
|
2347 |
+
砻
|
2348 |
+
坷
|
2349 |
+
艇
|
2350 |
+
赁
|
2351 |
+
界
|
2352 |
+
谤
|
2353 |
+
纣
|
2354 |
+
宴
|
2355 |
+
晃
|
2356 |
+
茹
|
2357 |
+
归
|
2358 |
+
饭
|
2359 |
+
梢
|
2360 |
+
铡
|
2361 |
+
街
|
2362 |
+
抄
|
2363 |
+
肼
|
2364 |
+
鬟
|
2365 |
+
苯
|
2366 |
+
颂
|
2367 |
+
撷
|
2368 |
+
戈
|
2369 |
+
炒
|
2370 |
+
咆
|
2371 |
+
茭
|
2372 |
+
瘙
|
2373 |
+
负
|
2374 |
+
仰
|
2375 |
+
客
|
2376 |
+
琉
|
2377 |
+
铢
|
2378 |
+
封
|
2379 |
+
卑
|
2380 |
+
珥
|
2381 |
+
椿
|
2382 |
+
镧
|
2383 |
+
窨
|
2384 |
+
鬲
|
2385 |
+
寿
|
2386 |
+
御
|
2387 |
+
袤
|
2388 |
+
铃
|
2389 |
+
萎
|
2390 |
+
砖
|
2391 |
+
餮
|
2392 |
+
脒
|
2393 |
+
裳
|
2394 |
+
肪
|
2395 |
+
孕
|
2396 |
+
嫣
|
2397 |
+
馗
|
2398 |
+
嵇
|
2399 |
+
恳
|
2400 |
+
氯
|
2401 |
+
江
|
2402 |
+
石
|
2403 |
+
褶
|
2404 |
+
冢
|
2405 |
+
祸
|
2406 |
+
阻
|
2407 |
+
狈
|
2408 |
+
羞
|
2409 |
+
银
|
2410 |
+
靳
|
2411 |
+
透
|
2412 |
+
咳
|
2413 |
+
叼
|
2414 |
+
敷
|
2415 |
+
芷
|
2416 |
+
啥
|
2417 |
+
它
|
2418 |
+
瓤
|
2419 |
+
兰
|
2420 |
+
痘
|
2421 |
+
懊
|
2422 |
+
逑
|
2423 |
+
肌
|
2424 |
+
往
|
2425 |
+
捺
|
2426 |
+
坊
|
2427 |
+
甩
|
2428 |
+
呻
|
2429 |
+
〃
|
2430 |
+
沦
|
2431 |
+
忘
|
2432 |
+
膻
|
2433 |
+
祟
|
2434 |
+
菅
|
2435 |
+
剧
|
2436 |
+
崆
|
2437 |
+
智
|
2438 |
+
坯
|
2439 |
+
臧
|
2440 |
+
霍
|
2441 |
+
墅
|
2442 |
+
攻
|
2443 |
+
眯
|
2444 |
+
倘
|
2445 |
+
拢
|
2446 |
+
骠
|
2447 |
+
铐
|
2448 |
+
庭
|
2449 |
+
岙
|
2450 |
+
瓠
|
2451 |
+
′
|
2452 |
+
缺
|
2453 |
+
泥
|
2454 |
+
迢
|
2455 |
+
捶
|
2456 |
+
?
|
2457 |
+
?
|
2458 |
+
郏
|
2459 |
+
喙
|
2460 |
+
掷
|
2461 |
+
沌
|
2462 |
+
纯
|
2463 |
+
秘
|
2464 |
+
种
|
2465 |
+
听
|
2466 |
+
绘
|
2467 |
+
固
|
2468 |
+
螨
|
2469 |
+
团
|
2470 |
+
香
|
2471 |
+
盗
|
2472 |
+
妒
|
2473 |
+
埚
|
2474 |
+
蓝
|
2475 |
+
拖
|
2476 |
+
旱
|
2477 |
+
荞
|
2478 |
+
铀
|
2479 |
+
血
|
2480 |
+
遏
|
2481 |
+
汲
|
2482 |
+
辰
|
2483 |
+
叩
|
2484 |
+
拽
|
2485 |
+
幅
|
2486 |
+
硬
|
2487 |
+
惶
|
2488 |
+
桀
|
2489 |
+
漠
|
2490 |
+
措
|
2491 |
+
泼
|
2492 |
+
唑
|
2493 |
+
齐
|
2494 |
+
肾
|
2495 |
+
念
|
2496 |
+
酱
|
2497 |
+
虚
|
2498 |
+
屁
|
2499 |
+
耶
|
2500 |
+
旗
|
2501 |
+
砦
|
2502 |
+
闵
|
2503 |
+
婉
|
2504 |
+
馆
|
2505 |
+
拭
|
2506 |
+
绅
|
2507 |
+
韧
|
2508 |
+
忏
|
2509 |
+
窝
|
2510 |
+
醋
|
2511 |
+
葺
|
2512 |
+
顾
|
2513 |
+
辞
|
2514 |
+
倜
|
2515 |
+
堆
|
2516 |
+
辋
|
2517 |
+
逆
|
2518 |
+
玟
|
2519 |
+
贱
|
2520 |
+
疾
|
2521 |
+
董
|
2522 |
+
惘
|
2523 |
+
倌
|
2524 |
+
锕
|
2525 |
+
淘
|
2526 |
+
嘀
|
2527 |
+
莽
|
2528 |
+
俭
|
2529 |
+
笏
|
2530 |
+
绑
|
2531 |
+
鲷
|
2532 |
+
杈
|
2533 |
+
择
|
2534 |
+
蟀
|
2535 |
+
粥
|
2536 |
+
嗯
|
2537 |
+
驰
|
2538 |
+
逾
|
2539 |
+
案
|
2540 |
+
谪
|
2541 |
+
褓
|
2542 |
+
胫
|
2543 |
+
哩
|
2544 |
+
昕
|
2545 |
+
颚
|
2546 |
+
鲢
|
2547 |
+
绠
|
2548 |
+
躺
|
2549 |
+
鹄
|
2550 |
+
崂
|
2551 |
+
儒
|
2552 |
+
俨
|
2553 |
+
丝
|
2554 |
+
尕
|
2555 |
+
泌
|
2556 |
+
啊
|
2557 |
+
萸
|
2558 |
+
彰
|
2559 |
+
幺
|
2560 |
+
吟
|
2561 |
+
骄
|
2562 |
+
苣
|
2563 |
+
弦
|
2564 |
+
脊
|
2565 |
+
瑰
|
2566 |
+
〈
|
2567 |
+
诛
|
2568 |
+
镁
|
2569 |
+
析
|
2570 |
+
闪
|
2571 |
+
剪
|
2572 |
+
侧
|
2573 |
+
哟
|
2574 |
+
框
|
2575 |
+
螃
|
2576 |
+
守
|
2577 |
+
嬗
|
2578 |
+
燕
|
2579 |
+
狭
|
2580 |
+
铈
|
2581 |
+
缮
|
2582 |
+
概
|
2583 |
+
迳
|
2584 |
+
痧
|
2585 |
+
鲲
|
2586 |
+
俯
|
2587 |
+
售
|
2588 |
+
笼
|
2589 |
+
痣
|
2590 |
+
扉
|
2591 |
+
挖
|
2592 |
+
满
|
2593 |
+
咋
|
2594 |
+
援
|
2595 |
+
邱
|
2596 |
+
扇
|
2597 |
+
歪
|
2598 |
+
便
|
2599 |
+
玑
|
2600 |
+
绦
|
2601 |
+
峡
|
2602 |
+
蛇
|
2603 |
+
叨
|
2604 |
+
〖
|
2605 |
+
泽
|
2606 |
+
胃
|
2607 |
+
斓
|
2608 |
+
喋
|
2609 |
+
怂
|
2610 |
+
坟
|
2611 |
+
猪
|
2612 |
+
该
|
2613 |
+
蚬
|
2614 |
+
炕
|
2615 |
+
弥
|
2616 |
+
赞
|
2617 |
+
棣
|
2618 |
+
晔
|
2619 |
+
娠
|
2620 |
+
挲
|
2621 |
+
狡
|
2622 |
+
创
|
2623 |
+
疖
|
2624 |
+
铕
|
2625 |
+
镭
|
2626 |
+
稷
|
2627 |
+
挫
|
2628 |
+
弭
|
2629 |
+
啾
|
2630 |
+
翔
|
2631 |
+
粉
|
2632 |
+
履
|
2633 |
+
苘
|
2634 |
+
哦
|
2635 |
+
楼
|
2636 |
+
秕
|
2637 |
+
铂
|
2638 |
+
土
|
2639 |
+
锣
|
2640 |
+
瘟
|
2641 |
+
挣
|
2642 |
+
栉
|
2643 |
+
习
|
2644 |
+
享
|
2645 |
+
桢
|
2646 |
+
袅
|
2647 |
+
磨
|
2648 |
+
桂
|
2649 |
+
谦
|
2650 |
+
延
|
2651 |
+
坚
|
2652 |
+
蔚
|
2653 |
+
噗
|
2654 |
+
署
|
2655 |
+
谟
|
2656 |
+
猬
|
2657 |
+
钎
|
2658 |
+
恐
|
2659 |
+
嬉
|
2660 |
+
雒
|
2661 |
+
倦
|
2662 |
+
衅
|
2663 |
+
亏
|
2664 |
+
璩
|
2665 |
+
睹
|
2666 |
+
刻
|
2667 |
+
殿
|
2668 |
+
王
|
2669 |
+
算
|
2670 |
+
雕
|
2671 |
+
麻
|
2672 |
+
丘
|
2673 |
+
柯
|
2674 |
+
骆
|
2675 |
+
丸
|
2676 |
+
塍
|
2677 |
+
谚
|
2678 |
+
添
|
2679 |
+
鲈
|
2680 |
+
垓
|
2681 |
+
桎
|
2682 |
+
蚯
|
2683 |
+
芥
|
2684 |
+
予
|
2685 |
+
飕
|
2686 |
+
镦
|
2687 |
+
谌
|
2688 |
+
窗
|
2689 |
+
醚
|
2690 |
+
菀
|
2691 |
+
亮
|
2692 |
+
搪
|
2693 |
+
莺
|
2694 |
+
蒿
|
2695 |
+
羁
|
2696 |
+
足
|
2697 |
+
J
|
2698 |
+
真
|
2699 |
+
轶
|
2700 |
+
悬
|
2701 |
+
衷
|
2702 |
+
靛
|
2703 |
+
翊
|
2704 |
+
掩
|
2705 |
+
哒
|
2706 |
+
炅
|
2707 |
+
掐
|
2708 |
+
冼
|
2709 |
+
妮
|
2710 |
+
l
|
2711 |
+
谐
|
2712 |
+
稚
|
2713 |
+
荆
|
2714 |
+
擒
|
2715 |
+
犯
|
2716 |
+
陵
|
2717 |
+
虏
|
2718 |
+
浓
|
2719 |
+
崽
|
2720 |
+
刍
|
2721 |
+
陌
|
2722 |
+
傻
|
2723 |
+
孜
|
2724 |
+
千
|
2725 |
+
靖
|
2726 |
+
演
|
2727 |
+
矜
|
2728 |
+
钕
|
2729 |
+
煽
|
2730 |
+
杰
|
2731 |
+
酗
|
2732 |
+
渗
|
2733 |
+
伞
|
2734 |
+
栋
|
2735 |
+
俗
|
2736 |
+
泫
|
2737 |
+
戍
|
2738 |
+
罕
|
2739 |
+
沾
|
2740 |
+
疽
|
2741 |
+
灏
|
2742 |
+
煦
|
2743 |
+
芬
|
2744 |
+
磴
|
2745 |
+
叱
|
2746 |
+
阱
|
2747 |
+
榉
|
2748 |
+
湃
|
2749 |
+
蜀
|
2750 |
+
叉
|
2751 |
+
醒
|
2752 |
+
彪
|
2753 |
+
租
|
2754 |
+
郡
|
2755 |
+
篷
|
2756 |
+
屎
|
2757 |
+
良
|
2758 |
+
垢
|
2759 |
+
隗
|
2760 |
+
弱
|
2761 |
+
陨
|
2762 |
+
峪
|
2763 |
+
砷
|
2764 |
+
掴
|
2765 |
+
颁
|
2766 |
+
胎
|
2767 |
+
雯
|
2768 |
+
绵
|
2769 |
+
贬
|
2770 |
+
沐
|
2771 |
+
撵
|
2772 |
+
隘
|
2773 |
+
篙
|
2774 |
+
暖
|
2775 |
+
曹
|
2776 |
+
陡
|
2777 |
+
栓
|
2778 |
+
填
|
2779 |
+
臼
|
2780 |
+
彦
|
2781 |
+
瓶
|
2782 |
+
琪
|
2783 |
+
潼
|
2784 |
+
哪
|
2785 |
+
鸡
|
2786 |
+
摩
|
2787 |
+
啦
|
2788 |
+
俟
|
2789 |
+
锋
|
2790 |
+
域
|
2791 |
+
耻
|
2792 |
+
蔫
|
2793 |
+
疯
|
2794 |
+
纹
|
2795 |
+
撇
|
2796 |
+
毒
|
2797 |
+
绶
|
2798 |
+
痛
|
2799 |
+
酯
|
2800 |
+
忍
|
2801 |
+
爪
|
2802 |
+
赳
|
2803 |
+
歆
|
2804 |
+
嘹
|
2805 |
+
辕
|
2806 |
+
烈
|
2807 |
+
册
|
2808 |
+
朴
|
2809 |
+
钱
|
2810 |
+
吮
|
2811 |
+
毯
|
2812 |
+
癜
|
2813 |
+
娃
|
2814 |
+
谀
|
2815 |
+
邵
|
2816 |
+
厮
|
2817 |
+
炽
|
2818 |
+
璞
|
2819 |
+
邃
|
2820 |
+
丐
|
2821 |
+
追
|
2822 |
+
词
|
2823 |
+
瓒
|
2824 |
+
忆
|
2825 |
+
轧
|
2826 |
+
芫
|
2827 |
+
谯
|
2828 |
+
喷
|
2829 |
+
弟
|
2830 |
+
半
|
2831 |
+
冕
|
2832 |
+
裙
|
2833 |
+
掖
|
2834 |
+
墉
|
2835 |
+
绮
|
2836 |
+
寝
|
2837 |
+
苔
|
2838 |
+
势
|
2839 |
+
顷
|
2840 |
+
褥
|
2841 |
+
切
|
2842 |
+
衮
|
2843 |
+
君
|
2844 |
+
佳
|
2845 |
+
嫒
|
2846 |
+
蚩
|
2847 |
+
霞
|
2848 |
+
佚
|
2849 |
+
洙
|
2850 |
+
逊
|
2851 |
+
镖
|
2852 |
+
暹
|
2853 |
+
唛
|
2854 |
+
&
|
2855 |
+
殒
|
2856 |
+
顶
|
2857 |
+
碗
|
2858 |
+
獗
|
2859 |
+
轭
|
2860 |
+
铺
|
2861 |
+
蛊
|
2862 |
+
废
|
2863 |
+
恹
|
2864 |
+
汨
|
2865 |
+
崩
|
2866 |
+
珍
|
2867 |
+
那
|
2868 |
+
杵
|
2869 |
+
曲
|
2870 |
+
纺
|
2871 |
+
夏
|
2872 |
+
薰
|
2873 |
+
傀
|
2874 |
+
闳
|
2875 |
+
淬
|
2876 |
+
姘
|
2877 |
+
舀
|
2878 |
+
拧
|
2879 |
+
卷
|
2880 |
+
楂
|
2881 |
+
恍
|
2882 |
+
讪
|
2883 |
+
厩
|
2884 |
+
寮
|
2885 |
+
篪
|
2886 |
+
赓
|
2887 |
+
乘
|
2888 |
+
灭
|
2889 |
+
盅
|
2890 |
+
鞣
|
2891 |
+
沟
|
2892 |
+
慎
|
2893 |
+
挂
|
2894 |
+
饺
|
2895 |
+
鼾
|
2896 |
+
杳
|
2897 |
+
树
|
2898 |
+
缨
|
2899 |
+
丛
|
2900 |
+
絮
|
2901 |
+
娌
|
2902 |
+
臻
|
2903 |
+
嗳
|
2904 |
+
篡
|
2905 |
+
侩
|
2906 |
+
述
|
2907 |
+
衰
|
2908 |
+
矛
|
2909 |
+
圈
|
2910 |
+
蚜
|
2911 |
+
匕
|
2912 |
+
筹
|
2913 |
+
匿
|
2914 |
+
濞
|
2915 |
+
晨
|
2916 |
+
叶
|
2917 |
+
骋
|
2918 |
+
郝
|
2919 |
+
挚
|
2920 |
+
蚴
|
2921 |
+
滞
|
2922 |
+
增
|
2923 |
+
侍
|
2924 |
+
描
|
2925 |
+
瓣
|
2926 |
+
吖
|
2927 |
+
嫦
|
2928 |
+
蟒
|
2929 |
+
匾
|
2930 |
+
圣
|
2931 |
+
赌
|
2932 |
+
毡
|
2933 |
+
癞
|
2934 |
+
恺
|
2935 |
+
百
|
2936 |
+
曳
|
2937 |
+
需
|
2938 |
+
篓
|
2939 |
+
肮
|
2940 |
+
庖
|
2941 |
+
帏
|
2942 |
+
卿
|
2943 |
+
驿
|
2944 |
+
遗
|
2945 |
+
蹬
|
2946 |
+
鬓
|
2947 |
+
骡
|
2948 |
+
歉
|
2949 |
+
芎
|
2950 |
+
胳
|
2951 |
+
屐
|
2952 |
+
禽
|
2953 |
+
烦
|
2954 |
+
晌
|
2955 |
+
寄
|
2956 |
+
媾
|
2957 |
+
狄
|
2958 |
+
翡
|
2959 |
+
苒
|
2960 |
+
船
|
2961 |
+
廉
|
2962 |
+
终
|
2963 |
+
痞
|
2964 |
+
殇
|
2965 |
+
々
|
2966 |
+
畦
|
2967 |
+
饶
|
2968 |
+
改
|
2969 |
+
拆
|
2970 |
+
悻
|
2971 |
+
萄
|
2972 |
+
£
|
2973 |
+
瓿
|
2974 |
+
乃
|
2975 |
+
訾
|
2976 |
+
桅
|
2977 |
+
匮
|
2978 |
+
溧
|
2979 |
+
拥
|
2980 |
+
纱
|
2981 |
+
铍
|
2982 |
+
骗
|
2983 |
+
蕃
|
2984 |
+
龋
|
2985 |
+
缬
|
2986 |
+
父
|
2987 |
+
佐
|
2988 |
+
疚
|
2989 |
+
栎
|
2990 |
+
醍
|
2991 |
+
掳
|
2992 |
+
蓄
|
2993 |
+
x
|
2994 |
+
惆
|
2995 |
+
颜
|
2996 |
+
鲆
|
2997 |
+
榆
|
2998 |
+
〔
|
2999 |
+
猎
|
3000 |
+
敌
|
3001 |
+
暴
|
3002 |
+
谥
|
3003 |
+
鲫
|
3004 |
+
贾
|
3005 |
+
罗
|
3006 |
+
玻
|
3007 |
+
缄
|
3008 |
+
扦
|
3009 |
+
芪
|
3010 |
+
癣
|
3011 |
+
落
|
3012 |
+
徒
|
3013 |
+
臾
|
3014 |
+
恿
|
3015 |
+
猩
|
3016 |
+
托
|
3017 |
+
邴
|
3018 |
+
肄
|
3019 |
+
牵
|
3020 |
+
春
|
3021 |
+
陛
|
3022 |
+
耀
|
3023 |
+
刊
|
3024 |
+
拓
|
3025 |
+
蓓
|
3026 |
+
邳
|
3027 |
+
堕
|
3028 |
+
寇
|
3029 |
+
枉
|
3030 |
+
淌
|
3031 |
+
啡
|
3032 |
+
湄
|
3033 |
+
兽
|
3034 |
+
酷
|
3035 |
+
萼
|
3036 |
+
碚
|
3037 |
+
濠
|
3038 |
+
萤
|
3039 |
+
夹
|
3040 |
+
旬
|
3041 |
+
戮
|
3042 |
+
梭
|
3043 |
+
琥
|
3044 |
+
椭
|
3045 |
+
昔
|
3046 |
+
勺
|
3047 |
+
蜊
|
3048 |
+
绐
|
3049 |
+
晚
|
3050 |
+
孺
|
3051 |
+
僵
|
3052 |
+
宣
|
3053 |
+
摄
|
3054 |
+
冽
|
3055 |
+
旨
|
3056 |
+
萌
|
3057 |
+
忙
|
3058 |
+
蚤
|
3059 |
+
眉
|
3060 |
+
噼
|
3061 |
+
蟑
|
3062 |
+
付
|
3063 |
+
契
|
3064 |
+
瓜
|
3065 |
+
悼
|
3066 |
+
颡
|
3067 |
+
壁
|
3068 |
+
曾
|
3069 |
+
窕
|
3070 |
+
颢
|
3071 |
+
澎
|
3072 |
+
仿
|
3073 |
+
俑
|
3074 |
+
浑
|
3075 |
+
嵌
|
3076 |
+
浣
|
3077 |
+
乍
|
3078 |
+
碌
|
3079 |
+
褪
|
3080 |
+
乱
|
3081 |
+
蔟
|
3082 |
+
隙
|
3083 |
+
玩
|
3084 |
+
剐
|
3085 |
+
葫
|
3086 |
+
箫
|
3087 |
+
纲
|
3088 |
+
围
|
3089 |
+
伐
|
3090 |
+
决
|
3091 |
+
伙
|
3092 |
+
漩
|
3093 |
+
瑟
|
3094 |
+
刑
|
3095 |
+
肓
|
3096 |
+
镳
|
3097 |
+
缓
|
3098 |
+
蹭
|
3099 |
+
氨
|
3100 |
+
皓
|
3101 |
+
典
|
3102 |
+
畲
|
3103 |
+
坍
|
3104 |
+
铑
|
3105 |
+
檐
|
3106 |
+
塑
|
3107 |
+
洞
|
3108 |
+
倬
|
3109 |
+
储
|
3110 |
+
胴
|
3111 |
+
淳
|
3112 |
+
戾
|
3113 |
+
吐
|
3114 |
+
灼
|
3115 |
+
惺
|
3116 |
+
妙
|
3117 |
+
毕
|
3118 |
+
珐
|
3119 |
+
缈
|
3120 |
+
虱
|
3121 |
+
盖
|
3122 |
+
羰
|
3123 |
+
鸿
|
3124 |
+
磅
|
3125 |
+
谓
|
3126 |
+
髅
|
3127 |
+
娴
|
3128 |
+
苴
|
3129 |
+
唷
|
3130 |
+
蚣
|
3131 |
+
霹
|
3132 |
+
抨
|
3133 |
+
贤
|
3134 |
+
唠
|
3135 |
+
犬
|
3136 |
+
誓
|
3137 |
+
逍
|
3138 |
+
庠
|
3139 |
+
逼
|
3140 |
+
麓
|
3141 |
+
籼
|
3142 |
+
釉
|
3143 |
+
呜
|
3144 |
+
碧
|
3145 |
+
秧
|
3146 |
+
氩
|
3147 |
+
摔
|
3148 |
+
霄
|
3149 |
+
穸
|
3150 |
+
纨
|
3151 |
+
辟
|
3152 |
+
妈
|
3153 |
+
映
|
3154 |
+
完
|
3155 |
+
牛
|
3156 |
+
缴
|
3157 |
+
嗷
|
3158 |
+
炊
|
3159 |
+
恩
|
3160 |
+
荔
|
3161 |
+
茆
|
3162 |
+
掉
|
3163 |
+
紊
|
3164 |
+
慌
|
3165 |
+
莓
|
3166 |
+
羟
|
3167 |
+
阙
|
3168 |
+
萁
|
3169 |
+
磐
|
3170 |
+
另
|
3171 |
+
蕹
|
3172 |
+
辱
|
3173 |
+
鳐
|
3174 |
+
湮
|
3175 |
+
吡
|
3176 |
+
吩
|
3177 |
+
唐
|
3178 |
+
睦
|
3179 |
+
垠
|
3180 |
+
舒
|
3181 |
+
圜
|
3182 |
+
冗
|
3183 |
+
瞿
|
3184 |
+
溺
|
3185 |
+
芾
|
3186 |
+
囱
|
3187 |
+
匠
|
3188 |
+
僳
|
3189 |
+
汐
|
3190 |
+
菩
|
3191 |
+
饬
|
3192 |
+
漓
|
3193 |
+
黑
|
3194 |
+
霰
|
3195 |
+
浸
|
3196 |
+
濡
|
3197 |
+
窥
|
3198 |
+
毂
|
3199 |
+
蒡
|
3200 |
+
兢
|
3201 |
+
驻
|
3202 |
+
鹉
|
3203 |
+
芮
|
3204 |
+
诙
|
3205 |
+
迫
|
3206 |
+
雳
|
3207 |
+
厂
|
3208 |
+
忐
|
3209 |
+
臆
|
3210 |
+
猴
|
3211 |
+
鸣
|
3212 |
+
蚪
|
3213 |
+
栈
|
3214 |
+
箕
|
3215 |
+
羡
|
3216 |
+
渐
|
3217 |
+
莆
|
3218 |
+
捍
|
3219 |
+
眈
|
3220 |
+
哓
|
3221 |
+
趴
|
3222 |
+
蹼
|
3223 |
+
埕
|
3224 |
+
嚣
|
3225 |
+
骛
|
3226 |
+
宏
|
3227 |
+
淄
|
3228 |
+
斑
|
3229 |
+
噜
|
3230 |
+
严
|
3231 |
+
瑛
|
3232 |
+
垃
|
3233 |
+
椎
|
3234 |
+
诱
|
3235 |
+
压
|
3236 |
+
庾
|
3237 |
+
绞
|
3238 |
+
焘
|
3239 |
+
廿
|
3240 |
+
抡
|
3241 |
+
迄
|
3242 |
+
棘
|
3243 |
+
夫
|
3244 |
+
纬
|
3245 |
+
锹
|
3246 |
+
眨
|
3247 |
+
瞌
|
3248 |
+
侠
|
3249 |
+
脐
|
3250 |
+
竞
|
3251 |
+
瀑
|
3252 |
+
孳
|
3253 |
+
骧
|
3254 |
+
遁
|
3255 |
+
姜
|
3256 |
+
颦
|
3257 |
+
荪
|
3258 |
+
滚
|
3259 |
+
萦
|
3260 |
+
伪
|
3261 |
+
逸
|
3262 |
+
粳
|
3263 |
+
爬
|
3264 |
+
锁
|
3265 |
+
矣
|
3266 |
+
役
|
3267 |
+
趣
|
3268 |
+
洒
|
3269 |
+
颔
|
3270 |
+
诏
|
3271 |
+
逐
|
3272 |
+
奸
|
3273 |
+
甭
|
3274 |
+
惠
|
3275 |
+
攀
|
3276 |
+
蹄
|
3277 |
+
泛
|
3278 |
+
尼
|
3279 |
+
拼
|
3280 |
+
阮
|
3281 |
+
鹰
|
3282 |
+
亚
|
3283 |
+
颈
|
3284 |
+
惑
|
3285 |
+
勒
|
3286 |
+
〉
|
3287 |
+
际
|
3288 |
+
肛
|
3289 |
+
爷
|
3290 |
+
刚
|
3291 |
+
钨
|
3292 |
+
丰
|
3293 |
+
养
|
3294 |
+
冶
|
3295 |
+
鲽
|
3296 |
+
辉
|
3297 |
+
蔻
|
3298 |
+
画
|
3299 |
+
覆
|
3300 |
+
皴
|
3301 |
+
妊
|
3302 |
+
麦
|
3303 |
+
返
|
3304 |
+
醉
|
3305 |
+
皂
|
3306 |
+
擀
|
3307 |
+
〗
|
3308 |
+
酶
|
3309 |
+
凑
|
3310 |
+
粹
|
3311 |
+
悟
|
3312 |
+
诀
|
3313 |
+
硖
|
3314 |
+
港
|
3315 |
+
卜
|
3316 |
+
z
|
3317 |
+
杀
|
3318 |
+
涕
|
3319 |
+
±
|
3320 |
+
舍
|
3321 |
+
铠
|
3322 |
+
抵
|
3323 |
+
弛
|
3324 |
+
段
|
3325 |
+
敝
|
3326 |
+
镐
|
3327 |
+
奠
|
3328 |
+
拂
|
3329 |
+
轴
|
3330 |
+
跛
|
3331 |
+
袱
|
3332 |
+
e
|
3333 |
+
t
|
3334 |
+
沉
|
3335 |
+
菇
|
3336 |
+
俎
|
3337 |
+
薪
|
3338 |
+
峦
|
3339 |
+
秭
|
3340 |
+
蟹
|
3341 |
+
历
|
3342 |
+
盟
|
3343 |
+
菠
|
3344 |
+
寡
|
3345 |
+
液
|
3346 |
+
肢
|
3347 |
+
喻
|
3348 |
+
染
|
3349 |
+
裱
|
3350 |
+
悱
|
3351 |
+
抱
|
3352 |
+
氙
|
3353 |
+
赤
|
3354 |
+
捅
|
3355 |
+
猛
|
3356 |
+
跑
|
3357 |
+
氮
|
3358 |
+
谣
|
3359 |
+
仁
|
3360 |
+
尺
|
3361 |
+
辊
|
3362 |
+
窍
|
3363 |
+
烙
|
3364 |
+
衍
|
3365 |
+
架
|
3366 |
+
擦
|
3367 |
+
倏
|
3368 |
+
璐
|
3369 |
+
瑁
|
3370 |
+
币
|
3371 |
+
楞
|
3372 |
+
胖
|
3373 |
+
夔
|
3374 |
+
趸
|
3375 |
+
邛
|
3376 |
+
惴
|
3377 |
+
饕
|
3378 |
+
虔
|
3379 |
+
蝎
|
3380 |
+
§
|
3381 |
+
哉
|
3382 |
+
贝
|
3383 |
+
宽
|
3384 |
+
辫
|
3385 |
+
炮
|
3386 |
+
扩
|
3387 |
+
饲
|
3388 |
+
籽
|
3389 |
+
魏
|
3390 |
+
菟
|
3391 |
+
锰
|
3392 |
+
伍
|
3393 |
+
猝
|
3394 |
+
末
|
3395 |
+
琳
|
3396 |
+
哚
|
3397 |
+
蛎
|
3398 |
+
邂
|
3399 |
+
呀
|
3400 |
+
姿
|
3401 |
+
鄞
|
3402 |
+
却
|
3403 |
+
歧
|
3404 |
+
仙
|
3405 |
+
恸
|
3406 |
+
椐
|
3407 |
+
森
|
3408 |
+
牒
|
3409 |
+
寤
|
3410 |
+
袒
|
3411 |
+
婆
|
3412 |
+
虢
|
3413 |
+
雅
|
3414 |
+
钉
|
3415 |
+
朵
|
3416 |
+
贼
|
3417 |
+
欲
|
3418 |
+
苞
|
3419 |
+
寰
|
3420 |
+
故
|
3421 |
+
龚
|
3422 |
+
坭
|
3423 |
+
嘘
|
3424 |
+
咫
|
3425 |
+
礼
|
3426 |
+
硷
|
3427 |
+
兀
|
3428 |
+
睢
|
3429 |
+
汶
|
3430 |
+
’
|
3431 |
+
铲
|
3432 |
+
烧
|
3433 |
+
绕
|
3434 |
+
诃
|
3435 |
+
浃
|
3436 |
+
钿
|
3437 |
+
哺
|
3438 |
+
柜
|
3439 |
+
讼
|
3440 |
+
颊
|
3441 |
+
璁
|
3442 |
+
腔
|
3443 |
+
洽
|
3444 |
+
咐
|
3445 |
+
脲
|
3446 |
+
簌
|
3447 |
+
筠
|
3448 |
+
镣
|
3449 |
+
玮
|
3450 |
+
鞠
|
3451 |
+
谁
|
3452 |
+
兼
|
3453 |
+
姆
|
3454 |
+
挥
|
3455 |
+
梯
|
3456 |
+
蝴
|
3457 |
+
谘
|
3458 |
+
漕
|
3459 |
+
刷
|
3460 |
+
躏
|
3461 |
+
宦
|
3462 |
+
弼
|
3463 |
+
b
|
3464 |
+
垌
|
3465 |
+
劈
|
3466 |
+
麟
|
3467 |
+
莉
|
3468 |
+
揭
|
3469 |
+
笙
|
3470 |
+
渎
|
3471 |
+
仕
|
3472 |
+
嗤
|
3473 |
+
仓
|
3474 |
+
配
|
3475 |
+
怏
|
3476 |
+
抬
|
3477 |
+
错
|
3478 |
+
泯
|
3479 |
+
镊
|
3480 |
+
孰
|
3481 |
+
猿
|
3482 |
+
邪
|
3483 |
+
仍
|
3484 |
+
秋
|
3485 |
+
鼬
|
3486 |
+
壹
|
3487 |
+
歇
|
3488 |
+
吵
|
3489 |
+
炼
|
3490 |
+
<
|
3491 |
+
尧
|
3492 |
+
射
|
3493 |
+
柬
|
3494 |
+
廷
|
3495 |
+
胧
|
3496 |
+
霾
|
3497 |
+
凳
|
3498 |
+
隋
|
3499 |
+
肚
|
3500 |
+
浮
|
3501 |
+
梦
|
3502 |
+
祥
|
3503 |
+
株
|
3504 |
+
堵
|
3505 |
+
退
|
3506 |
+
L
|
3507 |
+
鹫
|
3508 |
+
跎
|
3509 |
+
凶
|
3510 |
+
毽
|
3511 |
+
荟
|
3512 |
+
炫
|
3513 |
+
栩
|
3514 |
+
玳
|
3515 |
+
甜
|
3516 |
+
沂
|
3517 |
+
鹿
|
3518 |
+
顽
|
3519 |
+
伯
|
3520 |
+
爹
|
3521 |
+
赔
|
3522 |
+
蛴
|
3523 |
+
徐
|
3524 |
+
匡
|
3525 |
+
欣
|
3526 |
+
狰
|
3527 |
+
缸
|
3528 |
+
雹
|
3529 |
+
蟆
|
3530 |
+
疤
|
3531 |
+
默
|
3532 |
+
沤
|
3533 |
+
啜
|
3534 |
+
痂
|
3535 |
+
衣
|
3536 |
+
禅
|
3537 |
+
w
|
3538 |
+
i
|
3539 |
+
h
|
3540 |
+
辽
|
3541 |
+
葳
|
3542 |
+
黝
|
3543 |
+
钗
|
3544 |
+
停
|
3545 |
+
沽
|
3546 |
+
棒
|
3547 |
+
馨
|
3548 |
+
颌
|
3549 |
+
肉
|
3550 |
+
吴
|
3551 |
+
硫
|
3552 |
+
悯
|
3553 |
+
劾
|
3554 |
+
娈
|
3555 |
+
马
|
3556 |
+
啧
|
3557 |
+
吊
|
3558 |
+
悌
|
3559 |
+
镑
|
3560 |
+
峭
|
3561 |
+
帆
|
3562 |
+
瀣
|
3563 |
+
涉
|
3564 |
+
咸
|
3565 |
+
疸
|
3566 |
+
滋
|
3567 |
+
泣
|
3568 |
+
翦
|
3569 |
+
拙
|
3570 |
+
癸
|
3571 |
+
钥
|
3572 |
+
蜒
|
3573 |
+
+
|
3574 |
+
尾
|
3575 |
+
庄
|
3576 |
+
凝
|
3577 |
+
泉
|
3578 |
+
婢
|
3579 |
+
渴
|
3580 |
+
谊
|
3581 |
+
乞
|
3582 |
+
陆
|
3583 |
+
锉
|
3584 |
+
糊
|
3585 |
+
鸦
|
3586 |
+
淮
|
3587 |
+
I
|
3588 |
+
B
|
3589 |
+
N
|
3590 |
+
晦
|
3591 |
+
弗
|
3592 |
+
乔
|
3593 |
+
庥
|
3594 |
+
葡
|
3595 |
+
尻
|
3596 |
+
席
|
3597 |
+
橡
|
3598 |
+
傣
|
3599 |
+
渣
|
3600 |
+
拿
|
3601 |
+
惩
|
3602 |
+
麋
|
3603 |
+
斛
|
3604 |
+
缃
|
3605 |
+
矮
|
3606 |
+
蛏
|
3607 |
+
岘
|
3608 |
+
鸽
|
3609 |
+
姐
|
3610 |
+
膏
|
3611 |
+
催
|
3612 |
+
奔
|
3613 |
+
镒
|
3614 |
+
喱
|
3615 |
+
蠡
|
3616 |
+
摧
|
3617 |
+
钯
|
3618 |
+
胤
|
3619 |
+
柠
|
3620 |
+
拐
|
3621 |
+
璋
|
3622 |
+
鸥
|
3623 |
+
卢
|
3624 |
+
荡
|
3625 |
+
倾
|
3626 |
+
^
|
3627 |
+
_
|
3628 |
+
珀
|
3629 |
+
逄
|
3630 |
+
萧
|
3631 |
+
塾
|
3632 |
+
掇
|
3633 |
+
贮
|
3634 |
+
笆
|
3635 |
+
聂
|
3636 |
+
圃
|
3637 |
+
冲
|
3638 |
+
嵬
|
3639 |
+
M
|
3640 |
+
滔
|
3641 |
+
笕
|
3642 |
+
值
|
3643 |
+
炙
|
3644 |
+
偶
|
3645 |
+
蜱
|
3646 |
+
搐
|
3647 |
+
梆
|
3648 |
+
汪
|
3649 |
+
蔬
|
3650 |
+
腑
|
3651 |
+
鸯
|
3652 |
+
蹇
|
3653 |
+
敞
|
3654 |
+
绯
|
3655 |
+
仨
|
3656 |
+
祯
|
3657 |
+
谆
|
3658 |
+
梧
|
3659 |
+
糗
|
3660 |
+
鑫
|
3661 |
+
啸
|
3662 |
+
豺
|
3663 |
+
囹
|
3664 |
+
猾
|
3665 |
+
巢
|
3666 |
+
柄
|
3667 |
+
瀛
|
3668 |
+
筑
|
3669 |
+
踌
|
3670 |
+
沭
|
3671 |
+
暗
|
3672 |
+
苁
|
3673 |
+
鱿
|
3674 |
+
蹉
|
3675 |
+
脂
|
3676 |
+
蘖
|
3677 |
+
牢
|
3678 |
+
热
|
3679 |
+
木
|
3680 |
+
吸
|
3681 |
+
溃
|
3682 |
+
宠
|
3683 |
+
序
|
3684 |
+
泞
|
3685 |
+
偿
|
3686 |
+
拜
|
3687 |
+
檩
|
3688 |
+
厚
|
3689 |
+
朐
|
3690 |
+
毗
|
3691 |
+
螳
|
3692 |
+
吞
|
3693 |
+
媚
|
3694 |
+
朽
|
3695 |
+
担
|
3696 |
+
蝗
|
3697 |
+
橘
|
3698 |
+
畴
|
3699 |
+
祈
|
3700 |
+
糟
|
3701 |
+
盱
|
3702 |
+
隼
|
3703 |
+
郜
|
3704 |
+
惜
|
3705 |
+
珠
|
3706 |
+
裨
|
3707 |
+
铵
|
3708 |
+
焙
|
3709 |
+
琚
|
3710 |
+
唯
|
3711 |
+
咚
|
3712 |
+
噪
|
3713 |
+
骊
|
3714 |
+
丫
|
3715 |
+
滢
|
3716 |
+
勤
|
3717 |
+
棉
|
3718 |
+
呸
|
3719 |
+
咣
|
3720 |
+
淀
|
3721 |
+
隔
|
3722 |
+
蕾
|
3723 |
+
窈
|
3724 |
+
饨
|
3725 |
+
挨
|
3726 |
+
煅
|
3727 |
+
短
|
3728 |
+
匙
|
3729 |
+
粕
|
3730 |
+
镜
|
3731 |
+
赣
|
3732 |
+
撕
|
3733 |
+
墩
|
3734 |
+
酬
|
3735 |
+
馁
|
3736 |
+
豌
|
3737 |
+
颐
|
3738 |
+
抗
|
3739 |
+
酣
|
3740 |
+
氓
|
3741 |
+
佑
|
3742 |
+
搁
|
3743 |
+
哭
|
3744 |
+
递
|
3745 |
+
耷
|
3746 |
+
涡
|
3747 |
+
桃
|
3748 |
+
贻
|
3749 |
+
碣
|
3750 |
+
截
|
3751 |
+
瘦
|
3752 |
+
昭
|
3753 |
+
镌
|
3754 |
+
蔓
|
3755 |
+
氚
|
3756 |
+
甲
|
3757 |
+
猕
|
3758 |
+
蕴
|
3759 |
+
蓬
|
3760 |
+
散
|
3761 |
+
拾
|
3762 |
+
纛
|
3763 |
+
狼
|
3764 |
+
猷
|
3765 |
+
铎
|
3766 |
+
埋
|
3767 |
+
旖
|
3768 |
+
矾
|
3769 |
+
讳
|
3770 |
+
囊
|
3771 |
+
糜
|
3772 |
+
迈
|
3773 |
+
粟
|
3774 |
+
蚂
|
3775 |
+
紧
|
3776 |
+
鲳
|
3777 |
+
瘢
|
3778 |
+
栽
|
3779 |
+
稼
|
3780 |
+
羊
|
3781 |
+
锄
|
3782 |
+
斟
|
3783 |
+
睁
|
3784 |
+
桥
|
3785 |
+
瓮
|
3786 |
+
蹙
|
3787 |
+
祉
|
3788 |
+
醺
|
3789 |
+
鼻
|
3790 |
+
昱
|
3791 |
+
剃
|
3792 |
+
跳
|
3793 |
+
篱
|
3794 |
+
跷
|
3795 |
+
蒜
|
3796 |
+
翎
|
3797 |
+
宅
|
3798 |
+
晖
|
3799 |
+
嗑
|
3800 |
+
壑
|
3801 |
+
峻
|
3802 |
+
癫
|
3803 |
+
屏
|
3804 |
+
狠
|
3805 |
+
陋
|
3806 |
+
袜
|
3807 |
+
途
|
3808 |
+
憎
|
3809 |
+
祀
|
3810 |
+
莹
|
3811 |
+
滟
|
3812 |
+
佶
|
3813 |
+
溥
|
3814 |
+
臣
|
3815 |
+
约
|
3816 |
+
盛
|
3817 |
+
峰
|
3818 |
+
磁
|
3819 |
+
慵
|
3820 |
+
婪
|
3821 |
+
拦
|
3822 |
+
莅
|
3823 |
+
朕
|
3824 |
+
鹦
|
3825 |
+
粲
|
3826 |
+
裤
|
3827 |
+
哎
|
3828 |
+
疡
|
3829 |
+
嫖
|
3830 |
+
琵
|
3831 |
+
窟
|
3832 |
+
堪
|
3833 |
+
谛
|
3834 |
+
嘉
|
3835 |
+
儡
|
3836 |
+
鳝
|
3837 |
+
斩
|
3838 |
+
郾
|
3839 |
+
驸
|
3840 |
+
酊
|
3841 |
+
妄
|
3842 |
+
胜
|
3843 |
+
贺
|
3844 |
+
徙
|
3845 |
+
傅
|
3846 |
+
噌
|
3847 |
+
钢
|
3848 |
+
栅
|
3849 |
+
庇
|
3850 |
+
恋
|
3851 |
+
匝
|
3852 |
+
巯
|
3853 |
+
邈
|
3854 |
+
尸
|
3855 |
+
锚
|
3856 |
+
粗
|
3857 |
+
佟
|
3858 |
+
蛟
|
3859 |
+
薹
|
3860 |
+
纵
|
3861 |
+
蚊
|
3862 |
+
郅
|
3863 |
+
绢
|
3864 |
+
锐
|
3865 |
+
苗
|
3866 |
+
俞
|
3867 |
+
篆
|
3868 |
+
淆
|
3869 |
+
膀
|
3870 |
+
鲜
|
3871 |
+
煎
|
3872 |
+
诶
|
3873 |
+
秽
|
3874 |
+
寻
|
3875 |
+
涮
|
3876 |
+
刺
|
3877 |
+
怀
|
3878 |
+
噶
|
3879 |
+
巨
|
3880 |
+
褰
|
3881 |
+
魅
|
3882 |
+
灶
|
3883 |
+
灌
|
3884 |
+
桉
|
3885 |
+
藕
|
3886 |
+
谜
|
3887 |
+
舸
|
3888 |
+
薄
|
3889 |
+
搀
|
3890 |
+
恽
|
3891 |
+
借
|
3892 |
+
牯
|
3893 |
+
痉
|
3894 |
+
渥
|
3895 |
+
愿
|
3896 |
+
亓
|
3897 |
+
耘
|
3898 |
+
杠
|
3899 |
+
柩
|
3900 |
+
锔
|
3901 |
+
蚶
|
3902 |
+
钣
|
3903 |
+
珈
|
3904 |
+
喘
|
3905 |
+
蹒
|
3906 |
+
幽
|
3907 |
+
赐
|
3908 |
+
稗
|
3909 |
+
晤
|
3910 |
+
莱
|
3911 |
+
泔
|
3912 |
+
扯
|
3913 |
+
肯
|
3914 |
+
菪
|
3915 |
+
裆
|
3916 |
+
腩
|
3917 |
+
豉
|
3918 |
+
疆
|
3919 |
+
骜
|
3920 |
+
腐
|
3921 |
+
倭
|
3922 |
+
珏
|
3923 |
+
唔
|
3924 |
+
粮
|
3925 |
+
亡
|
3926 |
+
润
|
3927 |
+
慰
|
3928 |
+
伽
|
3929 |
+
橄
|
3930 |
+
玄
|
3931 |
+
誉
|
3932 |
+
醐
|
3933 |
+
胆
|
3934 |
+
龊
|
3935 |
+
粼
|
3936 |
+
塬
|
3937 |
+
陇
|
3938 |
+
彼
|
3939 |
+
削
|
3940 |
+
嗣
|
3941 |
+
绾
|
3942 |
+
芽
|
3943 |
+
妗
|
3944 |
+
垭
|
3945 |
+
瘴
|
3946 |
+
爽
|
3947 |
+
薏
|
3948 |
+
寨
|
3949 |
+
龈
|
3950 |
+
泠
|
3951 |
+
弹
|
3952 |
+
赢
|
3953 |
+
漪
|
3954 |
+
猫
|
3955 |
+
嘧
|
3956 |
+
涂
|
3957 |
+
恤
|
3958 |
+
圭
|
3959 |
+
茧
|
3960 |
+
烽
|
3961 |
+
屑
|
3962 |
+
痕
|
3963 |
+
巾
|
3964 |
+
赖
|
3965 |
+
荸
|
3966 |
+
凰
|
3967 |
+
腮
|
3968 |
+
畈
|
3969 |
+
亵
|
3970 |
+
蹲
|
3971 |
+
偃
|
3972 |
+
苇
|
3973 |
+
澜
|
3974 |
+
艮
|
3975 |
+
换
|
3976 |
+
骺
|
3977 |
+
烘
|
3978 |
+
苕
|
3979 |
+
梓
|
3980 |
+
颉
|
3981 |
+
肇
|
3982 |
+
哗
|
3983 |
+
悄
|
3984 |
+
氤
|
3985 |
+
涠
|
3986 |
+
葬
|
3987 |
+
屠
|
3988 |
+
鹭
|
3989 |
+
植
|
3990 |
+
竺
|
3991 |
+
佯
|
3992 |
+
诣
|
3993 |
+
鲇
|
3994 |
+
瘀
|
3995 |
+
鲅
|
3996 |
+
邦
|
3997 |
+
移
|
3998 |
+
滁
|
3999 |
+
冯
|
4000 |
+
耕
|
4001 |
+
癔
|
4002 |
+
戌
|
4003 |
+
茬
|
4004 |
+
沁
|
4005 |
+
巩
|
4006 |
+
悠
|
4007 |
+
湘
|
4008 |
+
洪
|
4009 |
+
痹
|
4010 |
+
锟
|
4011 |
+
循
|
4012 |
+
谋
|
4013 |
+
腕
|
4014 |
+
鳃
|
4015 |
+
钠
|
4016 |
+
捞
|
4017 |
+
焉
|
4018 |
+
迎
|
4019 |
+
碱
|
4020 |
+
伫
|
4021 |
+
急
|
4022 |
+
榷
|
4023 |
+
奈
|
4024 |
+
邝
|
4025 |
+
卯
|
4026 |
+
辄
|
4027 |
+
皲
|
4028 |
+
卟
|
4029 |
+
醛
|
4030 |
+
畹
|
4031 |
+
忧
|
4032 |
+
稳
|
4033 |
+
雄
|
4034 |
+
昼
|
4035 |
+
缩
|
4036 |
+
阈
|
4037 |
+
睑
|
4038 |
+
扌
|
4039 |
+
耗
|
4040 |
+
曦
|
4041 |
+
涅
|
4042 |
+
捏
|
4043 |
+
瞧
|
4044 |
+
邕
|
4045 |
+
淖
|
4046 |
+
漉
|
4047 |
+
铝
|
4048 |
+
耦
|
4049 |
+
禹
|
4050 |
+
湛
|
4051 |
+
喽
|
4052 |
+
莼
|
4053 |
+
琅
|
4054 |
+
诸
|
4055 |
+
苎
|
4056 |
+
纂
|
4057 |
+
硅
|
4058 |
+
始
|
4059 |
+
嗨
|
4060 |
+
傥
|
4061 |
+
燃
|
4062 |
+
臂
|
4063 |
+
赅
|
4064 |
+
嘈
|
4065 |
+
呆
|
4066 |
+
贵
|
4067 |
+
屹
|
4068 |
+
壮
|
4069 |
+
肋
|
4070 |
+
亍
|
4071 |
+
蚀
|
4072 |
+
卅
|
4073 |
+
豹
|
4074 |
+
腆
|
4075 |
+
邬
|
4076 |
+
迭
|
4077 |
+
浊
|
4078 |
+
}
|
4079 |
+
童
|
4080 |
+
螂
|
4081 |
+
捐
|
4082 |
+
圩
|
4083 |
+
勐
|
4084 |
+
触
|
4085 |
+
寞
|
4086 |
+
汊
|
4087 |
+
壤
|
4088 |
+
荫
|
4089 |
+
膺
|
4090 |
+
渌
|
4091 |
+
芳
|
4092 |
+
懿
|
4093 |
+
遴
|
4094 |
+
螈
|
4095 |
+
泰
|
4096 |
+
蓼
|
4097 |
+
蛤
|
4098 |
+
茜
|
4099 |
+
舅
|
4100 |
+
枫
|
4101 |
+
朔
|
4102 |
+
膝
|
4103 |
+
眙
|
4104 |
+
避
|
4105 |
+
梅
|
4106 |
+
判
|
4107 |
+
鹜
|
4108 |
+
璜
|
4109 |
+
牍
|
4110 |
+
缅
|
4111 |
+
垫
|
4112 |
+
藻
|
4113 |
+
黔
|
4114 |
+
侥
|
4115 |
+
惚
|
4116 |
+
懂
|
4117 |
+
踩
|
4118 |
+
腰
|
4119 |
+
腈
|
4120 |
+
札
|
4121 |
+
丞
|
4122 |
+
唾
|
4123 |
+
慈
|
4124 |
+
顿
|
4125 |
+
摹
|
4126 |
+
荻
|
4127 |
+
琬
|
4128 |
+
~
|
4129 |
+
斧
|
4130 |
+
沈
|
4131 |
+
滂
|
4132 |
+
胁
|
4133 |
+
胀
|
4134 |
+
幄
|
4135 |
+
莜
|
4136 |
+
Z
|
4137 |
+
匀
|
4138 |
+
鄄
|
4139 |
+
掌
|
4140 |
+
绰
|
4141 |
+
茎
|
4142 |
+
焚
|
4143 |
+
赋
|
4144 |
+
萱
|
4145 |
+
谑
|
4146 |
+
汁
|
4147 |
+
铒
|
4148 |
+
瞎
|
4149 |
+
夺
|
4150 |
+
蜗
|
4151 |
+
野
|
4152 |
+
娆
|
4153 |
+
冀
|
4154 |
+
弯
|
4155 |
+
篁
|
4156 |
+
懵
|
4157 |
+
灞
|
4158 |
+
隽
|
4159 |
+
芡
|
4160 |
+
脘
|
4161 |
+
俐
|
4162 |
+
辩
|
4163 |
+
芯
|
4164 |
+
掺
|
4165 |
+
喏
|
4166 |
+
膈
|
4167 |
+
蝈
|
4168 |
+
觐
|
4169 |
+
悚
|
4170 |
+
踹
|
4171 |
+
蔗
|
4172 |
+
熠
|
4173 |
+
鼠
|
4174 |
+
呵
|
4175 |
+
抓
|
4176 |
+
橼
|
4177 |
+
峨
|
4178 |
+
畜
|
4179 |
+
缔
|
4180 |
+
禾
|
4181 |
+
崭
|
4182 |
+
弃
|
4183 |
+
熊
|
4184 |
+
摒
|
4185 |
+
凸
|
4186 |
+
拗
|
4187 |
+
穹
|
4188 |
+
蒙
|
4189 |
+
抒
|
4190 |
+
祛
|
4191 |
+
劝
|
4192 |
+
闫
|
4193 |
+
扳
|
4194 |
+
阵
|
4195 |
+
醌
|
4196 |
+
踪
|
4197 |
+
喵
|
4198 |
+
侣
|
4199 |
+
搬
|
4200 |
+
仅
|
4201 |
+
荧
|
4202 |
+
赎
|
4203 |
+
蝾
|
4204 |
+
琦
|
4205 |
+
买
|
4206 |
+
婧
|
4207 |
+
瞄
|
4208 |
+
寓
|
4209 |
+
皎
|
4210 |
+
冻
|
4211 |
+
赝
|
4212 |
+
箩
|
4213 |
+
莫
|
4214 |
+
瞰
|
4215 |
+
郊
|
4216 |
+
笫
|
4217 |
+
姝
|
4218 |
+
筒
|
4219 |
+
枪
|
4220 |
+
遣
|
4221 |
+
煸
|
4222 |
+
袋
|
4223 |
+
舆
|
4224 |
+
痱
|
4225 |
+
涛
|
4226 |
+
母
|
4227 |
+
〇
|
4228 |
+
启
|
4229 |
+
践
|
4230 |
+
耙
|
4231 |
+
绲
|
4232 |
+
盘
|
4233 |
+
遂
|
4234 |
+
昊
|
4235 |
+
搞
|
4236 |
+
槿
|
4237 |
+
诬
|
4238 |
+
纰
|
4239 |
+
泓
|
4240 |
+
惨
|
4241 |
+
檬
|
4242 |
+
亻
|
4243 |
+
越
|
4244 |
+
C
|
4245 |
+
o
|
4246 |
+
憩
|
4247 |
+
熵
|
4248 |
+
祷
|
4249 |
+
钒
|
4250 |
+
暧
|
4251 |
+
塔
|
4252 |
+
阗
|
4253 |
+
胰
|
4254 |
+
咄
|
4255 |
+
娶
|
4256 |
+
魔
|
4257 |
+
琶
|
4258 |
+
钞
|
4259 |
+
邻
|
4260 |
+
扬
|
4261 |
+
杉
|
4262 |
+
殴
|
4263 |
+
咽
|
4264 |
+
弓
|
4265 |
+
〆
|
4266 |
+
髻
|
4267 |
+
】
|
4268 |
+
吭
|
4269 |
+
揽
|
4270 |
+
霆
|
4271 |
+
拄
|
4272 |
+
殖
|
4273 |
+
脆
|
4274 |
+
彻
|
4275 |
+
岩
|
4276 |
+
芝
|
4277 |
+
勃
|
4278 |
+
辣
|
4279 |
+
剌
|
4280 |
+
钝
|
4281 |
+
嘎
|
4282 |
+
甄
|
4283 |
+
佘
|
4284 |
+
皖
|
4285 |
+
伦
|
4286 |
+
授
|
4287 |
+
徕
|
4288 |
+
憔
|
4289 |
+
挪
|
4290 |
+
皇
|
4291 |
+
庞
|
4292 |
+
稔
|
4293 |
+
芜
|
4294 |
+
踏
|
4295 |
+
溴
|
4296 |
+
兖
|
4297 |
+
卒
|
4298 |
+
擢
|
4299 |
+
饥
|
4300 |
+
鳞
|
4301 |
+
煲
|
4302 |
+
‰
|
4303 |
+
账
|
4304 |
+
颗
|
4305 |
+
叻
|
4306 |
+
斯
|
4307 |
+
捧
|
4308 |
+
鳍
|
4309 |
+
琮
|
4310 |
+
讹
|
4311 |
+
蛙
|
4312 |
+
纽
|
4313 |
+
谭
|
4314 |
+
酸
|
4315 |
+
兔
|
4316 |
+
莒
|
4317 |
+
睇
|
4318 |
+
伟
|
4319 |
+
觑
|
4320 |
+
羲
|
4321 |
+
嗜
|
4322 |
+
宜
|
4323 |
+
褐
|
4324 |
+
旎
|
4325 |
+
辛
|
4326 |
+
卦
|
4327 |
+
诘
|
4328 |
+
筋
|
4329 |
+
鎏
|
4330 |
+
溪
|
4331 |
+
挛
|
4332 |
+
熔
|
4333 |
+
阜
|
4334 |
+
晰
|
4335 |
+
鳅
|
4336 |
+
丢
|
4337 |
+
奚
|
4338 |
+
灸
|
4339 |
+
呱
|
4340 |
+
献
|
4341 |
+
陉
|
4342 |
+
黛
|
4343 |
+
鸪
|
4344 |
+
甾
|
4345 |
+
萨
|
4346 |
+
疮
|
4347 |
+
拯
|
4348 |
+
洲
|
4349 |
+
疹
|
4350 |
+
辑
|
4351 |
+
叙
|
4352 |
+
恻
|
4353 |
+
谒
|
4354 |
+
允
|
4355 |
+
柔
|
4356 |
+
烂
|
4357 |
+
氏
|
4358 |
+
逅
|
4359 |
+
漆
|
4360 |
+
拎
|
4361 |
+
惋
|
4362 |
+
扈
|
4363 |
+
湟
|
4364 |
+
纭
|
4365 |
+
啕
|
4366 |
+
掬
|
4367 |
+
擞
|
4368 |
+
哥
|
4369 |
+
忽
|
4370 |
+
涤
|
4371 |
+
鸵
|
4372 |
+
靡
|
4373 |
+
郗
|
4374 |
+
瓷
|
4375 |
+
扁
|
4376 |
+
廊
|
4377 |
+
怨
|
4378 |
+
雏
|
4379 |
+
钮
|
4380 |
+
敦
|
4381 |
+
E
|
4382 |
+
懦
|
4383 |
+
憋
|
4384 |
+
汀
|
4385 |
+
拚
|
4386 |
+
啉
|
4387 |
+
腌
|
4388 |
+
岸
|
4389 |
+
f
|
4390 |
+
痼
|
4391 |
+
瞅
|
4392 |
+
尊
|
4393 |
+
咀
|
4394 |
+
眩
|
4395 |
+
飙
|
4396 |
+
忌
|
4397 |
+
仝
|
4398 |
+
迦
|
4399 |
+
熬
|
4400 |
+
毫
|
4401 |
+
胯
|
4402 |
+
篑
|
4403 |
+
茄
|
4404 |
+
腺
|
4405 |
+
凄
|
4406 |
+
舛
|
4407 |
+
碴
|
4408 |
+
锵
|
4409 |
+
诧
|
4410 |
+
羯
|
4411 |
+
後
|
4412 |
+
漏
|
4413 |
+
汤
|
4414 |
+
宓
|
4415 |
+
仞
|
4416 |
+
蚁
|
4417 |
+
壶
|
4418 |
+
谰
|
4419 |
+
皑
|
4420 |
+
铄
|
4421 |
+
棰
|
4422 |
+
罔
|
4423 |
+
辅
|
4424 |
+
晶
|
4425 |
+
苦
|
4426 |
+
牟
|
4427 |
+
闽
|
4428 |
+
\
|
4429 |
+
烃
|
4430 |
+
饮
|
4431 |
+
聿
|
4432 |
+
丙
|
4433 |
+
蛳
|
4434 |
+
朱
|
4435 |
+
煤
|
4436 |
+
涔
|
4437 |
+
鳖
|
4438 |
+
犁
|
4439 |
+
罐
|
4440 |
+
荼
|
4441 |
+
砒
|
4442 |
+
淦
|
4443 |
+
妤
|
4444 |
+
黏
|
4445 |
+
戎
|
4446 |
+
孑
|
4447 |
+
婕
|
4448 |
+
瑾
|
4449 |
+
戢
|
4450 |
+
钵
|
4451 |
+
枣
|
4452 |
+
捋
|
4453 |
+
砥
|
4454 |
+
衩
|
4455 |
+
狙
|
4456 |
+
桠
|
4457 |
+
稣
|
4458 |
+
阎
|
4459 |
+
肃
|
4460 |
+
梏
|
4461 |
+
诫
|
4462 |
+
孪
|
4463 |
+
昶
|
4464 |
+
婊
|
4465 |
+
衫
|
4466 |
+
嗔
|
4467 |
+
侃
|
4468 |
+
塞
|
4469 |
+
蜃
|
4470 |
+
樵
|
4471 |
+
峒
|
4472 |
+
貌
|
4473 |
+
屿
|
4474 |
+
欺
|
4475 |
+
缫
|
4476 |
+
阐
|
4477 |
+
栖
|
4478 |
+
诟
|
4479 |
+
珞
|
4480 |
+
荭
|
4481 |
+
吝
|
4482 |
+
萍
|
4483 |
+
嗽
|
4484 |
+
恂
|
4485 |
+
啻
|
4486 |
+
蜴
|
4487 |
+
磬
|
4488 |
+
峋
|
4489 |
+
俸
|
4490 |
+
豫
|
4491 |
+
谎
|
4492 |
+
徊
|
4493 |
+
镍
|
4494 |
+
韬
|
4495 |
+
魇
|
4496 |
+
晴
|
4497 |
+
U
|
4498 |
+
囟
|
4499 |
+
猜
|
4500 |
+
蛮
|
4501 |
+
坐
|
4502 |
+
囿
|
4503 |
+
伴
|
4504 |
+
亭
|
4505 |
+
肝
|
4506 |
+
佗
|
4507 |
+
蝠
|
4508 |
+
妃
|
4509 |
+
胞
|
4510 |
+
滩
|
4511 |
+
榴
|
4512 |
+
氖
|
4513 |
+
垩
|
4514 |
+
苋
|
4515 |
+
砣
|
4516 |
+
扪
|
4517 |
+
馏
|
4518 |
+
姓
|
4519 |
+
轩
|
4520 |
+
厉
|
4521 |
+
夥
|
4522 |
+
侈
|
4523 |
+
禀
|
4524 |
+
垒
|
4525 |
+
岑
|
4526 |
+
赏
|
4527 |
+
钛
|
4528 |
+
辐
|
4529 |
+
痔
|
4530 |
+
披
|
4531 |
+
纸
|
4532 |
+
碳
|
4533 |
+
“
|
4534 |
+
坞
|
4535 |
+
蠓
|
4536 |
+
挤
|
4537 |
+
荥
|
4538 |
+
沅
|
4539 |
+
悔
|
4540 |
+
铧
|
4541 |
+
帼
|
4542 |
+
蒌
|
4543 |
+
蝇
|
4544 |
+
a
|
4545 |
+
p
|
4546 |
+
y
|
4547 |
+
n
|
4548 |
+
g
|
4549 |
+
哀
|
4550 |
+
浆
|
4551 |
+
瑶
|
4552 |
+
凿
|
4553 |
+
桶
|
4554 |
+
馈
|
4555 |
+
皮
|
4556 |
+
奴
|
4557 |
+
苜
|
4558 |
+
佤
|
4559 |
+
伶
|
4560 |
+
晗
|
4561 |
+
铱
|
4562 |
+
炬
|
4563 |
+
优
|
4564 |
+
弊
|
4565 |
+
氢
|
4566 |
+
恃
|
4567 |
+
甫
|
4568 |
+
攥
|
4569 |
+
端
|
4570 |
+
锌
|
4571 |
+
灰
|
4572 |
+
稹
|
4573 |
+
炝
|
4574 |
+
曙
|
4575 |
+
邋
|
4576 |
+
亥
|
4577 |
+
眶
|
4578 |
+
碾
|
4579 |
+
拉
|
4580 |
+
萝
|
4581 |
+
绔
|
4582 |
+
捷
|
4583 |
+
浍
|
4584 |
+
腋
|
4585 |
+
姑
|
4586 |
+
菖
|
4587 |
+
凌
|
4588 |
+
涞
|
4589 |
+
麽
|
4590 |
+
锢
|
4591 |
+
桨
|
4592 |
+
潢
|
4593 |
+
绎
|
4594 |
+
镰
|
4595 |
+
殆
|
4596 |
+
锑
|
4597 |
+
渝
|
4598 |
+
铬
|
4599 |
+
困
|
4600 |
+
绽
|
4601 |
+
觎
|
4602 |
+
匈
|
4603 |
+
糙
|
4604 |
+
暑
|
4605 |
+
裹
|
4606 |
+
鸟
|
4607 |
+
盔
|
4608 |
+
肽
|
4609 |
+
迷
|
4610 |
+
綦
|
4611 |
+
『
|
4612 |
+
亳
|
4613 |
+
佝
|
4614 |
+
俘
|
4615 |
+
钴
|
4616 |
+
觇
|
4617 |
+
骥
|
4618 |
+
仆
|
4619 |
+
疝
|
4620 |
+
跪
|
4621 |
+
婶
|
4622 |
+
郯
|
4623 |
+
瀹
|
4624 |
+
唉
|
4625 |
+
脖
|
4626 |
+
踞
|
4627 |
+
针
|
4628 |
+
晾
|
4629 |
+
忒
|
4630 |
+
扼
|
4631 |
+
瞩
|
4632 |
+
叛
|
4633 |
+
椒
|
4634 |
+
疟
|
4635 |
+
嗡
|
4636 |
+
邗
|
4637 |
+
肆
|
4638 |
+
跆
|
4639 |
+
玫
|
4640 |
+
忡
|
4641 |
+
捣
|
4642 |
+
咧
|
4643 |
+
唆
|
4644 |
+
艄
|
4645 |
+
蘑
|
4646 |
+
潦
|
4647 |
+
笛
|
4648 |
+
阚
|
4649 |
+
沸
|
4650 |
+
泻
|
4651 |
+
掊
|
4652 |
+
菽
|
4653 |
+
贫
|
4654 |
+
斥
|
4655 |
+
髂
|
4656 |
+
孢
|
4657 |
+
镂
|
4658 |
+
赂
|
4659 |
+
麝
|
4660 |
+
鸾
|
4661 |
+
屡
|
4662 |
+
衬
|
4663 |
+
苷
|
4664 |
+
恪
|
4665 |
+
叠
|
4666 |
+
希
|
4667 |
+
粤
|
4668 |
+
爻
|
4669 |
+
喝
|
4670 |
+
茫
|
4671 |
+
惬
|
4672 |
+
郸
|
4673 |
+
绻
|
4674 |
+
庸
|
4675 |
+
撅
|
4676 |
+
碟
|
4677 |
+
宄
|
4678 |
+
妹
|
4679 |
+
膛
|
4680 |
+
叮
|
4681 |
+
饵
|
4682 |
+
崛
|
4683 |
+
嗲
|
4684 |
+
椅
|
4685 |
+
冤
|
4686 |
+
搅
|
4687 |
+
咕
|
4688 |
+
敛
|
4689 |
+
尹
|
4690 |
+
垦
|
4691 |
+
闷
|
4692 |
+
蝉
|
4693 |
+
霎
|
4694 |
+
勰
|
4695 |
+
败
|
4696 |
+
蓑
|
4697 |
+
泸
|
4698 |
+
肤
|
4699 |
+
鹌
|
4700 |
+
幌
|
4701 |
+
焦
|
4702 |
+
浠
|
4703 |
+
鞍
|
4704 |
+
刁
|
4705 |
+
舰
|
4706 |
+
乙
|
4707 |
+
竿
|
4708 |
+
裔
|
4709 |
+
。
|
4710 |
+
茵
|
4711 |
+
函
|
4712 |
+
伊
|
4713 |
+
兄
|
4714 |
+
丨
|
4715 |
+
娜
|
4716 |
+
匍
|
4717 |
+
謇
|
4718 |
+
莪
|
4719 |
+
宥
|
4720 |
+
似
|
4721 |
+
蝽
|
4722 |
+
翳
|
4723 |
+
酪
|
4724 |
+
翠
|
4725 |
+
粑
|
4726 |
+
薇
|
4727 |
+
祢
|
4728 |
+
骏
|
4729 |
+
赠
|
4730 |
+
叫
|
4731 |
+
Q
|
4732 |
+
噤
|
4733 |
+
噻
|
4734 |
+
竖
|
4735 |
+
芗
|
4736 |
+
莠
|
4737 |
+
潭
|
4738 |
+
俊
|
4739 |
+
羿
|
4740 |
+
耜
|
4741 |
+
O
|
4742 |
+
郫
|
4743 |
+
趁
|
4744 |
+
嗪
|
4745 |
+
囚
|
4746 |
+
蹶
|
4747 |
+
芒
|
4748 |
+
洁
|
4749 |
+
笋
|
4750 |
+
鹑
|
4751 |
+
敲
|
4752 |
+
硝
|
4753 |
+
啶
|
4754 |
+
堡
|
4755 |
+
渲
|
4756 |
+
揩
|
4757 |
+
』
|
4758 |
+
携
|
4759 |
+
宿
|
4760 |
+
遒
|
4761 |
+
颍
|
4762 |
+
扭
|
4763 |
+
棱
|
4764 |
+
割
|
4765 |
+
萜
|
4766 |
+
蔸
|
4767 |
+
葵
|
4768 |
+
琴
|
4769 |
+
捂
|
4770 |
+
饰
|
4771 |
+
衙
|
4772 |
+
耿
|
4773 |
+
掠
|
4774 |
+
募
|
4775 |
+
岂
|
4776 |
+
窖
|
4777 |
+
涟
|
4778 |
+
蔺
|
4779 |
+
瘤
|
4780 |
+
柞
|
4781 |
+
瞪
|
4782 |
+
怜
|
4783 |
+
匹
|
4784 |
+
距
|
4785 |
+
楔
|
4786 |
+
炜
|
4787 |
+
哆
|
4788 |
+
秦
|
4789 |
+
缎
|
4790 |
+
幼
|
4791 |
+
茁
|
4792 |
+
绪
|
4793 |
+
痨
|
4794 |
+
恨
|
4795 |
+
楸
|
4796 |
+
娅
|
4797 |
+
瓦
|
4798 |
+
桩
|
4799 |
+
雪
|
4800 |
+
嬴
|
4801 |
+
伏
|
4802 |
+
榔
|
4803 |
+
妥
|
4804 |
+
铿
|
4805 |
+
拌
|
4806 |
+
眠
|
4807 |
+
雍
|
4808 |
+
缇
|
4809 |
+
‘
|
4810 |
+
卓
|
4811 |
+
搓
|
4812 |
+
哌
|
4813 |
+
觞
|
4814 |
+
噩
|
4815 |
+
屈
|
4816 |
+
哧
|
4817 |
+
髓
|
4818 |
+
咦
|
4819 |
+
巅
|
4820 |
+
娑
|
4821 |
+
侑
|
4822 |
+
淫
|
4823 |
+
膳
|
4824 |
+
祝
|
4825 |
+
勾
|
4826 |
+
姊
|
4827 |
+
莴
|
4828 |
+
胄
|
4829 |
+
疃
|
4830 |
+
薛
|
4831 |
+
蜷
|
4832 |
+
胛
|
4833 |
+
巷
|
4834 |
+
芙
|
4835 |
+
芋
|
4836 |
+
熙
|
4837 |
+
闰
|
4838 |
+
勿
|
4839 |
+
窃
|
4840 |
+
狱
|
4841 |
+
剩
|
4842 |
+
钏
|
4843 |
+
幢
|
4844 |
+
陟
|
4845 |
+
铛
|
4846 |
+
慧
|
4847 |
+
靴
|
4848 |
+
耍
|
4849 |
+
k
|
4850 |
+
浙
|
4851 |
+
浇
|
4852 |
+
飨
|
4853 |
+
惟
|
4854 |
+
绗
|
4855 |
+
祜
|
4856 |
+
澈
|
4857 |
+
啼
|
4858 |
+
咪
|
4859 |
+
磷
|
4860 |
+
摞
|
4861 |
+
诅
|
4862 |
+
郦
|
4863 |
+
抹
|
4864 |
+
跃
|
4865 |
+
壬
|
4866 |
+
吕
|
4867 |
+
肖
|
4868 |
+
琏
|
4869 |
+
颤
|
4870 |
+
尴
|
4871 |
+
剡
|
4872 |
+
抠
|
4873 |
+
凋
|
4874 |
+
赚
|
4875 |
+
泊
|
4876 |
+
津
|
4877 |
+
宕
|
4878 |
+
殷
|
4879 |
+
倔
|
4880 |
+
氲
|
4881 |
+
漫
|
4882 |
+
邺
|
4883 |
+
涎
|
4884 |
+
怠
|
4885 |
+
$
|
4886 |
+
垮
|
4887 |
+
荬
|
4888 |
+
遵
|
4889 |
+
俏
|
4890 |
+
叹
|
4891 |
+
噢
|
4892 |
+
饽
|
4893 |
+
蜘
|
4894 |
+
孙
|
4895 |
+
筵
|
4896 |
+
疼
|
4897 |
+
鞭
|
4898 |
+
羧
|
4899 |
+
牦
|
4900 |
+
箭
|
4901 |
+
潴
|
4902 |
+
c
|
4903 |
+
眸
|
4904 |
+
祭
|
4905 |
+
髯
|
4906 |
+
啖
|
4907 |
+
坳
|
4908 |
+
愁
|
4909 |
+
芩
|
4910 |
+
驮
|
4911 |
+
倡
|
4912 |
+
巽
|
4913 |
+
穰
|
4914 |
+
沃
|
4915 |
+
胚
|
4916 |
+
怒
|
4917 |
+
凤
|
4918 |
+
槛
|
4919 |
+
剂
|
4920 |
+
趵
|
4921 |
+
嫁
|
4922 |
+
v
|
4923 |
+
邢
|
4924 |
+
灯
|
4925 |
+
鄢
|
4926 |
+
桐
|
4927 |
+
睽
|
4928 |
+
檗
|
4929 |
+
锯
|
4930 |
+
槟
|
4931 |
+
婷
|
4932 |
+
嵋
|
4933 |
+
圻
|
4934 |
+
诗
|
4935 |
+
蕈
|
4936 |
+
颠
|
4937 |
+
遭
|
4938 |
+
痢
|
4939 |
+
芸
|
4940 |
+
怯
|
4941 |
+
馥
|
4942 |
+
竭
|
4943 |
+
锗
|
4944 |
+
徜
|
4945 |
+
恭
|
4946 |
+
遍
|
4947 |
+
籁
|
4948 |
+
剑
|
4949 |
+
嘱
|
4950 |
+
苡
|
4951 |
+
龄
|
4952 |
+
僧
|
4953 |
+
桑
|
4954 |
+
潸
|
4955 |
+
弘
|
4956 |
+
澶
|
4957 |
+
楹
|
4958 |
+
悲
|
4959 |
+
讫
|
4960 |
+
愤
|
4961 |
+
腥
|
4962 |
+
悸
|
4963 |
+
谍
|
4964 |
+
椹
|
4965 |
+
呢
|
4966 |
+
桓
|
4967 |
+
葭
|
4968 |
+
攫
|
4969 |
+
阀
|
4970 |
+
翰
|
4971 |
+
躲
|
4972 |
+
敖
|
4973 |
+
柑
|
4974 |
+
郎
|
4975 |
+
笨
|
4976 |
+
橇
|
4977 |
+
呃
|
4978 |
+
魁
|
4979 |
+
燎
|
4980 |
+
脓
|
4981 |
+
葩
|
4982 |
+
磋
|
4983 |
+
垛
|
4984 |
+
玺
|
4985 |
+
狮
|
4986 |
+
沓
|
4987 |
+
砜
|
4988 |
+
蕊
|
4989 |
+
锺
|
4990 |
+
罹
|
4991 |
+
蕉
|
4992 |
+
翱
|
4993 |
+
虐
|
4994 |
+
闾
|
4995 |
+
巫
|
4996 |
+
旦
|
4997 |
+
茱
|
4998 |
+
嬷
|
4999 |
+
枯
|
5000 |
+
鹏
|
5001 |
+
贡
|
5002 |
+
芹
|
5003 |
+
汛
|
5004 |
+
矫
|
5005 |
+
绁
|
5006 |
+
拣
|
5007 |
+
禺
|
5008 |
+
佃
|
5009 |
+
讣
|
5010 |
+
舫
|
5011 |
+
惯
|
5012 |
+
乳
|
5013 |
+
趋
|
5014 |
+
疲
|
5015 |
+
挽
|
5016 |
+
岚
|
5017 |
+
虾
|
5018 |
+
衾
|
5019 |
+
蠹
|
5020 |
+
蹂
|
5021 |
+
飓
|
5022 |
+
氦
|
5023 |
+
铖
|
5024 |
+
孩
|
5025 |
+
稞
|
5026 |
+
瑜
|
5027 |
+
壅
|
5028 |
+
掀
|
5029 |
+
勘
|
5030 |
+
妓
|
5031 |
+
畅
|
5032 |
+
髋
|
5033 |
+
W
|
5034 |
+
庐
|
5035 |
+
牲
|
5036 |
+
蓿
|
5037 |
+
榕
|
5038 |
+
练
|
5039 |
+
垣
|
5040 |
+
唱
|
5041 |
+
邸
|
5042 |
+
菲
|
5043 |
+
昆
|
5044 |
+
婺
|
5045 |
+
穿
|
5046 |
+
绡
|
5047 |
+
麒
|
5048 |
+
蚱
|
5049 |
+
掂
|
5050 |
+
愚
|
5051 |
+
泷
|
5052 |
+
涪
|
5053 |
+
漳
|
5054 |
+
妩
|
5055 |
+
娉
|
5056 |
+
榄
|
5057 |
+
讷
|
5058 |
+
觅
|
5059 |
+
旧
|
5060 |
+
藤
|
5061 |
+
煮
|
5062 |
+
呛
|
5063 |
+
柳
|
5064 |
+
腓
|
5065 |
+
叭
|
5066 |
+
庵
|
5067 |
+
烷
|
5068 |
+
阡
|
5069 |
+
罂
|
5070 |
+
蜕
|
5071 |
+
擂
|
5072 |
+
猖
|
5073 |
+
咿
|
5074 |
+
媲
|
5075 |
+
脉
|
5076 |
+
【
|
5077 |
+
沏
|
5078 |
+
貅
|
5079 |
+
黠
|
5080 |
+
熏
|
5081 |
+
哲
|
5082 |
+
烁
|
5083 |
+
坦
|
5084 |
+
酵
|
5085 |
+
兜
|
5086 |
+
×
|
5087 |
+
潇
|
5088 |
+
撒
|
5089 |
+
剽
|
5090 |
+
珩
|
5091 |
+
圹
|
5092 |
+
乾
|
5093 |
+
摸
|
5094 |
+
樟
|
5095 |
+
帽
|
5096 |
+
嗒
|
5097 |
+
襄
|
5098 |
+
魂
|
5099 |
+
轿
|
5100 |
+
憬
|
5101 |
+
锡
|
5102 |
+
〕
|
5103 |
+
喃
|
5104 |
+
皆
|
5105 |
+
咖
|
5106 |
+
隅
|
5107 |
+
脸
|
5108 |
+
残
|
5109 |
+
泮
|
5110 |
+
袂
|
5111 |
+
鹂
|
5112 |
+
珊
|
5113 |
+
囤
|
5114 |
+
捆
|
5115 |
+
咤
|
5116 |
+
误
|
5117 |
+
徨
|
5118 |
+
闹
|
5119 |
+
淙
|
5120 |
+
芊
|
5121 |
+
淋
|
5122 |
+
怆
|
5123 |
+
囗
|
5124 |
+
拨
|
5125 |
+
梳
|
5126 |
+
渤
|
5127 |
+
R
|
5128 |
+
G
|
5129 |
+
绨
|
5130 |
+
蚓
|
5131 |
+
婀
|
5132 |
+
幡
|
5133 |
+
狩
|
5134 |
+
麾
|
5135 |
+
谢
|
5136 |
+
唢
|
5137 |
+
裸
|
5138 |
+
旌
|
5139 |
+
伉
|
5140 |
+
纶
|
5141 |
+
裂
|
5142 |
+
驳
|
5143 |
+
砼
|
5144 |
+
咛
|
5145 |
+
澄
|
5146 |
+
樨
|
5147 |
+
蹈
|
5148 |
+
宙
|
5149 |
+
澍
|
5150 |
+
倍
|
5151 |
+
貔
|
5152 |
+
操
|
5153 |
+
勇
|
5154 |
+
蟠
|
5155 |
+
摈
|
5156 |
+
砧
|
5157 |
+
虬
|
5158 |
+
够
|
5159 |
+
缁
|
5160 |
+
悦
|
5161 |
+
藿
|
5162 |
+
撸
|
5163 |
+
艹
|
5164 |
+
摁
|
5165 |
+
淹
|
5166 |
+
豇
|
5167 |
+
虎
|
5168 |
+
榭
|
5169 |
+
ˉ
|
5170 |
+
吱
|
5171 |
+
d
|
5172 |
+
°
|
5173 |
+
喧
|
5174 |
+
荀
|
5175 |
+
踱
|
5176 |
+
侮
|
5177 |
+
奋
|
5178 |
+
偕
|
5179 |
+
饷
|
5180 |
+
犍
|
5181 |
+
惮
|
5182 |
+
坑
|
5183 |
+
璎
|
5184 |
+
徘
|
5185 |
+
宛
|
5186 |
+
妆
|
5187 |
+
袈
|
5188 |
+
倩
|
5189 |
+
窦
|
5190 |
+
昂
|
5191 |
+
荏
|
5192 |
+
乖
|
5193 |
+
K
|
5194 |
+
怅
|
5195 |
+
撰
|
5196 |
+
鳙
|
5197 |
+
牙
|
5198 |
+
袁
|
5199 |
+
酞
|
5200 |
+
X
|
5201 |
+
痿
|
5202 |
+
琼
|
5203 |
+
闸
|
5204 |
+
雁
|
5205 |
+
趾
|
5206 |
+
荚
|
5207 |
+
虻
|
5208 |
+
涝
|
5209 |
+
《
|
5210 |
+
杏
|
5211 |
+
韭
|
5212 |
+
偈
|
5213 |
+
烤
|
5214 |
+
绫
|
5215 |
+
鞘
|
5216 |
+
卉
|
5217 |
+
症
|
5218 |
+
遢
|
5219 |
+
蓥
|
5220 |
+
诋
|
5221 |
+
杭
|
5222 |
+
荨
|
5223 |
+
匆
|
5224 |
+
竣
|
5225 |
+
簪
|
5226 |
+
辙
|
5227 |
+
敕
|
5228 |
+
虞
|
5229 |
+
丹
|
5230 |
+
缭
|
5231 |
+
咩
|
5232 |
+
黟
|
5233 |
+
m
|
5234 |
+
淤
|
5235 |
+
瑕
|
5236 |
+
咂
|
5237 |
+
铉
|
5238 |
+
硼
|
5239 |
+
茨
|
5240 |
+
嶂
|
5241 |
+
痒
|
5242 |
+
畸
|
5243 |
+
敬
|
5244 |
+
涿
|
5245 |
+
粪
|
5246 |
+
窘
|
5247 |
+
熟
|
5248 |
+
叔
|
5249 |
+
嫔
|
5250 |
+
盾
|
5251 |
+
忱
|
5252 |
+
裘
|
5253 |
+
憾
|
5254 |
+
梵
|
5255 |
+
赡
|
5256 |
+
珙
|
5257 |
+
咯
|
5258 |
+
娘
|
5259 |
+
庙
|
5260 |
+
溯
|
5261 |
+
胺
|
5262 |
+
葱
|
5263 |
+
痪
|
5264 |
+
摊
|
5265 |
+
荷
|
5266 |
+
卞
|
5267 |
+
乒
|
5268 |
+
髦
|
5269 |
+
寐
|
5270 |
+
铭
|
5271 |
+
坩
|
5272 |
+
胗
|
5273 |
+
枷
|
5274 |
+
爆
|
5275 |
+
溟
|
5276 |
+
嚼
|
5277 |
+
羚
|
5278 |
+
砬
|
5279 |
+
轨
|
5280 |
+
惊
|
5281 |
+
挠
|
5282 |
+
罄
|
5283 |
+
竽
|
5284 |
+
菏
|
5285 |
+
氧
|
5286 |
+
浅
|
5287 |
+
楣
|
5288 |
+
盼
|
5289 |
+
枢
|
5290 |
+
炸
|
5291 |
+
阆
|
5292 |
+
杯
|
5293 |
+
谏
|
5294 |
+
噬
|
5295 |
+
淇
|
5296 |
+
渺
|
5297 |
+
俪
|
5298 |
+
秆
|
5299 |
+
墓
|
5300 |
+
泪
|
5301 |
+
跻
|
5302 |
+
砌
|
5303 |
+
痰
|
5304 |
+
垡
|
5305 |
+
渡
|
5306 |
+
耽
|
5307 |
+
釜
|
5308 |
+
讶
|
5309 |
+
鳎
|
5310 |
+
煞
|
5311 |
+
呗
|
5312 |
+
韶
|
5313 |
+
舶
|
5314 |
+
绷
|
5315 |
+
鹳
|
5316 |
+
缜
|
5317 |
+
旷
|
5318 |
+
铊
|
5319 |
+
皱
|
5320 |
+
龌
|
5321 |
+
檀
|
5322 |
+
霖
|
5323 |
+
奄
|
5324 |
+
槐
|
5325 |
+
艳
|
5326 |
+
蝶
|
5327 |
+
旋
|
5328 |
+
哝
|
5329 |
+
赶
|
5330 |
+
骞
|
5331 |
+
蚧
|
5332 |
+
腊
|
5333 |
+
盈
|
5334 |
+
丁
|
5335 |
+
`
|
5336 |
+
蜚
|
5337 |
+
矸
|
5338 |
+
蝙
|
5339 |
+
睨
|
5340 |
+
嚓
|
5341 |
+
僻
|
5342 |
+
鬼
|
5343 |
+
醴
|
5344 |
+
夜
|
5345 |
+
彝
|
5346 |
+
磊
|
5347 |
+
笔
|
5348 |
+
拔
|
5349 |
+
栀
|
5350 |
+
糕
|
5351 |
+
厦
|
5352 |
+
邰
|
5353 |
+
纫
|
5354 |
+
逭
|
5355 |
+
纤
|
5356 |
+
眦
|
5357 |
+
膊
|
5358 |
+
馍
|
5359 |
+
躇
|
5360 |
+
烯
|
5361 |
+
蘼
|
5362 |
+
冬
|
5363 |
+
诤
|
5364 |
+
暄
|
5365 |
+
骶
|
5366 |
+
哑
|
5367 |
+
瘠
|
5368 |
+
」
|
5369 |
+
臊
|
5370 |
+
丕
|
5371 |
+
愈
|
5372 |
+
咱
|
5373 |
+
螺
|
5374 |
+
擅
|
5375 |
+
跋
|
5376 |
+
搏
|
5377 |
+
硪
|
5378 |
+
谄
|
5379 |
+
笠
|
5380 |
+
淡
|
5381 |
+
嘿
|
5382 |
+
骅
|
5383 |
+
谧
|
5384 |
+
鼎
|
5385 |
+
皋
|
5386 |
+
姚
|
5387 |
+
歼
|
5388 |
+
蠢
|
5389 |
+
驼
|
5390 |
+
耳
|
5391 |
+
胬
|
5392 |
+
挝
|
5393 |
+
涯
|
5394 |
+
狗
|
5395 |
+
蒽
|
5396 |
+
孓
|
5397 |
+
犷
|
5398 |
+
凉
|
5399 |
+
芦
|
5400 |
+
箴
|
5401 |
+
铤
|
5402 |
+
孤
|
5403 |
+
嘛
|
5404 |
+
坤
|
5405 |
+
V
|
5406 |
+
茴
|
5407 |
+
朦
|
5408 |
+
挞
|
5409 |
+
尖
|
5410 |
+
橙
|
5411 |
+
诞
|
5412 |
+
搴
|
5413 |
+
碇
|
5414 |
+
洵
|
5415 |
+
浚
|
5416 |
+
帚
|
5417 |
+
蜍
|
5418 |
+
漯
|
5419 |
+
柘
|
5420 |
+
嚎
|
5421 |
+
讽
|
5422 |
+
芭
|
5423 |
+
荤
|
5424 |
+
咻
|
5425 |
+
祠
|
5426 |
+
秉
|
5427 |
+
跖
|
5428 |
+
埃
|
5429 |
+
吓
|
5430 |
+
糯
|
5431 |
+
眷
|
5432 |
+
馒
|
5433 |
+
惹
|
5434 |
+
娼
|
5435 |
+
鲑
|
5436 |
+
嫩
|
5437 |
+
讴
|
5438 |
+
轮
|
5439 |
+
瞥
|
5440 |
+
靶
|
5441 |
+
褚
|
5442 |
+
乏
|
5443 |
+
缤
|
5444 |
+
宋
|
5445 |
+
帧
|
5446 |
+
删
|
5447 |
+
驱
|
5448 |
+
碎
|
5449 |
+
扑
|
5450 |
+
俩
|
5451 |
+
俄
|
5452 |
+
偏
|
5453 |
+
涣
|
5454 |
+
竹
|
5455 |
+
噱
|
5456 |
+
皙
|
5457 |
+
佰
|
5458 |
+
渚
|
5459 |
+
唧
|
5460 |
+
斡
|
5461 |
+
#
|
5462 |
+
镉
|
5463 |
+
刀
|
5464 |
+
崎
|
5465 |
+
筐
|
5466 |
+
佣
|
5467 |
+
夭
|
5468 |
+
贰
|
5469 |
+
肴
|
5470 |
+
峙
|
5471 |
+
哔
|
5472 |
+
艿
|
5473 |
+
匐
|
5474 |
+
牺
|
5475 |
+
镛
|
5476 |
+
缘
|
5477 |
+
仡
|
5478 |
+
嫡
|
5479 |
+
劣
|
5480 |
+
枸
|
5481 |
+
堀
|
5482 |
+
梨
|
5483 |
+
簿
|
5484 |
+
鸭
|
5485 |
+
蒸
|
5486 |
+
亦
|
5487 |
+
稽
|
5488 |
+
浴
|
5489 |
+
{
|
5490 |
+
衢
|
5491 |
+
束
|
5492 |
+
槲
|
5493 |
+
j
|
5494 |
+
阁
|
5495 |
+
揍
|
5496 |
+
疥
|
5497 |
+
棋
|
5498 |
+
潋
|
5499 |
+
聪
|
5500 |
+
窜
|
5501 |
+
乓
|
5502 |
+
睛
|
5503 |
+
插
|
5504 |
+
冉
|
5505 |
+
阪
|
5506 |
+
苍
|
5507 |
+
搽
|
5508 |
+
「
|
5509 |
+
蟾
|
5510 |
+
螟
|
5511 |
+
幸
|
5512 |
+
仇
|
5513 |
+
樽
|
5514 |
+
撂
|
5515 |
+
慢
|
5516 |
+
跤
|
5517 |
+
幔
|
5518 |
+
俚
|
5519 |
+
淅
|
5520 |
+
覃
|
5521 |
+
觊
|
5522 |
+
溶
|
5523 |
+
妖
|
5524 |
+
帛
|
5525 |
+
侨
|
5526 |
+
曰
|
5527 |
+
妾
|
5528 |
+
泗
|
5529 |
+
·
|
5530 |
+
:
|
5531 |
+
瀘
|
5532 |
+
風
|
5533 |
+
Ë
|
5534 |
+
(
|
5535 |
+
)
|
5536 |
+
∶
|
5537 |
+
紅
|
5538 |
+
紗
|
5539 |
+
瑭
|
5540 |
+
雲
|
5541 |
+
頭
|
5542 |
+
鶏
|
5543 |
+
財
|
5544 |
+
許
|
5545 |
+
•
|
5546 |
+
¥
|
5547 |
+
樂
|
5548 |
+
焗
|
5549 |
+
麗
|
5550 |
+
—
|
5551 |
+
;
|
5552 |
+
滙
|
5553 |
+
東
|
5554 |
+
榮
|
5555 |
+
繪
|
5556 |
+
興
|
5557 |
+
…
|
5558 |
+
門
|
5559 |
+
業
|
5560 |
+
π
|
5561 |
+
楊
|
5562 |
+
國
|
5563 |
+
顧
|
5564 |
+
é
|
5565 |
+
盤
|
5566 |
+
寳
|
5567 |
+
Λ
|
5568 |
+
龍
|
5569 |
+
鳳
|
5570 |
+
島
|
5571 |
+
誌
|
5572 |
+
緣
|
5573 |
+
結
|
5574 |
+
銭
|
5575 |
+
萬
|
5576 |
+
勝
|
5577 |
+
祎
|
5578 |
+
璟
|
5579 |
+
優
|
5580 |
+
歡
|
5581 |
+
臨
|
5582 |
+
時
|
5583 |
+
購
|
5584 |
+
=
|
5585 |
+
★
|
5586 |
+
藍
|
5587 |
+
昇
|
5588 |
+
鐵
|
5589 |
+
觀
|
5590 |
+
勅
|
5591 |
+
農
|
5592 |
+
聲
|
5593 |
+
畫
|
5594 |
+
兿
|
5595 |
+
術
|
5596 |
+
發
|
5597 |
+
劉
|
5598 |
+
記
|
5599 |
+
專
|
5600 |
+
耑
|
5601 |
+
園
|
5602 |
+
書
|
5603 |
+
壴
|
5604 |
+
種
|
5605 |
+
Ο
|
5606 |
+
●
|
5607 |
+
褀
|
5608 |
+
號
|
5609 |
+
銀
|
5610 |
+
匯
|
5611 |
+
敟
|
5612 |
+
锘
|
5613 |
+
葉
|
5614 |
+
橪
|
5615 |
+
廣
|
5616 |
+
進
|
5617 |
+
蒄
|
5618 |
+
鑽
|
5619 |
+
阝
|
5620 |
+
祙
|
5621 |
+
貢
|
5622 |
+
鍋
|
5623 |
+
豊
|
5624 |
+
夬
|
5625 |
+
喆
|
5626 |
+
團
|
5627 |
+
閣
|
5628 |
+
開
|
5629 |
+
燁
|
5630 |
+
賓
|
5631 |
+
館
|
5632 |
+
酡
|
5633 |
+
沔
|
5634 |
+
順
|
5635 |
+
+
|
5636 |
+
硚
|
5637 |
+
劵
|
5638 |
+
饸
|
5639 |
+
陽
|
5640 |
+
車
|
5641 |
+
湓
|
5642 |
+
復
|
5643 |
+
萊
|
5644 |
+
氣
|
5645 |
+
軒
|
5646 |
+
華
|
5647 |
+
堃
|
5648 |
+
迮
|
5649 |
+
纟
|
5650 |
+
戶
|
5651 |
+
馬
|
5652 |
+
學
|
5653 |
+
裡
|
5654 |
+
電
|
5655 |
+
嶽
|
5656 |
+
獨
|
5657 |
+
マ
|
5658 |
+
シ
|
5659 |
+
サ
|
5660 |
+
ジ
|
5661 |
+
燘
|
5662 |
+
袪
|
5663 |
+
環
|
5664 |
+
❤
|
5665 |
+
臺
|
5666 |
+
灣
|
5667 |
+
専
|
5668 |
+
賣
|
5669 |
+
孖
|
5670 |
+
聖
|
5671 |
+
攝
|
5672 |
+
線
|
5673 |
+
▪
|
5674 |
+
α
|
5675 |
+
傢
|
5676 |
+
俬
|
5677 |
+
夢
|
5678 |
+
達
|
5679 |
+
莊
|
5680 |
+
喬
|
5681 |
+
貝
|
5682 |
+
薩
|
5683 |
+
劍
|
5684 |
+
羅
|
5685 |
+
壓
|
5686 |
+
棛
|
5687 |
+
饦
|
5688 |
+
尃
|
5689 |
+
璈
|
5690 |
+
囍
|
5691 |
+
醫
|
5692 |
+
G
|
5693 |
+
I
|
5694 |
+
A
|
5695 |
+
#
|
5696 |
+
N
|
5697 |
+
鷄
|
5698 |
+
髙
|
5699 |
+
嬰
|
5700 |
+
啓
|
5701 |
+
約
|
5702 |
+
隹
|
5703 |
+
潔
|
5704 |
+
賴
|
5705 |
+
藝
|
5706 |
+
~
|
5707 |
+
寶
|
5708 |
+
籣
|
5709 |
+
麺
|
5710 |
+
|
5711 |
+
嶺
|
5712 |
+
√
|
5713 |
+
義
|
5714 |
+
網
|
5715 |
+
峩
|
5716 |
+
長
|
5717 |
+
∧
|
5718 |
+
魚
|
5719 |
+
機
|
5720 |
+
構
|
5721 |
+
②
|
5722 |
+
鳯
|
5723 |
+
偉
|
5724 |
+
L
|
5725 |
+
B
|
5726 |
+
㙟
|
5727 |
+
畵
|
5728 |
+
鴿
|
5729 |
+
'
|
5730 |
+
詩
|
5731 |
+
溝
|
5732 |
+
嚞
|
5733 |
+
屌
|
5734 |
+
藔
|
5735 |
+
佧
|
5736 |
+
玥
|
5737 |
+
蘭
|
5738 |
+
織
|
5739 |
+
1
|
5740 |
+
3
|
5741 |
+
9
|
5742 |
+
0
|
5743 |
+
7
|
5744 |
+
點
|
5745 |
+
砭
|
5746 |
+
鴨
|
5747 |
+
鋪
|
5748 |
+
銘
|
5749 |
+
廳
|
5750 |
+
弍
|
5751 |
+
‧
|
5752 |
+
創
|
5753 |
+
湯
|
5754 |
+
坶
|
5755 |
+
℃
|
5756 |
+
卩
|
5757 |
+
骝
|
5758 |
+
&
|
5759 |
+
烜
|
5760 |
+
荘
|
5761 |
+
當
|
5762 |
+
潤
|
5763 |
+
扞
|
5764 |
+
係
|
5765 |
+
懷
|
5766 |
+
碶
|
5767 |
+
钅
|
5768 |
+
蚨
|
5769 |
+
讠
|
5770 |
+
☆
|
5771 |
+
叢
|
5772 |
+
爲
|
5773 |
+
埗
|
5774 |
+
涫
|
5775 |
+
塗
|
5776 |
+
→
|
5777 |
+
楽
|
5778 |
+
現
|
5779 |
+
鯨
|
5780 |
+
愛
|
5781 |
+
瑪
|
5782 |
+
鈺
|
5783 |
+
忄
|
5784 |
+
悶
|
5785 |
+
藥
|
5786 |
+
飾
|
5787 |
+
樓
|
5788 |
+
視
|
5789 |
+
孬
|
5790 |
+
ㆍ
|
5791 |
+
燚
|
5792 |
+
苪
|
5793 |
+
師
|
5794 |
+
①
|
5795 |
+
丼
|
5796 |
+
锽
|
5797 |
+
│
|
5798 |
+
韓
|
5799 |
+
標
|
5800 |
+
è
|
5801 |
+
兒
|
5802 |
+
閏
|
5803 |
+
匋
|
5804 |
+
張
|
5805 |
+
漢
|
5806 |
+
Ü
|
5807 |
+
髪
|
5808 |
+
會
|
5809 |
+
閑
|
5810 |
+
檔
|
5811 |
+
習
|
5812 |
+
裝
|
5813 |
+
の
|
5814 |
+
峯
|
5815 |
+
菘
|
5816 |
+
輝
|
5817 |
+
И
|
5818 |
+
雞
|
5819 |
+
釣
|
5820 |
+
億
|
5821 |
+
浐
|
5822 |
+
K
|
5823 |
+
O
|
5824 |
+
R
|
5825 |
+
8
|
5826 |
+
H
|
5827 |
+
E
|
5828 |
+
P
|
5829 |
+
T
|
5830 |
+
W
|
5831 |
+
D
|
5832 |
+
S
|
5833 |
+
C
|
5834 |
+
M
|
5835 |
+
F
|
5836 |
+
姌
|
5837 |
+
饹
|
5838 |
+
»
|
5839 |
+
晞
|
5840 |
+
廰
|
5841 |
+
ä
|
5842 |
+
嵯
|
5843 |
+
鷹
|
5844 |
+
負
|
5845 |
+
飲
|
5846 |
+
絲
|
5847 |
+
冚
|
5848 |
+
楗
|
5849 |
+
澤
|
5850 |
+
綫
|
5851 |
+
區
|
5852 |
+
❋
|
5853 |
+
←
|
5854 |
+
質
|
5855 |
+
靑
|
5856 |
+
揚
|
5857 |
+
③
|
5858 |
+
滬
|
5859 |
+
統
|
5860 |
+
産
|
5861 |
+
協
|
5862 |
+
﹑
|
5863 |
+
乸
|
5864 |
+
畐
|
5865 |
+
經
|
5866 |
+
運
|
5867 |
+
際
|
5868 |
+
洺
|
5869 |
+
岽
|
5870 |
+
為
|
5871 |
+
粵
|
5872 |
+
諾
|
5873 |
+
崋
|
5874 |
+
豐
|
5875 |
+
碁
|
5876 |
+
ɔ
|
5877 |
+
V
|
5878 |
+
2
|
5879 |
+
6
|
5880 |
+
齋
|
5881 |
+
誠
|
5882 |
+
訂
|
5883 |
+
´
|
5884 |
+
勑
|
5885 |
+
雙
|
5886 |
+
陳
|
5887 |
+
無
|
5888 |
+
í
|
5889 |
+
泩
|
5890 |
+
媄
|
5891 |
+
夌
|
5892 |
+
刂
|
5893 |
+
i
|
5894 |
+
c
|
5895 |
+
t
|
5896 |
+
o
|
5897 |
+
r
|
5898 |
+
a
|
5899 |
+
嘢
|
5900 |
+
耄
|
5901 |
+
燴
|
5902 |
+
暃
|
5903 |
+
壽
|
5904 |
+
媽
|
5905 |
+
靈
|
5906 |
+
抻
|
5907 |
+
體
|
5908 |
+
唻
|
5909 |
+
É
|
5910 |
+
冮
|
5911 |
+
甹
|
5912 |
+
鎮
|
5913 |
+
錦
|
5914 |
+
ʌ
|
5915 |
+
蜛
|
5916 |
+
蠄
|
5917 |
+
尓
|
5918 |
+
駕
|
5919 |
+
戀
|
5920 |
+
飬
|
5921 |
+
逹
|
5922 |
+
倫
|
5923 |
+
貴
|
5924 |
+
極
|
5925 |
+
Я
|
5926 |
+
Й
|
5927 |
+
寬
|
5928 |
+
磚
|
5929 |
+
嶪
|
5930 |
+
郎
|
5931 |
+
職
|
5932 |
+
|
|
5933 |
+
間
|
5934 |
+
n
|
5935 |
+
d
|
5936 |
+
剎
|
5937 |
+
伈
|
5938 |
+
課
|
5939 |
+
飛
|
5940 |
+
橋
|
5941 |
+
瘊
|
5942 |
+
№
|
5943 |
+
譜
|
5944 |
+
骓
|
5945 |
+
圗
|
5946 |
+
滘
|
5947 |
+
縣
|
5948 |
+
粿
|
5949 |
+
咅
|
5950 |
+
養
|
5951 |
+
濤
|
5952 |
+
彳
|
5953 |
+
®
|
5954 |
+
%
|
5955 |
+
Ⅱ
|
5956 |
+
啰
|
5957 |
+
㴪
|
5958 |
+
見
|
5959 |
+
矞
|
5960 |
+
薬
|
5961 |
+
糁
|
5962 |
+
邨
|
5963 |
+
鲮
|
5964 |
+
顔
|
5965 |
+
罱
|
5966 |
+
З
|
5967 |
+
選
|
5968 |
+
話
|
5969 |
+
贏
|
5970 |
+
氪
|
5971 |
+
俵
|
5972 |
+
競
|
5973 |
+
瑩
|
5974 |
+
繡
|
5975 |
+
枱
|
5976 |
+
β
|
5977 |
+
綉
|
5978 |
+
á
|
5979 |
+
獅
|
5980 |
+
爾
|
5981 |
+
™
|
5982 |
+
麵
|
5983 |
+
戋
|
5984 |
+
淩
|
5985 |
+
徳
|
5986 |
+
個
|
5987 |
+
劇
|
5988 |
+
場
|
5989 |
+
務
|
5990 |
+
簡
|
5991 |
+
寵
|
5992 |
+
h
|
5993 |
+
實
|
5994 |
+
膠
|
5995 |
+
轱
|
5996 |
+
圖
|
5997 |
+
築
|
5998 |
+
嘣
|
5999 |
+
樹
|
6000 |
+
㸃
|
6001 |
+
營
|
6002 |
+
耵
|
6003 |
+
孫
|
6004 |
+
饃
|
6005 |
+
鄺
|
6006 |
+
飯
|
6007 |
+
麯
|
6008 |
+
遠
|
6009 |
+
輸
|
6010 |
+
坫
|
6011 |
+
孃
|
6012 |
+
乚
|
6013 |
+
閃
|
6014 |
+
鏢
|
6015 |
+
㎡
|
6016 |
+
題
|
6017 |
+
廠
|
6018 |
+
關
|
6019 |
+
↑
|
6020 |
+
爺
|
6021 |
+
將
|
6022 |
+
軍
|
6023 |
+
連
|
6024 |
+
篦
|
6025 |
+
覌
|
6026 |
+
參
|
6027 |
+
箸
|
6028 |
+
-
|
6029 |
+
窠
|
6030 |
+
棽
|
6031 |
+
寕
|
6032 |
+
夀
|
6033 |
+
爰
|
6034 |
+
歐
|
6035 |
+
呙
|
6036 |
+
閥
|
6037 |
+
頡
|
6038 |
+
熱
|
6039 |
+
雎
|
6040 |
+
垟
|
6041 |
+
裟
|
6042 |
+
凬
|
6043 |
+
勁
|
6044 |
+
帑
|
6045 |
+
馕
|
6046 |
+
夆
|
6047 |
+
疌
|
6048 |
+
枼
|
6049 |
+
馮
|
6050 |
+
貨
|
6051 |
+
蒤
|
6052 |
+
樸
|
6053 |
+
彧
|
6054 |
+
旸
|
6055 |
+
靜
|
6056 |
+
龢
|
6057 |
+
暢
|
6058 |
+
㐱
|
6059 |
+
鳥
|
6060 |
+
珺
|
6061 |
+
鏡
|
6062 |
+
灡
|
6063 |
+
爭
|
6064 |
+
堷
|
6065 |
+
廚
|
6066 |
+
Ó
|
6067 |
+
騰
|
6068 |
+
診
|
6069 |
+
┅
|
6070 |
+
蘇
|
6071 |
+
褔
|
6072 |
+
凱
|
6073 |
+
頂
|
6074 |
+
豕
|
6075 |
+
亞
|
6076 |
+
帥
|
6077 |
+
嘬
|
6078 |
+
⊥
|
6079 |
+
仺
|
6080 |
+
桖
|
6081 |
+
複
|
6082 |
+
饣
|
6083 |
+
絡
|
6084 |
+
穂
|
6085 |
+
顏
|
6086 |
+
棟
|
6087 |
+
納
|
6088 |
+
▏
|
6089 |
+
濟
|
6090 |
+
親
|
6091 |
+
設
|
6092 |
+
計
|
6093 |
+
攵
|
6094 |
+
埌
|
6095 |
+
烺
|
6096 |
+
ò
|
6097 |
+
頤
|
6098 |
+
燦
|
6099 |
+
蓮
|
6100 |
+
撻
|
6101 |
+
節
|
6102 |
+
講
|
6103 |
+
濱
|
6104 |
+
濃
|
6105 |
+
娽
|
6106 |
+
洳
|
6107 |
+
朿
|
6108 |
+
燈
|
6109 |
+
鈴
|
6110 |
+
護
|
6111 |
+
膚
|
6112 |
+
铔
|
6113 |
+
過
|
6114 |
+
補
|
6115 |
+
Z
|
6116 |
+
U
|
6117 |
+
5
|
6118 |
+
4
|
6119 |
+
坋
|
6120 |
+
闿
|
6121 |
+
䖝
|
6122 |
+
餘
|
6123 |
+
缐
|
6124 |
+
铞
|
6125 |
+
貿
|
6126 |
+
铪
|
6127 |
+
桼
|
6128 |
+
趙
|
6129 |
+
鍊
|
6130 |
+
[
|
6131 |
+
㐂
|
6132 |
+
垚
|
6133 |
+
菓
|
6134 |
+
揸
|
6135 |
+
捲
|
6136 |
+
鐘
|
6137 |
+
滏
|
6138 |
+
𣇉
|
6139 |
+
爍
|
6140 |
+
輪
|
6141 |
+
燜
|
6142 |
+
鴻
|
6143 |
+
鮮
|
6144 |
+
動
|
6145 |
+
鹞
|
6146 |
+
鷗
|
6147 |
+
丄
|
6148 |
+
慶
|
6149 |
+
鉌
|
6150 |
+
翥
|
6151 |
+
飮
|
6152 |
+
腸
|
6153 |
+
⇋
|
6154 |
+
漁
|
6155 |
+
覺
|
6156 |
+
來
|
6157 |
+
熘
|
6158 |
+
昴
|
6159 |
+
翏
|
6160 |
+
鲱
|
6161 |
+
圧
|
6162 |
+
鄉
|
6163 |
+
萭
|
6164 |
+
頔
|
6165 |
+
爐
|
6166 |
+
嫚
|
6167 |
+
г
|
6168 |
+
貭
|
6169 |
+
類
|
6170 |
+
聯
|
6171 |
+
幛
|
6172 |
+
輕
|
6173 |
+
訓
|
6174 |
+
鑒
|
6175 |
+
夋
|
6176 |
+
锨
|
6177 |
+
芃
|
6178 |
+
珣
|
6179 |
+
䝉
|
6180 |
+
扙
|
6181 |
+
嵐
|
6182 |
+
銷
|
6183 |
+
處
|
6184 |
+
ㄱ
|
6185 |
+
���
|
6186 |
+
誘
|
6187 |
+
苝
|
6188 |
+
歸
|
6189 |
+
儀
|
6190 |
+
燒
|
6191 |
+
楿
|
6192 |
+
內
|
6193 |
+
粢
|
6194 |
+
葒
|
6195 |
+
奧
|
6196 |
+
麥
|
6197 |
+
礻
|
6198 |
+
滿
|
6199 |
+
蠔
|
6200 |
+
穵
|
6201 |
+
瞭
|
6202 |
+
態
|
6203 |
+
鱬
|
6204 |
+
榞
|
6205 |
+
硂
|
6206 |
+
鄭
|
6207 |
+
黃
|
6208 |
+
煙
|
6209 |
+
祐
|
6210 |
+
奓
|
6211 |
+
逺
|
6212 |
+
*
|
6213 |
+
瑄
|
6214 |
+
獲
|
6215 |
+
聞
|
6216 |
+
薦
|
6217 |
+
讀
|
6218 |
+
這
|
6219 |
+
樣
|
6220 |
+
決
|
6221 |
+
問
|
6222 |
+
啟
|
6223 |
+
們
|
6224 |
+
執
|
6225 |
+
説
|
6226 |
+
轉
|
6227 |
+
單
|
6228 |
+
隨
|
6229 |
+
唘
|
6230 |
+
帶
|
6231 |
+
倉
|
6232 |
+
庫
|
6233 |
+
還
|
6234 |
+
贈
|
6235 |
+
尙
|
6236 |
+
皺
|
6237 |
+
■
|
6238 |
+
餅
|
6239 |
+
產
|
6240 |
+
○
|
6241 |
+
∈
|
6242 |
+
報
|
6243 |
+
狀
|
6244 |
+
楓
|
6245 |
+
賠
|
6246 |
+
琯
|
6247 |
+
嗮
|
6248 |
+
禮
|
6249 |
+
`
|
6250 |
+
傳
|
6251 |
+
>
|
6252 |
+
≤
|
6253 |
+
嗞
|
6254 |
+
Φ
|
6255 |
+
≥
|
6256 |
+
換
|
6257 |
+
咭
|
6258 |
+
∣
|
6259 |
+
↓
|
6260 |
+
曬
|
6261 |
+
ε
|
6262 |
+
応
|
6263 |
+
寫
|
6264 |
+
″
|
6265 |
+
終
|
6266 |
+
様
|
6267 |
+
純
|
6268 |
+
費
|
6269 |
+
療
|
6270 |
+
聨
|
6271 |
+
凍
|
6272 |
+
壐
|
6273 |
+
郵
|
6274 |
+
ü
|
6275 |
+
黒
|
6276 |
+
∫
|
6277 |
+
製
|
6278 |
+
塊
|
6279 |
+
調
|
6280 |
+
軽
|
6281 |
+
確
|
6282 |
+
撃
|
6283 |
+
級
|
6284 |
+
馴
|
6285 |
+
Ⅲ
|
6286 |
+
涇
|
6287 |
+
繹
|
6288 |
+
數
|
6289 |
+
碼
|
6290 |
+
證
|
6291 |
+
狒
|
6292 |
+
処
|
6293 |
+
劑
|
6294 |
+
<
|
6295 |
+
晧
|
6296 |
+
賀
|
6297 |
+
衆
|
6298 |
+
]
|
6299 |
+
櫥
|
6300 |
+
兩
|
6301 |
+
陰
|
6302 |
+
絶
|
6303 |
+
對
|
6304 |
+
鯉
|
6305 |
+
憶
|
6306 |
+
◎
|
6307 |
+
p
|
6308 |
+
e
|
6309 |
+
Y
|
6310 |
+
蕒
|
6311 |
+
煖
|
6312 |
+
頓
|
6313 |
+
測
|
6314 |
+
試
|
6315 |
+
鼽
|
6316 |
+
僑
|
6317 |
+
碩
|
6318 |
+
妝
|
6319 |
+
帯
|
6320 |
+
≈
|
6321 |
+
鐡
|
6322 |
+
舖
|
6323 |
+
權
|
6324 |
+
喫
|
6325 |
+
倆
|
6326 |
+
ˋ
|
6327 |
+
該
|
6328 |
+
悅
|
6329 |
+
ā
|
6330 |
+
俫
|
6331 |
+
.
|
6332 |
+
f
|
6333 |
+
s
|
6334 |
+
b
|
6335 |
+
m
|
6336 |
+
k
|
6337 |
+
g
|
6338 |
+
u
|
6339 |
+
j
|
6340 |
+
貼
|
6341 |
+
淨
|
6342 |
+
濕
|
6343 |
+
針
|
6344 |
+
適
|
6345 |
+
備
|
6346 |
+
l
|
6347 |
+
/
|
6348 |
+
給
|
6349 |
+
謢
|
6350 |
+
強
|
6351 |
+
觸
|
6352 |
+
衛
|
6353 |
+
與
|
6354 |
+
⊙
|
6355 |
+
$
|
6356 |
+
緯
|
6357 |
+
變
|
6358 |
+
⑴
|
6359 |
+
⑵
|
6360 |
+
⑶
|
6361 |
+
㎏
|
6362 |
+
殺
|
6363 |
+
∩
|
6364 |
+
幚
|
6365 |
+
─
|
6366 |
+
價
|
6367 |
+
▲
|
6368 |
+
離
|
6369 |
+
ú
|
6370 |
+
ó
|
6371 |
+
飄
|
6372 |
+
烏
|
6373 |
+
関
|
6374 |
+
閟
|
6375 |
+
﹝
|
6376 |
+
﹞
|
6377 |
+
邏
|
6378 |
+
輯
|
6379 |
+
鍵
|
6380 |
+
驗
|
6381 |
+
訣
|
6382 |
+
導
|
6383 |
+
歷
|
6384 |
+
屆
|
6385 |
+
層
|
6386 |
+
▼
|
6387 |
+
儱
|
6388 |
+
錄
|
6389 |
+
熳
|
6390 |
+
ē
|
6391 |
+
艦
|
6392 |
+
吋
|
6393 |
+
錶
|
6394 |
+
辧
|
6395 |
+
飼
|
6396 |
+
顯
|
6397 |
+
④
|
6398 |
+
禦
|
6399 |
+
販
|
6400 |
+
気
|
6401 |
+
対
|
6402 |
+
枰
|
6403 |
+
閩
|
6404 |
+
紀
|
6405 |
+
幹
|
6406 |
+
瞓
|
6407 |
+
貊
|
6408 |
+
淚
|
6409 |
+
△
|
6410 |
+
眞
|
6411 |
+
墊
|
6412 |
+
Ω
|
6413 |
+
獻
|
6414 |
+
褲
|
6415 |
+
縫
|
6416 |
+
緑
|
6417 |
+
亜
|
6418 |
+
鉅
|
6419 |
+
餠
|
6420 |
+
{
|
6421 |
+
}
|
6422 |
+
◆
|
6423 |
+
蘆
|
6424 |
+
薈
|
6425 |
+
█
|
6426 |
+
◇
|
6427 |
+
溫
|
6428 |
+
彈
|
6429 |
+
晳
|
6430 |
+
粧
|
6431 |
+
犸
|
6432 |
+
穩
|
6433 |
+
訊
|
6434 |
+
崬
|
6435 |
+
凖
|
6436 |
+
熥
|
6437 |
+
П
|
6438 |
+
舊
|
6439 |
+
條
|
6440 |
+
紋
|
6441 |
+
圍
|
6442 |
+
Ⅳ
|
6443 |
+
筆
|
6444 |
+
尷
|
6445 |
+
難
|
6446 |
+
雜
|
6447 |
+
錯
|
6448 |
+
綁
|
6449 |
+
識
|
6450 |
+
頰
|
6451 |
+
鎖
|
6452 |
+
艶
|
6453 |
+
□
|
6454 |
+
殁
|
6455 |
+
殼
|
6456 |
+
⑧
|
6457 |
+
├
|
6458 |
+
▕
|
6459 |
+
鵬
|
6460 |
+
ǐ
|
6461 |
+
ō
|
6462 |
+
ǒ
|
6463 |
+
糝
|
6464 |
+
綱
|
6465 |
+
▎
|
6466 |
+
μ
|
6467 |
+
盜
|
6468 |
+
饅
|
6469 |
+
醬
|
6470 |
+
籤
|
6471 |
+
蓋
|
6472 |
+
釀
|
6473 |
+
鹽
|
6474 |
+
據
|
6475 |
+
à
|
6476 |
+
ɡ
|
6477 |
+
辦
|
6478 |
+
◥
|
6479 |
+
彐
|
6480 |
+
┌
|
6481 |
+
婦
|
6482 |
+
獸
|
6483 |
+
鲩
|
6484 |
+
伱
|
6485 |
+
ī
|
6486 |
+
蒟
|
6487 |
+
蒻
|
6488 |
+
齊
|
6489 |
+
袆
|
6490 |
+
腦
|
6491 |
+
寧
|
6492 |
+
凈
|
6493 |
+
妳
|
6494 |
+
煥
|
6495 |
+
詢
|
6496 |
+
偽
|
6497 |
+
謹
|
6498 |
+
啫
|
6499 |
+
鯽
|
6500 |
+
騷
|
6501 |
+
鱸
|
6502 |
+
損
|
6503 |
+
傷
|
6504 |
+
鎻
|
6505 |
+
髮
|
6506 |
+
買
|
6507 |
+
冏
|
6508 |
+
儥
|
6509 |
+
両
|
6510 |
+
﹢
|
6511 |
+
∞
|
6512 |
+
載
|
6513 |
+
喰
|
6514 |
+
z
|
6515 |
+
羙
|
6516 |
+
悵
|
6517 |
+
燙
|
6518 |
+
曉
|
6519 |
+
員
|
6520 |
+
組
|
6521 |
+
徹
|
6522 |
+
艷
|
6523 |
+
痠
|
6524 |
+
鋼
|
6525 |
+
鼙
|
6526 |
+
縮
|
6527 |
+
細
|
6528 |
+
嚒
|
6529 |
+
爯
|
6530 |
+
≠
|
6531 |
+
維
|
6532 |
+
"
|
6533 |
+
鱻
|
6534 |
+
壇
|
6535 |
+
厍
|
6536 |
+
帰
|
6537 |
+
浥
|
6538 |
+
犇
|
6539 |
+
薡
|
6540 |
+
軎
|
6541 |
+
²
|
6542 |
+
應
|
6543 |
+
醜
|
6544 |
+
刪
|
6545 |
+
緻
|
6546 |
+
鶴
|
6547 |
+
賜
|
6548 |
+
噁
|
6549 |
+
軌
|
6550 |
+
尨
|
6551 |
+
镔
|
6552 |
+
鷺
|
6553 |
+
槗
|
6554 |
+
彌
|
6555 |
+
葚
|
6556 |
+
濛
|
6557 |
+
請
|
6558 |
+
溇
|
6559 |
+
緹
|
6560 |
+
賢
|
6561 |
+
訪
|
6562 |
+
獴
|
6563 |
+
瑅
|
6564 |
+
資
|
6565 |
+
縤
|
6566 |
+
陣
|
6567 |
+
蕟
|
6568 |
+
栢
|
6569 |
+
韻
|
6570 |
+
祼
|
6571 |
+
恁
|
6572 |
+
伢
|
6573 |
+
謝
|
6574 |
+
劃
|
6575 |
+
涑
|
6576 |
+
總
|
6577 |
+
衖
|
6578 |
+
踺
|
6579 |
+
砋
|
6580 |
+
凉
|
6581 |
+
籃
|
6582 |
+
駿
|
6583 |
+
苼
|
6584 |
+
瘋
|
6585 |
+
昽
|
6586 |
+
紡
|
6587 |
+
驊
|
6588 |
+
腎
|
6589 |
+
﹗
|
6590 |
+
響
|
6591 |
+
杋
|
6592 |
+
剛
|
6593 |
+
嚴
|
6594 |
+
禪
|
6595 |
+
歓
|
6596 |
+
槍
|
6597 |
+
傘
|
6598 |
+
檸
|
6599 |
+
檫
|
6600 |
+
炣
|
6601 |
+
勢
|
6602 |
+
鏜
|
6603 |
+
鎢
|
6604 |
+
銑
|
6605 |
+
尐
|
6606 |
+
減
|
6607 |
+
奪
|
6608 |
+
惡
|
6609 |
+
θ
|
6610 |
+
僮
|
6611 |
+
婭
|
6612 |
+
臘
|
6613 |
+
ū
|
6614 |
+
ì
|
6615 |
+
殻
|
6616 |
+
鉄
|
6617 |
+
∑
|
6618 |
+
蛲
|
6619 |
+
焼
|
6620 |
+
緖
|
6621 |
+
續
|
6622 |
+
紹
|
6623 |
+
懮
|
iopaint/model/original_sd_configs/sd_xl_base.yaml
ADDED
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
model:
|
2 |
+
target: sgm.models.diffusion.DiffusionEngine
|
3 |
+
params:
|
4 |
+
scale_factor: 0.13025
|
5 |
+
disable_first_stage_autocast: True
|
6 |
+
|
7 |
+
denoiser_config:
|
8 |
+
target: sgm.modules.diffusionmodules.denoiser.DiscreteDenoiser
|
9 |
+
params:
|
10 |
+
num_idx: 1000
|
11 |
+
|
12 |
+
scaling_config:
|
13 |
+
target: sgm.modules.diffusionmodules.denoiser_scaling.EpsScaling
|
14 |
+
discretization_config:
|
15 |
+
target: sgm.modules.diffusionmodules.discretizer.LegacyDDPMDiscretization
|
16 |
+
|
17 |
+
network_config:
|
18 |
+
target: sgm.modules.diffusionmodules.openaimodel.UNetModel
|
19 |
+
params:
|
20 |
+
adm_in_channels: 2816
|
21 |
+
num_classes: sequential
|
22 |
+
use_checkpoint: True
|
23 |
+
in_channels: 4
|
24 |
+
out_channels: 4
|
25 |
+
model_channels: 320
|
26 |
+
attention_resolutions: [4, 2]
|
27 |
+
num_res_blocks: 2
|
28 |
+
channel_mult: [1, 2, 4]
|
29 |
+
num_head_channels: 64
|
30 |
+
use_linear_in_transformer: True
|
31 |
+
transformer_depth: [1, 2, 10]
|
32 |
+
context_dim: 2048
|
33 |
+
spatial_transformer_attn_type: softmax-xformers
|
34 |
+
|
35 |
+
conditioner_config:
|
36 |
+
target: sgm.modules.GeneralConditioner
|
37 |
+
params:
|
38 |
+
emb_models:
|
39 |
+
- is_trainable: False
|
40 |
+
input_key: txt
|
41 |
+
target: sgm.modules.encoders.modules.FrozenCLIPEmbedder
|
42 |
+
params:
|
43 |
+
layer: hidden
|
44 |
+
layer_idx: 11
|
45 |
+
|
46 |
+
- is_trainable: False
|
47 |
+
input_key: txt
|
48 |
+
target: sgm.modules.encoders.modules.FrozenOpenCLIPEmbedder2
|
49 |
+
params:
|
50 |
+
arch: ViT-bigG-14
|
51 |
+
version: laion2b_s39b_b160k
|
52 |
+
freeze: True
|
53 |
+
layer: penultimate
|
54 |
+
always_return_pooled: True
|
55 |
+
legacy: False
|
56 |
+
|
57 |
+
- is_trainable: False
|
58 |
+
input_key: original_size_as_tuple
|
59 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
60 |
+
params:
|
61 |
+
outdim: 256
|
62 |
+
|
63 |
+
- is_trainable: False
|
64 |
+
input_key: crop_coords_top_left
|
65 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
66 |
+
params:
|
67 |
+
outdim: 256
|
68 |
+
|
69 |
+
- is_trainable: False
|
70 |
+
input_key: target_size_as_tuple
|
71 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
72 |
+
params:
|
73 |
+
outdim: 256
|
74 |
+
|
75 |
+
first_stage_config:
|
76 |
+
target: sgm.models.autoencoder.AutoencoderKL
|
77 |
+
params:
|
78 |
+
embed_dim: 4
|
79 |
+
monitor: val/rec_loss
|
80 |
+
ddconfig:
|
81 |
+
attn_type: vanilla-xformers
|
82 |
+
double_z: true
|
83 |
+
z_channels: 4
|
84 |
+
resolution: 256
|
85 |
+
in_channels: 3
|
86 |
+
out_ch: 3
|
87 |
+
ch: 128
|
88 |
+
ch_mult: [1, 2, 4, 4]
|
89 |
+
num_res_blocks: 2
|
90 |
+
attn_resolutions: []
|
91 |
+
dropout: 0.0
|
92 |
+
lossconfig:
|
93 |
+
target: torch.nn.Identity
|
iopaint/model/original_sd_configs/sd_xl_refiner.yaml
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
model:
|
2 |
+
target: sgm.models.diffusion.DiffusionEngine
|
3 |
+
params:
|
4 |
+
scale_factor: 0.13025
|
5 |
+
disable_first_stage_autocast: True
|
6 |
+
|
7 |
+
denoiser_config:
|
8 |
+
target: sgm.modules.diffusionmodules.denoiser.DiscreteDenoiser
|
9 |
+
params:
|
10 |
+
num_idx: 1000
|
11 |
+
|
12 |
+
scaling_config:
|
13 |
+
target: sgm.modules.diffusionmodules.denoiser_scaling.EpsScaling
|
14 |
+
discretization_config:
|
15 |
+
target: sgm.modules.diffusionmodules.discretizer.LegacyDDPMDiscretization
|
16 |
+
|
17 |
+
network_config:
|
18 |
+
target: sgm.modules.diffusionmodules.openaimodel.UNetModel
|
19 |
+
params:
|
20 |
+
adm_in_channels: 2560
|
21 |
+
num_classes: sequential
|
22 |
+
use_checkpoint: True
|
23 |
+
in_channels: 4
|
24 |
+
out_channels: 4
|
25 |
+
model_channels: 384
|
26 |
+
attention_resolutions: [4, 2]
|
27 |
+
num_res_blocks: 2
|
28 |
+
channel_mult: [1, 2, 4, 4]
|
29 |
+
num_head_channels: 64
|
30 |
+
use_linear_in_transformer: True
|
31 |
+
transformer_depth: 4
|
32 |
+
context_dim: [1280, 1280, 1280, 1280]
|
33 |
+
spatial_transformer_attn_type: softmax-xformers
|
34 |
+
|
35 |
+
conditioner_config:
|
36 |
+
target: sgm.modules.GeneralConditioner
|
37 |
+
params:
|
38 |
+
emb_models:
|
39 |
+
- is_trainable: False
|
40 |
+
input_key: txt
|
41 |
+
target: sgm.modules.encoders.modules.FrozenOpenCLIPEmbedder2
|
42 |
+
params:
|
43 |
+
arch: ViT-bigG-14
|
44 |
+
version: laion2b_s39b_b160k
|
45 |
+
legacy: False
|
46 |
+
freeze: True
|
47 |
+
layer: penultimate
|
48 |
+
always_return_pooled: True
|
49 |
+
|
50 |
+
- is_trainable: False
|
51 |
+
input_key: original_size_as_tuple
|
52 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
53 |
+
params:
|
54 |
+
outdim: 256
|
55 |
+
|
56 |
+
- is_trainable: False
|
57 |
+
input_key: crop_coords_top_left
|
58 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
59 |
+
params:
|
60 |
+
outdim: 256
|
61 |
+
|
62 |
+
- is_trainable: False
|
63 |
+
input_key: aesthetic_score
|
64 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
65 |
+
params:
|
66 |
+
outdim: 256
|
67 |
+
|
68 |
+
first_stage_config:
|
69 |
+
target: sgm.models.autoencoder.AutoencoderKL
|
70 |
+
params:
|
71 |
+
embed_dim: 4
|
72 |
+
monitor: val/rec_loss
|
73 |
+
ddconfig:
|
74 |
+
attn_type: vanilla-xformers
|
75 |
+
double_z: true
|
76 |
+
z_channels: 4
|
77 |
+
resolution: 256
|
78 |
+
in_channels: 3
|
79 |
+
out_ch: 3
|
80 |
+
ch: 128
|
81 |
+
ch_mult: [1, 2, 4, 4]
|
82 |
+
num_res_blocks: 2
|
83 |
+
attn_resolutions: []
|
84 |
+
dropout: 0.0
|
85 |
+
lossconfig:
|
86 |
+
target: torch.nn.Identity
|
iopaint/model/paint_by_example.py
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import PIL
|
2 |
+
import PIL.Image
|
3 |
+
import cv2
|
4 |
+
import torch
|
5 |
+
from loguru import logger
|
6 |
+
|
7 |
+
from iopaint.helper import decode_base64_to_image
|
8 |
+
from .base import DiffusionInpaintModel
|
9 |
+
from iopaint.schema import InpaintRequest
|
10 |
+
from .utils import get_torch_dtype, enable_low_mem, is_local_files_only
|
11 |
+
|
12 |
+
|
13 |
+
class PaintByExample(DiffusionInpaintModel):
|
14 |
+
name = "Fantasy-Studio/Paint-by-Example"
|
15 |
+
pad_mod = 8
|
16 |
+
min_size = 512
|
17 |
+
|
18 |
+
def init_model(self, device: torch.device, **kwargs):
|
19 |
+
from diffusers import DiffusionPipeline
|
20 |
+
|
21 |
+
use_gpu, torch_dtype = get_torch_dtype(device, kwargs.get("no_half", False))
|
22 |
+
model_kwargs = {
|
23 |
+
"local_files_only": is_local_files_only(**kwargs),
|
24 |
+
}
|
25 |
+
|
26 |
+
if kwargs["disable_nsfw"] or kwargs.get("cpu_offload", False):
|
27 |
+
logger.info("Disable Paint By Example Model NSFW checker")
|
28 |
+
model_kwargs.update(
|
29 |
+
dict(safety_checker=None, requires_safety_checker=False)
|
30 |
+
)
|
31 |
+
|
32 |
+
self.model = DiffusionPipeline.from_pretrained(
|
33 |
+
self.name, torch_dtype=torch_dtype, **model_kwargs
|
34 |
+
)
|
35 |
+
enable_low_mem(self.model, kwargs.get("low_mem", False))
|
36 |
+
|
37 |
+
# TODO: gpu_id
|
38 |
+
if kwargs.get("cpu_offload", False) and use_gpu:
|
39 |
+
self.model.image_encoder = self.model.image_encoder.to(device)
|
40 |
+
self.model.enable_sequential_cpu_offload(gpu_id=0)
|
41 |
+
else:
|
42 |
+
self.model = self.model.to(device)
|
43 |
+
|
44 |
+
def forward(self, image, mask, config: InpaintRequest):
|
45 |
+
"""Input image and output image have same size
|
46 |
+
image: [H, W, C] RGB
|
47 |
+
mask: [H, W, 1] 255 means area to repaint
|
48 |
+
return: BGR IMAGE
|
49 |
+
"""
|
50 |
+
if config.paint_by_example_example_image is None:
|
51 |
+
raise ValueError("paint_by_example_example_image is required")
|
52 |
+
example_image, _, _ = decode_base64_to_image(
|
53 |
+
config.paint_by_example_example_image
|
54 |
+
)
|
55 |
+
output = self.model(
|
56 |
+
image=PIL.Image.fromarray(image),
|
57 |
+
mask_image=PIL.Image.fromarray(mask[:, :, -1], mode="L"),
|
58 |
+
example_image=PIL.Image.fromarray(example_image),
|
59 |
+
num_inference_steps=config.sd_steps,
|
60 |
+
guidance_scale=config.sd_guidance_scale,
|
61 |
+
negative_prompt="out of frame, lowres, error, cropped, worst quality, low quality, jpeg artifacts, ugly, duplicate, morbid, mutilated, out of frame, mutation, deformed, blurry, dehydrated, bad anatomy, bad proportions, extra limbs, disfigured, gross proportions, malformed limbs, watermark, signature",
|
62 |
+
output_type="np.array",
|
63 |
+
generator=torch.manual_seed(config.sd_seed),
|
64 |
+
).images[0]
|
65 |
+
|
66 |
+
output = (output * 255).round().astype("uint8")
|
67 |
+
output = cv2.cvtColor(output, cv2.COLOR_RGB2BGR)
|
68 |
+
return output
|
iopaint/model/plms_sampler.py
ADDED
@@ -0,0 +1,225 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# From: https://github.com/CompVis/latent-diffusion/blob/main/ldm/models/diffusion/plms.py
|
2 |
+
import torch
|
3 |
+
import numpy as np
|
4 |
+
from .utils import make_ddim_timesteps, make_ddim_sampling_parameters, noise_like
|
5 |
+
from tqdm import tqdm
|
6 |
+
|
7 |
+
|
8 |
+
class PLMSSampler(object):
|
9 |
+
def __init__(self, model, schedule="linear", **kwargs):
|
10 |
+
super().__init__()
|
11 |
+
self.model = model
|
12 |
+
self.ddpm_num_timesteps = model.num_timesteps
|
13 |
+
self.schedule = schedule
|
14 |
+
|
15 |
+
def register_buffer(self, name, attr):
|
16 |
+
setattr(self, name, attr)
|
17 |
+
|
18 |
+
def make_schedule(self, ddim_num_steps, ddim_discretize="uniform", ddim_eta=0., verbose=True):
|
19 |
+
if ddim_eta != 0:
|
20 |
+
raise ValueError('ddim_eta must be 0 for PLMS')
|
21 |
+
self.ddim_timesteps = make_ddim_timesteps(ddim_discr_method=ddim_discretize, num_ddim_timesteps=ddim_num_steps,
|
22 |
+
num_ddpm_timesteps=self.ddpm_num_timesteps, verbose=verbose)
|
23 |
+
alphas_cumprod = self.model.alphas_cumprod
|
24 |
+
assert alphas_cumprod.shape[0] == self.ddpm_num_timesteps, 'alphas have to be defined for each timestep'
|
25 |
+
to_torch = lambda x: x.clone().detach().to(torch.float32).to(self.model.device)
|
26 |
+
|
27 |
+
self.register_buffer('betas', to_torch(self.model.betas))
|
28 |
+
self.register_buffer('alphas_cumprod', to_torch(alphas_cumprod))
|
29 |
+
self.register_buffer('alphas_cumprod_prev', to_torch(self.model.alphas_cumprod_prev))
|
30 |
+
|
31 |
+
# calculations for diffusion q(x_t | x_{t-1}) and others
|
32 |
+
self.register_buffer('sqrt_alphas_cumprod', to_torch(np.sqrt(alphas_cumprod.cpu())))
|
33 |
+
self.register_buffer('sqrt_one_minus_alphas_cumprod', to_torch(np.sqrt(1. - alphas_cumprod.cpu())))
|
34 |
+
self.register_buffer('log_one_minus_alphas_cumprod', to_torch(np.log(1. - alphas_cumprod.cpu())))
|
35 |
+
self.register_buffer('sqrt_recip_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod.cpu())))
|
36 |
+
self.register_buffer('sqrt_recipm1_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod.cpu() - 1)))
|
37 |
+
|
38 |
+
# ddim sampling parameters
|
39 |
+
ddim_sigmas, ddim_alphas, ddim_alphas_prev = make_ddim_sampling_parameters(alphacums=alphas_cumprod.cpu(),
|
40 |
+
ddim_timesteps=self.ddim_timesteps,
|
41 |
+
eta=ddim_eta, verbose=verbose)
|
42 |
+
self.register_buffer('ddim_sigmas', ddim_sigmas)
|
43 |
+
self.register_buffer('ddim_alphas', ddim_alphas)
|
44 |
+
self.register_buffer('ddim_alphas_prev', ddim_alphas_prev)
|
45 |
+
self.register_buffer('ddim_sqrt_one_minus_alphas', np.sqrt(1. - ddim_alphas))
|
46 |
+
sigmas_for_original_sampling_steps = ddim_eta * torch.sqrt(
|
47 |
+
(1 - self.alphas_cumprod_prev) / (1 - self.alphas_cumprod) * (
|
48 |
+
1 - self.alphas_cumprod / self.alphas_cumprod_prev))
|
49 |
+
self.register_buffer('ddim_sigmas_for_original_num_steps', sigmas_for_original_sampling_steps)
|
50 |
+
|
51 |
+
@torch.no_grad()
|
52 |
+
def sample(self,
|
53 |
+
steps,
|
54 |
+
batch_size,
|
55 |
+
shape,
|
56 |
+
conditioning=None,
|
57 |
+
callback=None,
|
58 |
+
normals_sequence=None,
|
59 |
+
img_callback=None,
|
60 |
+
quantize_x0=False,
|
61 |
+
eta=0.,
|
62 |
+
mask=None,
|
63 |
+
x0=None,
|
64 |
+
temperature=1.,
|
65 |
+
noise_dropout=0.,
|
66 |
+
score_corrector=None,
|
67 |
+
corrector_kwargs=None,
|
68 |
+
verbose=False,
|
69 |
+
x_T=None,
|
70 |
+
log_every_t=100,
|
71 |
+
unconditional_guidance_scale=1.,
|
72 |
+
unconditional_conditioning=None,
|
73 |
+
# this has to come in the same format as the conditioning, # e.g. as encoded tokens, ...
|
74 |
+
**kwargs
|
75 |
+
):
|
76 |
+
if conditioning is not None:
|
77 |
+
if isinstance(conditioning, dict):
|
78 |
+
cbs = conditioning[list(conditioning.keys())[0]].shape[0]
|
79 |
+
if cbs != batch_size:
|
80 |
+
print(f"Warning: Got {cbs} conditionings but batch-size is {batch_size}")
|
81 |
+
else:
|
82 |
+
if conditioning.shape[0] != batch_size:
|
83 |
+
print(f"Warning: Got {conditioning.shape[0]} conditionings but batch-size is {batch_size}")
|
84 |
+
|
85 |
+
self.make_schedule(ddim_num_steps=steps, ddim_eta=eta, verbose=verbose)
|
86 |
+
# sampling
|
87 |
+
C, H, W = shape
|
88 |
+
size = (batch_size, C, H, W)
|
89 |
+
print(f'Data shape for PLMS sampling is {size}')
|
90 |
+
|
91 |
+
samples = self.plms_sampling(conditioning, size,
|
92 |
+
callback=callback,
|
93 |
+
img_callback=img_callback,
|
94 |
+
quantize_denoised=quantize_x0,
|
95 |
+
mask=mask, x0=x0,
|
96 |
+
ddim_use_original_steps=False,
|
97 |
+
noise_dropout=noise_dropout,
|
98 |
+
temperature=temperature,
|
99 |
+
score_corrector=score_corrector,
|
100 |
+
corrector_kwargs=corrector_kwargs,
|
101 |
+
x_T=x_T,
|
102 |
+
log_every_t=log_every_t,
|
103 |
+
unconditional_guidance_scale=unconditional_guidance_scale,
|
104 |
+
unconditional_conditioning=unconditional_conditioning,
|
105 |
+
)
|
106 |
+
return samples
|
107 |
+
|
108 |
+
@torch.no_grad()
|
109 |
+
def plms_sampling(self, cond, shape,
|
110 |
+
x_T=None, ddim_use_original_steps=False,
|
111 |
+
callback=None, timesteps=None, quantize_denoised=False,
|
112 |
+
mask=None, x0=None, img_callback=None, log_every_t=100,
|
113 |
+
temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
|
114 |
+
unconditional_guidance_scale=1., unconditional_conditioning=None, ):
|
115 |
+
device = self.model.betas.device
|
116 |
+
b = shape[0]
|
117 |
+
if x_T is None:
|
118 |
+
img = torch.randn(shape, device=device)
|
119 |
+
else:
|
120 |
+
img = x_T
|
121 |
+
|
122 |
+
if timesteps is None:
|
123 |
+
timesteps = self.ddpm_num_timesteps if ddim_use_original_steps else self.ddim_timesteps
|
124 |
+
elif timesteps is not None and not ddim_use_original_steps:
|
125 |
+
subset_end = int(min(timesteps / self.ddim_timesteps.shape[0], 1) * self.ddim_timesteps.shape[0]) - 1
|
126 |
+
timesteps = self.ddim_timesteps[:subset_end]
|
127 |
+
|
128 |
+
time_range = list(reversed(range(0, timesteps))) if ddim_use_original_steps else np.flip(timesteps)
|
129 |
+
total_steps = timesteps if ddim_use_original_steps else timesteps.shape[0]
|
130 |
+
print(f"Running PLMS Sampling with {total_steps} timesteps")
|
131 |
+
|
132 |
+
iterator = tqdm(time_range, desc='PLMS Sampler', total=total_steps)
|
133 |
+
old_eps = []
|
134 |
+
|
135 |
+
for i, step in enumerate(iterator):
|
136 |
+
index = total_steps - i - 1
|
137 |
+
ts = torch.full((b,), step, device=device, dtype=torch.long)
|
138 |
+
ts_next = torch.full((b,), time_range[min(i + 1, len(time_range) - 1)], device=device, dtype=torch.long)
|
139 |
+
|
140 |
+
if mask is not None:
|
141 |
+
assert x0 is not None
|
142 |
+
img_orig = self.model.q_sample(x0, ts) # TODO: deterministic forward pass?
|
143 |
+
img = img_orig * mask + (1. - mask) * img
|
144 |
+
|
145 |
+
outs = self.p_sample_plms(img, cond, ts, index=index, use_original_steps=ddim_use_original_steps,
|
146 |
+
quantize_denoised=quantize_denoised, temperature=temperature,
|
147 |
+
noise_dropout=noise_dropout, score_corrector=score_corrector,
|
148 |
+
corrector_kwargs=corrector_kwargs,
|
149 |
+
unconditional_guidance_scale=unconditional_guidance_scale,
|
150 |
+
unconditional_conditioning=unconditional_conditioning,
|
151 |
+
old_eps=old_eps, t_next=ts_next)
|
152 |
+
img, pred_x0, e_t = outs
|
153 |
+
old_eps.append(e_t)
|
154 |
+
if len(old_eps) >= 4:
|
155 |
+
old_eps.pop(0)
|
156 |
+
if callback: callback(i)
|
157 |
+
if img_callback: img_callback(pred_x0, i)
|
158 |
+
|
159 |
+
return img
|
160 |
+
|
161 |
+
@torch.no_grad()
|
162 |
+
def p_sample_plms(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False,
|
163 |
+
temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
|
164 |
+
unconditional_guidance_scale=1., unconditional_conditioning=None, old_eps=None, t_next=None):
|
165 |
+
b, *_, device = *x.shape, x.device
|
166 |
+
|
167 |
+
def get_model_output(x, t):
|
168 |
+
if unconditional_conditioning is None or unconditional_guidance_scale == 1.:
|
169 |
+
e_t = self.model.apply_model(x, t, c)
|
170 |
+
else:
|
171 |
+
x_in = torch.cat([x] * 2)
|
172 |
+
t_in = torch.cat([t] * 2)
|
173 |
+
c_in = torch.cat([unconditional_conditioning, c])
|
174 |
+
e_t_uncond, e_t = self.model.apply_model(x_in, t_in, c_in).chunk(2)
|
175 |
+
e_t = e_t_uncond + unconditional_guidance_scale * (e_t - e_t_uncond)
|
176 |
+
|
177 |
+
if score_corrector is not None:
|
178 |
+
assert self.model.parameterization == "eps"
|
179 |
+
e_t = score_corrector.modify_score(self.model, e_t, x, t, c, **corrector_kwargs)
|
180 |
+
|
181 |
+
return e_t
|
182 |
+
|
183 |
+
alphas = self.model.alphas_cumprod if use_original_steps else self.ddim_alphas
|
184 |
+
alphas_prev = self.model.alphas_cumprod_prev if use_original_steps else self.ddim_alphas_prev
|
185 |
+
sqrt_one_minus_alphas = self.model.sqrt_one_minus_alphas_cumprod if use_original_steps else self.ddim_sqrt_one_minus_alphas
|
186 |
+
sigmas = self.model.ddim_sigmas_for_original_num_steps if use_original_steps else self.ddim_sigmas
|
187 |
+
|
188 |
+
def get_x_prev_and_pred_x0(e_t, index):
|
189 |
+
# select parameters corresponding to the currently considered timestep
|
190 |
+
a_t = torch.full((b, 1, 1, 1), alphas[index], device=device)
|
191 |
+
a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device)
|
192 |
+
sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device)
|
193 |
+
sqrt_one_minus_at = torch.full((b, 1, 1, 1), sqrt_one_minus_alphas[index], device=device)
|
194 |
+
|
195 |
+
# current prediction for x_0
|
196 |
+
pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt()
|
197 |
+
if quantize_denoised:
|
198 |
+
pred_x0, _, *_ = self.model.first_stage_model.quantize(pred_x0)
|
199 |
+
# direction pointing to x_t
|
200 |
+
dir_xt = (1. - a_prev - sigma_t ** 2).sqrt() * e_t
|
201 |
+
noise = sigma_t * noise_like(x.shape, device, repeat_noise) * temperature
|
202 |
+
if noise_dropout > 0.:
|
203 |
+
noise = torch.nn.functional.dropout(noise, p=noise_dropout)
|
204 |
+
x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise
|
205 |
+
return x_prev, pred_x0
|
206 |
+
|
207 |
+
e_t = get_model_output(x, t)
|
208 |
+
if len(old_eps) == 0:
|
209 |
+
# Pseudo Improved Euler (2nd order)
|
210 |
+
x_prev, pred_x0 = get_x_prev_and_pred_x0(e_t, index)
|
211 |
+
e_t_next = get_model_output(x_prev, t_next)
|
212 |
+
e_t_prime = (e_t + e_t_next) / 2
|
213 |
+
elif len(old_eps) == 1:
|
214 |
+
# 2nd order Pseudo Linear Multistep (Adams-Bashforth)
|
215 |
+
e_t_prime = (3 * e_t - old_eps[-1]) / 2
|
216 |
+
elif len(old_eps) == 2:
|
217 |
+
# 3nd order Pseudo Linear Multistep (Adams-Bashforth)
|
218 |
+
e_t_prime = (23 * e_t - 16 * old_eps[-1] + 5 * old_eps[-2]) / 12
|
219 |
+
elif len(old_eps) >= 3:
|
220 |
+
# 4nd order Pseudo Linear Multistep (Adams-Bashforth)
|
221 |
+
e_t_prime = (55 * e_t - 59 * old_eps[-1] + 37 * old_eps[-2] - 9 * old_eps[-3]) / 24
|
222 |
+
|
223 |
+
x_prev, pred_x0 = get_x_prev_and_pred_x0(e_t_prime, index)
|
224 |
+
|
225 |
+
return x_prev, pred_x0, e_t
|
iopaint/model/power_paint/pipeline_powerpaint.py
ADDED
@@ -0,0 +1,1243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright 2023 The HuggingFace Team. All rights reserved.
|
2 |
+
#
|
3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4 |
+
# you may not use this file except in compliance with the License.
|
5 |
+
# You may obtain a copy of the License at
|
6 |
+
#
|
7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8 |
+
#
|
9 |
+
# Unless required by applicable law or agreed to in writing, software
|
10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12 |
+
# See the License for the specific language governing permissions and
|
13 |
+
# limitations under the License.
|
14 |
+
|
15 |
+
import inspect
|
16 |
+
from typing import Any, Callable, Dict, List, Optional, Union
|
17 |
+
|
18 |
+
import numpy as np
|
19 |
+
import PIL
|
20 |
+
import torch
|
21 |
+
from packaging import version
|
22 |
+
from transformers import CLIPImageProcessor, CLIPTextModel, CLIPTokenizer
|
23 |
+
from diffusers.configuration_utils import FrozenDict
|
24 |
+
from diffusers.image_processor import VaeImageProcessor
|
25 |
+
from diffusers.loaders import (
|
26 |
+
FromSingleFileMixin,
|
27 |
+
LoraLoaderMixin,
|
28 |
+
TextualInversionLoaderMixin,
|
29 |
+
)
|
30 |
+
from diffusers.models import (
|
31 |
+
AsymmetricAutoencoderKL,
|
32 |
+
AutoencoderKL,
|
33 |
+
UNet2DConditionModel,
|
34 |
+
)
|
35 |
+
from diffusers.schedulers import KarrasDiffusionSchedulers
|
36 |
+
from diffusers.utils import (
|
37 |
+
deprecate,
|
38 |
+
is_accelerate_available,
|
39 |
+
is_accelerate_version,
|
40 |
+
logging,
|
41 |
+
)
|
42 |
+
from diffusers.utils.torch_utils import randn_tensor
|
43 |
+
from diffusers.pipelines.pipeline_utils import DiffusionPipeline
|
44 |
+
from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput
|
45 |
+
from diffusers.pipelines.stable_diffusion.safety_checker import (
|
46 |
+
StableDiffusionSafetyChecker,
|
47 |
+
)
|
48 |
+
|
49 |
+
|
50 |
+
logger = logging.get_logger(__name__) # pylint: disable=invalid-name
|
51 |
+
|
52 |
+
|
53 |
+
def prepare_mask_and_masked_image(
|
54 |
+
image, mask, height, width, return_image: bool = False
|
55 |
+
):
|
56 |
+
"""
|
57 |
+
Prepares a pair (image, mask) to be consumed by the Stable Diffusion pipeline. This means that those inputs will be
|
58 |
+
converted to ``torch.Tensor`` with shapes ``batch x channels x height x width`` where ``channels`` is ``3`` for the
|
59 |
+
``image`` and ``1`` for the ``mask``.
|
60 |
+
|
61 |
+
The ``image`` will be converted to ``torch.float32`` and normalized to be in ``[-1, 1]``. The ``mask`` will be
|
62 |
+
binarized (``mask > 0.5``) and cast to ``torch.float32`` too.
|
63 |
+
|
64 |
+
Args:
|
65 |
+
image (Union[np.array, PIL.Image, torch.Tensor]): The image to inpaint.
|
66 |
+
It can be a ``PIL.Image``, or a ``height x width x 3`` ``np.array`` or a ``channels x height x width``
|
67 |
+
``torch.Tensor`` or a ``batch x channels x height x width`` ``torch.Tensor``.
|
68 |
+
mask (_type_): The mask to apply to the image, i.e. regions to inpaint.
|
69 |
+
It can be a ``PIL.Image``, or a ``height x width`` ``np.array`` or a ``1 x height x width``
|
70 |
+
``torch.Tensor`` or a ``batch x 1 x height x width`` ``torch.Tensor``.
|
71 |
+
|
72 |
+
|
73 |
+
Raises:
|
74 |
+
ValueError: ``torch.Tensor`` images should be in the ``[-1, 1]`` range. ValueError: ``torch.Tensor`` mask
|
75 |
+
should be in the ``[0, 1]`` range. ValueError: ``mask`` and ``image`` should have the same spatial dimensions.
|
76 |
+
TypeError: ``mask`` is a ``torch.Tensor`` but ``image`` is not
|
77 |
+
(ot the other way around).
|
78 |
+
|
79 |
+
Returns:
|
80 |
+
tuple[torch.Tensor]: The pair (mask, masked_image) as ``torch.Tensor`` with 4
|
81 |
+
dimensions: ``batch x channels x height x width``.
|
82 |
+
"""
|
83 |
+
|
84 |
+
if image is None:
|
85 |
+
raise ValueError("`image` input cannot be undefined.")
|
86 |
+
|
87 |
+
if mask is None:
|
88 |
+
raise ValueError("`mask_image` input cannot be undefined.")
|
89 |
+
|
90 |
+
if isinstance(image, torch.Tensor):
|
91 |
+
if not isinstance(mask, torch.Tensor):
|
92 |
+
raise TypeError(
|
93 |
+
f"`image` is a torch.Tensor but `mask` (type: {type(mask)} is not"
|
94 |
+
)
|
95 |
+
|
96 |
+
# Batch single image
|
97 |
+
if image.ndim == 3:
|
98 |
+
assert (
|
99 |
+
image.shape[0] == 3
|
100 |
+
), "Image outside a batch should be of shape (3, H, W)"
|
101 |
+
image = image.unsqueeze(0)
|
102 |
+
|
103 |
+
# Batch and add channel dim for single mask
|
104 |
+
if mask.ndim == 2:
|
105 |
+
mask = mask.unsqueeze(0).unsqueeze(0)
|
106 |
+
|
107 |
+
# Batch single mask or add channel dim
|
108 |
+
if mask.ndim == 3:
|
109 |
+
# Single batched mask, no channel dim or single mask not batched but channel dim
|
110 |
+
if mask.shape[0] == 1:
|
111 |
+
mask = mask.unsqueeze(0)
|
112 |
+
|
113 |
+
# Batched masks no channel dim
|
114 |
+
else:
|
115 |
+
mask = mask.unsqueeze(1)
|
116 |
+
|
117 |
+
assert (
|
118 |
+
image.ndim == 4 and mask.ndim == 4
|
119 |
+
), "Image and Mask must have 4 dimensions"
|
120 |
+
assert (
|
121 |
+
image.shape[-2:] == mask.shape[-2:]
|
122 |
+
), "Image and Mask must have the same spatial dimensions"
|
123 |
+
assert (
|
124 |
+
image.shape[0] == mask.shape[0]
|
125 |
+
), "Image and Mask must have the same batch size"
|
126 |
+
|
127 |
+
# Check image is in [-1, 1]
|
128 |
+
if image.min() < -1 or image.max() > 1:
|
129 |
+
raise ValueError("Image should be in [-1, 1] range")
|
130 |
+
|
131 |
+
# Check mask is in [0, 1]
|
132 |
+
if mask.min() < 0 or mask.max() > 1:
|
133 |
+
raise ValueError("Mask should be in [0, 1] range")
|
134 |
+
|
135 |
+
# Binarize mask
|
136 |
+
mask[mask < 0.5] = 0
|
137 |
+
mask[mask >= 0.5] = 1
|
138 |
+
|
139 |
+
# Image as float32
|
140 |
+
image = image.to(dtype=torch.float32)
|
141 |
+
elif isinstance(mask, torch.Tensor):
|
142 |
+
raise TypeError(
|
143 |
+
f"`mask` is a torch.Tensor but `image` (type: {type(image)} is not"
|
144 |
+
)
|
145 |
+
else:
|
146 |
+
# preprocess image
|
147 |
+
if isinstance(image, (PIL.Image.Image, np.ndarray)):
|
148 |
+
image = [image]
|
149 |
+
if isinstance(image, list) and isinstance(image[0], PIL.Image.Image):
|
150 |
+
# resize all images w.r.t passed height an width
|
151 |
+
image = [
|
152 |
+
i.resize((width, height), resample=PIL.Image.LANCZOS) for i in image
|
153 |
+
]
|
154 |
+
image = [np.array(i.convert("RGB"))[None, :] for i in image]
|
155 |
+
image = np.concatenate(image, axis=0)
|
156 |
+
elif isinstance(image, list) and isinstance(image[0], np.ndarray):
|
157 |
+
image = np.concatenate([i[None, :] for i in image], axis=0)
|
158 |
+
|
159 |
+
image = image.transpose(0, 3, 1, 2)
|
160 |
+
image = torch.from_numpy(image).to(dtype=torch.float32) / 127.5 - 1.0
|
161 |
+
|
162 |
+
# preprocess mask
|
163 |
+
if isinstance(mask, (PIL.Image.Image, np.ndarray)):
|
164 |
+
mask = [mask]
|
165 |
+
|
166 |
+
if isinstance(mask, list) and isinstance(mask[0], PIL.Image.Image):
|
167 |
+
mask = [i.resize((width, height), resample=PIL.Image.LANCZOS) for i in mask]
|
168 |
+
mask = np.concatenate(
|
169 |
+
[np.array(m.convert("L"))[None, None, :] for m in mask], axis=0
|
170 |
+
)
|
171 |
+
mask = mask.astype(np.float32) / 255.0
|
172 |
+
elif isinstance(mask, list) and isinstance(mask[0], np.ndarray):
|
173 |
+
mask = np.concatenate([m[None, None, :] for m in mask], axis=0)
|
174 |
+
|
175 |
+
mask[mask < 0.5] = 0
|
176 |
+
mask[mask >= 0.5] = 1
|
177 |
+
mask = torch.from_numpy(mask)
|
178 |
+
|
179 |
+
masked_image = image * (mask < 0.5)
|
180 |
+
|
181 |
+
# n.b. ensure backwards compatibility as old function does not return image
|
182 |
+
if return_image:
|
183 |
+
return mask, masked_image, image
|
184 |
+
|
185 |
+
return mask, masked_image
|
186 |
+
|
187 |
+
|
188 |
+
class StableDiffusionInpaintPipeline(
|
189 |
+
DiffusionPipeline, TextualInversionLoaderMixin, LoraLoaderMixin, FromSingleFileMixin
|
190 |
+
):
|
191 |
+
r"""
|
192 |
+
Pipeline for text-guided image inpainting using Stable Diffusion.
|
193 |
+
|
194 |
+
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
195 |
+
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
196 |
+
|
197 |
+
The pipeline also inherits the following loading methods:
|
198 |
+
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
199 |
+
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
200 |
+
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
201 |
+
|
202 |
+
Args:
|
203 |
+
vae ([`AutoencoderKL`, `AsymmetricAutoencoderKL`]):
|
204 |
+
Variational Auto-Encoder (VAE) Model to encode and decode images to and from latent representations.
|
205 |
+
text_encoder ([`CLIPTextModel`]):
|
206 |
+
Frozen text-encoder ([clip-vit-large-patch14](https://huggingface.co/openai/clip-vit-large-patch14)).
|
207 |
+
tokenizer ([`~transformers.CLIPTokenizer`]):
|
208 |
+
A `CLIPTokenizer` to tokenize text.
|
209 |
+
unet ([`UNet2DConditionModel`]):
|
210 |
+
A `UNet2DConditionModel` to denoise the encoded image latents.
|
211 |
+
scheduler ([`SchedulerMixin`]):
|
212 |
+
A scheduler to be used in combination with `unet` to denoise the encoded image latents. Can be one of
|
213 |
+
[`DDIMScheduler`], [`LMSDiscreteScheduler`], or [`PNDMScheduler`].
|
214 |
+
safety_checker ([`StableDiffusionSafetyChecker`]):
|
215 |
+
Classification module that estimates whether generated images could be considered offensive or harmful.
|
216 |
+
Please refer to the [model card](https://huggingface.co/runwayml/stable-diffusion-v1-5) for more details
|
217 |
+
about a model's potential harms.
|
218 |
+
feature_extractor ([`~transformers.CLIPImageProcessor`]):
|
219 |
+
A `CLIPImageProcessor` to extract features from generated images; used as inputs to the `safety_checker`.
|
220 |
+
"""
|
221 |
+
_optional_components = ["safety_checker", "feature_extractor"]
|
222 |
+
|
223 |
+
def __init__(
|
224 |
+
self,
|
225 |
+
vae: Union[AutoencoderKL, AsymmetricAutoencoderKL],
|
226 |
+
text_encoder: CLIPTextModel,
|
227 |
+
tokenizer: CLIPTokenizer,
|
228 |
+
unet: UNet2DConditionModel,
|
229 |
+
scheduler: KarrasDiffusionSchedulers,
|
230 |
+
safety_checker: StableDiffusionSafetyChecker,
|
231 |
+
feature_extractor: CLIPImageProcessor,
|
232 |
+
requires_safety_checker: bool = True,
|
233 |
+
):
|
234 |
+
super().__init__()
|
235 |
+
|
236 |
+
if (
|
237 |
+
hasattr(scheduler.config, "steps_offset")
|
238 |
+
and scheduler.config.steps_offset != 1
|
239 |
+
):
|
240 |
+
deprecation_message = (
|
241 |
+
f"The configuration file of this scheduler: {scheduler} is outdated. `steps_offset`"
|
242 |
+
f" should be set to 1 instead of {scheduler.config.steps_offset}. Please make sure "
|
243 |
+
"to update the config accordingly as leaving `steps_offset` might led to incorrect results"
|
244 |
+
" in future versions. If you have downloaded this checkpoint from the Hugging Face Hub,"
|
245 |
+
" it would be very nice if you could open a Pull request for the `scheduler/scheduler_config.json`"
|
246 |
+
" file"
|
247 |
+
)
|
248 |
+
deprecate(
|
249 |
+
"steps_offset!=1", "1.0.0", deprecation_message, standard_warn=False
|
250 |
+
)
|
251 |
+
new_config = dict(scheduler.config)
|
252 |
+
new_config["steps_offset"] = 1
|
253 |
+
scheduler._internal_dict = FrozenDict(new_config)
|
254 |
+
|
255 |
+
if (
|
256 |
+
hasattr(scheduler.config, "skip_prk_steps")
|
257 |
+
and scheduler.config.skip_prk_steps is False
|
258 |
+
):
|
259 |
+
deprecation_message = (
|
260 |
+
f"The configuration file of this scheduler: {scheduler} has not set the configuration"
|
261 |
+
" `skip_prk_steps`. `skip_prk_steps` should be set to True in the configuration file. Please make"
|
262 |
+
" sure to update the config accordingly as not setting `skip_prk_steps` in the config might lead to"
|
263 |
+
" incorrect results in future versions. If you have downloaded this checkpoint from the Hugging Face"
|
264 |
+
" Hub, it would be very nice if you could open a Pull request for the"
|
265 |
+
" `scheduler/scheduler_config.json` file"
|
266 |
+
)
|
267 |
+
deprecate(
|
268 |
+
"skip_prk_steps not set",
|
269 |
+
"1.0.0",
|
270 |
+
deprecation_message,
|
271 |
+
standard_warn=False,
|
272 |
+
)
|
273 |
+
new_config = dict(scheduler.config)
|
274 |
+
new_config["skip_prk_steps"] = True
|
275 |
+
scheduler._internal_dict = FrozenDict(new_config)
|
276 |
+
|
277 |
+
if safety_checker is None and requires_safety_checker:
|
278 |
+
logger.warning(
|
279 |
+
f"You have disabled the safety checker for {self.__class__} by passing `safety_checker=None`. Ensure"
|
280 |
+
" that you abide to the conditions of the Stable Diffusion license and do not expose unfiltered"
|
281 |
+
" results in services or applications open to the public. Both the diffusers team and Hugging Face"
|
282 |
+
" strongly recommend to keep the safety filter enabled in all public facing circumstances, disabling"
|
283 |
+
" it only for use-cases that involve analyzing network behavior or auditing its results. For more"
|
284 |
+
" information, please have a look at https://github.com/huggingface/diffusers/pull/254 ."
|
285 |
+
)
|
286 |
+
|
287 |
+
if safety_checker is not None and feature_extractor is None:
|
288 |
+
raise ValueError(
|
289 |
+
"Make sure to define a feature extractor when loading {self.__class__} if you want to use the safety"
|
290 |
+
" checker. If you do not want to use the safety checker, you can pass `'safety_checker=None'` instead."
|
291 |
+
)
|
292 |
+
|
293 |
+
is_unet_version_less_0_9_0 = hasattr(
|
294 |
+
unet.config, "_diffusers_version"
|
295 |
+
) and version.parse(
|
296 |
+
version.parse(unet.config._diffusers_version).base_version
|
297 |
+
) < version.parse(
|
298 |
+
"0.9.0.dev0"
|
299 |
+
)
|
300 |
+
is_unet_sample_size_less_64 = (
|
301 |
+
hasattr(unet.config, "sample_size") and unet.config.sample_size < 64
|
302 |
+
)
|
303 |
+
if is_unet_version_less_0_9_0 and is_unet_sample_size_less_64:
|
304 |
+
deprecation_message = (
|
305 |
+
"The configuration file of the unet has set the default `sample_size` to smaller than"
|
306 |
+
" 64 which seems highly unlikely .If you're checkpoint is a fine-tuned version of any of the"
|
307 |
+
" following: \n- CompVis/stable-diffusion-v1-4 \n- CompVis/stable-diffusion-v1-3 \n-"
|
308 |
+
" CompVis/stable-diffusion-v1-2 \n- CompVis/stable-diffusion-v1-1 \n- runwayml/stable-diffusion-v1-5"
|
309 |
+
" \n- runwayml/stable-diffusion-inpainting \n you should change 'sample_size' to 64 in the"
|
310 |
+
" configuration file. Please make sure to update the config accordingly as leaving `sample_size=32`"
|
311 |
+
" in the config might lead to incorrect results in future versions. If you have downloaded this"
|
312 |
+
" checkpoint from the Hugging Face Hub, it would be very nice if you could open a Pull request for"
|
313 |
+
" the `unet/config.json` file"
|
314 |
+
)
|
315 |
+
deprecate(
|
316 |
+
"sample_size<64", "1.0.0", deprecation_message, standard_warn=False
|
317 |
+
)
|
318 |
+
new_config = dict(unet.config)
|
319 |
+
new_config["sample_size"] = 64
|
320 |
+
unet._internal_dict = FrozenDict(new_config)
|
321 |
+
|
322 |
+
# Check shapes, assume num_channels_latents == 4, num_channels_mask == 1, num_channels_masked == 4
|
323 |
+
if unet.config.in_channels != 9:
|
324 |
+
logger.info(
|
325 |
+
f"You have loaded a UNet with {unet.config.in_channels} input channels which."
|
326 |
+
)
|
327 |
+
|
328 |
+
self.register_modules(
|
329 |
+
vae=vae,
|
330 |
+
text_encoder=text_encoder,
|
331 |
+
tokenizer=tokenizer,
|
332 |
+
unet=unet,
|
333 |
+
scheduler=scheduler,
|
334 |
+
safety_checker=safety_checker,
|
335 |
+
feature_extractor=feature_extractor,
|
336 |
+
)
|
337 |
+
self.vae_scale_factor = 2 ** (len(self.vae.config.block_out_channels) - 1)
|
338 |
+
self.image_processor = VaeImageProcessor(vae_scale_factor=self.vae_scale_factor)
|
339 |
+
self.register_to_config(requires_safety_checker=requires_safety_checker)
|
340 |
+
|
341 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.enable_model_cpu_offload
|
342 |
+
def enable_model_cpu_offload(self, gpu_id=0):
|
343 |
+
r"""
|
344 |
+
Offload all models to CPU to reduce memory usage with a low impact on performance. Moves one whole model at a
|
345 |
+
time to the GPU when its `forward` method is called, and the model remains in GPU until the next model runs.
|
346 |
+
Memory savings are lower than using `enable_sequential_cpu_offload`, but performance is much better due to the
|
347 |
+
iterative execution of the `unet`.
|
348 |
+
"""
|
349 |
+
if is_accelerate_available() and is_accelerate_version(">=", "0.17.0.dev0"):
|
350 |
+
from accelerate import cpu_offload_with_hook
|
351 |
+
else:
|
352 |
+
raise ImportError(
|
353 |
+
"`enable_model_cpu_offload` requires `accelerate v0.17.0` or higher."
|
354 |
+
)
|
355 |
+
|
356 |
+
device = torch.device(f"cuda:{gpu_id}")
|
357 |
+
|
358 |
+
if self.device.type != "cpu":
|
359 |
+
self.to("cpu", silence_dtype_warnings=True)
|
360 |
+
torch.cuda.empty_cache() # otherwise we don't see the memory savings (but they probably exist)
|
361 |
+
|
362 |
+
hook = None
|
363 |
+
for cpu_offloaded_model in [self.text_encoder, self.unet, self.vae]:
|
364 |
+
_, hook = cpu_offload_with_hook(
|
365 |
+
cpu_offloaded_model, device, prev_module_hook=hook
|
366 |
+
)
|
367 |
+
|
368 |
+
if self.safety_checker is not None:
|
369 |
+
_, hook = cpu_offload_with_hook(
|
370 |
+
self.safety_checker, device, prev_module_hook=hook
|
371 |
+
)
|
372 |
+
|
373 |
+
# We'll offload the last model manually.
|
374 |
+
self.final_offload_hook = hook
|
375 |
+
|
376 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline._encode_prompt
|
377 |
+
def _encode_prompt(
|
378 |
+
self,
|
379 |
+
promptA,
|
380 |
+
promptB,
|
381 |
+
t,
|
382 |
+
device,
|
383 |
+
num_images_per_prompt,
|
384 |
+
do_classifier_free_guidance,
|
385 |
+
negative_promptA=None,
|
386 |
+
negative_promptB=None,
|
387 |
+
t_nag=None,
|
388 |
+
prompt_embeds: Optional[torch.FloatTensor] = None,
|
389 |
+
negative_prompt_embeds: Optional[torch.FloatTensor] = None,
|
390 |
+
lora_scale: Optional[float] = None,
|
391 |
+
):
|
392 |
+
r"""
|
393 |
+
Encodes the prompt into text encoder hidden states.
|
394 |
+
|
395 |
+
Args:
|
396 |
+
prompt (`str` or `List[str]`, *optional*):
|
397 |
+
prompt to be encoded
|
398 |
+
device: (`torch.device`):
|
399 |
+
torch device
|
400 |
+
num_images_per_prompt (`int`):
|
401 |
+
number of images that should be generated per prompt
|
402 |
+
do_classifier_free_guidance (`bool`):
|
403 |
+
whether to use classifier free guidance or not
|
404 |
+
negative_prompt (`str` or `List[str]`, *optional*):
|
405 |
+
The prompt or prompts not to guide the image generation. If not defined, one has to pass
|
406 |
+
`negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is
|
407 |
+
less than `1`).
|
408 |
+
prompt_embeds (`torch.FloatTensor`, *optional*):
|
409 |
+
Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not
|
410 |
+
provided, text embeddings will be generated from `prompt` input argument.
|
411 |
+
negative_prompt_embeds (`torch.FloatTensor`, *optional*):
|
412 |
+
Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt
|
413 |
+
weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input
|
414 |
+
argument.
|
415 |
+
lora_scale (`float`, *optional*):
|
416 |
+
A lora scale that will be applied to all LoRA layers of the text encoder if LoRA layers are loaded.
|
417 |
+
"""
|
418 |
+
# set lora scale so that monkey patched LoRA
|
419 |
+
# function of text encoder can correctly access it
|
420 |
+
if lora_scale is not None and isinstance(self, LoraLoaderMixin):
|
421 |
+
self._lora_scale = lora_scale
|
422 |
+
|
423 |
+
prompt = promptA
|
424 |
+
negative_prompt = negative_promptA
|
425 |
+
|
426 |
+
if promptA is not None and isinstance(promptA, str):
|
427 |
+
batch_size = 1
|
428 |
+
elif promptA is not None and isinstance(promptA, list):
|
429 |
+
batch_size = len(promptA)
|
430 |
+
else:
|
431 |
+
batch_size = prompt_embeds.shape[0]
|
432 |
+
|
433 |
+
if prompt_embeds is None:
|
434 |
+
# textual inversion: procecss multi-vector tokens if necessary
|
435 |
+
if isinstance(self, TextualInversionLoaderMixin):
|
436 |
+
promptA = self.maybe_convert_prompt(promptA, self.tokenizer)
|
437 |
+
|
438 |
+
text_inputsA = self.tokenizer(
|
439 |
+
promptA,
|
440 |
+
padding="max_length",
|
441 |
+
max_length=self.tokenizer.model_max_length,
|
442 |
+
truncation=True,
|
443 |
+
return_tensors="pt",
|
444 |
+
)
|
445 |
+
text_inputsB = self.tokenizer(
|
446 |
+
promptB,
|
447 |
+
padding="max_length",
|
448 |
+
max_length=self.tokenizer.model_max_length,
|
449 |
+
truncation=True,
|
450 |
+
return_tensors="pt",
|
451 |
+
)
|
452 |
+
text_input_idsA = text_inputsA.input_ids
|
453 |
+
text_input_idsB = text_inputsB.input_ids
|
454 |
+
untruncated_ids = self.tokenizer(
|
455 |
+
promptA, padding="longest", return_tensors="pt"
|
456 |
+
).input_ids
|
457 |
+
|
458 |
+
if untruncated_ids.shape[-1] >= text_input_idsA.shape[
|
459 |
+
-1
|
460 |
+
] and not torch.equal(text_input_idsA, untruncated_ids):
|
461 |
+
removed_text = self.tokenizer.batch_decode(
|
462 |
+
untruncated_ids[:, self.tokenizer.model_max_length - 1 : -1]
|
463 |
+
)
|
464 |
+
logger.warning(
|
465 |
+
"The following part of your input was truncated because CLIP can only handle sequences up to"
|
466 |
+
f" {self.tokenizer.model_max_length} tokens: {removed_text}"
|
467 |
+
)
|
468 |
+
|
469 |
+
if (
|
470 |
+
hasattr(self.text_encoder.config, "use_attention_mask")
|
471 |
+
and self.text_encoder.config.use_attention_mask
|
472 |
+
):
|
473 |
+
attention_mask = text_inputsA.attention_mask.to(device)
|
474 |
+
else:
|
475 |
+
attention_mask = None
|
476 |
+
|
477 |
+
# print("text_input_idsA: ",text_input_idsA)
|
478 |
+
# print("text_input_idsB: ",text_input_idsB)
|
479 |
+
# print('t: ',t)
|
480 |
+
|
481 |
+
prompt_embedsA = self.text_encoder(
|
482 |
+
text_input_idsA.to(device),
|
483 |
+
attention_mask=attention_mask,
|
484 |
+
)
|
485 |
+
prompt_embedsA = prompt_embedsA[0]
|
486 |
+
|
487 |
+
prompt_embedsB = self.text_encoder(
|
488 |
+
text_input_idsB.to(device),
|
489 |
+
attention_mask=attention_mask,
|
490 |
+
)
|
491 |
+
prompt_embedsB = prompt_embedsB[0]
|
492 |
+
prompt_embeds = prompt_embedsA * (t) + (1 - t) * prompt_embedsB
|
493 |
+
# print("prompt_embeds: ",prompt_embeds)
|
494 |
+
|
495 |
+
if self.text_encoder is not None:
|
496 |
+
prompt_embeds_dtype = self.text_encoder.dtype
|
497 |
+
elif self.unet is not None:
|
498 |
+
prompt_embeds_dtype = self.unet.dtype
|
499 |
+
else:
|
500 |
+
prompt_embeds_dtype = prompt_embeds.dtype
|
501 |
+
|
502 |
+
prompt_embeds = prompt_embeds.to(dtype=prompt_embeds_dtype, device=device)
|
503 |
+
|
504 |
+
bs_embed, seq_len, _ = prompt_embeds.shape
|
505 |
+
# duplicate text embeddings for each generation per prompt, using mps friendly method
|
506 |
+
prompt_embeds = prompt_embeds.repeat(1, num_images_per_prompt, 1)
|
507 |
+
prompt_embeds = prompt_embeds.view(
|
508 |
+
bs_embed * num_images_per_prompt, seq_len, -1
|
509 |
+
)
|
510 |
+
|
511 |
+
# get unconditional embeddings for classifier free guidance
|
512 |
+
if do_classifier_free_guidance and negative_prompt_embeds is None:
|
513 |
+
uncond_tokensA: List[str]
|
514 |
+
uncond_tokensB: List[str]
|
515 |
+
if negative_prompt is None:
|
516 |
+
uncond_tokensA = [""] * batch_size
|
517 |
+
uncond_tokensB = [""] * batch_size
|
518 |
+
elif prompt is not None and type(prompt) is not type(negative_prompt):
|
519 |
+
raise TypeError(
|
520 |
+
f"`negative_prompt` should be the same type to `prompt`, but got {type(negative_prompt)} !="
|
521 |
+
f" {type(prompt)}."
|
522 |
+
)
|
523 |
+
elif isinstance(negative_prompt, str):
|
524 |
+
uncond_tokensA = [negative_promptA]
|
525 |
+
uncond_tokensB = [negative_promptB]
|
526 |
+
elif batch_size != len(negative_prompt):
|
527 |
+
raise ValueError(
|
528 |
+
f"`negative_prompt`: {negative_prompt} has batch size {len(negative_prompt)}, but `prompt`:"
|
529 |
+
f" {prompt} has batch size {batch_size}. Please make sure that passed `negative_prompt` matches"
|
530 |
+
" the batch size of `prompt`."
|
531 |
+
)
|
532 |
+
else:
|
533 |
+
uncond_tokensA = negative_promptA
|
534 |
+
uncond_tokensB = negative_promptB
|
535 |
+
|
536 |
+
# textual inversion: procecss multi-vector tokens if necessary
|
537 |
+
if isinstance(self, TextualInversionLoaderMixin):
|
538 |
+
uncond_tokensA = self.maybe_convert_prompt(
|
539 |
+
uncond_tokensA, self.tokenizer
|
540 |
+
)
|
541 |
+
uncond_tokensB = self.maybe_convert_prompt(
|
542 |
+
uncond_tokensB, self.tokenizer
|
543 |
+
)
|
544 |
+
|
545 |
+
max_length = prompt_embeds.shape[1]
|
546 |
+
uncond_inputA = self.tokenizer(
|
547 |
+
uncond_tokensA,
|
548 |
+
padding="max_length",
|
549 |
+
max_length=max_length,
|
550 |
+
truncation=True,
|
551 |
+
return_tensors="pt",
|
552 |
+
)
|
553 |
+
uncond_inputB = self.tokenizer(
|
554 |
+
uncond_tokensB,
|
555 |
+
padding="max_length",
|
556 |
+
max_length=max_length,
|
557 |
+
truncation=True,
|
558 |
+
return_tensors="pt",
|
559 |
+
)
|
560 |
+
|
561 |
+
if (
|
562 |
+
hasattr(self.text_encoder.config, "use_attention_mask")
|
563 |
+
and self.text_encoder.config.use_attention_mask
|
564 |
+
):
|
565 |
+
attention_mask = uncond_inputA.attention_mask.to(device)
|
566 |
+
else:
|
567 |
+
attention_mask = None
|
568 |
+
|
569 |
+
negative_prompt_embedsA = self.text_encoder(
|
570 |
+
uncond_inputA.input_ids.to(device),
|
571 |
+
attention_mask=attention_mask,
|
572 |
+
)
|
573 |
+
negative_prompt_embedsB = self.text_encoder(
|
574 |
+
uncond_inputB.input_ids.to(device),
|
575 |
+
attention_mask=attention_mask,
|
576 |
+
)
|
577 |
+
negative_prompt_embeds = (
|
578 |
+
negative_prompt_embedsA[0] * (t_nag)
|
579 |
+
+ (1 - t_nag) * negative_prompt_embedsB[0]
|
580 |
+
)
|
581 |
+
|
582 |
+
# negative_prompt_embeds = negative_prompt_embeds[0]
|
583 |
+
|
584 |
+
if do_classifier_free_guidance:
|
585 |
+
# duplicate unconditional embeddings for each generation per prompt, using mps friendly method
|
586 |
+
seq_len = negative_prompt_embeds.shape[1]
|
587 |
+
|
588 |
+
negative_prompt_embeds = negative_prompt_embeds.to(
|
589 |
+
dtype=prompt_embeds_dtype, device=device
|
590 |
+
)
|
591 |
+
|
592 |
+
negative_prompt_embeds = negative_prompt_embeds.repeat(
|
593 |
+
1, num_images_per_prompt, 1
|
594 |
+
)
|
595 |
+
negative_prompt_embeds = negative_prompt_embeds.view(
|
596 |
+
batch_size * num_images_per_prompt, seq_len, -1
|
597 |
+
)
|
598 |
+
|
599 |
+
# For classifier free guidance, we need to do two forward passes.
|
600 |
+
# Here we concatenate the unconditional and text embeddings into a single batch
|
601 |
+
# to avoid doing two forward passes
|
602 |
+
# print("prompt_embeds: ",prompt_embeds)
|
603 |
+
prompt_embeds = torch.cat([negative_prompt_embeds, prompt_embeds])
|
604 |
+
|
605 |
+
return prompt_embeds
|
606 |
+
|
607 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.run_safety_checker
|
608 |
+
def run_safety_checker(self, image, device, dtype):
|
609 |
+
if self.safety_checker is None:
|
610 |
+
has_nsfw_concept = None
|
611 |
+
else:
|
612 |
+
if torch.is_tensor(image):
|
613 |
+
feature_extractor_input = self.image_processor.postprocess(
|
614 |
+
image, output_type="pil"
|
615 |
+
)
|
616 |
+
else:
|
617 |
+
feature_extractor_input = self.image_processor.numpy_to_pil(image)
|
618 |
+
safety_checker_input = self.feature_extractor(
|
619 |
+
feature_extractor_input, return_tensors="pt"
|
620 |
+
).to(device)
|
621 |
+
image, has_nsfw_concept = self.safety_checker(
|
622 |
+
images=image, clip_input=safety_checker_input.pixel_values.to(dtype)
|
623 |
+
)
|
624 |
+
return image, has_nsfw_concept
|
625 |
+
|
626 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.prepare_extra_step_kwargs
|
627 |
+
def prepare_extra_step_kwargs(self, generator, eta):
|
628 |
+
# prepare extra kwargs for the scheduler step, since not all schedulers have the same signature
|
629 |
+
# eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers.
|
630 |
+
# eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502
|
631 |
+
# and should be between [0, 1]
|
632 |
+
|
633 |
+
accepts_eta = "eta" in set(
|
634 |
+
inspect.signature(self.scheduler.step).parameters.keys()
|
635 |
+
)
|
636 |
+
extra_step_kwargs = {}
|
637 |
+
if accepts_eta:
|
638 |
+
extra_step_kwargs["eta"] = eta
|
639 |
+
|
640 |
+
# check if the scheduler accepts generator
|
641 |
+
accepts_generator = "generator" in set(
|
642 |
+
inspect.signature(self.scheduler.step).parameters.keys()
|
643 |
+
)
|
644 |
+
if accepts_generator:
|
645 |
+
extra_step_kwargs["generator"] = generator
|
646 |
+
return extra_step_kwargs
|
647 |
+
|
648 |
+
def check_inputs(
|
649 |
+
self,
|
650 |
+
prompt,
|
651 |
+
height,
|
652 |
+
width,
|
653 |
+
strength,
|
654 |
+
callback_steps,
|
655 |
+
negative_prompt=None,
|
656 |
+
prompt_embeds=None,
|
657 |
+
negative_prompt_embeds=None,
|
658 |
+
):
|
659 |
+
if strength < 0 or strength > 1:
|
660 |
+
raise ValueError(
|
661 |
+
f"The value of strength should in [0.0, 1.0] but is {strength}"
|
662 |
+
)
|
663 |
+
|
664 |
+
if height % 8 != 0 or width % 8 != 0:
|
665 |
+
raise ValueError(
|
666 |
+
f"`height` and `width` have to be divisible by 8 but are {height} and {width}."
|
667 |
+
)
|
668 |
+
|
669 |
+
if (callback_steps is None) or (
|
670 |
+
callback_steps is not None
|
671 |
+
and (not isinstance(callback_steps, int) or callback_steps <= 0)
|
672 |
+
):
|
673 |
+
raise ValueError(
|
674 |
+
f"`callback_steps` has to be a positive integer but is {callback_steps} of type"
|
675 |
+
f" {type(callback_steps)}."
|
676 |
+
)
|
677 |
+
|
678 |
+
if prompt is not None and prompt_embeds is not None:
|
679 |
+
raise ValueError(
|
680 |
+
f"Cannot forward both `prompt`: {prompt} and `prompt_embeds`: {prompt_embeds}. Please make sure to"
|
681 |
+
" only forward one of the two."
|
682 |
+
)
|
683 |
+
elif prompt is None and prompt_embeds is None:
|
684 |
+
raise ValueError(
|
685 |
+
"Provide either `prompt` or `prompt_embeds`. Cannot leave both `prompt` and `prompt_embeds` undefined."
|
686 |
+
)
|
687 |
+
elif prompt is not None and (
|
688 |
+
not isinstance(prompt, str) and not isinstance(prompt, list)
|
689 |
+
):
|
690 |
+
raise ValueError(
|
691 |
+
f"`prompt` has to be of type `str` or `list` but is {type(prompt)}"
|
692 |
+
)
|
693 |
+
|
694 |
+
if negative_prompt is not None and negative_prompt_embeds is not None:
|
695 |
+
raise ValueError(
|
696 |
+
f"Cannot forward both `negative_prompt`: {negative_prompt} and `negative_prompt_embeds`:"
|
697 |
+
f" {negative_prompt_embeds}. Please make sure to only forward one of the two."
|
698 |
+
)
|
699 |
+
|
700 |
+
if prompt_embeds is not None and negative_prompt_embeds is not None:
|
701 |
+
if prompt_embeds.shape != negative_prompt_embeds.shape:
|
702 |
+
raise ValueError(
|
703 |
+
"`prompt_embeds` and `negative_prompt_embeds` must have the same shape when passed directly, but"
|
704 |
+
f" got: `prompt_embeds` {prompt_embeds.shape} != `negative_prompt_embeds`"
|
705 |
+
f" {negative_prompt_embeds.shape}."
|
706 |
+
)
|
707 |
+
|
708 |
+
def prepare_latents(
|
709 |
+
self,
|
710 |
+
batch_size,
|
711 |
+
num_channels_latents,
|
712 |
+
height,
|
713 |
+
width,
|
714 |
+
dtype,
|
715 |
+
device,
|
716 |
+
generator,
|
717 |
+
latents=None,
|
718 |
+
image=None,
|
719 |
+
timestep=None,
|
720 |
+
is_strength_max=True,
|
721 |
+
return_noise=False,
|
722 |
+
return_image_latents=False,
|
723 |
+
):
|
724 |
+
shape = (
|
725 |
+
batch_size,
|
726 |
+
num_channels_latents,
|
727 |
+
height // self.vae_scale_factor,
|
728 |
+
width // self.vae_scale_factor,
|
729 |
+
)
|
730 |
+
if isinstance(generator, list) and len(generator) != batch_size:
|
731 |
+
raise ValueError(
|
732 |
+
f"You have passed a list of generators of length {len(generator)}, but requested an effective batch"
|
733 |
+
f" size of {batch_size}. Make sure the batch size matches the length of the generators."
|
734 |
+
)
|
735 |
+
|
736 |
+
if (image is None or timestep is None) and not is_strength_max:
|
737 |
+
raise ValueError(
|
738 |
+
"Since strength < 1. initial latents are to be initialised as a combination of Image + Noise."
|
739 |
+
"However, either the image or the noise timestep has not been provided."
|
740 |
+
)
|
741 |
+
|
742 |
+
if return_image_latents or (latents is None and not is_strength_max):
|
743 |
+
image = image.to(device=device, dtype=dtype)
|
744 |
+
image_latents = self._encode_vae_image(image=image, generator=generator)
|
745 |
+
|
746 |
+
if latents is None:
|
747 |
+
noise = randn_tensor(shape, generator=generator, device=device, dtype=dtype)
|
748 |
+
# if strength is 1. then initialise the latents to noise, else initial to image + noise
|
749 |
+
latents = (
|
750 |
+
noise
|
751 |
+
if is_strength_max
|
752 |
+
else self.scheduler.add_noise(image_latents, noise, timestep)
|
753 |
+
)
|
754 |
+
# if pure noise then scale the initial latents by the Scheduler's init sigma
|
755 |
+
latents = (
|
756 |
+
latents * self.scheduler.init_noise_sigma
|
757 |
+
if is_strength_max
|
758 |
+
else latents
|
759 |
+
)
|
760 |
+
else:
|
761 |
+
noise = latents.to(device)
|
762 |
+
latents = noise * self.scheduler.init_noise_sigma
|
763 |
+
|
764 |
+
outputs = (latents,)
|
765 |
+
|
766 |
+
if return_noise:
|
767 |
+
outputs += (noise,)
|
768 |
+
|
769 |
+
if return_image_latents:
|
770 |
+
outputs += (image_latents,)
|
771 |
+
|
772 |
+
return outputs
|
773 |
+
|
774 |
+
def _encode_vae_image(self, image: torch.Tensor, generator: torch.Generator):
|
775 |
+
if isinstance(generator, list):
|
776 |
+
image_latents = [
|
777 |
+
self.vae.encode(image[i : i + 1]).latent_dist.sample(
|
778 |
+
generator=generator[i]
|
779 |
+
)
|
780 |
+
for i in range(image.shape[0])
|
781 |
+
]
|
782 |
+
image_latents = torch.cat(image_latents, dim=0)
|
783 |
+
else:
|
784 |
+
image_latents = self.vae.encode(image).latent_dist.sample(
|
785 |
+
generator=generator
|
786 |
+
)
|
787 |
+
|
788 |
+
image_latents = self.vae.config.scaling_factor * image_latents
|
789 |
+
|
790 |
+
return image_latents
|
791 |
+
|
792 |
+
def prepare_mask_latents(
|
793 |
+
self,
|
794 |
+
mask,
|
795 |
+
masked_image,
|
796 |
+
batch_size,
|
797 |
+
height,
|
798 |
+
width,
|
799 |
+
dtype,
|
800 |
+
device,
|
801 |
+
generator,
|
802 |
+
do_classifier_free_guidance,
|
803 |
+
):
|
804 |
+
# resize the mask to latents shape as we concatenate the mask to the latents
|
805 |
+
# we do that before converting to dtype to avoid breaking in case we're using cpu_offload
|
806 |
+
# and half precision
|
807 |
+
mask = torch.nn.functional.interpolate(
|
808 |
+
mask, size=(height // self.vae_scale_factor, width // self.vae_scale_factor)
|
809 |
+
)
|
810 |
+
mask = mask.to(device=device, dtype=dtype)
|
811 |
+
|
812 |
+
masked_image = masked_image.to(device=device, dtype=dtype)
|
813 |
+
masked_image_latents = self._encode_vae_image(masked_image, generator=generator)
|
814 |
+
|
815 |
+
# duplicate mask and masked_image_latents for each generation per prompt, using mps friendly method
|
816 |
+
if mask.shape[0] < batch_size:
|
817 |
+
if not batch_size % mask.shape[0] == 0:
|
818 |
+
raise ValueError(
|
819 |
+
"The passed mask and the required batch size don't match. Masks are supposed to be duplicated to"
|
820 |
+
f" a total batch size of {batch_size}, but {mask.shape[0]} masks were passed. Make sure the number"
|
821 |
+
" of masks that you pass is divisible by the total requested batch size."
|
822 |
+
)
|
823 |
+
mask = mask.repeat(batch_size // mask.shape[0], 1, 1, 1)
|
824 |
+
if masked_image_latents.shape[0] < batch_size:
|
825 |
+
if not batch_size % masked_image_latents.shape[0] == 0:
|
826 |
+
raise ValueError(
|
827 |
+
"The passed images and the required batch size don't match. Images are supposed to be duplicated"
|
828 |
+
f" to a total batch size of {batch_size}, but {masked_image_latents.shape[0]} images were passed."
|
829 |
+
" Make sure the number of images that you pass is divisible by the total requested batch size."
|
830 |
+
)
|
831 |
+
masked_image_latents = masked_image_latents.repeat(
|
832 |
+
batch_size // masked_image_latents.shape[0], 1, 1, 1
|
833 |
+
)
|
834 |
+
|
835 |
+
mask = torch.cat([mask] * 2) if do_classifier_free_guidance else mask
|
836 |
+
masked_image_latents = (
|
837 |
+
torch.cat([masked_image_latents] * 2)
|
838 |
+
if do_classifier_free_guidance
|
839 |
+
else masked_image_latents
|
840 |
+
)
|
841 |
+
|
842 |
+
# aligning device to prevent device errors when concating it with the latent model input
|
843 |
+
masked_image_latents = masked_image_latents.to(device=device, dtype=dtype)
|
844 |
+
return mask, masked_image_latents
|
845 |
+
|
846 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_img2img.StableDiffusionImg2ImgPipeline.get_timesteps
|
847 |
+
def get_timesteps(self, num_inference_steps, strength, device):
|
848 |
+
# get the original timestep using init_timestep
|
849 |
+
init_timestep = min(int(num_inference_steps * strength), num_inference_steps)
|
850 |
+
|
851 |
+
t_start = max(num_inference_steps - init_timestep, 0)
|
852 |
+
timesteps = self.scheduler.timesteps[t_start * self.scheduler.order :]
|
853 |
+
|
854 |
+
return timesteps, num_inference_steps - t_start
|
855 |
+
|
856 |
+
@torch.no_grad()
|
857 |
+
def __call__(
|
858 |
+
self,
|
859 |
+
promptA: Union[str, List[str]] = None,
|
860 |
+
promptB: Union[str, List[str]] = None,
|
861 |
+
image: Union[torch.FloatTensor, PIL.Image.Image] = None,
|
862 |
+
mask_image: Union[torch.FloatTensor, PIL.Image.Image] = None,
|
863 |
+
height: Optional[int] = None,
|
864 |
+
width: Optional[int] = None,
|
865 |
+
strength: float = 1.0,
|
866 |
+
tradoff: float = 1.0,
|
867 |
+
tradoff_nag: float = 1.0,
|
868 |
+
num_inference_steps: int = 50,
|
869 |
+
guidance_scale: float = 7.5,
|
870 |
+
negative_promptA: Optional[Union[str, List[str]]] = None,
|
871 |
+
negative_promptB: Optional[Union[str, List[str]]] = None,
|
872 |
+
num_images_per_prompt: Optional[int] = 1,
|
873 |
+
eta: float = 0.0,
|
874 |
+
generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
|
875 |
+
latents: Optional[torch.FloatTensor] = None,
|
876 |
+
prompt_embeds: Optional[torch.FloatTensor] = None,
|
877 |
+
negative_prompt_embeds: Optional[torch.FloatTensor] = None,
|
878 |
+
output_type: Optional[str] = "pil",
|
879 |
+
return_dict: bool = True,
|
880 |
+
callback: Optional[Callable[[int, int, torch.FloatTensor], None]] = None,
|
881 |
+
callback_steps: int = 1,
|
882 |
+
cross_attention_kwargs: Optional[Dict[str, Any]] = None,
|
883 |
+
task_class: Union[torch.Tensor, float, int] = None,
|
884 |
+
):
|
885 |
+
r"""
|
886 |
+
The call function to the pipeline for generation.
|
887 |
+
|
888 |
+
Args:
|
889 |
+
prompt (`str` or `List[str]`, *optional*):
|
890 |
+
The prompt or prompts to guide image generation. If not defined, you need to pass `prompt_embeds`.
|
891 |
+
image (`PIL.Image.Image`):
|
892 |
+
`Image` or tensor representing an image batch to be inpainted (which parts of the image to be masked
|
893 |
+
out with `mask_image` and repainted according to `prompt`).
|
894 |
+
mask_image (`PIL.Image.Image`):
|
895 |
+
`Image` or tensor representing an image batch to mask `image`. White pixels in the mask are repainted
|
896 |
+
while black pixels are preserved. If `mask_image` is a PIL image, it is converted to a single channel
|
897 |
+
(luminance) before use. If it's a tensor, it should contain one color channel (L) instead of 3, so the
|
898 |
+
expected shape would be `(B, H, W, 1)`.
|
899 |
+
height (`int`, *optional*, defaults to `self.unet.config.sample_size * self.vae_scale_factor`):
|
900 |
+
The height in pixels of the generated image.
|
901 |
+
width (`int`, *optional*, defaults to `self.unet.config.sample_size * self.vae_scale_factor`):
|
902 |
+
The width in pixels of the generated image.
|
903 |
+
strength (`float`, *optional*, defaults to 1.0):
|
904 |
+
Indicates extent to transform the reference `image`. Must be between 0 and 1. `image` is used as a
|
905 |
+
starting point and more noise is added the higher the `strength`. The number of denoising steps depends
|
906 |
+
on the amount of noise initially added. When `strength` is 1, added noise is maximum and the denoising
|
907 |
+
process runs for the full number of iterations specified in `num_inference_steps`. A value of 1
|
908 |
+
essentially ignores `image`.
|
909 |
+
num_inference_steps (`int`, *optional*, defaults to 50):
|
910 |
+
The number of denoising steps. More denoising steps usually lead to a higher quality image at the
|
911 |
+
expense of slower inference. This parameter is modulated by `strength`.
|
912 |
+
guidance_scale (`float`, *optional*, defaults to 7.5):
|
913 |
+
A higher guidance scale value encourages the model to generate images closely linked to the text
|
914 |
+
`prompt` at the expense of lower image quality. Guidance scale is enabled when `guidance_scale > 1`.
|
915 |
+
negative_prompt (`str` or `List[str]`, *optional*):
|
916 |
+
The prompt or prompts to guide what to not include in image generation. If not defined, you need to
|
917 |
+
pass `negative_prompt_embeds` instead. Ignored when not using guidance (`guidance_scale < 1`).
|
918 |
+
num_images_per_prompt (`int`, *optional*, defaults to 1):
|
919 |
+
The number of images to generate per prompt.
|
920 |
+
eta (`float`, *optional*, defaults to 0.0):
|
921 |
+
Corresponds to parameter eta (η) from the [DDIM](https://arxiv.org/abs/2010.02502) paper. Only applies
|
922 |
+
to the [`~schedulers.DDIMScheduler`], and is ignored in other schedulers.
|
923 |
+
generator (`torch.Generator` or `List[torch.Generator]`, *optional*):
|
924 |
+
A [`torch.Generator`](https://pytorch.org/docs/stable/generated/torch.Generator.html) to make
|
925 |
+
generation deterministic.
|
926 |
+
latents (`torch.FloatTensor`, *optional*):
|
927 |
+
Pre-generated noisy latents sampled from a Gaussian distribution, to be used as inputs for image
|
928 |
+
generation. Can be used to tweak the same generation with different prompts. If not provided, a latents
|
929 |
+
tensor is generated by sampling using the supplied random `generator`.
|
930 |
+
prompt_embeds (`torch.FloatTensor`, *optional*):
|
931 |
+
Pre-generated text embeddings. Can be used to easily tweak text inputs (prompt weighting). If not
|
932 |
+
provided, text embeddings are generated from the `prompt` input argument.
|
933 |
+
negative_prompt_embeds (`torch.FloatTensor`, *optional*):
|
934 |
+
Pre-generated negative text embeddings. Can be used to easily tweak text inputs (prompt weighting). If
|
935 |
+
not provided, `negative_prompt_embeds` are generated from the `negative_prompt` input argument.
|
936 |
+
output_type (`str`, *optional*, defaults to `"pil"`):
|
937 |
+
The output format of the generated image. Choose between `PIL.Image` or `np.array`.
|
938 |
+
return_dict (`bool`, *optional*, defaults to `True`):
|
939 |
+
Whether or not to return a [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] instead of a
|
940 |
+
plain tuple.
|
941 |
+
callback (`Callable`, *optional*):
|
942 |
+
A function that calls every `callback_steps` steps during inference. The function is called with the
|
943 |
+
following arguments: `callback(step: int, timestep: int, latents: torch.FloatTensor)`.
|
944 |
+
callback_steps (`int`, *optional*, defaults to 1):
|
945 |
+
The frequency at which the `callback` function is called. If not specified, the callback is called at
|
946 |
+
every step.
|
947 |
+
cross_attention_kwargs (`dict`, *optional*):
|
948 |
+
A kwargs dictionary that if specified is passed along to the [`AttentionProcessor`] as defined in
|
949 |
+
[`self.processor`](https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/attention_processor.py).
|
950 |
+
|
951 |
+
Examples:
|
952 |
+
|
953 |
+
```py
|
954 |
+
>>> import PIL
|
955 |
+
>>> import requests
|
956 |
+
>>> import torch
|
957 |
+
>>> from io import BytesIO
|
958 |
+
|
959 |
+
>>> from diffusers import StableDiffusionInpaintPipeline
|
960 |
+
|
961 |
+
|
962 |
+
>>> def download_image(url):
|
963 |
+
... response = requests.get(url)
|
964 |
+
... return PIL.Image.open(BytesIO(response.content)).convert("RGB")
|
965 |
+
|
966 |
+
|
967 |
+
>>> img_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo.png"
|
968 |
+
>>> mask_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo_mask.png"
|
969 |
+
|
970 |
+
>>> init_image = download_image(img_url).resize((512, 512))
|
971 |
+
>>> mask_image = download_image(mask_url).resize((512, 512))
|
972 |
+
|
973 |
+
>>> pipe = StableDiffusionInpaintPipeline.from_pretrained(
|
974 |
+
... "runwayml/stable-diffusion-inpainting", torch_dtype=torch.float16
|
975 |
+
... )
|
976 |
+
>>> pipe = pipe.to("cuda")
|
977 |
+
|
978 |
+
>>> prompt = "Face of a yellow cat, high resolution, sitting on a park bench"
|
979 |
+
>>> image = pipe(prompt=prompt, image=init_image, mask_image=mask_image).images[0]
|
980 |
+
```
|
981 |
+
|
982 |
+
Returns:
|
983 |
+
[`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`:
|
984 |
+
If `return_dict` is `True`, [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] is returned,
|
985 |
+
otherwise a `tuple` is returned where the first element is a list with the generated images and the
|
986 |
+
second element is a list of `bool`s indicating whether the corresponding generated image contains
|
987 |
+
"not-safe-for-work" (nsfw) content.
|
988 |
+
"""
|
989 |
+
# 0. Default height and width to unet
|
990 |
+
height = height or self.unet.config.sample_size * self.vae_scale_factor
|
991 |
+
width = width or self.unet.config.sample_size * self.vae_scale_factor
|
992 |
+
prompt = promptA
|
993 |
+
negative_prompt = negative_promptA
|
994 |
+
# 1. Check inputs
|
995 |
+
self.check_inputs(
|
996 |
+
prompt,
|
997 |
+
height,
|
998 |
+
width,
|
999 |
+
strength,
|
1000 |
+
callback_steps,
|
1001 |
+
negative_prompt,
|
1002 |
+
prompt_embeds,
|
1003 |
+
negative_prompt_embeds,
|
1004 |
+
)
|
1005 |
+
|
1006 |
+
# 2. Define call parameters
|
1007 |
+
if prompt is not None and isinstance(prompt, str):
|
1008 |
+
batch_size = 1
|
1009 |
+
elif prompt is not None and isinstance(prompt, list):
|
1010 |
+
batch_size = len(prompt)
|
1011 |
+
else:
|
1012 |
+
batch_size = prompt_embeds.shape[0]
|
1013 |
+
|
1014 |
+
device = self._execution_device
|
1015 |
+
# here `guidance_scale` is defined analog to the guidance weight `w` of equation (2)
|
1016 |
+
# of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1`
|
1017 |
+
# corresponds to doing no classifier free guidance.
|
1018 |
+
do_classifier_free_guidance = guidance_scale > 1.0
|
1019 |
+
|
1020 |
+
# 3. Encode input prompt
|
1021 |
+
text_encoder_lora_scale = (
|
1022 |
+
cross_attention_kwargs.get("scale", None)
|
1023 |
+
if cross_attention_kwargs is not None
|
1024 |
+
else None
|
1025 |
+
)
|
1026 |
+
prompt_embeds = self._encode_prompt(
|
1027 |
+
promptA,
|
1028 |
+
promptB,
|
1029 |
+
tradoff,
|
1030 |
+
device,
|
1031 |
+
num_images_per_prompt,
|
1032 |
+
do_classifier_free_guidance,
|
1033 |
+
negative_promptA,
|
1034 |
+
negative_promptB,
|
1035 |
+
tradoff_nag,
|
1036 |
+
prompt_embeds=prompt_embeds,
|
1037 |
+
negative_prompt_embeds=negative_prompt_embeds,
|
1038 |
+
lora_scale=text_encoder_lora_scale,
|
1039 |
+
)
|
1040 |
+
|
1041 |
+
# 4. set timesteps
|
1042 |
+
self.scheduler.set_timesteps(num_inference_steps, device=device)
|
1043 |
+
timesteps, num_inference_steps = self.get_timesteps(
|
1044 |
+
num_inference_steps=num_inference_steps, strength=strength, device=device
|
1045 |
+
)
|
1046 |
+
# check that number of inference steps is not < 1 - as this doesn't make sense
|
1047 |
+
if num_inference_steps < 1:
|
1048 |
+
raise ValueError(
|
1049 |
+
f"After adjusting the num_inference_steps by strength parameter: {strength}, the number of pipeline"
|
1050 |
+
f"steps is {num_inference_steps} which is < 1 and not appropriate for this pipeline."
|
1051 |
+
)
|
1052 |
+
# at which timestep to set the initial noise (n.b. 50% if strength is 0.5)
|
1053 |
+
latent_timestep = timesteps[:1].repeat(batch_size * num_images_per_prompt)
|
1054 |
+
# create a boolean to check if the strength is set to 1. if so then initialise the latents with pure noise
|
1055 |
+
is_strength_max = strength == 1.0
|
1056 |
+
|
1057 |
+
# 5. Preprocess mask and image
|
1058 |
+
mask, masked_image, init_image = prepare_mask_and_masked_image(
|
1059 |
+
image, mask_image, height, width, return_image=True
|
1060 |
+
)
|
1061 |
+
mask_condition = mask.clone()
|
1062 |
+
|
1063 |
+
# 6. Prepare latent variables
|
1064 |
+
num_channels_latents = self.vae.config.latent_channels
|
1065 |
+
num_channels_unet = self.unet.config.in_channels
|
1066 |
+
return_image_latents = num_channels_unet == 4
|
1067 |
+
|
1068 |
+
latents_outputs = self.prepare_latents(
|
1069 |
+
batch_size * num_images_per_prompt,
|
1070 |
+
num_channels_latents,
|
1071 |
+
height,
|
1072 |
+
width,
|
1073 |
+
prompt_embeds.dtype,
|
1074 |
+
device,
|
1075 |
+
generator,
|
1076 |
+
latents,
|
1077 |
+
image=init_image,
|
1078 |
+
timestep=latent_timestep,
|
1079 |
+
is_strength_max=is_strength_max,
|
1080 |
+
return_noise=True,
|
1081 |
+
return_image_latents=return_image_latents,
|
1082 |
+
)
|
1083 |
+
|
1084 |
+
if return_image_latents:
|
1085 |
+
latents, noise, image_latents = latents_outputs
|
1086 |
+
else:
|
1087 |
+
latents, noise = latents_outputs
|
1088 |
+
|
1089 |
+
# 7. Prepare mask latent variables
|
1090 |
+
mask, masked_image_latents = self.prepare_mask_latents(
|
1091 |
+
mask,
|
1092 |
+
masked_image,
|
1093 |
+
batch_size * num_images_per_prompt,
|
1094 |
+
height,
|
1095 |
+
width,
|
1096 |
+
prompt_embeds.dtype,
|
1097 |
+
device,
|
1098 |
+
generator,
|
1099 |
+
do_classifier_free_guidance,
|
1100 |
+
)
|
1101 |
+
|
1102 |
+
# 8. Check that sizes of mask, masked image and latents match
|
1103 |
+
if num_channels_unet == 9:
|
1104 |
+
# default case for runwayml/stable-diffusion-inpainting
|
1105 |
+
num_channels_mask = mask.shape[1]
|
1106 |
+
num_channels_masked_image = masked_image_latents.shape[1]
|
1107 |
+
if (
|
1108 |
+
num_channels_latents + num_channels_mask + num_channels_masked_image
|
1109 |
+
!= self.unet.config.in_channels
|
1110 |
+
):
|
1111 |
+
raise ValueError(
|
1112 |
+
f"Incorrect configuration settings! The config of `pipeline.unet`: {self.unet.config} expects"
|
1113 |
+
f" {self.unet.config.in_channels} but received `num_channels_latents`: {num_channels_latents} +"
|
1114 |
+
f" `num_channels_mask`: {num_channels_mask} + `num_channels_masked_image`: {num_channels_masked_image}"
|
1115 |
+
f" = {num_channels_latents+num_channels_masked_image+num_channels_mask}. Please verify the config of"
|
1116 |
+
" `pipeline.unet` or your `mask_image` or `image` input."
|
1117 |
+
)
|
1118 |
+
elif num_channels_unet != 4:
|
1119 |
+
raise ValueError(
|
1120 |
+
f"The unet {self.unet.__class__} should have either 4 or 9 input channels, not {self.unet.config.in_channels}."
|
1121 |
+
)
|
1122 |
+
|
1123 |
+
# 9. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline
|
1124 |
+
extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)
|
1125 |
+
|
1126 |
+
# 10. Denoising loop
|
1127 |
+
num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order
|
1128 |
+
with self.progress_bar(total=num_inference_steps) as progress_bar:
|
1129 |
+
for i, t in enumerate(timesteps):
|
1130 |
+
# expand the latents if we are doing classifier free guidance
|
1131 |
+
latent_model_input = (
|
1132 |
+
torch.cat([latents] * 2) if do_classifier_free_guidance else latents
|
1133 |
+
)
|
1134 |
+
|
1135 |
+
# concat latents, mask, masked_image_latents in the channel dimension
|
1136 |
+
latent_model_input = self.scheduler.scale_model_input(
|
1137 |
+
latent_model_input, t
|
1138 |
+
)
|
1139 |
+
|
1140 |
+
if num_channels_unet == 9:
|
1141 |
+
latent_model_input = torch.cat(
|
1142 |
+
[latent_model_input, mask, masked_image_latents], dim=1
|
1143 |
+
)
|
1144 |
+
|
1145 |
+
# predict the noise residual
|
1146 |
+
if task_class is not None:
|
1147 |
+
noise_pred = self.unet(
|
1148 |
+
sample=latent_model_input,
|
1149 |
+
timestep=t,
|
1150 |
+
encoder_hidden_states=prompt_embeds,
|
1151 |
+
cross_attention_kwargs=cross_attention_kwargs,
|
1152 |
+
return_dict=False,
|
1153 |
+
task_class=task_class,
|
1154 |
+
)[0]
|
1155 |
+
else:
|
1156 |
+
noise_pred = self.unet(
|
1157 |
+
latent_model_input,
|
1158 |
+
t,
|
1159 |
+
encoder_hidden_states=prompt_embeds,
|
1160 |
+
cross_attention_kwargs=cross_attention_kwargs,
|
1161 |
+
return_dict=False,
|
1162 |
+
)[0]
|
1163 |
+
|
1164 |
+
# perform guidance
|
1165 |
+
if do_classifier_free_guidance:
|
1166 |
+
noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
|
1167 |
+
noise_pred = noise_pred_uncond + guidance_scale * (
|
1168 |
+
noise_pred_text - noise_pred_uncond
|
1169 |
+
)
|
1170 |
+
|
1171 |
+
# compute the previous noisy sample x_t -> x_t-1
|
1172 |
+
latents = self.scheduler.step(
|
1173 |
+
noise_pred, t, latents, **extra_step_kwargs, return_dict=False
|
1174 |
+
)[0]
|
1175 |
+
|
1176 |
+
if num_channels_unet == 4:
|
1177 |
+
init_latents_proper = image_latents[:1]
|
1178 |
+
init_mask = mask[:1]
|
1179 |
+
|
1180 |
+
if i < len(timesteps) - 1:
|
1181 |
+
noise_timestep = timesteps[i + 1]
|
1182 |
+
init_latents_proper = self.scheduler.add_noise(
|
1183 |
+
init_latents_proper, noise, torch.tensor([noise_timestep])
|
1184 |
+
)
|
1185 |
+
|
1186 |
+
latents = (
|
1187 |
+
1 - init_mask
|
1188 |
+
) * init_latents_proper + init_mask * latents
|
1189 |
+
|
1190 |
+
# call the callback, if provided
|
1191 |
+
if i == len(timesteps) - 1 or (
|
1192 |
+
(i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0
|
1193 |
+
):
|
1194 |
+
progress_bar.update()
|
1195 |
+
if callback is not None and i % callback_steps == 0:
|
1196 |
+
callback(self, i, t, {})
|
1197 |
+
|
1198 |
+
if not output_type == "latent":
|
1199 |
+
condition_kwargs = {}
|
1200 |
+
if isinstance(self.vae, AsymmetricAutoencoderKL):
|
1201 |
+
init_image = init_image.to(
|
1202 |
+
device=device, dtype=masked_image_latents.dtype
|
1203 |
+
)
|
1204 |
+
init_image_condition = init_image.clone()
|
1205 |
+
init_image = self._encode_vae_image(init_image, generator=generator)
|
1206 |
+
mask_condition = mask_condition.to(
|
1207 |
+
device=device, dtype=masked_image_latents.dtype
|
1208 |
+
)
|
1209 |
+
condition_kwargs = {
|
1210 |
+
"image": init_image_condition,
|
1211 |
+
"mask": mask_condition,
|
1212 |
+
}
|
1213 |
+
image = self.vae.decode(
|
1214 |
+
latents / self.vae.config.scaling_factor,
|
1215 |
+
return_dict=False,
|
1216 |
+
**condition_kwargs,
|
1217 |
+
)[0]
|
1218 |
+
image, has_nsfw_concept = self.run_safety_checker(
|
1219 |
+
image, device, prompt_embeds.dtype
|
1220 |
+
)
|
1221 |
+
else:
|
1222 |
+
image = latents
|
1223 |
+
has_nsfw_concept = None
|
1224 |
+
|
1225 |
+
if has_nsfw_concept is None:
|
1226 |
+
do_denormalize = [True] * image.shape[0]
|
1227 |
+
else:
|
1228 |
+
do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept]
|
1229 |
+
|
1230 |
+
image = self.image_processor.postprocess(
|
1231 |
+
image, output_type=output_type, do_denormalize=do_denormalize
|
1232 |
+
)
|
1233 |
+
|
1234 |
+
# Offload last model to CPU
|
1235 |
+
if hasattr(self, "final_offload_hook") and self.final_offload_hook is not None:
|
1236 |
+
self.final_offload_hook.offload()
|
1237 |
+
|
1238 |
+
if not return_dict:
|
1239 |
+
return (image, has_nsfw_concept)
|
1240 |
+
|
1241 |
+
return StableDiffusionPipelineOutput(
|
1242 |
+
images=image, nsfw_content_detected=has_nsfw_concept
|
1243 |
+
)
|
iopaint/model/power_paint/pipeline_powerpaint_controlnet.py
ADDED
@@ -0,0 +1,1775 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright 2023 The HuggingFace Team. All rights reserved.
|
2 |
+
#
|
3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4 |
+
# you may not use this file except in compliance with the License.
|
5 |
+
# You may obtain a copy of the License at
|
6 |
+
#
|
7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8 |
+
#
|
9 |
+
# Unless required by applicable law or agreed to in writing, software
|
10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12 |
+
# See the License for the specific language governing permissions and
|
13 |
+
# limitations under the License.
|
14 |
+
|
15 |
+
# This model implementation is heavily inspired by https://github.com/haofanwang/ControlNet-for-Diffusers/
|
16 |
+
|
17 |
+
import inspect
|
18 |
+
import warnings
|
19 |
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
20 |
+
|
21 |
+
import numpy as np
|
22 |
+
import PIL.Image
|
23 |
+
import torch
|
24 |
+
import torch.nn.functional as F
|
25 |
+
from transformers import CLIPImageProcessor, CLIPTextModel, CLIPTokenizer
|
26 |
+
|
27 |
+
from diffusers.image_processor import VaeImageProcessor
|
28 |
+
from diffusers.loaders import FromSingleFileMixin, LoraLoaderMixin, TextualInversionLoaderMixin
|
29 |
+
from diffusers.models import AutoencoderKL, ControlNetModel, UNet2DConditionModel
|
30 |
+
from diffusers.schedulers import KarrasDiffusionSchedulers
|
31 |
+
from diffusers.utils import (
|
32 |
+
is_accelerate_available,
|
33 |
+
is_accelerate_version,
|
34 |
+
logging,
|
35 |
+
replace_example_docstring,
|
36 |
+
)
|
37 |
+
from diffusers.utils.torch_utils import randn_tensor,is_compiled_module
|
38 |
+
from diffusers.pipelines.pipeline_utils import DiffusionPipeline
|
39 |
+
from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput
|
40 |
+
from diffusers.pipelines.stable_diffusion.safety_checker import StableDiffusionSafetyChecker
|
41 |
+
from diffusers.pipelines.controlnet import MultiControlNetModel
|
42 |
+
|
43 |
+
|
44 |
+
|
45 |
+
|
46 |
+
logger = logging.get_logger(__name__) # pylint: disable=invalid-name
|
47 |
+
|
48 |
+
|
49 |
+
EXAMPLE_DOC_STRING = """
|
50 |
+
Examples:
|
51 |
+
```py
|
52 |
+
>>> # !pip install transformers accelerate
|
53 |
+
>>> from diffusers import StableDiffusionControlNetInpaintPipeline, ControlNetModel, DDIMScheduler
|
54 |
+
>>> from diffusers.utils import load_image
|
55 |
+
>>> import numpy as np
|
56 |
+
>>> import torch
|
57 |
+
|
58 |
+
>>> init_image = load_image(
|
59 |
+
... "https://huggingface.co/datasets/diffusers/test-arrays/resolve/main/stable_diffusion_inpaint/boy.png"
|
60 |
+
... )
|
61 |
+
>>> init_image = init_image.resize((512, 512))
|
62 |
+
|
63 |
+
>>> generator = torch.Generator(device="cpu").manual_seed(1)
|
64 |
+
|
65 |
+
>>> mask_image = load_image(
|
66 |
+
... "https://huggingface.co/datasets/diffusers/test-arrays/resolve/main/stable_diffusion_inpaint/boy_mask.png"
|
67 |
+
... )
|
68 |
+
>>> mask_image = mask_image.resize((512, 512))
|
69 |
+
|
70 |
+
|
71 |
+
>>> def make_inpaint_condition(image, image_mask):
|
72 |
+
... image = np.array(image.convert("RGB")).astype(np.float32) / 255.0
|
73 |
+
... image_mask = np.array(image_mask.convert("L")).astype(np.float32) / 255.0
|
74 |
+
|
75 |
+
... assert image.shape[0:1] == image_mask.shape[0:1], "image and image_mask must have the same image size"
|
76 |
+
... image[image_mask > 0.5] = -1.0 # set as masked pixel
|
77 |
+
... image = np.expand_dims(image, 0).transpose(0, 3, 1, 2)
|
78 |
+
... image = torch.from_numpy(image)
|
79 |
+
... return image
|
80 |
+
|
81 |
+
|
82 |
+
>>> control_image = make_inpaint_condition(init_image, mask_image)
|
83 |
+
|
84 |
+
>>> controlnet = ControlNetModel.from_pretrained(
|
85 |
+
... "lllyasviel/control_v11p_sd15_inpaint", torch_dtype=torch.float16
|
86 |
+
... )
|
87 |
+
>>> pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained(
|
88 |
+
... "runwayml/stable-diffusion-v1-5", controlnet=controlnet, torch_dtype=torch.float16
|
89 |
+
... )
|
90 |
+
|
91 |
+
>>> pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config)
|
92 |
+
>>> pipe.enable_model_cpu_offload()
|
93 |
+
|
94 |
+
>>> # generate image
|
95 |
+
>>> image = pipe(
|
96 |
+
... "a handsome man with ray-ban sunglasses",
|
97 |
+
... num_inference_steps=20,
|
98 |
+
... generator=generator,
|
99 |
+
... eta=1.0,
|
100 |
+
... image=init_image,
|
101 |
+
... mask_image=mask_image,
|
102 |
+
... control_image=control_image,
|
103 |
+
... ).images[0]
|
104 |
+
```
|
105 |
+
"""
|
106 |
+
|
107 |
+
|
108 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_inpaint.prepare_mask_and_masked_image
|
109 |
+
def prepare_mask_and_masked_image(image, mask, height, width, return_image=False):
|
110 |
+
"""
|
111 |
+
Prepares a pair (image, mask) to be consumed by the Stable Diffusion pipeline. This means that those inputs will be
|
112 |
+
converted to ``torch.Tensor`` with shapes ``batch x channels x height x width`` where ``channels`` is ``3`` for the
|
113 |
+
``image`` and ``1`` for the ``mask``.
|
114 |
+
|
115 |
+
The ``image`` will be converted to ``torch.float32`` and normalized to be in ``[-1, 1]``. The ``mask`` will be
|
116 |
+
binarized (``mask > 0.5``) and cast to ``torch.float32`` too.
|
117 |
+
|
118 |
+
Args:
|
119 |
+
image (Union[np.array, PIL.Image, torch.Tensor]): The image to inpaint.
|
120 |
+
It can be a ``PIL.Image``, or a ``height x width x 3`` ``np.array`` or a ``channels x height x width``
|
121 |
+
``torch.Tensor`` or a ``batch x channels x height x width`` ``torch.Tensor``.
|
122 |
+
mask (_type_): The mask to apply to the image, i.e. regions to inpaint.
|
123 |
+
It can be a ``PIL.Image``, or a ``height x width`` ``np.array`` or a ``1 x height x width``
|
124 |
+
``torch.Tensor`` or a ``batch x 1 x height x width`` ``torch.Tensor``.
|
125 |
+
|
126 |
+
|
127 |
+
Raises:
|
128 |
+
ValueError: ``torch.Tensor`` images should be in the ``[-1, 1]`` range. ValueError: ``torch.Tensor`` mask
|
129 |
+
should be in the ``[0, 1]`` range. ValueError: ``mask`` and ``image`` should have the same spatial dimensions.
|
130 |
+
TypeError: ``mask`` is a ``torch.Tensor`` but ``image`` is not
|
131 |
+
(ot the other way around).
|
132 |
+
|
133 |
+
Returns:
|
134 |
+
tuple[torch.Tensor]: The pair (mask, masked_image) as ``torch.Tensor`` with 4
|
135 |
+
dimensions: ``batch x channels x height x width``.
|
136 |
+
"""
|
137 |
+
|
138 |
+
if image is None:
|
139 |
+
raise ValueError("`image` input cannot be undefined.")
|
140 |
+
|
141 |
+
if mask is None:
|
142 |
+
raise ValueError("`mask_image` input cannot be undefined.")
|
143 |
+
|
144 |
+
if isinstance(image, torch.Tensor):
|
145 |
+
if not isinstance(mask, torch.Tensor):
|
146 |
+
raise TypeError(f"`image` is a torch.Tensor but `mask` (type: {type(mask)} is not")
|
147 |
+
|
148 |
+
# Batch single image
|
149 |
+
if image.ndim == 3:
|
150 |
+
assert image.shape[0] == 3, "Image outside a batch should be of shape (3, H, W)"
|
151 |
+
image = image.unsqueeze(0)
|
152 |
+
|
153 |
+
# Batch and add channel dim for single mask
|
154 |
+
if mask.ndim == 2:
|
155 |
+
mask = mask.unsqueeze(0).unsqueeze(0)
|
156 |
+
|
157 |
+
# Batch single mask or add channel dim
|
158 |
+
if mask.ndim == 3:
|
159 |
+
# Single batched mask, no channel dim or single mask not batched but channel dim
|
160 |
+
if mask.shape[0] == 1:
|
161 |
+
mask = mask.unsqueeze(0)
|
162 |
+
|
163 |
+
# Batched masks no channel dim
|
164 |
+
else:
|
165 |
+
mask = mask.unsqueeze(1)
|
166 |
+
|
167 |
+
assert image.ndim == 4 and mask.ndim == 4, "Image and Mask must have 4 dimensions"
|
168 |
+
assert image.shape[-2:] == mask.shape[-2:], "Image and Mask must have the same spatial dimensions"
|
169 |
+
assert image.shape[0] == mask.shape[0], "Image and Mask must have the same batch size"
|
170 |
+
|
171 |
+
# Check image is in [-1, 1]
|
172 |
+
if image.min() < -1 or image.max() > 1:
|
173 |
+
raise ValueError("Image should be in [-1, 1] range")
|
174 |
+
|
175 |
+
# Check mask is in [0, 1]
|
176 |
+
if mask.min() < 0 or mask.max() > 1:
|
177 |
+
raise ValueError("Mask should be in [0, 1] range")
|
178 |
+
|
179 |
+
# Binarize mask
|
180 |
+
mask[mask < 0.5] = 0
|
181 |
+
mask[mask >= 0.5] = 1
|
182 |
+
|
183 |
+
# Image as float32
|
184 |
+
image = image.to(dtype=torch.float32)
|
185 |
+
elif isinstance(mask, torch.Tensor):
|
186 |
+
raise TypeError(f"`mask` is a torch.Tensor but `image` (type: {type(image)} is not")
|
187 |
+
else:
|
188 |
+
# preprocess image
|
189 |
+
if isinstance(image, (PIL.Image.Image, np.ndarray)):
|
190 |
+
image = [image]
|
191 |
+
if isinstance(image, list) and isinstance(image[0], PIL.Image.Image):
|
192 |
+
# resize all images w.r.t passed height an width
|
193 |
+
image = [i.resize((width, height), resample=PIL.Image.LANCZOS) for i in image]
|
194 |
+
image = [np.array(i.convert("RGB"))[None, :] for i in image]
|
195 |
+
image = np.concatenate(image, axis=0)
|
196 |
+
elif isinstance(image, list) and isinstance(image[0], np.ndarray):
|
197 |
+
image = np.concatenate([i[None, :] for i in image], axis=0)
|
198 |
+
|
199 |
+
image = image.transpose(0, 3, 1, 2)
|
200 |
+
image = torch.from_numpy(image).to(dtype=torch.float32) / 127.5 - 1.0
|
201 |
+
|
202 |
+
# preprocess mask
|
203 |
+
if isinstance(mask, (PIL.Image.Image, np.ndarray)):
|
204 |
+
mask = [mask]
|
205 |
+
|
206 |
+
if isinstance(mask, list) and isinstance(mask[0], PIL.Image.Image):
|
207 |
+
mask = [i.resize((width, height), resample=PIL.Image.LANCZOS) for i in mask]
|
208 |
+
mask = np.concatenate([np.array(m.convert("L"))[None, None, :] for m in mask], axis=0)
|
209 |
+
mask = mask.astype(np.float32) / 255.0
|
210 |
+
elif isinstance(mask, list) and isinstance(mask[0], np.ndarray):
|
211 |
+
mask = np.concatenate([m[None, None, :] for m in mask], axis=0)
|
212 |
+
|
213 |
+
mask[mask < 0.5] = 0
|
214 |
+
mask[mask >= 0.5] = 1
|
215 |
+
mask = torch.from_numpy(mask)
|
216 |
+
|
217 |
+
masked_image = image * (mask < 0.5)
|
218 |
+
|
219 |
+
# n.b. ensure backwards compatibility as old function does not return image
|
220 |
+
if return_image:
|
221 |
+
return mask, masked_image, image
|
222 |
+
|
223 |
+
return mask, masked_image
|
224 |
+
|
225 |
+
|
226 |
+
class StableDiffusionControlNetInpaintPipeline(
|
227 |
+
DiffusionPipeline, TextualInversionLoaderMixin, LoraLoaderMixin, FromSingleFileMixin
|
228 |
+
):
|
229 |
+
r"""
|
230 |
+
Pipeline for text-to-image generation using Stable Diffusion with ControlNet guidance.
|
231 |
+
|
232 |
+
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
233 |
+
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
234 |
+
|
235 |
+
In addition the pipeline inherits the following loading methods:
|
236 |
+
- *Textual-Inversion*: [`loaders.TextualInversionLoaderMixin.load_textual_inversion`]
|
237 |
+
|
238 |
+
<Tip>
|
239 |
+
|
240 |
+
This pipeline can be used both with checkpoints that have been specifically fine-tuned for inpainting, such as
|
241 |
+
[runwayml/stable-diffusion-inpainting](https://huggingface.co/runwayml/stable-diffusion-inpainting)
|
242 |
+
as well as default text-to-image stable diffusion checkpoints, such as
|
243 |
+
[runwayml/stable-diffusion-v1-5](https://huggingface.co/runwayml/stable-diffusion-v1-5).
|
244 |
+
Default text-to-image stable diffusion checkpoints might be preferable for controlnets that have been fine-tuned on
|
245 |
+
those, such as [lllyasviel/control_v11p_sd15_inpaint](https://huggingface.co/lllyasviel/control_v11p_sd15_inpaint).
|
246 |
+
|
247 |
+
</Tip>
|
248 |
+
|
249 |
+
Args:
|
250 |
+
vae ([`AutoencoderKL`]):
|
251 |
+
Variational Auto-Encoder (VAE) Model to encode and decode images to and from latent representations.
|
252 |
+
text_encoder ([`CLIPTextModel`]):
|
253 |
+
Frozen text-encoder. Stable Diffusion uses the text portion of
|
254 |
+
[CLIP](https://huggingface.co/docs/transformers/model_doc/clip#transformers.CLIPTextModel), specifically
|
255 |
+
the [clip-vit-large-patch14](https://huggingface.co/openai/clip-vit-large-patch14) variant.
|
256 |
+
tokenizer (`CLIPTokenizer`):
|
257 |
+
Tokenizer of class
|
258 |
+
[CLIPTokenizer](https://huggingface.co/docs/transformers/v4.21.0/en/model_doc/clip#transformers.CLIPTokenizer).
|
259 |
+
unet ([`UNet2DConditionModel`]): Conditional U-Net architecture to denoise the encoded image latents.
|
260 |
+
controlnet ([`ControlNetModel`] or `List[ControlNetModel]`):
|
261 |
+
Provides additional conditioning to the unet during the denoising process. If you set multiple ControlNets
|
262 |
+
as a list, the outputs from each ControlNet are added together to create one combined additional
|
263 |
+
conditioning.
|
264 |
+
scheduler ([`SchedulerMixin`]):
|
265 |
+
A scheduler to be used in combination with `unet` to denoise the encoded image latents. Can be one of
|
266 |
+
[`DDIMScheduler`], [`LMSDiscreteScheduler`], or [`PNDMScheduler`].
|
267 |
+
safety_checker ([`StableDiffusionSafetyChecker`]):
|
268 |
+
Classification module that estimates whether generated images could be considered offensive or harmful.
|
269 |
+
Please, refer to the [model card](https://huggingface.co/runwayml/stable-diffusion-v1-5) for details.
|
270 |
+
feature_extractor ([`CLIPImageProcessor`]):
|
271 |
+
Model that extracts features from generated images to be used as inputs for the `safety_checker`.
|
272 |
+
"""
|
273 |
+
_optional_components = ["safety_checker", "feature_extractor"]
|
274 |
+
|
275 |
+
def __init__(
|
276 |
+
self,
|
277 |
+
vae: AutoencoderKL,
|
278 |
+
text_encoder: CLIPTextModel,
|
279 |
+
tokenizer: CLIPTokenizer,
|
280 |
+
unet: UNet2DConditionModel,
|
281 |
+
controlnet: Union[ControlNetModel, List[ControlNetModel], Tuple[ControlNetModel], MultiControlNetModel],
|
282 |
+
scheduler: KarrasDiffusionSchedulers,
|
283 |
+
safety_checker: StableDiffusionSafetyChecker,
|
284 |
+
feature_extractor: CLIPImageProcessor,
|
285 |
+
requires_safety_checker: bool = True,
|
286 |
+
):
|
287 |
+
super().__init__()
|
288 |
+
|
289 |
+
if safety_checker is None and requires_safety_checker:
|
290 |
+
logger.warning(
|
291 |
+
f"You have disabled the safety checker for {self.__class__} by passing `safety_checker=None`. Ensure"
|
292 |
+
" that you abide to the conditions of the Stable Diffusion license and do not expose unfiltered"
|
293 |
+
" results in services or applications open to the public. Both the diffusers team and Hugging Face"
|
294 |
+
" strongly recommend to keep the safety filter enabled in all public facing circumstances, disabling"
|
295 |
+
" it only for use-cases that involve analyzing network behavior or auditing its results. For more"
|
296 |
+
" information, please have a look at https://github.com/huggingface/diffusers/pull/254 ."
|
297 |
+
)
|
298 |
+
|
299 |
+
if safety_checker is not None and feature_extractor is None:
|
300 |
+
raise ValueError(
|
301 |
+
"Make sure to define a feature extractor when loading {self.__class__} if you want to use the safety"
|
302 |
+
" checker. If you do not want to use the safety checker, you can pass `'safety_checker=None'` instead."
|
303 |
+
)
|
304 |
+
|
305 |
+
if isinstance(controlnet, (list, tuple)):
|
306 |
+
controlnet = MultiControlNetModel(controlnet)
|
307 |
+
|
308 |
+
self.register_modules(
|
309 |
+
vae=vae,
|
310 |
+
text_encoder=text_encoder,
|
311 |
+
tokenizer=tokenizer,
|
312 |
+
unet=unet,
|
313 |
+
controlnet=controlnet,
|
314 |
+
scheduler=scheduler,
|
315 |
+
safety_checker=safety_checker,
|
316 |
+
feature_extractor=feature_extractor,
|
317 |
+
)
|
318 |
+
self.vae_scale_factor = 2 ** (len(self.vae.config.block_out_channels) - 1)
|
319 |
+
self.image_processor = VaeImageProcessor(vae_scale_factor=self.vae_scale_factor)
|
320 |
+
self.control_image_processor = VaeImageProcessor(
|
321 |
+
vae_scale_factor=self.vae_scale_factor, do_convert_rgb=True, do_normalize=False
|
322 |
+
)
|
323 |
+
self.register_to_config(requires_safety_checker=requires_safety_checker)
|
324 |
+
|
325 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.enable_vae_slicing
|
326 |
+
def enable_vae_slicing(self):
|
327 |
+
r"""
|
328 |
+
Enable sliced VAE decoding. When this option is enabled, the VAE will split the input tensor in slices to
|
329 |
+
compute decoding in several steps. This is useful to save some memory and allow larger batch sizes.
|
330 |
+
"""
|
331 |
+
self.vae.enable_slicing()
|
332 |
+
|
333 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.disable_vae_slicing
|
334 |
+
def disable_vae_slicing(self):
|
335 |
+
r"""
|
336 |
+
Disable sliced VAE decoding. If `enable_vae_slicing` was previously enabled, this method will go back to
|
337 |
+
computing decoding in one step.
|
338 |
+
"""
|
339 |
+
self.vae.disable_slicing()
|
340 |
+
|
341 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.enable_vae_tiling
|
342 |
+
def enable_vae_tiling(self):
|
343 |
+
r"""
|
344 |
+
Enable tiled VAE decoding. When this option is enabled, the VAE will split the input tensor into tiles to
|
345 |
+
compute decoding and encoding in several steps. This is useful for saving a large amount of memory and to allow
|
346 |
+
processing larger images.
|
347 |
+
"""
|
348 |
+
self.vae.enable_tiling()
|
349 |
+
|
350 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.disable_vae_tiling
|
351 |
+
def disable_vae_tiling(self):
|
352 |
+
r"""
|
353 |
+
Disable tiled VAE decoding. If `enable_vae_tiling` was previously enabled, this method will go back to
|
354 |
+
computing decoding in one step.
|
355 |
+
"""
|
356 |
+
self.vae.disable_tiling()
|
357 |
+
|
358 |
+
def enable_model_cpu_offload(self, gpu_id=0):
|
359 |
+
r"""
|
360 |
+
Offloads all models to CPU using accelerate, reducing memory usage with a low impact on performance. Compared
|
361 |
+
to `enable_sequential_cpu_offload`, this method moves one whole model at a time to the GPU when its `forward`
|
362 |
+
method is called, and the model remains in GPU until the next model runs. Memory savings are lower than with
|
363 |
+
`enable_sequential_cpu_offload`, but performance is much better due to the iterative execution of the `unet`.
|
364 |
+
"""
|
365 |
+
if is_accelerate_available() and is_accelerate_version(">=", "0.17.0.dev0"):
|
366 |
+
from accelerate import cpu_offload_with_hook
|
367 |
+
else:
|
368 |
+
raise ImportError("`enable_model_cpu_offload` requires `accelerate v0.17.0` or higher.")
|
369 |
+
|
370 |
+
device = torch.device(f"cuda:{gpu_id}")
|
371 |
+
|
372 |
+
hook = None
|
373 |
+
for cpu_offloaded_model in [self.text_encoder, self.unet, self.vae]:
|
374 |
+
_, hook = cpu_offload_with_hook(cpu_offloaded_model, device, prev_module_hook=hook)
|
375 |
+
|
376 |
+
if self.safety_checker is not None:
|
377 |
+
# the safety checker can offload the vae again
|
378 |
+
_, hook = cpu_offload_with_hook(self.safety_checker, device, prev_module_hook=hook)
|
379 |
+
|
380 |
+
# control net hook has be manually offloaded as it alternates with unet
|
381 |
+
cpu_offload_with_hook(self.controlnet, device)
|
382 |
+
|
383 |
+
# We'll offload the last model manually.
|
384 |
+
self.final_offload_hook = hook
|
385 |
+
|
386 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline._encode_prompt
|
387 |
+
def _encode_prompt(
|
388 |
+
self,
|
389 |
+
promptA,
|
390 |
+
promptB,
|
391 |
+
t,
|
392 |
+
device,
|
393 |
+
num_images_per_prompt,
|
394 |
+
do_classifier_free_guidance,
|
395 |
+
negative_promptA=None,
|
396 |
+
negative_promptB=None,
|
397 |
+
t_nag = None,
|
398 |
+
prompt_embeds: Optional[torch.FloatTensor] = None,
|
399 |
+
negative_prompt_embeds: Optional[torch.FloatTensor] = None,
|
400 |
+
lora_scale: Optional[float] = None,
|
401 |
+
):
|
402 |
+
r"""
|
403 |
+
Encodes the prompt into text encoder hidden states.
|
404 |
+
|
405 |
+
Args:
|
406 |
+
prompt (`str` or `List[str]`, *optional*):
|
407 |
+
prompt to be encoded
|
408 |
+
device: (`torch.device`):
|
409 |
+
torch device
|
410 |
+
num_images_per_prompt (`int`):
|
411 |
+
number of images that should be generated per prompt
|
412 |
+
do_classifier_free_guidance (`bool`):
|
413 |
+
whether to use classifier free guidance or not
|
414 |
+
negative_prompt (`str` or `List[str]`, *optional*):
|
415 |
+
The prompt or prompts not to guide the image generation. If not defined, one has to pass
|
416 |
+
`negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is
|
417 |
+
less than `1`).
|
418 |
+
prompt_embeds (`torch.FloatTensor`, *optional*):
|
419 |
+
Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not
|
420 |
+
provided, text embeddings will be generated from `prompt` input argument.
|
421 |
+
negative_prompt_embeds (`torch.FloatTensor`, *optional*):
|
422 |
+
Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt
|
423 |
+
weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input
|
424 |
+
argument.
|
425 |
+
lora_scale (`float`, *optional*):
|
426 |
+
A lora scale that will be applied to all LoRA layers of the text encoder if LoRA layers are loaded.
|
427 |
+
"""
|
428 |
+
# set lora scale so that monkey patched LoRA
|
429 |
+
# function of text encoder can correctly access it
|
430 |
+
if lora_scale is not None and isinstance(self, LoraLoaderMixin):
|
431 |
+
self._lora_scale = lora_scale
|
432 |
+
|
433 |
+
prompt = promptA
|
434 |
+
negative_prompt = negative_promptA
|
435 |
+
|
436 |
+
if promptA is not None and isinstance(promptA, str):
|
437 |
+
batch_size = 1
|
438 |
+
elif promptA is not None and isinstance(promptA, list):
|
439 |
+
batch_size = len(promptA)
|
440 |
+
else:
|
441 |
+
batch_size = prompt_embeds.shape[0]
|
442 |
+
|
443 |
+
if prompt_embeds is None:
|
444 |
+
# textual inversion: procecss multi-vector tokens if necessary
|
445 |
+
if isinstance(self, TextualInversionLoaderMixin):
|
446 |
+
promptA = self.maybe_convert_prompt(promptA, self.tokenizer)
|
447 |
+
|
448 |
+
text_inputsA = self.tokenizer(
|
449 |
+
promptA,
|
450 |
+
padding="max_length",
|
451 |
+
max_length=self.tokenizer.model_max_length,
|
452 |
+
truncation=True,
|
453 |
+
return_tensors="pt",
|
454 |
+
)
|
455 |
+
text_inputsB = self.tokenizer(
|
456 |
+
promptB,
|
457 |
+
padding="max_length",
|
458 |
+
max_length=self.tokenizer.model_max_length,
|
459 |
+
truncation=True,
|
460 |
+
return_tensors="pt",
|
461 |
+
)
|
462 |
+
text_input_idsA = text_inputsA.input_ids
|
463 |
+
text_input_idsB = text_inputsB.input_ids
|
464 |
+
untruncated_ids = self.tokenizer(promptA, padding="longest", return_tensors="pt").input_ids
|
465 |
+
|
466 |
+
if untruncated_ids.shape[-1] >= text_input_idsA.shape[-1] and not torch.equal(
|
467 |
+
text_input_idsA, untruncated_ids
|
468 |
+
):
|
469 |
+
removed_text = self.tokenizer.batch_decode(
|
470 |
+
untruncated_ids[:, self.tokenizer.model_max_length - 1 : -1]
|
471 |
+
)
|
472 |
+
logger.warning(
|
473 |
+
"The following part of your input was truncated because CLIP can only handle sequences up to"
|
474 |
+
f" {self.tokenizer.model_max_length} tokens: {removed_text}"
|
475 |
+
)
|
476 |
+
|
477 |
+
if hasattr(self.text_encoder.config, "use_attention_mask") and self.text_encoder.config.use_attention_mask:
|
478 |
+
attention_mask = text_inputsA.attention_mask.to(device)
|
479 |
+
else:
|
480 |
+
attention_mask = None
|
481 |
+
|
482 |
+
# print("text_input_idsA: ",text_input_idsA)
|
483 |
+
# print("text_input_idsB: ",text_input_idsB)
|
484 |
+
# print('t: ',t)
|
485 |
+
|
486 |
+
prompt_embedsA = self.text_encoder(
|
487 |
+
text_input_idsA.to(device),
|
488 |
+
attention_mask=attention_mask,
|
489 |
+
)
|
490 |
+
prompt_embedsA = prompt_embedsA[0]
|
491 |
+
|
492 |
+
prompt_embedsB = self.text_encoder(
|
493 |
+
text_input_idsB.to(device),
|
494 |
+
attention_mask=attention_mask,
|
495 |
+
)
|
496 |
+
prompt_embedsB = prompt_embedsB[0]
|
497 |
+
prompt_embeds = prompt_embedsA*(t)+(1-t)*prompt_embedsB
|
498 |
+
# print("prompt_embeds: ",prompt_embeds)
|
499 |
+
|
500 |
+
if self.text_encoder is not None:
|
501 |
+
prompt_embeds_dtype = self.text_encoder.dtype
|
502 |
+
elif self.unet is not None:
|
503 |
+
prompt_embeds_dtype = self.unet.dtype
|
504 |
+
else:
|
505 |
+
prompt_embeds_dtype = prompt_embeds.dtype
|
506 |
+
|
507 |
+
prompt_embeds = prompt_embeds.to(dtype=prompt_embeds_dtype, device=device)
|
508 |
+
|
509 |
+
bs_embed, seq_len, _ = prompt_embeds.shape
|
510 |
+
# duplicate text embeddings for each generation per prompt, using mps friendly method
|
511 |
+
prompt_embeds = prompt_embeds.repeat(1, num_images_per_prompt, 1)
|
512 |
+
prompt_embeds = prompt_embeds.view(bs_embed * num_images_per_prompt, seq_len, -1)
|
513 |
+
|
514 |
+
# get unconditional embeddings for classifier free guidance
|
515 |
+
if do_classifier_free_guidance and negative_prompt_embeds is None:
|
516 |
+
uncond_tokensA: List[str]
|
517 |
+
uncond_tokensB: List[str]
|
518 |
+
if negative_prompt is None:
|
519 |
+
uncond_tokensA = [""] * batch_size
|
520 |
+
uncond_tokensB = [""] * batch_size
|
521 |
+
elif prompt is not None and type(prompt) is not type(negative_prompt):
|
522 |
+
raise TypeError(
|
523 |
+
f"`negative_prompt` should be the same type to `prompt`, but got {type(negative_prompt)} !="
|
524 |
+
f" {type(prompt)}."
|
525 |
+
)
|
526 |
+
elif isinstance(negative_prompt, str):
|
527 |
+
uncond_tokensA = [negative_promptA]
|
528 |
+
uncond_tokensB = [negative_promptB]
|
529 |
+
elif batch_size != len(negative_prompt):
|
530 |
+
raise ValueError(
|
531 |
+
f"`negative_prompt`: {negative_prompt} has batch size {len(negative_prompt)}, but `prompt`:"
|
532 |
+
f" {prompt} has batch size {batch_size}. Please make sure that passed `negative_prompt` matches"
|
533 |
+
" the batch size of `prompt`."
|
534 |
+
)
|
535 |
+
else:
|
536 |
+
uncond_tokensA = negative_promptA
|
537 |
+
uncond_tokensB = negative_promptB
|
538 |
+
|
539 |
+
# textual inversion: procecss multi-vector tokens if necessary
|
540 |
+
if isinstance(self, TextualInversionLoaderMixin):
|
541 |
+
uncond_tokensA = self.maybe_convert_prompt(uncond_tokensA, self.tokenizer)
|
542 |
+
uncond_tokensB = self.maybe_convert_prompt(uncond_tokensB, self.tokenizer)
|
543 |
+
|
544 |
+
max_length = prompt_embeds.shape[1]
|
545 |
+
uncond_inputA = self.tokenizer(
|
546 |
+
uncond_tokensA,
|
547 |
+
padding="max_length",
|
548 |
+
max_length=max_length,
|
549 |
+
truncation=True,
|
550 |
+
return_tensors="pt",
|
551 |
+
)
|
552 |
+
uncond_inputB = self.tokenizer(
|
553 |
+
uncond_tokensB,
|
554 |
+
padding="max_length",
|
555 |
+
max_length=max_length,
|
556 |
+
truncation=True,
|
557 |
+
return_tensors="pt",
|
558 |
+
)
|
559 |
+
|
560 |
+
if hasattr(self.text_encoder.config, "use_attention_mask") and self.text_encoder.config.use_attention_mask:
|
561 |
+
attention_mask = uncond_inputA.attention_mask.to(device)
|
562 |
+
else:
|
563 |
+
attention_mask = None
|
564 |
+
|
565 |
+
negative_prompt_embedsA = self.text_encoder(
|
566 |
+
uncond_inputA.input_ids.to(device),
|
567 |
+
attention_mask=attention_mask,
|
568 |
+
)
|
569 |
+
negative_prompt_embedsB = self.text_encoder(
|
570 |
+
uncond_inputB.input_ids.to(device),
|
571 |
+
attention_mask=attention_mask,
|
572 |
+
)
|
573 |
+
negative_prompt_embeds = negative_prompt_embedsA[0]*(t_nag)+(1-t_nag)*negative_prompt_embedsB[0]
|
574 |
+
|
575 |
+
# negative_prompt_embeds = negative_prompt_embeds[0]
|
576 |
+
|
577 |
+
if do_classifier_free_guidance:
|
578 |
+
# duplicate unconditional embeddings for each generation per prompt, using mps friendly method
|
579 |
+
seq_len = negative_prompt_embeds.shape[1]
|
580 |
+
|
581 |
+
negative_prompt_embeds = negative_prompt_embeds.to(dtype=prompt_embeds_dtype, device=device)
|
582 |
+
|
583 |
+
negative_prompt_embeds = negative_prompt_embeds.repeat(1, num_images_per_prompt, 1)
|
584 |
+
negative_prompt_embeds = negative_prompt_embeds.view(batch_size * num_images_per_prompt, seq_len, -1)
|
585 |
+
|
586 |
+
# For classifier free guidance, we need to do two forward passes.
|
587 |
+
# Here we concatenate the unconditional and text embeddings into a single batch
|
588 |
+
# to avoid doing two forward passes
|
589 |
+
# print("prompt_embeds: ",prompt_embeds)
|
590 |
+
prompt_embeds = torch.cat([negative_prompt_embeds, prompt_embeds])
|
591 |
+
|
592 |
+
return prompt_embeds
|
593 |
+
|
594 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.run_safety_checker
|
595 |
+
def run_safety_checker(self, image, device, dtype):
|
596 |
+
if self.safety_checker is None:
|
597 |
+
has_nsfw_concept = None
|
598 |
+
else:
|
599 |
+
if torch.is_tensor(image):
|
600 |
+
feature_extractor_input = self.image_processor.postprocess(image, output_type="pil")
|
601 |
+
else:
|
602 |
+
feature_extractor_input = self.image_processor.numpy_to_pil(image)
|
603 |
+
safety_checker_input = self.feature_extractor(feature_extractor_input, return_tensors="pt").to(device)
|
604 |
+
image, has_nsfw_concept = self.safety_checker(
|
605 |
+
images=image, clip_input=safety_checker_input.pixel_values.to(dtype)
|
606 |
+
)
|
607 |
+
return image, has_nsfw_concept
|
608 |
+
|
609 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.decode_latents
|
610 |
+
def decode_latents(self, latents):
|
611 |
+
warnings.warn(
|
612 |
+
"The decode_latents method is deprecated and will be removed in a future version. Please"
|
613 |
+
" use VaeImageProcessor instead",
|
614 |
+
FutureWarning,
|
615 |
+
)
|
616 |
+
latents = 1 / self.vae.config.scaling_factor * latents
|
617 |
+
image = self.vae.decode(latents, return_dict=False)[0]
|
618 |
+
image = (image / 2 + 0.5).clamp(0, 1)
|
619 |
+
# we always cast to float32 as this does not cause significant overhead and is compatible with bfloat16
|
620 |
+
image = image.cpu().permute(0, 2, 3, 1).float().numpy()
|
621 |
+
return image
|
622 |
+
|
623 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.prepare_extra_step_kwargs
|
624 |
+
def prepare_extra_step_kwargs(self, generator, eta):
|
625 |
+
# prepare extra kwargs for the scheduler step, since not all schedulers have the same signature
|
626 |
+
# eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers.
|
627 |
+
# eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502
|
628 |
+
# and should be between [0, 1]
|
629 |
+
|
630 |
+
accepts_eta = "eta" in set(inspect.signature(self.scheduler.step).parameters.keys())
|
631 |
+
extra_step_kwargs = {}
|
632 |
+
if accepts_eta:
|
633 |
+
extra_step_kwargs["eta"] = eta
|
634 |
+
|
635 |
+
# check if the scheduler accepts generator
|
636 |
+
accepts_generator = "generator" in set(inspect.signature(self.scheduler.step).parameters.keys())
|
637 |
+
if accepts_generator:
|
638 |
+
extra_step_kwargs["generator"] = generator
|
639 |
+
return extra_step_kwargs
|
640 |
+
|
641 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_img2img.StableDiffusionImg2ImgPipeline.get_timesteps
|
642 |
+
def get_timesteps(self, num_inference_steps, strength, device):
|
643 |
+
# get the original timestep using init_timestep
|
644 |
+
init_timestep = min(int(num_inference_steps * strength), num_inference_steps)
|
645 |
+
|
646 |
+
t_start = max(num_inference_steps - init_timestep, 0)
|
647 |
+
timesteps = self.scheduler.timesteps[t_start * self.scheduler.order :]
|
648 |
+
|
649 |
+
return timesteps, num_inference_steps - t_start
|
650 |
+
|
651 |
+
def check_inputs(
|
652 |
+
self,
|
653 |
+
prompt,
|
654 |
+
image,
|
655 |
+
height,
|
656 |
+
width,
|
657 |
+
callback_steps,
|
658 |
+
negative_prompt=None,
|
659 |
+
prompt_embeds=None,
|
660 |
+
negative_prompt_embeds=None,
|
661 |
+
controlnet_conditioning_scale=1.0,
|
662 |
+
control_guidance_start=0.0,
|
663 |
+
control_guidance_end=1.0,
|
664 |
+
):
|
665 |
+
if height % 8 != 0 or width % 8 != 0:
|
666 |
+
raise ValueError(f"`height` and `width` have to be divisible by 8 but are {height} and {width}.")
|
667 |
+
|
668 |
+
if (callback_steps is None) or (
|
669 |
+
callback_steps is not None and (not isinstance(callback_steps, int) or callback_steps <= 0)
|
670 |
+
):
|
671 |
+
raise ValueError(
|
672 |
+
f"`callback_steps` has to be a positive integer but is {callback_steps} of type"
|
673 |
+
f" {type(callback_steps)}."
|
674 |
+
)
|
675 |
+
|
676 |
+
if prompt is not None and prompt_embeds is not None:
|
677 |
+
raise ValueError(
|
678 |
+
f"Cannot forward both `prompt`: {prompt} and `prompt_embeds`: {prompt_embeds}. Please make sure to"
|
679 |
+
" only forward one of the two."
|
680 |
+
)
|
681 |
+
elif prompt is None and prompt_embeds is None:
|
682 |
+
raise ValueError(
|
683 |
+
"Provide either `prompt` or `prompt_embeds`. Cannot leave both `prompt` and `prompt_embeds` undefined."
|
684 |
+
)
|
685 |
+
elif prompt is not None and (not isinstance(prompt, str) and not isinstance(prompt, list)):
|
686 |
+
raise ValueError(f"`prompt` has to be of type `str` or `list` but is {type(prompt)}")
|
687 |
+
|
688 |
+
if negative_prompt is not None and negative_prompt_embeds is not None:
|
689 |
+
raise ValueError(
|
690 |
+
f"Cannot forward both `negative_prompt`: {negative_prompt} and `negative_prompt_embeds`:"
|
691 |
+
f" {negative_prompt_embeds}. Please make sure to only forward one of the two."
|
692 |
+
)
|
693 |
+
|
694 |
+
if prompt_embeds is not None and negative_prompt_embeds is not None:
|
695 |
+
if prompt_embeds.shape != negative_prompt_embeds.shape:
|
696 |
+
raise ValueError(
|
697 |
+
"`prompt_embeds` and `negative_prompt_embeds` must have the same shape when passed directly, but"
|
698 |
+
f" got: `prompt_embeds` {prompt_embeds.shape} != `negative_prompt_embeds`"
|
699 |
+
f" {negative_prompt_embeds.shape}."
|
700 |
+
)
|
701 |
+
|
702 |
+
# `prompt` needs more sophisticated handling when there are multiple
|
703 |
+
# conditionings.
|
704 |
+
if isinstance(self.controlnet, MultiControlNetModel):
|
705 |
+
if isinstance(prompt, list):
|
706 |
+
logger.warning(
|
707 |
+
f"You have {len(self.controlnet.nets)} ControlNets and you have passed {len(prompt)}"
|
708 |
+
" prompts. The conditionings will be fixed across the prompts."
|
709 |
+
)
|
710 |
+
|
711 |
+
# Check `image`
|
712 |
+
is_compiled = hasattr(F, "scaled_dot_product_attention") and isinstance(
|
713 |
+
self.controlnet, torch._dynamo.eval_frame.OptimizedModule
|
714 |
+
)
|
715 |
+
|
716 |
+
if (
|
717 |
+
isinstance(self.controlnet, ControlNetModel)
|
718 |
+
or is_compiled
|
719 |
+
and isinstance(self.controlnet._orig_mod, ControlNetModel)
|
720 |
+
):
|
721 |
+
self.check_image(image, prompt, prompt_embeds)
|
722 |
+
elif (
|
723 |
+
isinstance(self.controlnet, MultiControlNetModel)
|
724 |
+
or is_compiled
|
725 |
+
and isinstance(self.controlnet._orig_mod, MultiControlNetModel)
|
726 |
+
):
|
727 |
+
if not isinstance(image, list):
|
728 |
+
raise TypeError("For multiple controlnets: `image` must be type `list`")
|
729 |
+
|
730 |
+
# When `image` is a nested list:
|
731 |
+
# (e.g. [[canny_image_1, pose_image_1], [canny_image_2, pose_image_2]])
|
732 |
+
elif any(isinstance(i, list) for i in image):
|
733 |
+
raise ValueError("A single batch of multiple conditionings are supported at the moment.")
|
734 |
+
elif len(image) != len(self.controlnet.nets):
|
735 |
+
raise ValueError(
|
736 |
+
f"For multiple controlnets: `image` must have the same length as the number of controlnets, but got {len(image)} images and {len(self.controlnet.nets)} ControlNets."
|
737 |
+
)
|
738 |
+
|
739 |
+
for image_ in image:
|
740 |
+
self.check_image(image_, prompt, prompt_embeds)
|
741 |
+
else:
|
742 |
+
assert False
|
743 |
+
|
744 |
+
# Check `controlnet_conditioning_scale`
|
745 |
+
if (
|
746 |
+
isinstance(self.controlnet, ControlNetModel)
|
747 |
+
or is_compiled
|
748 |
+
and isinstance(self.controlnet._orig_mod, ControlNetModel)
|
749 |
+
):
|
750 |
+
if not isinstance(controlnet_conditioning_scale, float):
|
751 |
+
raise TypeError("For single controlnet: `controlnet_conditioning_scale` must be type `float`.")
|
752 |
+
elif (
|
753 |
+
isinstance(self.controlnet, MultiControlNetModel)
|
754 |
+
or is_compiled
|
755 |
+
and isinstance(self.controlnet._orig_mod, MultiControlNetModel)
|
756 |
+
):
|
757 |
+
if isinstance(controlnet_conditioning_scale, list):
|
758 |
+
if any(isinstance(i, list) for i in controlnet_conditioning_scale):
|
759 |
+
raise ValueError("A single batch of multiple conditionings are supported at the moment.")
|
760 |
+
elif isinstance(controlnet_conditioning_scale, list) and len(controlnet_conditioning_scale) != len(
|
761 |
+
self.controlnet.nets
|
762 |
+
):
|
763 |
+
raise ValueError(
|
764 |
+
"For multiple controlnets: When `controlnet_conditioning_scale` is specified as `list`, it must have"
|
765 |
+
" the same length as the number of controlnets"
|
766 |
+
)
|
767 |
+
else:
|
768 |
+
assert False
|
769 |
+
|
770 |
+
if len(control_guidance_start) != len(control_guidance_end):
|
771 |
+
raise ValueError(
|
772 |
+
f"`control_guidance_start` has {len(control_guidance_start)} elements, but `control_guidance_end` has {len(control_guidance_end)} elements. Make sure to provide the same number of elements to each list."
|
773 |
+
)
|
774 |
+
|
775 |
+
if isinstance(self.controlnet, MultiControlNetModel):
|
776 |
+
if len(control_guidance_start) != len(self.controlnet.nets):
|
777 |
+
raise ValueError(
|
778 |
+
f"`control_guidance_start`: {control_guidance_start} has {len(control_guidance_start)} elements but there are {len(self.controlnet.nets)} controlnets available. Make sure to provide {len(self.controlnet.nets)}."
|
779 |
+
)
|
780 |
+
|
781 |
+
for start, end in zip(control_guidance_start, control_guidance_end):
|
782 |
+
if start >= end:
|
783 |
+
raise ValueError(
|
784 |
+
f"control guidance start: {start} cannot be larger or equal to control guidance end: {end}."
|
785 |
+
)
|
786 |
+
if start < 0.0:
|
787 |
+
raise ValueError(f"control guidance start: {start} can't be smaller than 0.")
|
788 |
+
if end > 1.0:
|
789 |
+
raise ValueError(f"control guidance end: {end} can't be larger than 1.0.")
|
790 |
+
|
791 |
+
# Copied from diffusers.pipelines.controlnet.pipeline_controlnet.StableDiffusionControlNetPipeline.check_image
|
792 |
+
def check_image(self, image, prompt, prompt_embeds):
|
793 |
+
image_is_pil = isinstance(image, PIL.Image.Image)
|
794 |
+
image_is_tensor = isinstance(image, torch.Tensor)
|
795 |
+
image_is_np = isinstance(image, np.ndarray)
|
796 |
+
image_is_pil_list = isinstance(image, list) and isinstance(image[0], PIL.Image.Image)
|
797 |
+
image_is_tensor_list = isinstance(image, list) and isinstance(image[0], torch.Tensor)
|
798 |
+
image_is_np_list = isinstance(image, list) and isinstance(image[0], np.ndarray)
|
799 |
+
|
800 |
+
if (
|
801 |
+
not image_is_pil
|
802 |
+
and not image_is_tensor
|
803 |
+
and not image_is_np
|
804 |
+
and not image_is_pil_list
|
805 |
+
and not image_is_tensor_list
|
806 |
+
and not image_is_np_list
|
807 |
+
):
|
808 |
+
raise TypeError(
|
809 |
+
f"image must be passed and be one of PIL image, numpy array, torch tensor, list of PIL images, list of numpy arrays or list of torch tensors, but is {type(image)}"
|
810 |
+
)
|
811 |
+
|
812 |
+
if image_is_pil:
|
813 |
+
image_batch_size = 1
|
814 |
+
else:
|
815 |
+
image_batch_size = len(image)
|
816 |
+
|
817 |
+
if prompt is not None and isinstance(prompt, str):
|
818 |
+
prompt_batch_size = 1
|
819 |
+
elif prompt is not None and isinstance(prompt, list):
|
820 |
+
prompt_batch_size = len(prompt)
|
821 |
+
elif prompt_embeds is not None:
|
822 |
+
prompt_batch_size = prompt_embeds.shape[0]
|
823 |
+
|
824 |
+
if image_batch_size != 1 and image_batch_size != prompt_batch_size:
|
825 |
+
raise ValueError(
|
826 |
+
f"If image batch size is not 1, image batch size must be same as prompt batch size. image batch size: {image_batch_size}, prompt batch size: {prompt_batch_size}"
|
827 |
+
)
|
828 |
+
|
829 |
+
# Copied from diffusers.pipelines.controlnet.pipeline_controlnet.StableDiffusionControlNetPipeline.prepare_image
|
830 |
+
def prepare_control_image(
|
831 |
+
self,
|
832 |
+
image,
|
833 |
+
width,
|
834 |
+
height,
|
835 |
+
batch_size,
|
836 |
+
num_images_per_prompt,
|
837 |
+
device,
|
838 |
+
dtype,
|
839 |
+
do_classifier_free_guidance=False,
|
840 |
+
guess_mode=False,
|
841 |
+
):
|
842 |
+
image = self.control_image_processor.preprocess(image, height=height, width=width).to(dtype=torch.float32)
|
843 |
+
image_batch_size = image.shape[0]
|
844 |
+
|
845 |
+
if image_batch_size == 1:
|
846 |
+
repeat_by = batch_size
|
847 |
+
else:
|
848 |
+
# image batch size is the same as prompt batch size
|
849 |
+
repeat_by = num_images_per_prompt
|
850 |
+
|
851 |
+
image = image.repeat_interleave(repeat_by, dim=0)
|
852 |
+
|
853 |
+
image = image.to(device=device, dtype=dtype)
|
854 |
+
|
855 |
+
if do_classifier_free_guidance and not guess_mode:
|
856 |
+
image = torch.cat([image] * 2)
|
857 |
+
|
858 |
+
return image
|
859 |
+
|
860 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_inpaint.StableDiffusionInpaintPipeline.prepare_latents
|
861 |
+
def prepare_latents(
|
862 |
+
self,
|
863 |
+
batch_size,
|
864 |
+
num_channels_latents,
|
865 |
+
height,
|
866 |
+
width,
|
867 |
+
dtype,
|
868 |
+
device,
|
869 |
+
generator,
|
870 |
+
latents=None,
|
871 |
+
image=None,
|
872 |
+
timestep=None,
|
873 |
+
is_strength_max=True,
|
874 |
+
return_noise=False,
|
875 |
+
return_image_latents=False,
|
876 |
+
):
|
877 |
+
shape = (batch_size, num_channels_latents, height // self.vae_scale_factor, width // self.vae_scale_factor)
|
878 |
+
if isinstance(generator, list) and len(generator) != batch_size:
|
879 |
+
raise ValueError(
|
880 |
+
f"You have passed a list of generators of length {len(generator)}, but requested an effective batch"
|
881 |
+
f" size of {batch_size}. Make sure the batch size matches the length of the generators."
|
882 |
+
)
|
883 |
+
|
884 |
+
if (image is None or timestep is None) and not is_strength_max:
|
885 |
+
raise ValueError(
|
886 |
+
"Since strength < 1. initial latents are to be initialised as a combination of Image + Noise."
|
887 |
+
"However, either the image or the noise timestep has not been provided."
|
888 |
+
)
|
889 |
+
|
890 |
+
if return_image_latents or (latents is None and not is_strength_max):
|
891 |
+
image = image.to(device=device, dtype=dtype)
|
892 |
+
image_latents = self._encode_vae_image(image=image, generator=generator)
|
893 |
+
|
894 |
+
if latents is None:
|
895 |
+
noise = randn_tensor(shape, generator=generator, device=device, dtype=dtype)
|
896 |
+
# if strength is 1. then initialise the latents to noise, else initial to image + noise
|
897 |
+
latents = noise if is_strength_max else self.scheduler.add_noise(image_latents, noise, timestep)
|
898 |
+
# if pure noise then scale the initial latents by the Scheduler's init sigma
|
899 |
+
latents = latents * self.scheduler.init_noise_sigma if is_strength_max else latents
|
900 |
+
else:
|
901 |
+
noise = latents.to(device)
|
902 |
+
latents = noise * self.scheduler.init_noise_sigma
|
903 |
+
|
904 |
+
outputs = (latents,)
|
905 |
+
|
906 |
+
if return_noise:
|
907 |
+
outputs += (noise,)
|
908 |
+
|
909 |
+
if return_image_latents:
|
910 |
+
outputs += (image_latents,)
|
911 |
+
|
912 |
+
return outputs
|
913 |
+
|
914 |
+
def _default_height_width(self, height, width, image):
|
915 |
+
# NOTE: It is possible that a list of images have different
|
916 |
+
# dimensions for each image, so just checking the first image
|
917 |
+
# is not _exactly_ correct, but it is simple.
|
918 |
+
while isinstance(image, list):
|
919 |
+
image = image[0]
|
920 |
+
|
921 |
+
if height is None:
|
922 |
+
if isinstance(image, PIL.Image.Image):
|
923 |
+
height = image.height
|
924 |
+
elif isinstance(image, torch.Tensor):
|
925 |
+
height = image.shape[2]
|
926 |
+
|
927 |
+
height = (height // 8) * 8 # round down to nearest multiple of 8
|
928 |
+
|
929 |
+
if width is None:
|
930 |
+
if isinstance(image, PIL.Image.Image):
|
931 |
+
width = image.width
|
932 |
+
elif isinstance(image, torch.Tensor):
|
933 |
+
width = image.shape[3]
|
934 |
+
|
935 |
+
width = (width // 8) * 8 # round down to nearest multiple of 8
|
936 |
+
|
937 |
+
return height, width
|
938 |
+
|
939 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_inpaint.StableDiffusionInpaintPipeline.prepare_mask_latents
|
940 |
+
def prepare_mask_latents(
|
941 |
+
self, mask, masked_image, batch_size, height, width, dtype, device, generator, do_classifier_free_guidance
|
942 |
+
):
|
943 |
+
# resize the mask to latents shape as we concatenate the mask to the latents
|
944 |
+
# we do that before converting to dtype to avoid breaking in case we're using cpu_offload
|
945 |
+
# and half precision
|
946 |
+
mask = torch.nn.functional.interpolate(
|
947 |
+
mask, size=(height // self.vae_scale_factor, width // self.vae_scale_factor)
|
948 |
+
)
|
949 |
+
mask = mask.to(device=device, dtype=dtype)
|
950 |
+
|
951 |
+
masked_image = masked_image.to(device=device, dtype=dtype)
|
952 |
+
masked_image_latents = self._encode_vae_image(masked_image, generator=generator)
|
953 |
+
|
954 |
+
# duplicate mask and masked_image_latents for each generation per prompt, using mps friendly method
|
955 |
+
if mask.shape[0] < batch_size:
|
956 |
+
if not batch_size % mask.shape[0] == 0:
|
957 |
+
raise ValueError(
|
958 |
+
"The passed mask and the required batch size don't match. Masks are supposed to be duplicated to"
|
959 |
+
f" a total batch size of {batch_size}, but {mask.shape[0]} masks were passed. Make sure the number"
|
960 |
+
" of masks that you pass is divisible by the total requested batch size."
|
961 |
+
)
|
962 |
+
mask = mask.repeat(batch_size // mask.shape[0], 1, 1, 1)
|
963 |
+
if masked_image_latents.shape[0] < batch_size:
|
964 |
+
if not batch_size % masked_image_latents.shape[0] == 0:
|
965 |
+
raise ValueError(
|
966 |
+
"The passed images and the required batch size don't match. Images are supposed to be duplicated"
|
967 |
+
f" to a total batch size of {batch_size}, but {masked_image_latents.shape[0]} images were passed."
|
968 |
+
" Make sure the number of images that you pass is divisible by the total requested batch size."
|
969 |
+
)
|
970 |
+
masked_image_latents = masked_image_latents.repeat(batch_size // masked_image_latents.shape[0], 1, 1, 1)
|
971 |
+
|
972 |
+
mask = torch.cat([mask] * 2) if do_classifier_free_guidance else mask
|
973 |
+
masked_image_latents = (
|
974 |
+
torch.cat([masked_image_latents] * 2) if do_classifier_free_guidance else masked_image_latents
|
975 |
+
)
|
976 |
+
|
977 |
+
# aligning device to prevent device errors when concating it with the latent model input
|
978 |
+
masked_image_latents = masked_image_latents.to(device=device, dtype=dtype)
|
979 |
+
return mask, masked_image_latents
|
980 |
+
|
981 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_inpaint.StableDiffusionInpaintPipeline._encode_vae_image
|
982 |
+
def _encode_vae_image(self, image: torch.Tensor, generator: torch.Generator):
|
983 |
+
if isinstance(generator, list):
|
984 |
+
image_latents = [
|
985 |
+
self.vae.encode(image[i : i + 1]).latent_dist.sample(generator=generator[i])
|
986 |
+
for i in range(image.shape[0])
|
987 |
+
]
|
988 |
+
image_latents = torch.cat(image_latents, dim=0)
|
989 |
+
else:
|
990 |
+
image_latents = self.vae.encode(image).latent_dist.sample(generator=generator)
|
991 |
+
|
992 |
+
image_latents = self.vae.config.scaling_factor * image_latents
|
993 |
+
|
994 |
+
return image_latents
|
995 |
+
|
996 |
+
@torch.no_grad()
|
997 |
+
def predict_woControl(
|
998 |
+
self,
|
999 |
+
promptA: Union[str, List[str]] = None,
|
1000 |
+
promptB: Union[str, List[str]] = None,
|
1001 |
+
image: Union[torch.FloatTensor, PIL.Image.Image] = None,
|
1002 |
+
mask_image: Union[torch.FloatTensor, PIL.Image.Image] = None,
|
1003 |
+
height: Optional[int] = None,
|
1004 |
+
width: Optional[int] = None,
|
1005 |
+
strength: float = 1.0,
|
1006 |
+
tradoff: float = 1.0,
|
1007 |
+
tradoff_nag: float = 1.0,
|
1008 |
+
num_inference_steps: int = 50,
|
1009 |
+
guidance_scale: float = 7.5,
|
1010 |
+
negative_promptA: Optional[Union[str, List[str]]] = None,
|
1011 |
+
negative_promptB: Optional[Union[str, List[str]]] = None,
|
1012 |
+
num_images_per_prompt: Optional[int] = 1,
|
1013 |
+
eta: float = 0.0,
|
1014 |
+
generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
|
1015 |
+
latents: Optional[torch.FloatTensor] = None,
|
1016 |
+
prompt_embeds: Optional[torch.FloatTensor] = None,
|
1017 |
+
negative_prompt_embeds: Optional[torch.FloatTensor] = None,
|
1018 |
+
output_type: Optional[str] = "pil",
|
1019 |
+
return_dict: bool = True,
|
1020 |
+
callback: Optional[Callable[[int, int, torch.FloatTensor], None]] = None,
|
1021 |
+
callback_steps: int = 1,
|
1022 |
+
cross_attention_kwargs: Optional[Dict[str, Any]] = None,
|
1023 |
+
task_class: Union[torch.Tensor, float, int] = None,
|
1024 |
+
):
|
1025 |
+
r"""
|
1026 |
+
The call function to the pipeline for generation.
|
1027 |
+
|
1028 |
+
Args:
|
1029 |
+
prompt (`str` or `List[str]`, *optional*):
|
1030 |
+
The prompt or prompts to guide image generation. If not defined, you need to pass `prompt_embeds`.
|
1031 |
+
image (`PIL.Image.Image`):
|
1032 |
+
`Image` or tensor representing an image batch to be inpainted (which parts of the image to be masked
|
1033 |
+
out with `mask_image` and repainted according to `prompt`).
|
1034 |
+
mask_image (`PIL.Image.Image`):
|
1035 |
+
`Image` or tensor representing an image batch to mask `image`. White pixels in the mask are repainted
|
1036 |
+
while black pixels are preserved. If `mask_image` is a PIL image, it is converted to a single channel
|
1037 |
+
(luminance) before use. If it's a tensor, it should contain one color channel (L) instead of 3, so the
|
1038 |
+
expected shape would be `(B, H, W, 1)`.
|
1039 |
+
height (`int`, *optional*, defaults to `self.unet.config.sample_size * self.vae_scale_factor`):
|
1040 |
+
The height in pixels of the generated image.
|
1041 |
+
width (`int`, *optional*, defaults to `self.unet.config.sample_size * self.vae_scale_factor`):
|
1042 |
+
The width in pixels of the generated image.
|
1043 |
+
strength (`float`, *optional*, defaults to 1.0):
|
1044 |
+
Indicates extent to transform the reference `image`. Must be between 0 and 1. `image` is used as a
|
1045 |
+
starting point and more noise is added the higher the `strength`. The number of denoising steps depends
|
1046 |
+
on the amount of noise initially added. When `strength` is 1, added noise is maximum and the denoising
|
1047 |
+
process runs for the full number of iterations specified in `num_inference_steps`. A value of 1
|
1048 |
+
essentially ignores `image`.
|
1049 |
+
num_inference_steps (`int`, *optional*, defaults to 50):
|
1050 |
+
The number of denoising steps. More denoising steps usually lead to a higher quality image at the
|
1051 |
+
expense of slower inference. This parameter is modulated by `strength`.
|
1052 |
+
guidance_scale (`float`, *optional*, defaults to 7.5):
|
1053 |
+
A higher guidance scale value encourages the model to generate images closely linked to the text
|
1054 |
+
`prompt` at the expense of lower image quality. Guidance scale is enabled when `guidance_scale > 1`.
|
1055 |
+
negative_prompt (`str` or `List[str]`, *optional*):
|
1056 |
+
The prompt or prompts to guide what to not include in image generation. If not defined, you need to
|
1057 |
+
pass `negative_prompt_embeds` instead. Ignored when not using guidance (`guidance_scale < 1`).
|
1058 |
+
num_images_per_prompt (`int`, *optional*, defaults to 1):
|
1059 |
+
The number of images to generate per prompt.
|
1060 |
+
eta (`float`, *optional*, defaults to 0.0):
|
1061 |
+
Corresponds to parameter eta (η) from the [DDIM](https://arxiv.org/abs/2010.02502) paper. Only applies
|
1062 |
+
to the [`~schedulers.DDIMScheduler`], and is ignored in other schedulers.
|
1063 |
+
generator (`torch.Generator` or `List[torch.Generator]`, *optional*):
|
1064 |
+
A [`torch.Generator`](https://pytorch.org/docs/stable/generated/torch.Generator.html) to make
|
1065 |
+
generation deterministic.
|
1066 |
+
latents (`torch.FloatTensor`, *optional*):
|
1067 |
+
Pre-generated noisy latents sampled from a Gaussian distribution, to be used as inputs for image
|
1068 |
+
generation. Can be used to tweak the same generation with different prompts. If not provided, a latents
|
1069 |
+
tensor is generated by sampling using the supplied random `generator`.
|
1070 |
+
prompt_embeds (`torch.FloatTensor`, *optional*):
|
1071 |
+
Pre-generated text embeddings. Can be used to easily tweak text inputs (prompt weighting). If not
|
1072 |
+
provided, text embeddings are generated from the `prompt` input argument.
|
1073 |
+
negative_prompt_embeds (`torch.FloatTensor`, *optional*):
|
1074 |
+
Pre-generated negative text embeddings. Can be used to easily tweak text inputs (prompt weighting). If
|
1075 |
+
not provided, `negative_prompt_embeds` are generated from the `negative_prompt` input argument.
|
1076 |
+
output_type (`str`, *optional*, defaults to `"pil"`):
|
1077 |
+
The output format of the generated image. Choose between `PIL.Image` or `np.array`.
|
1078 |
+
return_dict (`bool`, *optional*, defaults to `True`):
|
1079 |
+
Whether or not to return a [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] instead of a
|
1080 |
+
plain tuple.
|
1081 |
+
callback (`Callable`, *optional*):
|
1082 |
+
A function that calls every `callback_steps` steps during inference. The function is called with the
|
1083 |
+
following arguments: `callback(step: int, timestep: int, latents: torch.FloatTensor)`.
|
1084 |
+
callback_steps (`int`, *optional*, defaults to 1):
|
1085 |
+
The frequency at which the `callback` function is called. If not specified, the callback is called at
|
1086 |
+
every step.
|
1087 |
+
cross_attention_kwargs (`dict`, *optional*):
|
1088 |
+
A kwargs dictionary that if specified is passed along to the [`AttentionProcessor`] as defined in
|
1089 |
+
[`self.processor`](https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/attention_processor.py).
|
1090 |
+
|
1091 |
+
Examples:
|
1092 |
+
|
1093 |
+
```py
|
1094 |
+
>>> import PIL
|
1095 |
+
>>> import requests
|
1096 |
+
>>> import torch
|
1097 |
+
>>> from io import BytesIO
|
1098 |
+
|
1099 |
+
>>> from diffusers import StableDiffusionInpaintPipeline
|
1100 |
+
|
1101 |
+
|
1102 |
+
>>> def download_image(url):
|
1103 |
+
... response = requests.get(url)
|
1104 |
+
... return PIL.Image.open(BytesIO(response.content)).convert("RGB")
|
1105 |
+
|
1106 |
+
|
1107 |
+
>>> img_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo.png"
|
1108 |
+
>>> mask_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo_mask.png"
|
1109 |
+
|
1110 |
+
>>> init_image = download_image(img_url).resize((512, 512))
|
1111 |
+
>>> mask_image = download_image(mask_url).resize((512, 512))
|
1112 |
+
|
1113 |
+
>>> pipe = StableDiffusionInpaintPipeline.from_pretrained(
|
1114 |
+
... "runwayml/stable-diffusion-inpainting", torch_dtype=torch.float16
|
1115 |
+
... )
|
1116 |
+
>>> pipe = pipe.to("cuda")
|
1117 |
+
|
1118 |
+
>>> prompt = "Face of a yellow cat, high resolution, sitting on a park bench"
|
1119 |
+
>>> image = pipe(prompt=prompt, image=init_image, mask_image=mask_image).images[0]
|
1120 |
+
```
|
1121 |
+
|
1122 |
+
Returns:
|
1123 |
+
[`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`:
|
1124 |
+
If `return_dict` is `True`, [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] is returned,
|
1125 |
+
otherwise a `tuple` is returned where the first element is a list with the generated images and the
|
1126 |
+
second element is a list of `bool`s indicating whether the corresponding generated image contains
|
1127 |
+
"not-safe-for-work" (nsfw) content.
|
1128 |
+
"""
|
1129 |
+
# 0. Default height and width to unet
|
1130 |
+
height = height or self.unet.config.sample_size * self.vae_scale_factor
|
1131 |
+
width = width or self.unet.config.sample_size * self.vae_scale_factor
|
1132 |
+
prompt = promptA
|
1133 |
+
negative_prompt = negative_promptA
|
1134 |
+
# 1. Check inputs
|
1135 |
+
self.check_inputs(
|
1136 |
+
prompt,
|
1137 |
+
height,
|
1138 |
+
width,
|
1139 |
+
strength,
|
1140 |
+
callback_steps,
|
1141 |
+
negative_prompt,
|
1142 |
+
prompt_embeds,
|
1143 |
+
negative_prompt_embeds,
|
1144 |
+
)
|
1145 |
+
|
1146 |
+
# 2. Define call parameters
|
1147 |
+
if prompt is not None and isinstance(prompt, str):
|
1148 |
+
batch_size = 1
|
1149 |
+
elif prompt is not None and isinstance(prompt, list):
|
1150 |
+
batch_size = len(prompt)
|
1151 |
+
else:
|
1152 |
+
batch_size = prompt_embeds.shape[0]
|
1153 |
+
|
1154 |
+
device = self._execution_device
|
1155 |
+
# here `guidance_scale` is defined analog to the guidance weight `w` of equation (2)
|
1156 |
+
# of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1`
|
1157 |
+
# corresponds to doing no classifier free guidance.
|
1158 |
+
do_classifier_free_guidance = guidance_scale > 1.0
|
1159 |
+
|
1160 |
+
# 3. Encode input prompt
|
1161 |
+
text_encoder_lora_scale = (
|
1162 |
+
cross_attention_kwargs.get("scale", None) if cross_attention_kwargs is not None else None
|
1163 |
+
)
|
1164 |
+
prompt_embeds = self._encode_prompt(
|
1165 |
+
promptA,
|
1166 |
+
promptB,
|
1167 |
+
tradoff,
|
1168 |
+
device,
|
1169 |
+
num_images_per_prompt,
|
1170 |
+
do_classifier_free_guidance,
|
1171 |
+
negative_promptA,
|
1172 |
+
negative_promptB,
|
1173 |
+
tradoff_nag,
|
1174 |
+
prompt_embeds=prompt_embeds,
|
1175 |
+
negative_prompt_embeds=negative_prompt_embeds,
|
1176 |
+
lora_scale=text_encoder_lora_scale,
|
1177 |
+
)
|
1178 |
+
|
1179 |
+
# 4. set timesteps
|
1180 |
+
self.scheduler.set_timesteps(num_inference_steps, device=device)
|
1181 |
+
timesteps, num_inference_steps = self.get_timesteps(
|
1182 |
+
num_inference_steps=num_inference_steps, strength=strength, device=device
|
1183 |
+
)
|
1184 |
+
# check that number of inference steps is not < 1 - as this doesn't make sense
|
1185 |
+
if num_inference_steps < 1:
|
1186 |
+
raise ValueError(
|
1187 |
+
f"After adjusting the num_inference_steps by strength parameter: {strength}, the number of pipeline"
|
1188 |
+
f"steps is {num_inference_steps} which is < 1 and not appropriate for this pipeline."
|
1189 |
+
)
|
1190 |
+
# at which timestep to set the initial noise (n.b. 50% if strength is 0.5)
|
1191 |
+
latent_timestep = timesteps[:1].repeat(batch_size * num_images_per_prompt)
|
1192 |
+
# create a boolean to check if the strength is set to 1. if so then initialise the latents with pure noise
|
1193 |
+
is_strength_max = strength == 1.0
|
1194 |
+
|
1195 |
+
# 5. Preprocess mask and image
|
1196 |
+
mask, masked_image, init_image = prepare_mask_and_masked_image(
|
1197 |
+
image, mask_image, height, width, return_image=True
|
1198 |
+
)
|
1199 |
+
mask_condition = mask.clone()
|
1200 |
+
|
1201 |
+
# 6. Prepare latent variables
|
1202 |
+
num_channels_latents = self.vae.config.latent_channels
|
1203 |
+
num_channels_unet = self.unet.config.in_channels
|
1204 |
+
return_image_latents = num_channels_unet == 4
|
1205 |
+
|
1206 |
+
latents_outputs = self.prepare_latents(
|
1207 |
+
batch_size * num_images_per_prompt,
|
1208 |
+
num_channels_latents,
|
1209 |
+
height,
|
1210 |
+
width,
|
1211 |
+
prompt_embeds.dtype,
|
1212 |
+
device,
|
1213 |
+
generator,
|
1214 |
+
latents,
|
1215 |
+
image=init_image,
|
1216 |
+
timestep=latent_timestep,
|
1217 |
+
is_strength_max=is_strength_max,
|
1218 |
+
return_noise=True,
|
1219 |
+
return_image_latents=return_image_latents,
|
1220 |
+
)
|
1221 |
+
|
1222 |
+
if return_image_latents:
|
1223 |
+
latents, noise, image_latents = latents_outputs
|
1224 |
+
else:
|
1225 |
+
latents, noise = latents_outputs
|
1226 |
+
|
1227 |
+
# 7. Prepare mask latent variables
|
1228 |
+
mask, masked_image_latents = self.prepare_mask_latents(
|
1229 |
+
mask,
|
1230 |
+
masked_image,
|
1231 |
+
batch_size * num_images_per_prompt,
|
1232 |
+
height,
|
1233 |
+
width,
|
1234 |
+
prompt_embeds.dtype,
|
1235 |
+
device,
|
1236 |
+
generator,
|
1237 |
+
do_classifier_free_guidance,
|
1238 |
+
)
|
1239 |
+
|
1240 |
+
# 8. Check that sizes of mask, masked image and latents match
|
1241 |
+
if num_channels_unet == 9:
|
1242 |
+
# default case for runwayml/stable-diffusion-inpainting
|
1243 |
+
num_channels_mask = mask.shape[1]
|
1244 |
+
num_channels_masked_image = masked_image_latents.shape[1]
|
1245 |
+
if num_channels_latents + num_channels_mask + num_channels_masked_image != self.unet.config.in_channels:
|
1246 |
+
raise ValueError(
|
1247 |
+
f"Incorrect configuration settings! The config of `pipeline.unet`: {self.unet.config} expects"
|
1248 |
+
f" {self.unet.config.in_channels} but received `num_channels_latents`: {num_channels_latents} +"
|
1249 |
+
f" `num_channels_mask`: {num_channels_mask} + `num_channels_masked_image`: {num_channels_masked_image}"
|
1250 |
+
f" = {num_channels_latents+num_channels_masked_image+num_channels_mask}. Please verify the config of"
|
1251 |
+
" `pipeline.unet` or your `mask_image` or `image` input."
|
1252 |
+
)
|
1253 |
+
elif num_channels_unet != 4:
|
1254 |
+
raise ValueError(
|
1255 |
+
f"The unet {self.unet.__class__} should have either 4 or 9 input channels, not {self.unet.config.in_channels}."
|
1256 |
+
)
|
1257 |
+
|
1258 |
+
# 9. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline
|
1259 |
+
extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)
|
1260 |
+
|
1261 |
+
# 10. Denoising loop
|
1262 |
+
num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order
|
1263 |
+
with self.progress_bar(total=num_inference_steps) as progress_bar:
|
1264 |
+
for i, t in enumerate(timesteps):
|
1265 |
+
# expand the latents if we are doing classifier free guidance
|
1266 |
+
latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents
|
1267 |
+
|
1268 |
+
# concat latents, mask, masked_image_latents in the channel dimension
|
1269 |
+
latent_model_input = self.scheduler.scale_model_input(latent_model_input, t)
|
1270 |
+
|
1271 |
+
if num_channels_unet == 9:
|
1272 |
+
latent_model_input = torch.cat([latent_model_input, mask, masked_image_latents], dim=1)
|
1273 |
+
|
1274 |
+
# predict the noise residual
|
1275 |
+
if task_class is not None:
|
1276 |
+
noise_pred = self.unet(
|
1277 |
+
sample = latent_model_input,
|
1278 |
+
timestep = t,
|
1279 |
+
encoder_hidden_states=prompt_embeds,
|
1280 |
+
cross_attention_kwargs=cross_attention_kwargs,
|
1281 |
+
return_dict=False,
|
1282 |
+
task_class = task_class,
|
1283 |
+
)[0]
|
1284 |
+
else:
|
1285 |
+
noise_pred = self.unet(
|
1286 |
+
latent_model_input,
|
1287 |
+
t,
|
1288 |
+
encoder_hidden_states=prompt_embeds,
|
1289 |
+
cross_attention_kwargs=cross_attention_kwargs,
|
1290 |
+
return_dict=False,
|
1291 |
+
)[0]
|
1292 |
+
|
1293 |
+
# perform guidance
|
1294 |
+
if do_classifier_free_guidance:
|
1295 |
+
noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
|
1296 |
+
noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)
|
1297 |
+
|
1298 |
+
# compute the previous noisy sample x_t -> x_t-1
|
1299 |
+
latents = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs, return_dict=False)[0]
|
1300 |
+
|
1301 |
+
if num_channels_unet == 4:
|
1302 |
+
init_latents_proper = image_latents[:1]
|
1303 |
+
init_mask = mask[:1]
|
1304 |
+
|
1305 |
+
if i < len(timesteps) - 1:
|
1306 |
+
noise_timestep = timesteps[i + 1]
|
1307 |
+
init_latents_proper = self.scheduler.add_noise(
|
1308 |
+
init_latents_proper, noise, torch.tensor([noise_timestep])
|
1309 |
+
)
|
1310 |
+
|
1311 |
+
latents = (1 - init_mask) * init_latents_proper + init_mask * latents
|
1312 |
+
|
1313 |
+
# call the callback, if provided
|
1314 |
+
if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0):
|
1315 |
+
progress_bar.update()
|
1316 |
+
if callback is not None and i % callback_steps == 0:
|
1317 |
+
callback(i, t, latents)
|
1318 |
+
|
1319 |
+
if not output_type == "latent":
|
1320 |
+
condition_kwargs = {}
|
1321 |
+
if isinstance(self.vae, AsymmetricAutoencoderKL):
|
1322 |
+
init_image = init_image.to(device=device, dtype=masked_image_latents.dtype)
|
1323 |
+
init_image_condition = init_image.clone()
|
1324 |
+
init_image = self._encode_vae_image(init_image, generator=generator)
|
1325 |
+
mask_condition = mask_condition.to(device=device, dtype=masked_image_latents.dtype)
|
1326 |
+
condition_kwargs = {"image": init_image_condition, "mask": mask_condition}
|
1327 |
+
image = self.vae.decode(latents / self.vae.config.scaling_factor, return_dict=False, **condition_kwargs)[0]
|
1328 |
+
image, has_nsfw_concept = self.run_safety_checker(image, device, prompt_embeds.dtype)
|
1329 |
+
else:
|
1330 |
+
image = latents
|
1331 |
+
has_nsfw_concept = None
|
1332 |
+
|
1333 |
+
if has_nsfw_concept is None:
|
1334 |
+
do_denormalize = [True] * image.shape[0]
|
1335 |
+
else:
|
1336 |
+
do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept]
|
1337 |
+
|
1338 |
+
image = self.image_processor.postprocess(image, output_type=output_type, do_denormalize=do_denormalize)
|
1339 |
+
|
1340 |
+
# Offload last model to CPU
|
1341 |
+
if hasattr(self, "final_offload_hook") and self.final_offload_hook is not None:
|
1342 |
+
self.final_offload_hook.offload()
|
1343 |
+
|
1344 |
+
if not return_dict:
|
1345 |
+
return (image, has_nsfw_concept)
|
1346 |
+
|
1347 |
+
return StableDiffusionPipelineOutput(images=image, nsfw_content_detected=has_nsfw_concept)
|
1348 |
+
|
1349 |
+
|
1350 |
+
@torch.no_grad()
|
1351 |
+
@replace_example_docstring(EXAMPLE_DOC_STRING)
|
1352 |
+
def __call__(
|
1353 |
+
self,
|
1354 |
+
promptA: Union[str, List[str]] = None,
|
1355 |
+
promptB: Union[str, List[str]] = None,
|
1356 |
+
image: Union[torch.Tensor, PIL.Image.Image] = None,
|
1357 |
+
mask_image: Union[torch.Tensor, PIL.Image.Image] = None,
|
1358 |
+
control_image: Union[
|
1359 |
+
torch.FloatTensor,
|
1360 |
+
PIL.Image.Image,
|
1361 |
+
np.ndarray,
|
1362 |
+
List[torch.FloatTensor],
|
1363 |
+
List[PIL.Image.Image],
|
1364 |
+
List[np.ndarray],
|
1365 |
+
] = None,
|
1366 |
+
height: Optional[int] = None,
|
1367 |
+
width: Optional[int] = None,
|
1368 |
+
strength: float = 1.0,
|
1369 |
+
tradoff: float = 1.0,
|
1370 |
+
tradoff_nag: float = 1.0,
|
1371 |
+
num_inference_steps: int = 50,
|
1372 |
+
guidance_scale: float = 7.5,
|
1373 |
+
negative_promptA: Optional[Union[str, List[str]]] = None,
|
1374 |
+
negative_promptB: Optional[Union[str, List[str]]] = None,
|
1375 |
+
num_images_per_prompt: Optional[int] = 1,
|
1376 |
+
eta: float = 0.0,
|
1377 |
+
generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
|
1378 |
+
latents: Optional[torch.FloatTensor] = None,
|
1379 |
+
prompt_embeds: Optional[torch.FloatTensor] = None,
|
1380 |
+
negative_prompt_embeds: Optional[torch.FloatTensor] = None,
|
1381 |
+
output_type: Optional[str] = "pil",
|
1382 |
+
return_dict: bool = True,
|
1383 |
+
callback: Optional[Callable[[int, int, torch.FloatTensor], None]] = None,
|
1384 |
+
callback_steps: int = 1,
|
1385 |
+
cross_attention_kwargs: Optional[Dict[str, Any]] = None,
|
1386 |
+
controlnet_conditioning_scale: Union[float, List[float]] = 0.5,
|
1387 |
+
guess_mode: bool = False,
|
1388 |
+
control_guidance_start: Union[float, List[float]] = 0.0,
|
1389 |
+
control_guidance_end: Union[float, List[float]] = 1.0,
|
1390 |
+
):
|
1391 |
+
r"""
|
1392 |
+
Function invoked when calling the pipeline for generation.
|
1393 |
+
|
1394 |
+
Args:
|
1395 |
+
prompt (`str` or `List[str]`, *optional*):
|
1396 |
+
The prompt or prompts to guide the image generation. If not defined, one has to pass `prompt_embeds`.
|
1397 |
+
instead.
|
1398 |
+
image (`torch.FloatTensor`, `PIL.Image.Image`, `List[torch.FloatTensor]`, `List[PIL.Image.Image]`,
|
1399 |
+
`List[List[torch.FloatTensor]]`, or `List[List[PIL.Image.Image]]`):
|
1400 |
+
The ControlNet input condition. ControlNet uses this input condition to generate guidance to Unet. If
|
1401 |
+
the type is specified as `Torch.FloatTensor`, it is passed to ControlNet as is. `PIL.Image.Image` can
|
1402 |
+
also be accepted as an image. The dimensions of the output image defaults to `image`'s dimensions. If
|
1403 |
+
height and/or width are passed, `image` is resized according to them. If multiple ControlNets are
|
1404 |
+
specified in init, images must be passed as a list such that each element of the list can be correctly
|
1405 |
+
batched for input to a single controlnet.
|
1406 |
+
height (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):
|
1407 |
+
The height in pixels of the generated image.
|
1408 |
+
width (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):
|
1409 |
+
The width in pixels of the generated image.
|
1410 |
+
strength (`float`, *optional*, defaults to 1.):
|
1411 |
+
Conceptually, indicates how much to transform the masked portion of the reference `image`. Must be
|
1412 |
+
between 0 and 1. `image` will be used as a starting point, adding more noise to it the larger the
|
1413 |
+
`strength`. The number of denoising steps depends on the amount of noise initially added. When
|
1414 |
+
`strength` is 1, added noise will be maximum and the denoising process will run for the full number of
|
1415 |
+
iterations specified in `num_inference_steps`. A value of 1, therefore, essentially ignores the masked
|
1416 |
+
portion of the reference `image`.
|
1417 |
+
num_inference_steps (`int`, *optional*, defaults to 50):
|
1418 |
+
The number of denoising steps. More denoising steps usually lead to a higher quality image at the
|
1419 |
+
expense of slower inference.
|
1420 |
+
guidance_scale (`float`, *optional*, defaults to 7.5):
|
1421 |
+
Guidance scale as defined in [Classifier-Free Diffusion Guidance](https://arxiv.org/abs/2207.12598).
|
1422 |
+
`guidance_scale` is defined as `w` of equation 2. of [Imagen
|
1423 |
+
Paper](https://arxiv.org/pdf/2205.11487.pdf). Guidance scale is enabled by setting `guidance_scale >
|
1424 |
+
1`. Higher guidance scale encourages to generate images that are closely linked to the text `prompt`,
|
1425 |
+
usually at the expense of lower image quality.
|
1426 |
+
negative_prompt (`str` or `List[str]`, *optional*):
|
1427 |
+
The prompt or prompts not to guide the image generation. If not defined, one has to pass
|
1428 |
+
`negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is
|
1429 |
+
less than `1`).
|
1430 |
+
num_images_per_prompt (`int`, *optional*, defaults to 1):
|
1431 |
+
The number of images to generate per prompt.
|
1432 |
+
eta (`float`, *optional*, defaults to 0.0):
|
1433 |
+
Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to
|
1434 |
+
[`schedulers.DDIMScheduler`], will be ignored for others.
|
1435 |
+
generator (`torch.Generator` or `List[torch.Generator]`, *optional*):
|
1436 |
+
One or a list of [torch generator(s)](https://pytorch.org/docs/stable/generated/torch.Generator.html)
|
1437 |
+
to make generation deterministic.
|
1438 |
+
latents (`torch.FloatTensor`, *optional*):
|
1439 |
+
Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image
|
1440 |
+
generation. Can be used to tweak the same generation with different prompts. If not provided, a latents
|
1441 |
+
tensor will ge generated by sampling using the supplied random `generator`.
|
1442 |
+
prompt_embeds (`torch.FloatTensor`, *optional*):
|
1443 |
+
Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not
|
1444 |
+
provided, text embeddings will be generated from `prompt` input argument.
|
1445 |
+
negative_prompt_embeds (`torch.FloatTensor`, *optional*):
|
1446 |
+
Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt
|
1447 |
+
weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input
|
1448 |
+
argument.
|
1449 |
+
output_type (`str`, *optional*, defaults to `"pil"`):
|
1450 |
+
The output format of the generate image. Choose between
|
1451 |
+
[PIL](https://pillow.readthedocs.io/en/stable/): `PIL.Image.Image` or `np.array`.
|
1452 |
+
return_dict (`bool`, *optional*, defaults to `True`):
|
1453 |
+
Whether or not to return a [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] instead of a
|
1454 |
+
plain tuple.
|
1455 |
+
callback (`Callable`, *optional*):
|
1456 |
+
A function that will be called every `callback_steps` steps during inference. The function will be
|
1457 |
+
called with the following arguments: `callback(step: int, timestep: int, latents: torch.FloatTensor)`.
|
1458 |
+
callback_steps (`int`, *optional*, defaults to 1):
|
1459 |
+
The frequency at which the `callback` function will be called. If not specified, the callback will be
|
1460 |
+
called at every step.
|
1461 |
+
cross_attention_kwargs (`dict`, *optional*):
|
1462 |
+
A kwargs dictionary that if specified is passed along to the `AttentionProcessor` as defined under
|
1463 |
+
`self.processor` in
|
1464 |
+
[diffusers.models.attention_processor](https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/attention_processor.py).
|
1465 |
+
controlnet_conditioning_scale (`float` or `List[float]`, *optional*, defaults to 0.5):
|
1466 |
+
The outputs of the controlnet are multiplied by `controlnet_conditioning_scale` before they are added
|
1467 |
+
to the residual in the original unet. If multiple ControlNets are specified in init, you can set the
|
1468 |
+
corresponding scale as a list. Note that by default, we use a smaller conditioning scale for inpainting
|
1469 |
+
than for [`~StableDiffusionControlNetPipeline.__call__`].
|
1470 |
+
guess_mode (`bool`, *optional*, defaults to `False`):
|
1471 |
+
In this mode, the ControlNet encoder will try best to recognize the content of the input image even if
|
1472 |
+
you remove all prompts. The `guidance_scale` between 3.0 and 5.0 is recommended.
|
1473 |
+
control_guidance_start (`float` or `List[float]`, *optional*, defaults to 0.0):
|
1474 |
+
The percentage of total steps at which the controlnet starts applying.
|
1475 |
+
control_guidance_end (`float` or `List[float]`, *optional*, defaults to 1.0):
|
1476 |
+
The percentage of total steps at which the controlnet stops applying.
|
1477 |
+
|
1478 |
+
Examples:
|
1479 |
+
|
1480 |
+
Returns:
|
1481 |
+
[`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`:
|
1482 |
+
[`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] if `return_dict` is True, otherwise a `tuple.
|
1483 |
+
When returning a tuple, the first element is a list with the generated images, and the second element is a
|
1484 |
+
list of `bool`s denoting whether the corresponding generated image likely represents "not-safe-for-work"
|
1485 |
+
(nsfw) content, according to the `safety_checker`.
|
1486 |
+
"""
|
1487 |
+
controlnet = self.controlnet._orig_mod if is_compiled_module(self.controlnet) else self.controlnet
|
1488 |
+
|
1489 |
+
# 0. Default height and width to unet
|
1490 |
+
height, width = self._default_height_width(height, width, image)
|
1491 |
+
|
1492 |
+
prompt = promptA
|
1493 |
+
negative_prompt = negative_promptA
|
1494 |
+
|
1495 |
+
# align format for control guidance
|
1496 |
+
if not isinstance(control_guidance_start, list) and isinstance(control_guidance_end, list):
|
1497 |
+
control_guidance_start = len(control_guidance_end) * [control_guidance_start]
|
1498 |
+
elif not isinstance(control_guidance_end, list) and isinstance(control_guidance_start, list):
|
1499 |
+
control_guidance_end = len(control_guidance_start) * [control_guidance_end]
|
1500 |
+
elif not isinstance(control_guidance_start, list) and not isinstance(control_guidance_end, list):
|
1501 |
+
mult = len(controlnet.nets) if isinstance(controlnet, MultiControlNetModel) else 1
|
1502 |
+
control_guidance_start, control_guidance_end = mult * [control_guidance_start], mult * [
|
1503 |
+
control_guidance_end
|
1504 |
+
]
|
1505 |
+
|
1506 |
+
# 1. Check inputs. Raise error if not correct
|
1507 |
+
self.check_inputs(
|
1508 |
+
prompt,
|
1509 |
+
control_image,
|
1510 |
+
height,
|
1511 |
+
width,
|
1512 |
+
callback_steps,
|
1513 |
+
negative_prompt,
|
1514 |
+
prompt_embeds,
|
1515 |
+
negative_prompt_embeds,
|
1516 |
+
controlnet_conditioning_scale,
|
1517 |
+
control_guidance_start,
|
1518 |
+
control_guidance_end,
|
1519 |
+
)
|
1520 |
+
|
1521 |
+
# 2. Define call parameters
|
1522 |
+
if prompt is not None and isinstance(prompt, str):
|
1523 |
+
batch_size = 1
|
1524 |
+
elif prompt is not None and isinstance(prompt, list):
|
1525 |
+
batch_size = len(prompt)
|
1526 |
+
else:
|
1527 |
+
batch_size = prompt_embeds.shape[0]
|
1528 |
+
|
1529 |
+
device = self._execution_device
|
1530 |
+
# here `guidance_scale` is defined analog to the guidance weight `w` of equation (2)
|
1531 |
+
# of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1`
|
1532 |
+
# corresponds to doing no classifier free guidance.
|
1533 |
+
do_classifier_free_guidance = guidance_scale > 1.0
|
1534 |
+
|
1535 |
+
if isinstance(controlnet, MultiControlNetModel) and isinstance(controlnet_conditioning_scale, float):
|
1536 |
+
controlnet_conditioning_scale = [controlnet_conditioning_scale] * len(controlnet.nets)
|
1537 |
+
|
1538 |
+
global_pool_conditions = (
|
1539 |
+
controlnet.config.global_pool_conditions
|
1540 |
+
if isinstance(controlnet, ControlNetModel)
|
1541 |
+
else controlnet.nets[0].config.global_pool_conditions
|
1542 |
+
)
|
1543 |
+
guess_mode = guess_mode or global_pool_conditions
|
1544 |
+
|
1545 |
+
# 3. Encode input prompt
|
1546 |
+
text_encoder_lora_scale = (
|
1547 |
+
cross_attention_kwargs.get("scale", None) if cross_attention_kwargs is not None else None
|
1548 |
+
)
|
1549 |
+
prompt_embeds = self._encode_prompt(
|
1550 |
+
promptA,
|
1551 |
+
promptB,
|
1552 |
+
tradoff,
|
1553 |
+
device,
|
1554 |
+
num_images_per_prompt,
|
1555 |
+
do_classifier_free_guidance,
|
1556 |
+
negative_promptA,
|
1557 |
+
negative_promptB,
|
1558 |
+
tradoff_nag,
|
1559 |
+
prompt_embeds=prompt_embeds,
|
1560 |
+
negative_prompt_embeds=negative_prompt_embeds,
|
1561 |
+
lora_scale=text_encoder_lora_scale,
|
1562 |
+
)
|
1563 |
+
|
1564 |
+
# 4. Prepare image
|
1565 |
+
if isinstance(controlnet, ControlNetModel):
|
1566 |
+
control_image = self.prepare_control_image(
|
1567 |
+
image=control_image,
|
1568 |
+
width=width,
|
1569 |
+
height=height,
|
1570 |
+
batch_size=batch_size * num_images_per_prompt,
|
1571 |
+
num_images_per_prompt=num_images_per_prompt,
|
1572 |
+
device=device,
|
1573 |
+
dtype=controlnet.dtype,
|
1574 |
+
do_classifier_free_guidance=do_classifier_free_guidance,
|
1575 |
+
guess_mode=guess_mode,
|
1576 |
+
)
|
1577 |
+
elif isinstance(controlnet, MultiControlNetModel):
|
1578 |
+
control_images = []
|
1579 |
+
|
1580 |
+
for control_image_ in control_image:
|
1581 |
+
control_image_ = self.prepare_control_image(
|
1582 |
+
image=control_image_,
|
1583 |
+
width=width,
|
1584 |
+
height=height,
|
1585 |
+
batch_size=batch_size * num_images_per_prompt,
|
1586 |
+
num_images_per_prompt=num_images_per_prompt,
|
1587 |
+
device=device,
|
1588 |
+
dtype=controlnet.dtype,
|
1589 |
+
do_classifier_free_guidance=do_classifier_free_guidance,
|
1590 |
+
guess_mode=guess_mode,
|
1591 |
+
)
|
1592 |
+
|
1593 |
+
control_images.append(control_image_)
|
1594 |
+
|
1595 |
+
control_image = control_images
|
1596 |
+
else:
|
1597 |
+
assert False
|
1598 |
+
|
1599 |
+
# 4. Preprocess mask and image - resizes image and mask w.r.t height and width
|
1600 |
+
mask, masked_image, init_image = prepare_mask_and_masked_image(
|
1601 |
+
image, mask_image, height, width, return_image=True
|
1602 |
+
)
|
1603 |
+
|
1604 |
+
# 5. Prepare timesteps
|
1605 |
+
self.scheduler.set_timesteps(num_inference_steps, device=device)
|
1606 |
+
timesteps, num_inference_steps = self.get_timesteps(
|
1607 |
+
num_inference_steps=num_inference_steps, strength=strength, device=device
|
1608 |
+
)
|
1609 |
+
# at which timestep to set the initial noise (n.b. 50% if strength is 0.5)
|
1610 |
+
latent_timestep = timesteps[:1].repeat(batch_size * num_images_per_prompt)
|
1611 |
+
# create a boolean to check if the strength is set to 1. if so then initialise the latents with pure noise
|
1612 |
+
is_strength_max = strength == 1.0
|
1613 |
+
|
1614 |
+
# 6. Prepare latent variables
|
1615 |
+
num_channels_latents = self.vae.config.latent_channels
|
1616 |
+
num_channels_unet = self.unet.config.in_channels
|
1617 |
+
return_image_latents = num_channels_unet == 4
|
1618 |
+
latents_outputs = self.prepare_latents(
|
1619 |
+
batch_size * num_images_per_prompt,
|
1620 |
+
num_channels_latents,
|
1621 |
+
height,
|
1622 |
+
width,
|
1623 |
+
prompt_embeds.dtype,
|
1624 |
+
device,
|
1625 |
+
generator,
|
1626 |
+
latents,
|
1627 |
+
image=init_image,
|
1628 |
+
timestep=latent_timestep,
|
1629 |
+
is_strength_max=is_strength_max,
|
1630 |
+
return_noise=True,
|
1631 |
+
return_image_latents=return_image_latents,
|
1632 |
+
)
|
1633 |
+
|
1634 |
+
if return_image_latents:
|
1635 |
+
latents, noise, image_latents = latents_outputs
|
1636 |
+
else:
|
1637 |
+
latents, noise = latents_outputs
|
1638 |
+
|
1639 |
+
# 7. Prepare mask latent variables
|
1640 |
+
mask, masked_image_latents = self.prepare_mask_latents(
|
1641 |
+
mask,
|
1642 |
+
masked_image,
|
1643 |
+
batch_size * num_images_per_prompt,
|
1644 |
+
height,
|
1645 |
+
width,
|
1646 |
+
prompt_embeds.dtype,
|
1647 |
+
device,
|
1648 |
+
generator,
|
1649 |
+
do_classifier_free_guidance,
|
1650 |
+
)
|
1651 |
+
|
1652 |
+
# 7. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline
|
1653 |
+
extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)
|
1654 |
+
|
1655 |
+
# 7.1 Create tensor stating which controlnets to keep
|
1656 |
+
controlnet_keep = []
|
1657 |
+
for i in range(len(timesteps)):
|
1658 |
+
keeps = [
|
1659 |
+
1.0 - float(i / len(timesteps) < s or (i + 1) / len(timesteps) > e)
|
1660 |
+
for s, e in zip(control_guidance_start, control_guidance_end)
|
1661 |
+
]
|
1662 |
+
controlnet_keep.append(keeps[0] if isinstance(controlnet, ControlNetModel) else keeps)
|
1663 |
+
|
1664 |
+
# 8. Denoising loop
|
1665 |
+
num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order
|
1666 |
+
with self.progress_bar(total=num_inference_steps) as progress_bar:
|
1667 |
+
for i, t in enumerate(timesteps):
|
1668 |
+
# expand the latents if we are doing classifier free guidance
|
1669 |
+
latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents
|
1670 |
+
latent_model_input = self.scheduler.scale_model_input(latent_model_input, t)
|
1671 |
+
|
1672 |
+
# controlnet(s) inference
|
1673 |
+
if guess_mode and do_classifier_free_guidance:
|
1674 |
+
# Infer ControlNet only for the conditional batch.
|
1675 |
+
control_model_input = latents
|
1676 |
+
control_model_input = self.scheduler.scale_model_input(control_model_input, t)
|
1677 |
+
controlnet_prompt_embeds = prompt_embeds.chunk(2)[1]
|
1678 |
+
else:
|
1679 |
+
control_model_input = latent_model_input
|
1680 |
+
controlnet_prompt_embeds = prompt_embeds
|
1681 |
+
|
1682 |
+
if isinstance(controlnet_keep[i], list):
|
1683 |
+
cond_scale = [c * s for c, s in zip(controlnet_conditioning_scale, controlnet_keep[i])]
|
1684 |
+
else:
|
1685 |
+
controlnet_cond_scale = controlnet_conditioning_scale
|
1686 |
+
if isinstance(controlnet_cond_scale, list):
|
1687 |
+
controlnet_cond_scale = controlnet_cond_scale[0]
|
1688 |
+
cond_scale = controlnet_cond_scale * controlnet_keep[i]
|
1689 |
+
|
1690 |
+
down_block_res_samples, mid_block_res_sample = self.controlnet(
|
1691 |
+
control_model_input,
|
1692 |
+
t,
|
1693 |
+
encoder_hidden_states=controlnet_prompt_embeds,
|
1694 |
+
controlnet_cond=control_image,
|
1695 |
+
conditioning_scale=cond_scale,
|
1696 |
+
guess_mode=guess_mode,
|
1697 |
+
return_dict=False,
|
1698 |
+
)
|
1699 |
+
|
1700 |
+
if guess_mode and do_classifier_free_guidance:
|
1701 |
+
# Infered ControlNet only for the conditional batch.
|
1702 |
+
# To apply the output of ControlNet to both the unconditional and conditional batches,
|
1703 |
+
# add 0 to the unconditional batch to keep it unchanged.
|
1704 |
+
down_block_res_samples = [torch.cat([torch.zeros_like(d), d]) for d in down_block_res_samples]
|
1705 |
+
mid_block_res_sample = torch.cat([torch.zeros_like(mid_block_res_sample), mid_block_res_sample])
|
1706 |
+
|
1707 |
+
# predict the noise residual
|
1708 |
+
if num_channels_unet == 9:
|
1709 |
+
latent_model_input = torch.cat([latent_model_input, mask, masked_image_latents], dim=1)
|
1710 |
+
|
1711 |
+
noise_pred = self.unet(
|
1712 |
+
latent_model_input,
|
1713 |
+
t,
|
1714 |
+
encoder_hidden_states=prompt_embeds,
|
1715 |
+
cross_attention_kwargs=cross_attention_kwargs,
|
1716 |
+
down_block_additional_residuals=down_block_res_samples,
|
1717 |
+
mid_block_additional_residual=mid_block_res_sample,
|
1718 |
+
return_dict=False,
|
1719 |
+
)[0]
|
1720 |
+
|
1721 |
+
# perform guidance
|
1722 |
+
if do_classifier_free_guidance:
|
1723 |
+
noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
|
1724 |
+
noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)
|
1725 |
+
|
1726 |
+
# compute the previous noisy sample x_t -> x_t-1
|
1727 |
+
latents = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs, return_dict=False)[0]
|
1728 |
+
|
1729 |
+
if num_channels_unet == 4:
|
1730 |
+
init_latents_proper = image_latents[:1]
|
1731 |
+
init_mask = mask[:1]
|
1732 |
+
|
1733 |
+
if i < len(timesteps) - 1:
|
1734 |
+
noise_timestep = timesteps[i + 1]
|
1735 |
+
init_latents_proper = self.scheduler.add_noise(
|
1736 |
+
init_latents_proper, noise, torch.tensor([noise_timestep])
|
1737 |
+
)
|
1738 |
+
|
1739 |
+
latents = (1 - init_mask) * init_latents_proper + init_mask * latents
|
1740 |
+
|
1741 |
+
# call the callback, if provided
|
1742 |
+
if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0):
|
1743 |
+
progress_bar.update()
|
1744 |
+
if callback is not None and i % callback_steps == 0:
|
1745 |
+
callback(i, t, latents)
|
1746 |
+
|
1747 |
+
# If we do sequential model offloading, let's offload unet and controlnet
|
1748 |
+
# manually for max memory savings
|
1749 |
+
if hasattr(self, "final_offload_hook") and self.final_offload_hook is not None:
|
1750 |
+
self.unet.to("cpu")
|
1751 |
+
self.controlnet.to("cpu")
|
1752 |
+
torch.cuda.empty_cache()
|
1753 |
+
|
1754 |
+
if not output_type == "latent":
|
1755 |
+
image = self.vae.decode(latents / self.vae.config.scaling_factor, return_dict=False)[0]
|
1756 |
+
image, has_nsfw_concept = self.run_safety_checker(image, device, prompt_embeds.dtype)
|
1757 |
+
else:
|
1758 |
+
image = latents
|
1759 |
+
has_nsfw_concept = None
|
1760 |
+
|
1761 |
+
if has_nsfw_concept is None:
|
1762 |
+
do_denormalize = [True] * image.shape[0]
|
1763 |
+
else:
|
1764 |
+
do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept]
|
1765 |
+
|
1766 |
+
image = self.image_processor.postprocess(image, output_type=output_type, do_denormalize=do_denormalize)
|
1767 |
+
|
1768 |
+
# Offload last model to CPU
|
1769 |
+
if hasattr(self, "final_offload_hook") and self.final_offload_hook is not None:
|
1770 |
+
self.final_offload_hook.offload()
|
1771 |
+
|
1772 |
+
if not return_dict:
|
1773 |
+
return (image, has_nsfw_concept)
|
1774 |
+
|
1775 |
+
return StableDiffusionPipelineOutput(images=image, nsfw_content_detected=has_nsfw_concept)
|
iopaint/model/power_paint/power_paint.py
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from PIL import Image
|
2 |
+
import PIL.Image
|
3 |
+
import cv2
|
4 |
+
import torch
|
5 |
+
from loguru import logger
|
6 |
+
|
7 |
+
from ..base import DiffusionInpaintModel
|
8 |
+
from ..helper.cpu_text_encoder import CPUTextEncoderWrapper
|
9 |
+
from ..utils import (
|
10 |
+
handle_from_pretrained_exceptions,
|
11 |
+
get_torch_dtype,
|
12 |
+
enable_low_mem,
|
13 |
+
is_local_files_only,
|
14 |
+
)
|
15 |
+
from iopaint.schema import InpaintRequest
|
16 |
+
from .powerpaint_tokenizer import add_task_to_prompt
|
17 |
+
from ...const import POWERPAINT_NAME
|
18 |
+
|
19 |
+
|
20 |
+
class PowerPaint(DiffusionInpaintModel):
|
21 |
+
name = POWERPAINT_NAME
|
22 |
+
pad_mod = 8
|
23 |
+
min_size = 512
|
24 |
+
lcm_lora_id = "latent-consistency/lcm-lora-sdv1-5"
|
25 |
+
|
26 |
+
def init_model(self, device: torch.device, **kwargs):
|
27 |
+
from .pipeline_powerpaint import StableDiffusionInpaintPipeline
|
28 |
+
from .powerpaint_tokenizer import PowerPaintTokenizer
|
29 |
+
|
30 |
+
use_gpu, torch_dtype = get_torch_dtype(device, kwargs.get("no_half", False))
|
31 |
+
model_kwargs = {"local_files_only": is_local_files_only(**kwargs)}
|
32 |
+
if kwargs["disable_nsfw"] or kwargs.get("cpu_offload", False):
|
33 |
+
logger.info("Disable Stable Diffusion Model NSFW checker")
|
34 |
+
model_kwargs.update(
|
35 |
+
dict(
|
36 |
+
safety_checker=None,
|
37 |
+
feature_extractor=None,
|
38 |
+
requires_safety_checker=False,
|
39 |
+
)
|
40 |
+
)
|
41 |
+
|
42 |
+
self.model = handle_from_pretrained_exceptions(
|
43 |
+
StableDiffusionInpaintPipeline.from_pretrained,
|
44 |
+
pretrained_model_name_or_path=self.name,
|
45 |
+
variant="fp16",
|
46 |
+
torch_dtype=torch_dtype,
|
47 |
+
**model_kwargs,
|
48 |
+
)
|
49 |
+
self.model.tokenizer = PowerPaintTokenizer(self.model.tokenizer)
|
50 |
+
|
51 |
+
enable_low_mem(self.model, kwargs.get("low_mem", False))
|
52 |
+
|
53 |
+
if kwargs.get("cpu_offload", False) and use_gpu:
|
54 |
+
logger.info("Enable sequential cpu offload")
|
55 |
+
self.model.enable_sequential_cpu_offload(gpu_id=0)
|
56 |
+
else:
|
57 |
+
self.model = self.model.to(device)
|
58 |
+
if kwargs["sd_cpu_textencoder"]:
|
59 |
+
logger.info("Run Stable Diffusion TextEncoder on CPU")
|
60 |
+
self.model.text_encoder = CPUTextEncoderWrapper(
|
61 |
+
self.model.text_encoder, torch_dtype
|
62 |
+
)
|
63 |
+
|
64 |
+
self.callback = kwargs.pop("callback", None)
|
65 |
+
|
66 |
+
def forward(self, image, mask, config: InpaintRequest):
|
67 |
+
"""Input image and output image have same size
|
68 |
+
image: [H, W, C] RGB
|
69 |
+
mask: [H, W, 1] 255 means area to repaint
|
70 |
+
return: BGR IMAGE
|
71 |
+
"""
|
72 |
+
self.set_scheduler(config)
|
73 |
+
|
74 |
+
img_h, img_w = image.shape[:2]
|
75 |
+
promptA, promptB, negative_promptA, negative_promptB = add_task_to_prompt(
|
76 |
+
config.prompt, config.negative_prompt, config.powerpaint_task
|
77 |
+
)
|
78 |
+
|
79 |
+
output = self.model(
|
80 |
+
image=PIL.Image.fromarray(image),
|
81 |
+
promptA=promptA,
|
82 |
+
promptB=promptB,
|
83 |
+
tradoff=config.fitting_degree,
|
84 |
+
tradoff_nag=config.fitting_degree,
|
85 |
+
negative_promptA=negative_promptA,
|
86 |
+
negative_promptB=negative_promptB,
|
87 |
+
mask_image=PIL.Image.fromarray(mask[:, :, -1], mode="L"),
|
88 |
+
num_inference_steps=config.sd_steps,
|
89 |
+
strength=config.sd_strength,
|
90 |
+
guidance_scale=config.sd_guidance_scale,
|
91 |
+
output_type="np",
|
92 |
+
callback=self.callback,
|
93 |
+
height=img_h,
|
94 |
+
width=img_w,
|
95 |
+
generator=torch.manual_seed(config.sd_seed),
|
96 |
+
callback_steps=1,
|
97 |
+
).images[0]
|
98 |
+
|
99 |
+
output = (output * 255).round().astype("uint8")
|
100 |
+
output = cv2.cvtColor(output, cv2.COLOR_RGB2BGR)
|
101 |
+
return output
|
iopaint/model/sd.py
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import PIL.Image
|
2 |
+
import cv2
|
3 |
+
import torch
|
4 |
+
from loguru import logger
|
5 |
+
|
6 |
+
from .base import DiffusionInpaintModel
|
7 |
+
from .helper.cpu_text_encoder import CPUTextEncoderWrapper
|
8 |
+
from .original_sd_configs import get_config_files
|
9 |
+
from .utils import (
|
10 |
+
handle_from_pretrained_exceptions,
|
11 |
+
get_torch_dtype,
|
12 |
+
enable_low_mem,
|
13 |
+
is_local_files_only,
|
14 |
+
)
|
15 |
+
from iopaint.schema import InpaintRequest, ModelType
|
16 |
+
|
17 |
+
|
18 |
+
class SD(DiffusionInpaintModel):
|
19 |
+
pad_mod = 8
|
20 |
+
min_size = 512
|
21 |
+
lcm_lora_id = "latent-consistency/lcm-lora-sdv1-5"
|
22 |
+
|
23 |
+
def init_model(self, device: torch.device, **kwargs):
|
24 |
+
from diffusers.pipelines.stable_diffusion import StableDiffusionInpaintPipeline
|
25 |
+
|
26 |
+
use_gpu, torch_dtype = get_torch_dtype(device, kwargs.get("no_half", False))
|
27 |
+
|
28 |
+
model_kwargs = {
|
29 |
+
**kwargs.get("pipe_components", {}),
|
30 |
+
"local_files_only": is_local_files_only(**kwargs),
|
31 |
+
}
|
32 |
+
disable_nsfw_checker = kwargs["disable_nsfw"] or kwargs.get(
|
33 |
+
"cpu_offload", False
|
34 |
+
)
|
35 |
+
if disable_nsfw_checker:
|
36 |
+
logger.info("Disable Stable Diffusion Model NSFW checker")
|
37 |
+
model_kwargs.update(
|
38 |
+
dict(
|
39 |
+
safety_checker=None,
|
40 |
+
feature_extractor=None,
|
41 |
+
requires_safety_checker=False,
|
42 |
+
)
|
43 |
+
)
|
44 |
+
|
45 |
+
if self.model_info.is_single_file_diffusers:
|
46 |
+
if self.model_info.model_type == ModelType.DIFFUSERS_SD:
|
47 |
+
model_kwargs["num_in_channels"] = 4
|
48 |
+
else:
|
49 |
+
model_kwargs["num_in_channels"] = 9
|
50 |
+
|
51 |
+
self.model = StableDiffusionInpaintPipeline.from_single_file(
|
52 |
+
self.model_id_or_path,
|
53 |
+
torch_dtype=torch_dtype,
|
54 |
+
load_safety_checker=not disable_nsfw_checker,
|
55 |
+
config_files=get_config_files(),
|
56 |
+
**model_kwargs,
|
57 |
+
)
|
58 |
+
else:
|
59 |
+
self.model = handle_from_pretrained_exceptions(
|
60 |
+
StableDiffusionInpaintPipeline.from_pretrained,
|
61 |
+
pretrained_model_name_or_path=self.model_id_or_path,
|
62 |
+
variant="fp16",
|
63 |
+
torch_dtype=torch_dtype,
|
64 |
+
**model_kwargs,
|
65 |
+
)
|
66 |
+
|
67 |
+
enable_low_mem(self.model, kwargs.get("low_mem", False))
|
68 |
+
|
69 |
+
if kwargs.get("cpu_offload", False) and use_gpu:
|
70 |
+
logger.info("Enable sequential cpu offload")
|
71 |
+
self.model.enable_sequential_cpu_offload(gpu_id=0)
|
72 |
+
else:
|
73 |
+
self.model = self.model.to(device)
|
74 |
+
if kwargs["sd_cpu_textencoder"]:
|
75 |
+
logger.info("Run Stable Diffusion TextEncoder on CPU")
|
76 |
+
self.model.text_encoder = CPUTextEncoderWrapper(
|
77 |
+
self.model.text_encoder, torch_dtype
|
78 |
+
)
|
79 |
+
|
80 |
+
self.callback = kwargs.pop("callback", None)
|
81 |
+
|
82 |
+
def forward(self, image, mask, config: InpaintRequest):
|
83 |
+
"""Input image and output image have same size
|
84 |
+
image: [H, W, C] RGB
|
85 |
+
mask: [H, W, 1] 255 means area to repaint
|
86 |
+
return: BGR IMAGE
|
87 |
+
"""
|
88 |
+
self.set_scheduler(config)
|
89 |
+
|
90 |
+
img_h, img_w = image.shape[:2]
|
91 |
+
|
92 |
+
output = self.model(
|
93 |
+
image=PIL.Image.fromarray(image),
|
94 |
+
prompt=config.prompt,
|
95 |
+
negative_prompt=config.negative_prompt,
|
96 |
+
mask_image=PIL.Image.fromarray(mask[:, :, -1], mode="L"),
|
97 |
+
num_inference_steps=config.sd_steps,
|
98 |
+
strength=config.sd_strength,
|
99 |
+
guidance_scale=config.sd_guidance_scale,
|
100 |
+
output_type="np",
|
101 |
+
callback_on_step_end=self.callback,
|
102 |
+
height=img_h,
|
103 |
+
width=img_w,
|
104 |
+
generator=torch.manual_seed(config.sd_seed),
|
105 |
+
).images[0]
|
106 |
+
|
107 |
+
output = (output * 255).round().astype("uint8")
|
108 |
+
output = cv2.cvtColor(output, cv2.COLOR_RGB2BGR)
|
109 |
+
return output
|
110 |
+
|
111 |
+
|
112 |
+
class SD15(SD):
|
113 |
+
name = "runwayml/stable-diffusion-inpainting"
|
114 |
+
model_id_or_path = "runwayml/stable-diffusion-inpainting"
|
115 |
+
|
116 |
+
|
117 |
+
class Anything4(SD):
|
118 |
+
name = "Sanster/anything-4.0-inpainting"
|
119 |
+
model_id_or_path = "Sanster/anything-4.0-inpainting"
|
120 |
+
|
121 |
+
|
122 |
+
class RealisticVision14(SD):
|
123 |
+
name = "Sanster/Realistic_Vision_V1.4-inpainting"
|
124 |
+
model_id_or_path = "Sanster/Realistic_Vision_V1.4-inpainting"
|
125 |
+
|
126 |
+
|
127 |
+
class SD2(SD):
|
128 |
+
name = "stabilityai/stable-diffusion-2-inpainting"
|
129 |
+
model_id_or_path = "stabilityai/stable-diffusion-2-inpainting"
|
iopaint/model/sdxl.py
ADDED
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
import PIL.Image
|
4 |
+
import cv2
|
5 |
+
import torch
|
6 |
+
from diffusers import AutoencoderKL
|
7 |
+
from loguru import logger
|
8 |
+
|
9 |
+
from iopaint.schema import InpaintRequest, ModelType
|
10 |
+
|
11 |
+
from .base import DiffusionInpaintModel
|
12 |
+
from .helper.cpu_text_encoder import CPUTextEncoderWrapper
|
13 |
+
from .original_sd_configs import get_config_files
|
14 |
+
from .utils import (
|
15 |
+
handle_from_pretrained_exceptions,
|
16 |
+
get_torch_dtype,
|
17 |
+
enable_low_mem,
|
18 |
+
is_local_files_only,
|
19 |
+
)
|
20 |
+
|
21 |
+
|
22 |
+
class SDXL(DiffusionInpaintModel):
|
23 |
+
name = "diffusers/stable-diffusion-xl-1.0-inpainting-0.1"
|
24 |
+
pad_mod = 8
|
25 |
+
min_size = 512
|
26 |
+
lcm_lora_id = "latent-consistency/lcm-lora-sdxl"
|
27 |
+
model_id_or_path = "diffusers/stable-diffusion-xl-1.0-inpainting-0.1"
|
28 |
+
|
29 |
+
def init_model(self, device: torch.device, **kwargs):
|
30 |
+
from diffusers.pipelines import StableDiffusionXLInpaintPipeline
|
31 |
+
|
32 |
+
use_gpu, torch_dtype = get_torch_dtype(device, kwargs.get("no_half", False))
|
33 |
+
|
34 |
+
if self.model_info.model_type == ModelType.DIFFUSERS_SDXL:
|
35 |
+
num_in_channels = 4
|
36 |
+
else:
|
37 |
+
num_in_channels = 9
|
38 |
+
|
39 |
+
if os.path.isfile(self.model_id_or_path):
|
40 |
+
self.model = StableDiffusionXLInpaintPipeline.from_single_file(
|
41 |
+
self.model_id_or_path,
|
42 |
+
torch_dtype=torch_dtype,
|
43 |
+
num_in_channels=num_in_channels,
|
44 |
+
load_safety_checker=False,
|
45 |
+
config_files=get_config_files()
|
46 |
+
)
|
47 |
+
else:
|
48 |
+
model_kwargs = {
|
49 |
+
**kwargs.get("pipe_components", {}),
|
50 |
+
"local_files_only": is_local_files_only(**kwargs),
|
51 |
+
}
|
52 |
+
if "vae" not in model_kwargs:
|
53 |
+
vae = AutoencoderKL.from_pretrained(
|
54 |
+
"madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch_dtype
|
55 |
+
)
|
56 |
+
model_kwargs["vae"] = vae
|
57 |
+
self.model = handle_from_pretrained_exceptions(
|
58 |
+
StableDiffusionXLInpaintPipeline.from_pretrained,
|
59 |
+
pretrained_model_name_or_path=self.model_id_or_path,
|
60 |
+
torch_dtype=torch_dtype,
|
61 |
+
variant="fp16",
|
62 |
+
**model_kwargs
|
63 |
+
)
|
64 |
+
|
65 |
+
enable_low_mem(self.model, kwargs.get("low_mem", False))
|
66 |
+
|
67 |
+
if kwargs.get("cpu_offload", False) and use_gpu:
|
68 |
+
logger.info("Enable sequential cpu offload")
|
69 |
+
self.model.enable_sequential_cpu_offload(gpu_id=0)
|
70 |
+
else:
|
71 |
+
self.model = self.model.to(device)
|
72 |
+
if kwargs["sd_cpu_textencoder"]:
|
73 |
+
logger.info("Run Stable Diffusion TextEncoder on CPU")
|
74 |
+
self.model.text_encoder = CPUTextEncoderWrapper(
|
75 |
+
self.model.text_encoder, torch_dtype
|
76 |
+
)
|
77 |
+
self.model.text_encoder_2 = CPUTextEncoderWrapper(
|
78 |
+
self.model.text_encoder_2, torch_dtype
|
79 |
+
)
|
80 |
+
|
81 |
+
self.callback = kwargs.pop("callback", None)
|
82 |
+
|
83 |
+
def forward(self, image, mask, config: InpaintRequest):
|
84 |
+
"""Input image and output image have same size
|
85 |
+
image: [H, W, C] RGB
|
86 |
+
mask: [H, W, 1] 255 means area to repaint
|
87 |
+
return: BGR IMAGE
|
88 |
+
"""
|
89 |
+
self.set_scheduler(config)
|
90 |
+
|
91 |
+
img_h, img_w = image.shape[:2]
|
92 |
+
|
93 |
+
output = self.model(
|
94 |
+
image=PIL.Image.fromarray(image),
|
95 |
+
prompt=config.prompt,
|
96 |
+
negative_prompt=config.negative_prompt,
|
97 |
+
mask_image=PIL.Image.fromarray(mask[:, :, -1], mode="L"),
|
98 |
+
num_inference_steps=config.sd_steps,
|
99 |
+
strength=0.999 if config.sd_strength == 1.0 else config.sd_strength,
|
100 |
+
guidance_scale=config.sd_guidance_scale,
|
101 |
+
output_type="np",
|
102 |
+
callback_on_step_end=self.callback,
|
103 |
+
height=img_h,
|
104 |
+
width=img_w,
|
105 |
+
generator=torch.manual_seed(config.sd_seed),
|
106 |
+
).images[0]
|
107 |
+
|
108 |
+
output = (output * 255).round().astype("uint8")
|
109 |
+
output = cv2.cvtColor(output, cv2.COLOR_RGB2BGR)
|
110 |
+
return output
|
iopaint/plugins/realesrgan.py
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import numpy as np
|
3 |
+
import torch
|
4 |
+
from loguru import logger
|
5 |
+
|
6 |
+
from iopaint.helper import download_model
|
7 |
+
from iopaint.plugins.base_plugin import BasePlugin
|
8 |
+
from iopaint.schema import RunPluginRequest, RealESRGANModel
|
9 |
+
|
10 |
+
|
11 |
+
class RealESRGANUpscaler(BasePlugin):
|
12 |
+
name = "RealESRGAN"
|
13 |
+
support_gen_image = True
|
14 |
+
|
15 |
+
def __init__(self, name, device, no_half=False):
|
16 |
+
super().__init__()
|
17 |
+
self.model_name = name
|
18 |
+
self.device = device
|
19 |
+
self.no_half = no_half
|
20 |
+
self._init_model(name)
|
21 |
+
|
22 |
+
def _init_model(self, name):
|
23 |
+
from basicsr.archs.rrdbnet_arch import RRDBNet
|
24 |
+
from realesrgan import RealESRGANer
|
25 |
+
from realesrgan.archs.srvgg_arch import SRVGGNetCompact
|
26 |
+
|
27 |
+
REAL_ESRGAN_MODELS = {
|
28 |
+
RealESRGANModel.realesr_general_x4v3: {
|
29 |
+
"url": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth",
|
30 |
+
"scale": 4,
|
31 |
+
"model": lambda: SRVGGNetCompact(
|
32 |
+
num_in_ch=3,
|
33 |
+
num_out_ch=3,
|
34 |
+
num_feat=64,
|
35 |
+
num_conv=32,
|
36 |
+
upscale=4,
|
37 |
+
act_type="prelu",
|
38 |
+
),
|
39 |
+
"model_md5": "91a7644643c884ee00737db24e478156",
|
40 |
+
},
|
41 |
+
RealESRGANModel.RealESRGAN_x4plus: {
|
42 |
+
"url": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth",
|
43 |
+
"scale": 4,
|
44 |
+
"model": lambda: RRDBNet(
|
45 |
+
num_in_ch=3,
|
46 |
+
num_out_ch=3,
|
47 |
+
num_feat=64,
|
48 |
+
num_block=23,
|
49 |
+
num_grow_ch=32,
|
50 |
+
scale=4,
|
51 |
+
),
|
52 |
+
"model_md5": "99ec365d4afad750833258a1a24f44ca",
|
53 |
+
},
|
54 |
+
RealESRGANModel.RealESRGAN_x4plus_anime_6B: {
|
55 |
+
"url": "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth",
|
56 |
+
"scale": 4,
|
57 |
+
"model": lambda: RRDBNet(
|
58 |
+
num_in_ch=3,
|
59 |
+
num_out_ch=3,
|
60 |
+
num_feat=64,
|
61 |
+
num_block=6,
|
62 |
+
num_grow_ch=32,
|
63 |
+
scale=4,
|
64 |
+
),
|
65 |
+
"model_md5": "d58ce384064ec1591c2ea7b79dbf47ba",
|
66 |
+
},
|
67 |
+
}
|
68 |
+
if name not in REAL_ESRGAN_MODELS:
|
69 |
+
raise ValueError(f"Unknown RealESRGAN model name: {name}")
|
70 |
+
model_info = REAL_ESRGAN_MODELS[name]
|
71 |
+
|
72 |
+
model_path = download_model(model_info["url"], model_info["model_md5"])
|
73 |
+
logger.info(f"RealESRGAN model path: {model_path}")
|
74 |
+
|
75 |
+
self.model = RealESRGANer(
|
76 |
+
scale=model_info["scale"],
|
77 |
+
model_path=model_path,
|
78 |
+
model=model_info["model"](),
|
79 |
+
half=True if "cuda" in str(self.device) and not self.no_half else False,
|
80 |
+
tile=512,
|
81 |
+
tile_pad=10,
|
82 |
+
pre_pad=10,
|
83 |
+
device=self.device,
|
84 |
+
)
|
85 |
+
|
86 |
+
def switch_model(self, new_model_name: str):
|
87 |
+
if self.model_name == new_model_name:
|
88 |
+
return
|
89 |
+
self._init_model(new_model_name)
|
90 |
+
self.model_name = new_model_name
|
91 |
+
|
92 |
+
def gen_image(self, rgb_np_img, req: RunPluginRequest) -> np.ndarray:
|
93 |
+
bgr_np_img = cv2.cvtColor(rgb_np_img, cv2.COLOR_RGB2BGR)
|
94 |
+
logger.info(f"RealESRGAN input shape: {bgr_np_img.shape}, scale: {req.scale}")
|
95 |
+
result = self.forward(bgr_np_img, req.scale)
|
96 |
+
logger.info(f"RealESRGAN output shape: {result.shape}")
|
97 |
+
return result
|
98 |
+
|
99 |
+
@torch.inference_mode()
|
100 |
+
def forward(self, bgr_np_img, scale: float):
|
101 |
+
# 输出是 BGR
|
102 |
+
upsampled = self.model.enhance(bgr_np_img, outscale=scale)[0]
|
103 |
+
return upsampled
|
104 |
+
|
105 |
+
def check_dep(self):
|
106 |
+
try:
|
107 |
+
import realesrgan
|
108 |
+
except ImportError:
|
109 |
+
return "RealESRGAN is not installed, please install it first. pip install realesrgan"
|
iopaint/plugins/remove_bg.py
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import cv2
|
3 |
+
import numpy as np
|
4 |
+
from loguru import logger
|
5 |
+
from torch.hub import get_dir
|
6 |
+
|
7 |
+
from iopaint.plugins.base_plugin import BasePlugin
|
8 |
+
from iopaint.schema import RunPluginRequest, RemoveBGModel
|
9 |
+
|
10 |
+
|
11 |
+
class RemoveBG(BasePlugin):
|
12 |
+
name = "RemoveBG"
|
13 |
+
support_gen_mask = True
|
14 |
+
support_gen_image = True
|
15 |
+
|
16 |
+
def __init__(self, model_name):
|
17 |
+
super().__init__()
|
18 |
+
self.model_name = model_name
|
19 |
+
|
20 |
+
hub_dir = get_dir()
|
21 |
+
model_dir = os.path.join(hub_dir, "checkpoints")
|
22 |
+
os.environ["U2NET_HOME"] = model_dir
|
23 |
+
|
24 |
+
self._init_session(model_name)
|
25 |
+
|
26 |
+
def _init_session(self, model_name: str):
|
27 |
+
if model_name == RemoveBGModel.briaai_rmbg_1_4:
|
28 |
+
from iopaint.plugins.briarmbg import (
|
29 |
+
create_briarmbg_session,
|
30 |
+
briarmbg_process,
|
31 |
+
)
|
32 |
+
|
33 |
+
self.session = create_briarmbg_session()
|
34 |
+
self.remove = briarmbg_process
|
35 |
+
else:
|
36 |
+
from rembg import new_session, remove
|
37 |
+
|
38 |
+
self.session = new_session(model_name=model_name)
|
39 |
+
self.remove = remove
|
40 |
+
|
41 |
+
def switch_model(self, new_model_name):
|
42 |
+
if self.model_name == new_model_name:
|
43 |
+
return
|
44 |
+
|
45 |
+
logger.info(
|
46 |
+
f"Switching removebg model from {self.model_name} to {new_model_name}"
|
47 |
+
)
|
48 |
+
self._init_session(new_model_name)
|
49 |
+
self.model_name = new_model_name
|
50 |
+
|
51 |
+
def gen_image(self, rgb_np_img, req: RunPluginRequest) -> np.ndarray:
|
52 |
+
bgr_np_img = cv2.cvtColor(rgb_np_img, cv2.COLOR_RGB2BGR)
|
53 |
+
|
54 |
+
# return BGRA image
|
55 |
+
output = self.remove(bgr_np_img, session=self.session)
|
56 |
+
return cv2.cvtColor(output, cv2.COLOR_BGRA2RGBA)
|
57 |
+
|
58 |
+
def gen_mask(self, rgb_np_img, req: RunPluginRequest) -> np.ndarray:
|
59 |
+
bgr_np_img = cv2.cvtColor(rgb_np_img, cv2.COLOR_RGB2BGR)
|
60 |
+
|
61 |
+
# return BGR image, 255 means foreground, 0 means background
|
62 |
+
output = self.remove(bgr_np_img, session=self.session, only_mask=True)
|
63 |
+
return output
|
64 |
+
|
65 |
+
def check_dep(self):
|
66 |
+
try:
|
67 |
+
import rembg
|
68 |
+
except ImportError:
|
69 |
+
return (
|
70 |
+
"RemoveBG is not installed, please install it first. pip install rembg"
|
71 |
+
)
|
iopaint/plugins/restoreformer.py
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import numpy as np
|
3 |
+
from loguru import logger
|
4 |
+
|
5 |
+
from iopaint.helper import download_model
|
6 |
+
from iopaint.plugins.base_plugin import BasePlugin
|
7 |
+
from iopaint.schema import RunPluginRequest
|
8 |
+
|
9 |
+
|
10 |
+
class RestoreFormerPlugin(BasePlugin):
|
11 |
+
name = "RestoreFormer"
|
12 |
+
support_gen_image = True
|
13 |
+
|
14 |
+
def __init__(self, device, upscaler=None):
|
15 |
+
super().__init__()
|
16 |
+
from .gfpganer import MyGFPGANer
|
17 |
+
|
18 |
+
url = "https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/RestoreFormer.pth"
|
19 |
+
model_md5 = "eaeeff6c4a1caa1673977cb374e6f699"
|
20 |
+
model_path = download_model(url, model_md5)
|
21 |
+
logger.info(f"RestoreFormer model path: {model_path}")
|
22 |
+
|
23 |
+
import facexlib
|
24 |
+
|
25 |
+
if hasattr(facexlib.detection.retinaface, "device"):
|
26 |
+
facexlib.detection.retinaface.device = device
|
27 |
+
|
28 |
+
self.face_enhancer = MyGFPGANer(
|
29 |
+
model_path=model_path,
|
30 |
+
upscale=1,
|
31 |
+
arch="RestoreFormer",
|
32 |
+
channel_multiplier=2,
|
33 |
+
device=device,
|
34 |
+
bg_upsampler=upscaler.model if upscaler is not None else None,
|
35 |
+
)
|
36 |
+
|
37 |
+
def gen_image(self, rgb_np_img, req: RunPluginRequest) -> np.ndarray:
|
38 |
+
weight = 0.5
|
39 |
+
bgr_np_img = cv2.cvtColor(rgb_np_img, cv2.COLOR_RGB2BGR)
|
40 |
+
logger.info(f"RestoreFormer input shape: {bgr_np_img.shape}")
|
41 |
+
_, _, bgr_output = self.face_enhancer.enhance(
|
42 |
+
bgr_np_img,
|
43 |
+
has_aligned=False,
|
44 |
+
only_center_face=False,
|
45 |
+
paste_back=True,
|
46 |
+
weight=weight,
|
47 |
+
)
|
48 |
+
logger.info(f"RestoreFormer output shape: {bgr_output.shape}")
|
49 |
+
return bgr_output
|
50 |
+
|
51 |
+
def check_dep(self):
|
52 |
+
try:
|
53 |
+
import gfpgan
|
54 |
+
except ImportError:
|
55 |
+
return (
|
56 |
+
"gfpgan is not installed, please install it first. pip install gfpgan"
|
57 |
+
)
|
iopaint/plugins/segment_anything/modeling/prompt_encoder.py
ADDED
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
2 |
+
# All rights reserved.
|
3 |
+
|
4 |
+
# This source code is licensed under the license found in the
|
5 |
+
# LICENSE file in the root directory of this source tree.
|
6 |
+
|
7 |
+
import numpy as np
|
8 |
+
import torch
|
9 |
+
from torch import nn
|
10 |
+
|
11 |
+
from typing import Any, Optional, Tuple, Type
|
12 |
+
|
13 |
+
from .common import LayerNorm2d
|
14 |
+
|
15 |
+
|
16 |
+
class PromptEncoder(nn.Module):
|
17 |
+
def __init__(
|
18 |
+
self,
|
19 |
+
embed_dim: int,
|
20 |
+
image_embedding_size: Tuple[int, int],
|
21 |
+
input_image_size: Tuple[int, int],
|
22 |
+
mask_in_chans: int,
|
23 |
+
activation: Type[nn.Module] = nn.GELU,
|
24 |
+
) -> None:
|
25 |
+
"""
|
26 |
+
Encodes prompts for input to SAM's mask decoder.
|
27 |
+
|
28 |
+
Arguments:
|
29 |
+
embed_dim (int): The prompts' embedding dimension
|
30 |
+
image_embedding_size (tuple(int, int)): The spatial size of the
|
31 |
+
image embedding, as (H, W).
|
32 |
+
input_image_size (int): The padded size of the image as input
|
33 |
+
to the image encoder, as (H, W).
|
34 |
+
mask_in_chans (int): The number of hidden channels used for
|
35 |
+
encoding input masks.
|
36 |
+
activation (nn.Module): The activation to use when encoding
|
37 |
+
input masks.
|
38 |
+
"""
|
39 |
+
super().__init__()
|
40 |
+
self.embed_dim = embed_dim
|
41 |
+
self.input_image_size = input_image_size
|
42 |
+
self.image_embedding_size = image_embedding_size
|
43 |
+
self.pe_layer = PositionEmbeddingRandom(embed_dim // 2)
|
44 |
+
|
45 |
+
self.num_point_embeddings: int = 4 # pos/neg point + 2 box corners
|
46 |
+
point_embeddings = [nn.Embedding(1, embed_dim) for i in range(self.num_point_embeddings)]
|
47 |
+
self.point_embeddings = nn.ModuleList(point_embeddings)
|
48 |
+
self.not_a_point_embed = nn.Embedding(1, embed_dim)
|
49 |
+
|
50 |
+
self.mask_input_size = (4 * image_embedding_size[0], 4 * image_embedding_size[1])
|
51 |
+
self.mask_downscaling = nn.Sequential(
|
52 |
+
nn.Conv2d(1, mask_in_chans // 4, kernel_size=2, stride=2),
|
53 |
+
LayerNorm2d(mask_in_chans // 4),
|
54 |
+
activation(),
|
55 |
+
nn.Conv2d(mask_in_chans // 4, mask_in_chans, kernel_size=2, stride=2),
|
56 |
+
LayerNorm2d(mask_in_chans),
|
57 |
+
activation(),
|
58 |
+
nn.Conv2d(mask_in_chans, embed_dim, kernel_size=1),
|
59 |
+
)
|
60 |
+
self.no_mask_embed = nn.Embedding(1, embed_dim)
|
61 |
+
|
62 |
+
def get_dense_pe(self) -> torch.Tensor:
|
63 |
+
"""
|
64 |
+
Returns the positional encoding used to encode point prompts,
|
65 |
+
applied to a dense set of points the shape of the image encoding.
|
66 |
+
|
67 |
+
Returns:
|
68 |
+
torch.Tensor: Positional encoding with shape
|
69 |
+
1x(embed_dim)x(embedding_h)x(embedding_w)
|
70 |
+
"""
|
71 |
+
return self.pe_layer(self.image_embedding_size).unsqueeze(0)
|
72 |
+
|
73 |
+
def _embed_points(
|
74 |
+
self,
|
75 |
+
points: torch.Tensor,
|
76 |
+
labels: torch.Tensor,
|
77 |
+
pad: bool,
|
78 |
+
) -> torch.Tensor:
|
79 |
+
"""Embeds point prompts."""
|
80 |
+
points = points + 0.5 # Shift to center of pixel
|
81 |
+
if pad:
|
82 |
+
padding_point = torch.zeros((points.shape[0], 1, 2), device=points.device)
|
83 |
+
padding_label = -torch.ones((labels.shape[0], 1), device=labels.device)
|
84 |
+
points = torch.cat([points, padding_point], dim=1)
|
85 |
+
labels = torch.cat([labels, padding_label], dim=1)
|
86 |
+
point_embedding = self.pe_layer.forward_with_coords(points, self.input_image_size)
|
87 |
+
point_embedding[labels == -1] = 0.0
|
88 |
+
point_embedding[labels == -1] += self.not_a_point_embed.weight
|
89 |
+
point_embedding[labels == 0] += self.point_embeddings[0].weight
|
90 |
+
point_embedding[labels == 1] += self.point_embeddings[1].weight
|
91 |
+
return point_embedding
|
92 |
+
|
93 |
+
def _embed_boxes(self, boxes: torch.Tensor) -> torch.Tensor:
|
94 |
+
"""Embeds box prompts."""
|
95 |
+
boxes = boxes + 0.5 # Shift to center of pixel
|
96 |
+
coords = boxes.reshape(-1, 2, 2)
|
97 |
+
corner_embedding = self.pe_layer.forward_with_coords(coords, self.input_image_size)
|
98 |
+
corner_embedding[:, 0, :] += self.point_embeddings[2].weight
|
99 |
+
corner_embedding[:, 1, :] += self.point_embeddings[3].weight
|
100 |
+
return corner_embedding
|
101 |
+
|
102 |
+
def _embed_masks(self, masks: torch.Tensor) -> torch.Tensor:
|
103 |
+
"""Embeds mask inputs."""
|
104 |
+
mask_embedding = self.mask_downscaling(masks)
|
105 |
+
return mask_embedding
|
106 |
+
|
107 |
+
def _get_batch_size(
|
108 |
+
self,
|
109 |
+
points: Optional[Tuple[torch.Tensor, torch.Tensor]],
|
110 |
+
boxes: Optional[torch.Tensor],
|
111 |
+
masks: Optional[torch.Tensor],
|
112 |
+
) -> int:
|
113 |
+
"""
|
114 |
+
Gets the batch size of the output given the batch size of the input prompts.
|
115 |
+
"""
|
116 |
+
if points is not None:
|
117 |
+
return points[0].shape[0]
|
118 |
+
elif boxes is not None:
|
119 |
+
return boxes.shape[0]
|
120 |
+
elif masks is not None:
|
121 |
+
return masks.shape[0]
|
122 |
+
else:
|
123 |
+
return 1
|
124 |
+
|
125 |
+
def _get_device(self) -> torch.device:
|
126 |
+
return self.point_embeddings[0].weight.device
|
127 |
+
|
128 |
+
def forward(
|
129 |
+
self,
|
130 |
+
points: Optional[Tuple[torch.Tensor, torch.Tensor]],
|
131 |
+
boxes: Optional[torch.Tensor],
|
132 |
+
masks: Optional[torch.Tensor],
|
133 |
+
) -> Tuple[torch.Tensor, torch.Tensor]:
|
134 |
+
"""
|
135 |
+
Embeds different types of prompts, returning both sparse and dense
|
136 |
+
embeddings.
|
137 |
+
|
138 |
+
Arguments:
|
139 |
+
points (tuple(torch.Tensor, torch.Tensor) or none): point coordinates
|
140 |
+
and labels to embed.
|
141 |
+
boxes (torch.Tensor or none): boxes to embed
|
142 |
+
masks (torch.Tensor or none): masks to embed
|
143 |
+
|
144 |
+
Returns:
|
145 |
+
torch.Tensor: sparse embeddings for the points and boxes, with shape
|
146 |
+
BxNx(embed_dim), where N is determined by the number of input points
|
147 |
+
and boxes.
|
148 |
+
torch.Tensor: dense embeddings for the masks, in the shape
|
149 |
+
Bx(embed_dim)x(embed_H)x(embed_W)
|
150 |
+
"""
|
151 |
+
bs = self._get_batch_size(points, boxes, masks)
|
152 |
+
sparse_embeddings = torch.empty((bs, 0, self.embed_dim), device=self._get_device())
|
153 |
+
if points is not None:
|
154 |
+
coords, labels = points
|
155 |
+
point_embeddings = self._embed_points(coords, labels, pad=(boxes is None))
|
156 |
+
sparse_embeddings = torch.cat([sparse_embeddings, point_embeddings], dim=1)
|
157 |
+
if boxes is not None:
|
158 |
+
box_embeddings = self._embed_boxes(boxes)
|
159 |
+
sparse_embeddings = torch.cat([sparse_embeddings, box_embeddings], dim=1)
|
160 |
+
|
161 |
+
if masks is not None:
|
162 |
+
dense_embeddings = self._embed_masks(masks)
|
163 |
+
else:
|
164 |
+
dense_embeddings = self.no_mask_embed.weight.reshape(1, -1, 1, 1).expand(
|
165 |
+
bs, -1, self.image_embedding_size[0], self.image_embedding_size[1]
|
166 |
+
)
|
167 |
+
|
168 |
+
return sparse_embeddings, dense_embeddings
|
169 |
+
|
170 |
+
|
171 |
+
class PositionEmbeddingRandom(nn.Module):
|
172 |
+
"""
|
173 |
+
Positional encoding using random spatial frequencies.
|
174 |
+
"""
|
175 |
+
|
176 |
+
def __init__(self, num_pos_feats: int = 64, scale: Optional[float] = None) -> None:
|
177 |
+
super().__init__()
|
178 |
+
if scale is None or scale <= 0.0:
|
179 |
+
scale = 1.0
|
180 |
+
self.register_buffer(
|
181 |
+
"positional_encoding_gaussian_matrix",
|
182 |
+
scale * torch.randn((2, num_pos_feats)),
|
183 |
+
)
|
184 |
+
|
185 |
+
def _pe_encoding(self, coords: torch.Tensor) -> torch.Tensor:
|
186 |
+
"""Positionally encode points that are normalized to [0,1]."""
|
187 |
+
# assuming coords are in [0, 1]^2 square and have d_1 x ... x d_n x 2 shape
|
188 |
+
coords = 2 * coords - 1
|
189 |
+
coords = coords @ self.positional_encoding_gaussian_matrix
|
190 |
+
coords = 2 * np.pi * coords
|
191 |
+
# outputs d_1 x ... x d_n x C shape
|
192 |
+
return torch.cat([torch.sin(coords), torch.cos(coords)], dim=-1)
|
193 |
+
|
194 |
+
def forward(self, size: Tuple[int, int]) -> torch.Tensor:
|
195 |
+
"""Generate positional encoding for a grid of the specified size."""
|
196 |
+
h, w = size
|
197 |
+
device: Any = self.positional_encoding_gaussian_matrix.device
|
198 |
+
grid = torch.ones((h, w), device=device, dtype=torch.float32)
|
199 |
+
y_embed = grid.cumsum(dim=0) - 0.5
|
200 |
+
x_embed = grid.cumsum(dim=1) - 0.5
|
201 |
+
y_embed = y_embed / h
|
202 |
+
x_embed = x_embed / w
|
203 |
+
|
204 |
+
pe = self._pe_encoding(torch.stack([x_embed, y_embed], dim=-1))
|
205 |
+
return pe.permute(2, 0, 1) # C x H x W
|
206 |
+
|
207 |
+
def forward_with_coords(
|
208 |
+
self, coords_input: torch.Tensor, image_size: Tuple[int, int]
|
209 |
+
) -> torch.Tensor:
|
210 |
+
"""Positionally encode points that are not normalized to [0,1]."""
|
211 |
+
coords = coords_input.clone()
|
212 |
+
coords[:, :, 0] = coords[:, :, 0] / image_size[1]
|
213 |
+
coords[:, :, 1] = coords[:, :, 1] / image_size[0]
|
214 |
+
return self._pe_encoding(coords.to(torch.float)) # B x N x C
|
iopaint/plugins/segment_anything/modeling/sam.py
ADDED
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
2 |
+
# All rights reserved.
|
3 |
+
|
4 |
+
# This source code is licensed under the license found in the
|
5 |
+
# LICENSE file in the root directory of this source tree.
|
6 |
+
|
7 |
+
import torch
|
8 |
+
from torch import nn
|
9 |
+
from torch.nn import functional as F
|
10 |
+
|
11 |
+
from typing import Any, Dict, List, Tuple
|
12 |
+
|
13 |
+
from .image_encoder import ImageEncoderViT
|
14 |
+
from .mask_decoder import MaskDecoder
|
15 |
+
from .prompt_encoder import PromptEncoder
|
16 |
+
|
17 |
+
|
18 |
+
class Sam(nn.Module):
|
19 |
+
mask_threshold: float = 0.0
|
20 |
+
image_format: str = "RGB"
|
21 |
+
|
22 |
+
def __init__(
|
23 |
+
self,
|
24 |
+
image_encoder: ImageEncoderViT,
|
25 |
+
prompt_encoder: PromptEncoder,
|
26 |
+
mask_decoder: MaskDecoder,
|
27 |
+
pixel_mean: List[float] = [123.675, 116.28, 103.53],
|
28 |
+
pixel_std: List[float] = [58.395, 57.12, 57.375],
|
29 |
+
) -> None:
|
30 |
+
"""
|
31 |
+
SAM predicts object masks from an image and input prompts.
|
32 |
+
|
33 |
+
Arguments:
|
34 |
+
image_encoder (ImageEncoderViT): The backbone used to encode the
|
35 |
+
image into image embeddings that allow for efficient mask prediction.
|
36 |
+
prompt_encoder (PromptEncoder): Encodes various types of input prompts.
|
37 |
+
mask_decoder (MaskDecoder): Predicts masks from the image embeddings
|
38 |
+
and encoded prompts.
|
39 |
+
pixel_mean (list(float)): Mean values for normalizing pixels in the input image.
|
40 |
+
pixel_std (list(float)): Std values for normalizing pixels in the input image.
|
41 |
+
"""
|
42 |
+
super().__init__()
|
43 |
+
self.image_encoder = image_encoder
|
44 |
+
self.prompt_encoder = prompt_encoder
|
45 |
+
self.mask_decoder = mask_decoder
|
46 |
+
self.register_buffer("pixel_mean", torch.Tensor(pixel_mean).view(-1, 1, 1), False)
|
47 |
+
self.register_buffer("pixel_std", torch.Tensor(pixel_std).view(-1, 1, 1), False)
|
48 |
+
|
49 |
+
@property
|
50 |
+
def device(self) -> Any:
|
51 |
+
return self.pixel_mean.device
|
52 |
+
|
53 |
+
@torch.no_grad()
|
54 |
+
def forward(
|
55 |
+
self,
|
56 |
+
batched_input: List[Dict[str, Any]],
|
57 |
+
multimask_output: bool,
|
58 |
+
) -> List[Dict[str, torch.Tensor]]:
|
59 |
+
"""
|
60 |
+
Predicts masks end-to-end from provided images and prompts.
|
61 |
+
If prompts are not known in advance, using SamPredictor is
|
62 |
+
recommended over calling the model directly.
|
63 |
+
|
64 |
+
Arguments:
|
65 |
+
batched_input (list(dict)): A list over input images, each a
|
66 |
+
dictionary with the following keys. A prompt key can be
|
67 |
+
excluded if it is not present.
|
68 |
+
'image': The image as a torch tensor in 3xHxW format,
|
69 |
+
already transformed for input to the model.
|
70 |
+
'original_size': (tuple(int, int)) The original size of
|
71 |
+
the image before transformation, as (H, W).
|
72 |
+
'point_coords': (torch.Tensor) Batched point prompts for
|
73 |
+
this image, with shape BxNx2. Already transformed to the
|
74 |
+
input frame of the model.
|
75 |
+
'point_labels': (torch.Tensor) Batched labels for point prompts,
|
76 |
+
with shape BxN.
|
77 |
+
'boxes': (torch.Tensor) Batched box inputs, with shape Bx4.
|
78 |
+
Already transformed to the input frame of the model.
|
79 |
+
'mask_inputs': (torch.Tensor) Batched mask inputs to the model,
|
80 |
+
in the form Bx1xHxW.
|
81 |
+
multimask_output (bool): Whether the model should predict multiple
|
82 |
+
disambiguating masks, or return a single mask.
|
83 |
+
|
84 |
+
Returns:
|
85 |
+
(list(dict)): A list over input images, where each element is
|
86 |
+
as dictionary with the following keys.
|
87 |
+
'masks': (torch.Tensor) Batched binary mask predictions,
|
88 |
+
with shape BxCxHxW, where B is the number of input promts,
|
89 |
+
C is determiend by multimask_output, and (H, W) is the
|
90 |
+
original size of the image.
|
91 |
+
'iou_predictions': (torch.Tensor) The model's predictions
|
92 |
+
of mask quality, in shape BxC.
|
93 |
+
'low_res_logits': (torch.Tensor) Low resolution logits with
|
94 |
+
shape BxCxHxW, where H=W=256. Can be passed as mask input
|
95 |
+
to subsequent iterations of prediction.
|
96 |
+
"""
|
97 |
+
input_images = torch.stack([self.preprocess(x["image"]) for x in batched_input], dim=0)
|
98 |
+
image_embeddings = self.image_encoder(input_images)
|
99 |
+
|
100 |
+
outputs = []
|
101 |
+
for image_record, curr_embedding in zip(batched_input, image_embeddings):
|
102 |
+
if "point_coords" in image_record:
|
103 |
+
points = (image_record["point_coords"], image_record["point_labels"])
|
104 |
+
else:
|
105 |
+
points = None
|
106 |
+
sparse_embeddings, dense_embeddings = self.prompt_encoder(
|
107 |
+
points=points,
|
108 |
+
boxes=image_record.get("boxes", None),
|
109 |
+
masks=image_record.get("mask_inputs", None),
|
110 |
+
)
|
111 |
+
low_res_masks, iou_predictions = self.mask_decoder(
|
112 |
+
image_embeddings=curr_embedding.unsqueeze(0),
|
113 |
+
image_pe=self.prompt_encoder.get_dense_pe(),
|
114 |
+
sparse_prompt_embeddings=sparse_embeddings,
|
115 |
+
dense_prompt_embeddings=dense_embeddings,
|
116 |
+
multimask_output=multimask_output,
|
117 |
+
)
|
118 |
+
masks = self.postprocess_masks(
|
119 |
+
low_res_masks,
|
120 |
+
input_size=image_record["image"].shape[-2:],
|
121 |
+
original_size=image_record["original_size"],
|
122 |
+
)
|
123 |
+
masks = masks > self.mask_threshold
|
124 |
+
outputs.append(
|
125 |
+
{
|
126 |
+
"masks": masks,
|
127 |
+
"iou_predictions": iou_predictions,
|
128 |
+
"low_res_logits": low_res_masks,
|
129 |
+
}
|
130 |
+
)
|
131 |
+
return outputs
|
132 |
+
|
133 |
+
def postprocess_masks(
|
134 |
+
self,
|
135 |
+
masks: torch.Tensor,
|
136 |
+
input_size: Tuple[int, ...],
|
137 |
+
original_size: Tuple[int, ...],
|
138 |
+
) -> torch.Tensor:
|
139 |
+
"""
|
140 |
+
Remove padding and upscale masks to the original image size.
|
141 |
+
|
142 |
+
Arguments:
|
143 |
+
masks (torch.Tensor): Batched masks from the mask_decoder,
|
144 |
+
in BxCxHxW format.
|
145 |
+
input_size (tuple(int, int)): The size of the image input to the
|
146 |
+
model, in (H, W) format. Used to remove padding.
|
147 |
+
original_size (tuple(int, int)): The original size of the image
|
148 |
+
before resizing for input to the model, in (H, W) format.
|
149 |
+
|
150 |
+
Returns:
|
151 |
+
(torch.Tensor): Batched masks in BxCxHxW format, where (H, W)
|
152 |
+
is given by original_size.
|
153 |
+
"""
|
154 |
+
masks = F.interpolate(
|
155 |
+
masks,
|
156 |
+
(self.image_encoder.img_size, self.image_encoder.img_size),
|
157 |
+
mode="bilinear",
|
158 |
+
align_corners=False,
|
159 |
+
)
|
160 |
+
masks = masks[..., : input_size[0], : input_size[1]]
|
161 |
+
masks = F.interpolate(masks, original_size, mode="bilinear", align_corners=False)
|
162 |
+
return masks
|
163 |
+
|
164 |
+
def preprocess(self, x: torch.Tensor) -> torch.Tensor:
|
165 |
+
"""Normalize pixel values and pad to a square input."""
|
166 |
+
# Normalize colors
|
167 |
+
x = (x - self.pixel_mean) / self.pixel_std
|
168 |
+
|
169 |
+
# Pad
|
170 |
+
h, w = x.shape[-2:]
|
171 |
+
padh = self.image_encoder.img_size - h
|
172 |
+
padw = self.image_encoder.img_size - w
|
173 |
+
x = F.pad(x, (0, padw, 0, padh))
|
174 |
+
return x
|
iopaint/plugins/segment_anything/predictor.py
ADDED
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
2 |
+
# All rights reserved.
|
3 |
+
|
4 |
+
# This source code is licensed under the license found in the
|
5 |
+
# LICENSE file in the root directory of this source tree.
|
6 |
+
|
7 |
+
import numpy as np
|
8 |
+
import torch
|
9 |
+
|
10 |
+
from .modeling import Sam
|
11 |
+
|
12 |
+
from typing import Optional, Tuple
|
13 |
+
|
14 |
+
|
15 |
+
class SamPredictor:
|
16 |
+
def __init__(
|
17 |
+
self,
|
18 |
+
sam_model: Sam,
|
19 |
+
) -> None:
|
20 |
+
"""
|
21 |
+
Uses SAM to calculate the image embedding for an image, and then
|
22 |
+
allow repeated, efficient mask prediction given prompts.
|
23 |
+
|
24 |
+
Arguments:
|
25 |
+
sam_model (Sam): The model to use for mask prediction.
|
26 |
+
"""
|
27 |
+
super().__init__()
|
28 |
+
self.model = sam_model
|
29 |
+
from .utils.transforms import ResizeLongestSide
|
30 |
+
|
31 |
+
self.transform = ResizeLongestSide(sam_model.image_encoder.img_size)
|
32 |
+
self.reset_image()
|
33 |
+
|
34 |
+
def set_image(
|
35 |
+
self,
|
36 |
+
image: np.ndarray,
|
37 |
+
image_format: str = "RGB",
|
38 |
+
) -> None:
|
39 |
+
"""
|
40 |
+
Calculates the image embeddings for the provided image, allowing
|
41 |
+
masks to be predicted with the 'predict' method.
|
42 |
+
|
43 |
+
Arguments:
|
44 |
+
image (np.ndarray): The image for calculating masks. Expects an
|
45 |
+
image in HWC uint8 format, with pixel values in [0, 255].
|
46 |
+
image_format (str): The color format of the image, in ['RGB', 'BGR'].
|
47 |
+
"""
|
48 |
+
assert image_format in [
|
49 |
+
"RGB",
|
50 |
+
"BGR",
|
51 |
+
], f"image_format must be in ['RGB', 'BGR'], is {image_format}."
|
52 |
+
if image_format != self.model.image_format:
|
53 |
+
image = image[..., ::-1]
|
54 |
+
|
55 |
+
# Transform the image to the form expected by the model
|
56 |
+
input_image = self.transform.apply_image(image)
|
57 |
+
input_image_torch = torch.as_tensor(input_image, device=self.device)
|
58 |
+
input_image_torch = input_image_torch.permute(2, 0, 1).contiguous()[
|
59 |
+
None, :, :, :
|
60 |
+
]
|
61 |
+
|
62 |
+
self.set_torch_image(input_image_torch, image.shape[:2])
|
63 |
+
|
64 |
+
@torch.no_grad()
|
65 |
+
def set_torch_image(
|
66 |
+
self,
|
67 |
+
transformed_image: torch.Tensor,
|
68 |
+
original_image_size: Tuple[int, ...],
|
69 |
+
) -> None:
|
70 |
+
"""
|
71 |
+
Calculates the image embeddings for the provided image, allowing
|
72 |
+
masks to be predicted with the 'predict' method. Expects the input
|
73 |
+
image to be already transformed to the format expected by the model.
|
74 |
+
|
75 |
+
Arguments:
|
76 |
+
transformed_image (torch.Tensor): The input image, with shape
|
77 |
+
1x3xHxW, which has been transformed with ResizeLongestSide.
|
78 |
+
original_image_size (tuple(int, int)): The size of the image
|
79 |
+
before transformation, in (H, W) format.
|
80 |
+
"""
|
81 |
+
assert (
|
82 |
+
len(transformed_image.shape) == 4
|
83 |
+
and transformed_image.shape[1] == 3
|
84 |
+
and max(*transformed_image.shape[2:]) == self.model.image_encoder.img_size
|
85 |
+
), f"set_torch_image input must be BCHW with long side {self.model.image_encoder.img_size}."
|
86 |
+
self.reset_image()
|
87 |
+
|
88 |
+
self.original_size = original_image_size
|
89 |
+
self.input_size = tuple(transformed_image.shape[-2:])
|
90 |
+
input_image = self.model.preprocess(transformed_image)
|
91 |
+
self.features = self.model.image_encoder(input_image)
|
92 |
+
self.is_image_set = True
|
93 |
+
|
94 |
+
def predict(
|
95 |
+
self,
|
96 |
+
point_coords: Optional[np.ndarray] = None,
|
97 |
+
point_labels: Optional[np.ndarray] = None,
|
98 |
+
box: Optional[np.ndarray] = None,
|
99 |
+
mask_input: Optional[np.ndarray] = None,
|
100 |
+
multimask_output: bool = True,
|
101 |
+
return_logits: bool = False,
|
102 |
+
) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
103 |
+
"""
|
104 |
+
Predict masks for the given input prompts, using the currently set image.
|
105 |
+
|
106 |
+
Arguments:
|
107 |
+
point_coords (np.ndarray or None): A Nx2 array of point prompts to the
|
108 |
+
model. Each point is in (X,Y) in pixels.
|
109 |
+
point_labels (np.ndarray or None): A length N array of labels for the
|
110 |
+
point prompts. 1 indicates a foreground point and 0 indicates a
|
111 |
+
background point.
|
112 |
+
box (np.ndarray or None): A length 4 array given a box prompt to the
|
113 |
+
model, in XYXY format.
|
114 |
+
mask_input (np.ndarray): A low resolution mask input to the model, typically
|
115 |
+
coming from a previous prediction iteration. Has form 1xHxW, where
|
116 |
+
for SAM, H=W=256.
|
117 |
+
multimask_output (bool): If true, the model will return three masks.
|
118 |
+
For ambiguous input prompts (such as a single click), this will often
|
119 |
+
produce better masks than a single prediction. If only a single
|
120 |
+
mask is needed, the model's predicted quality score can be used
|
121 |
+
to select the best mask. For non-ambiguous prompts, such as multiple
|
122 |
+
input prompts, multimask_output=False can give better results.
|
123 |
+
return_logits (bool): If true, returns un-thresholded masks logits
|
124 |
+
instead of a binary mask.
|
125 |
+
|
126 |
+
Returns:
|
127 |
+
(np.ndarray): The output masks in CxHxW format, where C is the
|
128 |
+
number of masks, and (H, W) is the original image size.
|
129 |
+
(np.ndarray): An array of length C containing the model's
|
130 |
+
predictions for the quality of each mask.
|
131 |
+
(np.ndarray): An array of shape CxHxW, where C is the number
|
132 |
+
of masks and H=W=256. These low resolution logits can be passed to
|
133 |
+
a subsequent iteration as mask input.
|
134 |
+
"""
|
135 |
+
if not self.is_image_set:
|
136 |
+
raise RuntimeError(
|
137 |
+
"An image must be set with .set_image(...) before mask prediction."
|
138 |
+
)
|
139 |
+
|
140 |
+
# Transform input prompts
|
141 |
+
coords_torch, labels_torch, box_torch, mask_input_torch = None, None, None, None
|
142 |
+
if point_coords is not None:
|
143 |
+
assert (
|
144 |
+
point_labels is not None
|
145 |
+
), "point_labels must be supplied if point_coords is supplied."
|
146 |
+
point_coords = self.transform.apply_coords(point_coords, self.original_size)
|
147 |
+
coords_torch = torch.as_tensor(
|
148 |
+
point_coords, dtype=torch.float, device=self.device
|
149 |
+
)
|
150 |
+
labels_torch = torch.as_tensor(
|
151 |
+
point_labels, dtype=torch.int, device=self.device
|
152 |
+
)
|
153 |
+
coords_torch, labels_torch = coords_torch[None, :, :], labels_torch[None, :]
|
154 |
+
if box is not None:
|
155 |
+
box = self.transform.apply_boxes(box, self.original_size)
|
156 |
+
box_torch = torch.as_tensor(box, dtype=torch.float, device=self.device)
|
157 |
+
box_torch = box_torch[None, :]
|
158 |
+
if mask_input is not None:
|
159 |
+
mask_input_torch = torch.as_tensor(
|
160 |
+
mask_input, dtype=torch.float, device=self.device
|
161 |
+
)
|
162 |
+
mask_input_torch = mask_input_torch[None, :, :, :]
|
163 |
+
|
164 |
+
masks, iou_predictions, low_res_masks = self.predict_torch(
|
165 |
+
coords_torch,
|
166 |
+
labels_torch,
|
167 |
+
box_torch,
|
168 |
+
mask_input_torch,
|
169 |
+
multimask_output,
|
170 |
+
return_logits=return_logits,
|
171 |
+
)
|
172 |
+
|
173 |
+
masks = masks[0].detach().cpu().numpy()
|
174 |
+
iou_predictions = iou_predictions[0].detach().cpu().numpy()
|
175 |
+
low_res_masks = low_res_masks[0].detach().cpu().numpy()
|
176 |
+
return masks, iou_predictions, low_res_masks
|
177 |
+
|
178 |
+
@torch.no_grad()
|
179 |
+
def predict_torch(
|
180 |
+
self,
|
181 |
+
point_coords: Optional[torch.Tensor],
|
182 |
+
point_labels: Optional[torch.Tensor],
|
183 |
+
boxes: Optional[torch.Tensor] = None,
|
184 |
+
mask_input: Optional[torch.Tensor] = None,
|
185 |
+
multimask_output: bool = True,
|
186 |
+
return_logits: bool = False,
|
187 |
+
) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
188 |
+
"""
|
189 |
+
Predict masks for the given input prompts, using the currently set image.
|
190 |
+
Input prompts are batched torch tensors and are expected to already be
|
191 |
+
transformed to the input frame using ResizeLongestSide.
|
192 |
+
|
193 |
+
Arguments:
|
194 |
+
point_coords (torch.Tensor or None): A BxNx2 array of point prompts to the
|
195 |
+
model. Each point is in (X,Y) in pixels.
|
196 |
+
point_labels (torch.Tensor or None): A BxN array of labels for the
|
197 |
+
point prompts. 1 indicates a foreground point and 0 indicates a
|
198 |
+
background point.
|
199 |
+
box (np.ndarray or None): A Bx4 array given a box prompt to the
|
200 |
+
model, in XYXY format.
|
201 |
+
mask_input (np.ndarray): A low resolution mask input to the model, typically
|
202 |
+
coming from a previous prediction iteration. Has form Bx1xHxW, where
|
203 |
+
for SAM, H=W=256. Masks returned by a previous iteration of the
|
204 |
+
predict method do not need further transformation.
|
205 |
+
multimask_output (bool): If true, the model will return three masks.
|
206 |
+
For ambiguous input prompts (such as a single click), this will often
|
207 |
+
produce better masks than a single prediction. If only a single
|
208 |
+
mask is needed, the model's predicted quality score can be used
|
209 |
+
to select the best mask. For non-ambiguous prompts, such as multiple
|
210 |
+
input prompts, multimask_output=False can give better results.
|
211 |
+
return_logits (bool): If true, returns un-thresholded masks logits
|
212 |
+
instead of a binary mask.
|
213 |
+
|
214 |
+
Returns:
|
215 |
+
(torch.Tensor): The output masks in BxCxHxW format, where C is the
|
216 |
+
number of masks, and (H, W) is the original image size.
|
217 |
+
(torch.Tensor): An array of shape BxC containing the model's
|
218 |
+
predictions for the quality of each mask.
|
219 |
+
(torch.Tensor): An array of shape BxCxHxW, where C is the number
|
220 |
+
of masks and H=W=256. These low res logits can be passed to
|
221 |
+
a subsequent iteration as mask input.
|
222 |
+
"""
|
223 |
+
if not self.is_image_set:
|
224 |
+
raise RuntimeError(
|
225 |
+
"An image must be set with .set_image(...) before mask prediction."
|
226 |
+
)
|
227 |
+
|
228 |
+
if point_coords is not None:
|
229 |
+
points = (point_coords, point_labels)
|
230 |
+
else:
|
231 |
+
points = None
|
232 |
+
|
233 |
+
# Embed prompts
|
234 |
+
sparse_embeddings, dense_embeddings = self.model.prompt_encoder(
|
235 |
+
points=points,
|
236 |
+
boxes=boxes,
|
237 |
+
masks=mask_input,
|
238 |
+
)
|
239 |
+
|
240 |
+
# Predict masks
|
241 |
+
low_res_masks, iou_predictions = self.model.mask_decoder(
|
242 |
+
image_embeddings=self.features,
|
243 |
+
image_pe=self.model.prompt_encoder.get_dense_pe(),
|
244 |
+
sparse_prompt_embeddings=sparse_embeddings,
|
245 |
+
dense_prompt_embeddings=dense_embeddings,
|
246 |
+
multimask_output=multimask_output,
|
247 |
+
)
|
248 |
+
|
249 |
+
# Upscale the masks to the original image resolution
|
250 |
+
masks = self.model.postprocess_masks(
|
251 |
+
low_res_masks, self.input_size, self.original_size
|
252 |
+
)
|
253 |
+
|
254 |
+
if not return_logits:
|
255 |
+
masks = masks > self.model.mask_threshold
|
256 |
+
|
257 |
+
return masks, iou_predictions, low_res_masks
|
258 |
+
|
259 |
+
def get_image_embedding(self) -> torch.Tensor:
|
260 |
+
"""
|
261 |
+
Returns the image embeddings for the currently set image, with
|
262 |
+
shape 1xCxHxW, where C is the embedding dimension and (H,W) are
|
263 |
+
the embedding spatial dimension of SAM (typically C=256, H=W=64).
|
264 |
+
"""
|
265 |
+
if not self.is_image_set:
|
266 |
+
raise RuntimeError(
|
267 |
+
"An image must be set with .set_image(...) to generate an embedding."
|
268 |
+
)
|
269 |
+
assert (
|
270 |
+
self.features is not None
|
271 |
+
), "Features must exist if an image has been set."
|
272 |
+
return self.features
|
273 |
+
|
274 |
+
@property
|
275 |
+
def device(self) -> torch.device:
|
276 |
+
return self.model.device
|
277 |
+
|
278 |
+
def reset_image(self) -> None:
|
279 |
+
"""Resets the currently set image."""
|
280 |
+
self.is_image_set = False
|
281 |
+
self.features = None
|
282 |
+
self.orig_h = None
|
283 |
+
self.orig_w = None
|
284 |
+
self.input_h = None
|
285 |
+
self.input_w = None
|
iopaint/runtime.py
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# https://github.com/huggingface/huggingface_hub/blob/5a12851f54bf614be39614034ed3a9031922d297/src/huggingface_hub/utils/_runtime.py
|
2 |
+
import os
|
3 |
+
import platform
|
4 |
+
import sys
|
5 |
+
from pathlib import Path
|
6 |
+
|
7 |
+
import packaging.version
|
8 |
+
from iopaint.schema import Device
|
9 |
+
from loguru import logger
|
10 |
+
from rich import print
|
11 |
+
from typing import Dict, Any
|
12 |
+
|
13 |
+
|
14 |
+
_PY_VERSION: str = sys.version.split()[0].rstrip("+")
|
15 |
+
|
16 |
+
if packaging.version.Version(_PY_VERSION) < packaging.version.Version("3.8.0"):
|
17 |
+
import importlib_metadata # type: ignore
|
18 |
+
else:
|
19 |
+
import importlib.metadata as importlib_metadata # type: ignore
|
20 |
+
|
21 |
+
_package_versions = {}
|
22 |
+
|
23 |
+
_CANDIDATES = [
|
24 |
+
"torch",
|
25 |
+
"torchvision",
|
26 |
+
"Pillow",
|
27 |
+
"diffusers",
|
28 |
+
"transformers",
|
29 |
+
"opencv-python",
|
30 |
+
"accelerate",
|
31 |
+
"iopaint",
|
32 |
+
"rembg",
|
33 |
+
"realesrgan",
|
34 |
+
"gfpgan",
|
35 |
+
]
|
36 |
+
# Check once at runtime
|
37 |
+
for name in _CANDIDATES:
|
38 |
+
_package_versions[name] = "N/A"
|
39 |
+
try:
|
40 |
+
_package_versions[name] = importlib_metadata.version(name)
|
41 |
+
except importlib_metadata.PackageNotFoundError:
|
42 |
+
pass
|
43 |
+
|
44 |
+
|
45 |
+
def dump_environment_info() -> Dict[str, str]:
|
46 |
+
"""Dump information about the machine to help debugging issues."""
|
47 |
+
|
48 |
+
# Generic machine info
|
49 |
+
info: Dict[str, Any] = {
|
50 |
+
"Platform": platform.platform(),
|
51 |
+
"Python version": platform.python_version(),
|
52 |
+
}
|
53 |
+
info.update(_package_versions)
|
54 |
+
print("\n".join([f"- {prop}: {val}" for prop, val in info.items()]) + "\n")
|
55 |
+
return info
|
56 |
+
|
57 |
+
|
58 |
+
def check_device(device: Device) -> Device:
|
59 |
+
if device == Device.cuda:
|
60 |
+
import platform
|
61 |
+
|
62 |
+
if platform.system() == "Darwin":
|
63 |
+
logger.warning("MacOS does not support cuda, use cpu instead")
|
64 |
+
return Device.cpu
|
65 |
+
else:
|
66 |
+
import torch
|
67 |
+
|
68 |
+
if not torch.cuda.is_available():
|
69 |
+
logger.warning("CUDA is not available, use cpu instead")
|
70 |
+
return Device.cpu
|
71 |
+
elif device == Device.mps:
|
72 |
+
import torch
|
73 |
+
|
74 |
+
if not torch.backends.mps.is_available():
|
75 |
+
logger.warning("mps is not available, use cpu instead")
|
76 |
+
return Device.cpu
|
77 |
+
return device
|
78 |
+
|
79 |
+
|
80 |
+
def setup_model_dir(model_dir: Path):
|
81 |
+
model_dir = model_dir.expanduser().absolute()
|
82 |
+
logger.info(f"Model directory: {model_dir}")
|
83 |
+
os.environ["U2NET_HOME"] = str(model_dir)
|
84 |
+
os.environ["XDG_CACHE_HOME"] = str(model_dir)
|
85 |
+
if not model_dir.exists():
|
86 |
+
logger.info(f"Create model directory: {model_dir}")
|
87 |
+
model_dir.mkdir(exist_ok=True, parents=True)
|
88 |
+
return model_dir
|
iopaint/schema.py
ADDED
@@ -0,0 +1,458 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import random
|
2 |
+
from enum import Enum
|
3 |
+
from pathlib import Path
|
4 |
+
from typing import Optional, Literal, List
|
5 |
+
|
6 |
+
from iopaint.const import (
|
7 |
+
INSTRUCT_PIX2PIX_NAME,
|
8 |
+
KANDINSKY22_NAME,
|
9 |
+
POWERPAINT_NAME,
|
10 |
+
ANYTEXT_NAME,
|
11 |
+
SDXL_CONTROLNET_CHOICES,
|
12 |
+
SD2_CONTROLNET_CHOICES,
|
13 |
+
SD_CONTROLNET_CHOICES,
|
14 |
+
)
|
15 |
+
from loguru import logger
|
16 |
+
from pydantic import BaseModel, Field, field_validator, computed_field
|
17 |
+
|
18 |
+
|
19 |
+
class ModelType(str, Enum):
|
20 |
+
INPAINT = "inpaint" # LaMa, MAT...
|
21 |
+
DIFFUSERS_SD = "diffusers_sd"
|
22 |
+
DIFFUSERS_SD_INPAINT = "diffusers_sd_inpaint"
|
23 |
+
DIFFUSERS_SDXL = "diffusers_sdxl"
|
24 |
+
DIFFUSERS_SDXL_INPAINT = "diffusers_sdxl_inpaint"
|
25 |
+
DIFFUSERS_OTHER = "diffusers_other"
|
26 |
+
|
27 |
+
|
28 |
+
class ModelInfo(BaseModel):
|
29 |
+
name: str
|
30 |
+
path: str
|
31 |
+
model_type: ModelType
|
32 |
+
is_single_file_diffusers: bool = False
|
33 |
+
|
34 |
+
@computed_field
|
35 |
+
@property
|
36 |
+
def need_prompt(self) -> bool:
|
37 |
+
return self.model_type in [
|
38 |
+
ModelType.DIFFUSERS_SD,
|
39 |
+
ModelType.DIFFUSERS_SDXL,
|
40 |
+
ModelType.DIFFUSERS_SD_INPAINT,
|
41 |
+
ModelType.DIFFUSERS_SDXL_INPAINT,
|
42 |
+
] or self.name in [
|
43 |
+
INSTRUCT_PIX2PIX_NAME,
|
44 |
+
KANDINSKY22_NAME,
|
45 |
+
POWERPAINT_NAME,
|
46 |
+
ANYTEXT_NAME,
|
47 |
+
]
|
48 |
+
|
49 |
+
@computed_field
|
50 |
+
@property
|
51 |
+
def controlnets(self) -> List[str]:
|
52 |
+
if self.model_type in [
|
53 |
+
ModelType.DIFFUSERS_SDXL,
|
54 |
+
ModelType.DIFFUSERS_SDXL_INPAINT,
|
55 |
+
]:
|
56 |
+
return SDXL_CONTROLNET_CHOICES
|
57 |
+
if self.model_type in [ModelType.DIFFUSERS_SD, ModelType.DIFFUSERS_SD_INPAINT]:
|
58 |
+
if "sd2" in self.name.lower():
|
59 |
+
return SD2_CONTROLNET_CHOICES
|
60 |
+
else:
|
61 |
+
return SD_CONTROLNET_CHOICES
|
62 |
+
if self.name == POWERPAINT_NAME:
|
63 |
+
return SD_CONTROLNET_CHOICES
|
64 |
+
return []
|
65 |
+
|
66 |
+
@computed_field
|
67 |
+
@property
|
68 |
+
def support_strength(self) -> bool:
|
69 |
+
return self.model_type in [
|
70 |
+
ModelType.DIFFUSERS_SD,
|
71 |
+
ModelType.DIFFUSERS_SDXL,
|
72 |
+
ModelType.DIFFUSERS_SD_INPAINT,
|
73 |
+
ModelType.DIFFUSERS_SDXL_INPAINT,
|
74 |
+
] or self.name in [POWERPAINT_NAME, ANYTEXT_NAME]
|
75 |
+
|
76 |
+
@computed_field
|
77 |
+
@property
|
78 |
+
def support_outpainting(self) -> bool:
|
79 |
+
return self.model_type in [
|
80 |
+
ModelType.DIFFUSERS_SD,
|
81 |
+
ModelType.DIFFUSERS_SDXL,
|
82 |
+
ModelType.DIFFUSERS_SD_INPAINT,
|
83 |
+
ModelType.DIFFUSERS_SDXL_INPAINT,
|
84 |
+
] or self.name in [KANDINSKY22_NAME, POWERPAINT_NAME]
|
85 |
+
|
86 |
+
@computed_field
|
87 |
+
@property
|
88 |
+
def support_lcm_lora(self) -> bool:
|
89 |
+
return self.model_type in [
|
90 |
+
ModelType.DIFFUSERS_SD,
|
91 |
+
ModelType.DIFFUSERS_SDXL,
|
92 |
+
ModelType.DIFFUSERS_SD_INPAINT,
|
93 |
+
ModelType.DIFFUSERS_SDXL_INPAINT,
|
94 |
+
]
|
95 |
+
|
96 |
+
@computed_field
|
97 |
+
@property
|
98 |
+
def support_controlnet(self) -> bool:
|
99 |
+
return self.model_type in [
|
100 |
+
ModelType.DIFFUSERS_SD,
|
101 |
+
ModelType.DIFFUSERS_SDXL,
|
102 |
+
ModelType.DIFFUSERS_SD_INPAINT,
|
103 |
+
ModelType.DIFFUSERS_SDXL_INPAINT,
|
104 |
+
]
|
105 |
+
|
106 |
+
@computed_field
|
107 |
+
@property
|
108 |
+
def support_freeu(self) -> bool:
|
109 |
+
return self.model_type in [
|
110 |
+
ModelType.DIFFUSERS_SD,
|
111 |
+
ModelType.DIFFUSERS_SDXL,
|
112 |
+
ModelType.DIFFUSERS_SD_INPAINT,
|
113 |
+
ModelType.DIFFUSERS_SDXL_INPAINT,
|
114 |
+
] or self.name in [INSTRUCT_PIX2PIX_NAME]
|
115 |
+
|
116 |
+
|
117 |
+
class Choices(str, Enum):
|
118 |
+
@classmethod
|
119 |
+
def values(cls):
|
120 |
+
return [member.value for member in cls]
|
121 |
+
|
122 |
+
|
123 |
+
class RealESRGANModel(Choices):
|
124 |
+
realesr_general_x4v3 = "realesr-general-x4v3"
|
125 |
+
RealESRGAN_x4plus = "RealESRGAN_x4plus"
|
126 |
+
RealESRGAN_x4plus_anime_6B = "RealESRGAN_x4plus_anime_6B"
|
127 |
+
|
128 |
+
|
129 |
+
class RemoveBGModel(Choices):
|
130 |
+
u2net = "u2net"
|
131 |
+
u2netp = "u2netp"
|
132 |
+
u2net_human_seg = "u2net_human_seg"
|
133 |
+
u2net_cloth_seg = "u2net_cloth_seg"
|
134 |
+
silueta = "silueta"
|
135 |
+
isnet_general_use = "isnet-general-use"
|
136 |
+
briaai_rmbg_1_4 = "briaai/RMBG-1.4"
|
137 |
+
|
138 |
+
|
139 |
+
class Device(Choices):
|
140 |
+
cpu = "cpu"
|
141 |
+
cuda = "cuda"
|
142 |
+
mps = "mps"
|
143 |
+
|
144 |
+
|
145 |
+
class InteractiveSegModel(Choices):
|
146 |
+
vit_b = "vit_b"
|
147 |
+
vit_l = "vit_l"
|
148 |
+
vit_h = "vit_h"
|
149 |
+
mobile_sam = "mobile_sam"
|
150 |
+
|
151 |
+
|
152 |
+
class PluginInfo(BaseModel):
|
153 |
+
name: str
|
154 |
+
support_gen_image: bool = False
|
155 |
+
support_gen_mask: bool = False
|
156 |
+
|
157 |
+
|
158 |
+
class CV2Flag(str, Enum):
|
159 |
+
INPAINT_NS = "INPAINT_NS"
|
160 |
+
INPAINT_TELEA = "INPAINT_TELEA"
|
161 |
+
|
162 |
+
|
163 |
+
class HDStrategy(str, Enum):
|
164 |
+
# Use original image size
|
165 |
+
ORIGINAL = "Original"
|
166 |
+
# Resize the longer side of the image to a specific size(hd_strategy_resize_limit),
|
167 |
+
# then do inpainting on the resized image. Finally, resize the inpainting result to the original size.
|
168 |
+
# The area outside the mask will not lose quality.
|
169 |
+
RESIZE = "Resize"
|
170 |
+
# Crop masking area(with a margin controlled by hd_strategy_crop_margin) from the original image to do inpainting
|
171 |
+
CROP = "Crop"
|
172 |
+
|
173 |
+
|
174 |
+
class LDMSampler(str, Enum):
|
175 |
+
ddim = "ddim"
|
176 |
+
plms = "plms"
|
177 |
+
|
178 |
+
|
179 |
+
class SDSampler(str, Enum):
|
180 |
+
dpm_plus_plus_2m = "DPM++ 2M"
|
181 |
+
dpm_plus_plus_2m_karras = "DPM++ 2M Karras"
|
182 |
+
dpm_plus_plus_2m_sde = "DPM++ 2M SDE"
|
183 |
+
dpm_plus_plus_2m_sde_karras = "DPM++ 2M SDE Karras"
|
184 |
+
dpm_plus_plus_sde = "DPM++ SDE"
|
185 |
+
dpm_plus_plus_sde_karras = "DPM++ SDE Karras"
|
186 |
+
dpm2 = "DPM2"
|
187 |
+
dpm2_karras = "DPM2 Karras"
|
188 |
+
dpm2_a = "DPM2 a"
|
189 |
+
dpm2_a_karras = "DPM2 a Karras"
|
190 |
+
euler = "Euler"
|
191 |
+
euler_a = "Euler a"
|
192 |
+
heun = "Heun"
|
193 |
+
lms = "LMS"
|
194 |
+
lms_karras = "LMS Karras"
|
195 |
+
|
196 |
+
ddim = "DDIM"
|
197 |
+
pndm = "PNDM"
|
198 |
+
uni_pc = "UniPC"
|
199 |
+
lcm = "LCM"
|
200 |
+
|
201 |
+
|
202 |
+
class FREEUConfig(BaseModel):
|
203 |
+
s1: float = 0.9
|
204 |
+
s2: float = 0.2
|
205 |
+
b1: float = 1.2
|
206 |
+
b2: float = 1.4
|
207 |
+
|
208 |
+
|
209 |
+
class PowerPaintTask(str, Enum):
|
210 |
+
text_guided = "text-guided"
|
211 |
+
shape_guided = "shape-guided"
|
212 |
+
object_remove = "object-remove"
|
213 |
+
outpainting = "outpainting"
|
214 |
+
|
215 |
+
|
216 |
+
class ApiConfig(BaseModel):
|
217 |
+
host: str
|
218 |
+
port: int
|
219 |
+
inbrowser: bool
|
220 |
+
model: str
|
221 |
+
no_half: bool
|
222 |
+
low_mem: bool
|
223 |
+
cpu_offload: bool
|
224 |
+
disable_nsfw_checker: bool
|
225 |
+
local_files_only: bool
|
226 |
+
cpu_textencoder: bool
|
227 |
+
device: Device
|
228 |
+
input: Optional[Path]
|
229 |
+
output_dir: Optional[Path]
|
230 |
+
quality: int
|
231 |
+
enable_interactive_seg: bool
|
232 |
+
interactive_seg_model: InteractiveSegModel
|
233 |
+
interactive_seg_device: Device
|
234 |
+
enable_remove_bg: bool
|
235 |
+
remove_bg_model: str
|
236 |
+
enable_anime_seg: bool
|
237 |
+
enable_realesrgan: bool
|
238 |
+
realesrgan_device: Device
|
239 |
+
realesrgan_model: RealESRGANModel
|
240 |
+
enable_gfpgan: bool
|
241 |
+
gfpgan_device: Device
|
242 |
+
enable_restoreformer: bool
|
243 |
+
restoreformer_device: Device
|
244 |
+
|
245 |
+
|
246 |
+
class InpaintRequest(BaseModel):
|
247 |
+
image: Optional[str] = Field(None, description="base64 encoded image")
|
248 |
+
mask: Optional[str] = Field(None, description="base64 encoded mask")
|
249 |
+
|
250 |
+
ldm_steps: int = Field(20, description="Steps for ldm model.")
|
251 |
+
ldm_sampler: str = Field(LDMSampler.plms, discription="Sampler for ldm model.")
|
252 |
+
zits_wireframe: bool = Field(True, description="Enable wireframe for zits model.")
|
253 |
+
|
254 |
+
hd_strategy: str = Field(
|
255 |
+
HDStrategy.CROP,
|
256 |
+
description="Different way to preprocess image, only used by erase models(e.g. lama/mat)",
|
257 |
+
)
|
258 |
+
hd_strategy_crop_trigger_size: int = Field(
|
259 |
+
800,
|
260 |
+
description="Crop trigger size for hd_strategy=CROP, if the longer side of the image is larger than this value, use crop strategy",
|
261 |
+
)
|
262 |
+
hd_strategy_crop_margin: int = Field(
|
263 |
+
128, description="Crop margin for hd_strategy=CROP"
|
264 |
+
)
|
265 |
+
hd_strategy_resize_limit: int = Field(
|
266 |
+
1280, description="Resize limit for hd_strategy=RESIZE"
|
267 |
+
)
|
268 |
+
|
269 |
+
prompt: str = Field("", description="Prompt for diffusion models.")
|
270 |
+
negative_prompt: str = Field(
|
271 |
+
"", description="Negative prompt for diffusion models."
|
272 |
+
)
|
273 |
+
use_croper: bool = Field(
|
274 |
+
False, description="Crop image before doing diffusion inpainting"
|
275 |
+
)
|
276 |
+
croper_x: int = Field(0, description="Crop x for croper")
|
277 |
+
croper_y: int = Field(0, description="Crop y for croper")
|
278 |
+
croper_height: int = Field(512, description="Crop height for croper")
|
279 |
+
croper_width: int = Field(512, description="Crop width for croper")
|
280 |
+
|
281 |
+
use_extender: bool = Field(
|
282 |
+
False, description="Extend image before doing sd outpainting"
|
283 |
+
)
|
284 |
+
extender_x: int = Field(0, description="Extend x for extender")
|
285 |
+
extender_y: int = Field(0, description="Extend y for extender")
|
286 |
+
extender_height: int = Field(640, description="Extend height for extender")
|
287 |
+
extender_width: int = Field(640, description="Extend width for extender")
|
288 |
+
|
289 |
+
sd_scale: float = Field(
|
290 |
+
1.0,
|
291 |
+
description="Resize the image before doing sd inpainting, the area outside the mask will not lose quality.",
|
292 |
+
gt=0.0,
|
293 |
+
le=1.0,
|
294 |
+
)
|
295 |
+
sd_mask_blur: int = Field(
|
296 |
+
11,
|
297 |
+
description="Blur the edge of mask area. The higher the number the smoother blend with the original image",
|
298 |
+
)
|
299 |
+
sd_strength: float = Field(
|
300 |
+
1.0,
|
301 |
+
description="Strength is a measure of how much noise is added to the base image, which influences how similar the output is to the base image. Higher value means more noise and more different from the base image",
|
302 |
+
le=1.0,
|
303 |
+
)
|
304 |
+
sd_steps: int = Field(
|
305 |
+
50,
|
306 |
+
description="The number of denoising steps. More denoising steps usually lead to a higher quality image at the expense of slower inference.",
|
307 |
+
)
|
308 |
+
sd_guidance_scale: float = Field(
|
309 |
+
7.5,
|
310 |
+
help="Higher guidance scale encourages to generate images that are closely linked to the text prompt, usually at the expense of lower image quality.",
|
311 |
+
)
|
312 |
+
sd_sampler: str = Field(
|
313 |
+
SDSampler.uni_pc, description="Sampler for diffusion model."
|
314 |
+
)
|
315 |
+
sd_seed: int = Field(
|
316 |
+
42,
|
317 |
+
description="Seed for diffusion model. -1 mean random seed",
|
318 |
+
validate_default=True,
|
319 |
+
)
|
320 |
+
sd_match_histograms: bool = Field(
|
321 |
+
False,
|
322 |
+
description="Match histograms between inpainting area and original image.",
|
323 |
+
)
|
324 |
+
|
325 |
+
sd_outpainting_softness: float = Field(20.0)
|
326 |
+
sd_outpainting_space: float = Field(20.0)
|
327 |
+
|
328 |
+
sd_freeu: bool = Field(
|
329 |
+
False,
|
330 |
+
description="Enable freeu mode. https://huggingface.co/docs/diffusers/main/en/using-diffusers/freeu",
|
331 |
+
)
|
332 |
+
sd_freeu_config: FREEUConfig = FREEUConfig()
|
333 |
+
|
334 |
+
sd_lcm_lora: bool = Field(
|
335 |
+
False,
|
336 |
+
description="Enable lcm-lora mode. https://huggingface.co/docs/diffusers/main/en/using-diffusers/inference_with_lcm#texttoimage",
|
337 |
+
)
|
338 |
+
|
339 |
+
sd_keep_unmasked_area: bool = Field(
|
340 |
+
True, description="Keep unmasked area unchanged"
|
341 |
+
)
|
342 |
+
|
343 |
+
cv2_flag: CV2Flag = Field(
|
344 |
+
CV2Flag.INPAINT_NS,
|
345 |
+
description="Flag for opencv inpainting: https://docs.opencv.org/4.6.0/d7/d8b/group__photo__inpaint.html#gga8002a65f5a3328fbf15df81b842d3c3ca05e763003a805e6c11c673a9f4ba7d07",
|
346 |
+
)
|
347 |
+
cv2_radius: int = Field(
|
348 |
+
4,
|
349 |
+
description="Radius of a circular neighborhood of each point inpainted that is considered by the algorithm",
|
350 |
+
)
|
351 |
+
|
352 |
+
# Paint by Example
|
353 |
+
paint_by_example_example_image: Optional[str] = Field(
|
354 |
+
None, description="Base64 encoded example image for paint by example model"
|
355 |
+
)
|
356 |
+
|
357 |
+
# InstructPix2Pix
|
358 |
+
p2p_image_guidance_scale: float = Field(1.5, description="Image guidance scale")
|
359 |
+
|
360 |
+
# ControlNet
|
361 |
+
enable_controlnet: bool = Field(False, description="Enable controlnet")
|
362 |
+
controlnet_conditioning_scale: float = Field(
|
363 |
+
0.4, description="Conditioning scale", ge=0.0, le=1.0
|
364 |
+
)
|
365 |
+
controlnet_method: str = Field(
|
366 |
+
"lllyasviel/control_v11p_sd15_canny", description="Controlnet method"
|
367 |
+
)
|
368 |
+
|
369 |
+
# PowerPaint
|
370 |
+
powerpaint_task: PowerPaintTask = Field(
|
371 |
+
PowerPaintTask.text_guided, description="PowerPaint task"
|
372 |
+
)
|
373 |
+
fitting_degree: float = Field(
|
374 |
+
1.0,
|
375 |
+
description="Control the fitting degree of the generated objects to the mask shape.",
|
376 |
+
gt=0.0,
|
377 |
+
le=1.0,
|
378 |
+
)
|
379 |
+
|
380 |
+
@field_validator("sd_seed")
|
381 |
+
@classmethod
|
382 |
+
def sd_seed_validator(cls, v: int) -> int:
|
383 |
+
if v == -1:
|
384 |
+
return random.randint(1, 99999999)
|
385 |
+
return v
|
386 |
+
|
387 |
+
@field_validator("controlnet_conditioning_scale")
|
388 |
+
@classmethod
|
389 |
+
def validate_field(cls, v: float, values):
|
390 |
+
use_extender = values.data["use_extender"]
|
391 |
+
enable_controlnet = values.data["enable_controlnet"]
|
392 |
+
if use_extender and enable_controlnet:
|
393 |
+
logger.info(f"Extender is enabled, set controlnet_conditioning_scale=0")
|
394 |
+
return 0
|
395 |
+
return v
|
396 |
+
|
397 |
+
|
398 |
+
class RunPluginRequest(BaseModel):
|
399 |
+
name: str
|
400 |
+
image: str = Field(..., description="base64 encoded image")
|
401 |
+
clicks: List[List[int]] = Field(
|
402 |
+
[], description="Clicks for interactive seg, [[x,y,0/1], [x2,y2,0/1]]"
|
403 |
+
)
|
404 |
+
scale: float = Field(2.0, description="Scale for upscaling")
|
405 |
+
|
406 |
+
|
407 |
+
MediaTab = Literal["input", "output"]
|
408 |
+
|
409 |
+
|
410 |
+
class MediasResponse(BaseModel):
|
411 |
+
name: str
|
412 |
+
height: int
|
413 |
+
width: int
|
414 |
+
ctime: float
|
415 |
+
mtime: float
|
416 |
+
|
417 |
+
|
418 |
+
class GenInfoResponse(BaseModel):
|
419 |
+
prompt: str = ""
|
420 |
+
negative_prompt: str = ""
|
421 |
+
|
422 |
+
|
423 |
+
class ServerConfigResponse(BaseModel):
|
424 |
+
plugins: List[PluginInfo]
|
425 |
+
modelInfos: List[ModelInfo]
|
426 |
+
removeBGModel: RemoveBGModel
|
427 |
+
removeBGModels: List[RemoveBGModel]
|
428 |
+
realesrganModel: RealESRGANModel
|
429 |
+
realesrganModels: List[RealESRGANModel]
|
430 |
+
interactiveSegModel: InteractiveSegModel
|
431 |
+
interactiveSegModels: List[InteractiveSegModel]
|
432 |
+
enableFileManager: bool
|
433 |
+
enableAutoSaving: bool
|
434 |
+
enableControlnet: bool
|
435 |
+
controlnetMethod: Optional[str]
|
436 |
+
disableModelSwitch: bool
|
437 |
+
isDesktop: bool
|
438 |
+
samplers: List[str]
|
439 |
+
|
440 |
+
|
441 |
+
class SwitchModelRequest(BaseModel):
|
442 |
+
name: str
|
443 |
+
|
444 |
+
|
445 |
+
class SwitchPluginModelRequest(BaseModel):
|
446 |
+
plugin_name: str
|
447 |
+
model_name: str
|
448 |
+
|
449 |
+
|
450 |
+
AdjustMaskOperate = Literal["expand", "shrink", "reverse"]
|
451 |
+
|
452 |
+
|
453 |
+
class AdjustMaskRequest(BaseModel):
|
454 |
+
mask: str = Field(
|
455 |
+
..., description="base64 encoded mask. 255 means area to do inpaint"
|
456 |
+
)
|
457 |
+
operate: AdjustMaskOperate = Field(..., description="expand/shrink/reverse")
|
458 |
+
kernel_size: int = Field(5, description="Kernel size for expanding mask")
|
iopaint/single_processing.py
ADDED
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import base64
|
2 |
+
import io
|
3 |
+
import json
|
4 |
+
from pathlib import Path
|
5 |
+
from typing import Dict, Optional
|
6 |
+
|
7 |
+
import cv2
|
8 |
+
import psutil
|
9 |
+
from PIL import Image
|
10 |
+
from loguru import logger
|
11 |
+
from rich.console import Console
|
12 |
+
from rich.progress import (
|
13 |
+
Progress,
|
14 |
+
SpinnerColumn,
|
15 |
+
TimeElapsedColumn,
|
16 |
+
MofNCompleteColumn,
|
17 |
+
TextColumn,
|
18 |
+
BarColumn,
|
19 |
+
TaskProgressColumn,
|
20 |
+
)
|
21 |
+
|
22 |
+
from iopaint.helper import pil_to_bytes_single
|
23 |
+
from iopaint.model.utils import torch_gc
|
24 |
+
from iopaint.model_manager import ModelManager
|
25 |
+
from iopaint.schema import InpaintRequest
|
26 |
+
import numpy as np
|
27 |
+
|
28 |
+
|
29 |
+
def glob_images(path: Path) -> Dict[str, Path]:
|
30 |
+
# png/jpg/jpeg
|
31 |
+
if path.is_file():
|
32 |
+
return {path.stem: path}
|
33 |
+
elif path.is_dir():
|
34 |
+
res = {}
|
35 |
+
for it in path.glob("*.*"):
|
36 |
+
if it.suffix.lower() in [".png", ".jpg", ".jpeg"]:
|
37 |
+
res[it.stem] = it
|
38 |
+
return res
|
39 |
+
|
40 |
+
|
41 |
+
# def batch_inpaint(
|
42 |
+
# model: str,
|
43 |
+
# device,
|
44 |
+
# image: Path,
|
45 |
+
# mask: Path,
|
46 |
+
# config: Optional[Path] = None,
|
47 |
+
# concat: bool = False,
|
48 |
+
# ):
|
49 |
+
# if config is None:
|
50 |
+
# inpaint_request = InpaintRequest()
|
51 |
+
# else:
|
52 |
+
# with open(config, "r", encoding="utf-8") as f:
|
53 |
+
# inpaint_request = InpaintRequest(**json.load(f))
|
54 |
+
#
|
55 |
+
# model_manager = ModelManager(name=model, device=device)
|
56 |
+
#
|
57 |
+
# img = cv2.imread(str(image))
|
58 |
+
# img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
59 |
+
#
|
60 |
+
# mask_img = cv2.imread(str(mask), cv2.IMREAD_GRAYSCALE)
|
61 |
+
#
|
62 |
+
# if mask_img.shape[:2] != img.shape[:2]:
|
63 |
+
# mask_img = cv2.resize(
|
64 |
+
# mask_img,
|
65 |
+
# (img.shape[1], img.shape[0]),
|
66 |
+
# interpolation=cv2.INTER_NEAREST,
|
67 |
+
# )
|
68 |
+
#
|
69 |
+
# mask_img[mask_img >= 127] = 255
|
70 |
+
# mask_img[mask_img < 127] = 0
|
71 |
+
#
|
72 |
+
# # bgr
|
73 |
+
# inpaint_result = model_manager(img, mask_img, inpaint_request)
|
74 |
+
# inpaint_result = cv2.cvtColor(inpaint_result, cv2.COLOR_BGR2RGB)
|
75 |
+
#
|
76 |
+
# if concat:
|
77 |
+
# mask_img = cv2.cvtColor(mask_img, cv2.COLOR_GRAY2RGB)
|
78 |
+
# inpaint_result = cv2.hconcat([img, mask_img, inpaint_result])
|
79 |
+
#
|
80 |
+
# # Convert the NumPy array to PIL Image
|
81 |
+
# pil_image = Image.fromarray(inpaint_result)
|
82 |
+
#
|
83 |
+
# # Encode the PIL Image as base64 string
|
84 |
+
# with io.BytesIO() as output_buffer:
|
85 |
+
# pil_image.save(output_buffer, format='PNG')
|
86 |
+
# base64_image = base64.b64encode(output_buffer.getvalue()).decode('utf-8')
|
87 |
+
#
|
88 |
+
# return base64_image
|
89 |
+
|
90 |
+
def batch_inpaint(
|
91 |
+
model: str,
|
92 |
+
device,
|
93 |
+
input_base64: str,
|
94 |
+
mask_base64: str,
|
95 |
+
config_base64: Optional[str] = None,
|
96 |
+
concat: bool = False,
|
97 |
+
):
|
98 |
+
if config_base64 is None:
|
99 |
+
inpaint_request = InpaintRequest()
|
100 |
+
else:
|
101 |
+
config_json = base64.b64decode(config_base64)
|
102 |
+
inpaint_request = InpaintRequest(**json.loads(config_json))
|
103 |
+
|
104 |
+
model_manager = ModelManager(name=model, device=device)
|
105 |
+
|
106 |
+
# Decode input image from base64
|
107 |
+
input_image_data = base64.b64decode(input_base64)
|
108 |
+
input_image = cv2.imdecode(np.frombuffer(input_image_data, np.uint8), cv2.IMREAD_COLOR)
|
109 |
+
|
110 |
+
# Decode mask image from base64
|
111 |
+
mask_image_data = base64.b64decode(mask_base64)
|
112 |
+
mask_image = cv2.imdecode(np.frombuffer(mask_image_data, np.uint8), cv2.IMREAD_GRAYSCALE)
|
113 |
+
|
114 |
+
if mask_image.shape[:2] != input_image.shape[:2]:
|
115 |
+
mask_image = cv2.resize(
|
116 |
+
mask_image,
|
117 |
+
(input_image.shape[1], input_image.shape[0]),
|
118 |
+
interpolation=cv2.INTER_NEAREST,
|
119 |
+
)
|
120 |
+
|
121 |
+
mask_image[mask_image >= 127] = 255
|
122 |
+
mask_image[mask_image < 127] = 0
|
123 |
+
|
124 |
+
# Run inpainting
|
125 |
+
inpaint_result = model_manager(input_image, mask_image, inpaint_request)
|
126 |
+
|
127 |
+
if concat:
|
128 |
+
mask_image = cv2.cvtColor(mask_image, cv2.COLOR_GRAY2RGB)
|
129 |
+
inpaint_result = cv2.hconcat([input_image, mask_image, inpaint_result])
|
130 |
+
|
131 |
+
# Convert NumPy array to PIL Image
|
132 |
+
pil_image = Image.fromarray(inpaint_result)
|
133 |
+
|
134 |
+
# Encode PIL Image to base64 string
|
135 |
+
with io.BytesIO() as output_buffer:
|
136 |
+
pil_image.save(output_buffer, format='PNG')
|
137 |
+
base64_image = base64.b64encode(output_buffer.getvalue()).decode('utf-8')
|
138 |
+
|
139 |
+
return base64_image
|
140 |
+
|
141 |
+
|
142 |
+
def batch_inpaint_cv2(
|
143 |
+
model: str,
|
144 |
+
device,
|
145 |
+
input_base: str,
|
146 |
+
mask_base: str,
|
147 |
+
config_base64: Optional[str] = None,
|
148 |
+
concat: bool = False,
|
149 |
+
):
|
150 |
+
if config_base64 is None:
|
151 |
+
inpaint_request = InpaintRequest()
|
152 |
+
else:
|
153 |
+
config_json = base64.b64decode(config_base64)
|
154 |
+
inpaint_request = InpaintRequest(**json.loads(config_json))
|
155 |
+
|
156 |
+
model_manager = ModelManager(name=model, device=device)
|
157 |
+
|
158 |
+
# Decode input image from base
|
159 |
+
input_image = input_base
|
160 |
+
# Decode mask image from base
|
161 |
+
mask_image = mask_base
|
162 |
+
|
163 |
+
if mask_image.shape[:2] != input_image.shape[:2]:
|
164 |
+
mask_image = cv2.resize(
|
165 |
+
mask_image,
|
166 |
+
(input_image.shape[1], input_image.shape[0]),
|
167 |
+
interpolation=cv2.INTER_NEAREST,
|
168 |
+
)
|
169 |
+
|
170 |
+
mask_image[mask_image >= 127] = 255
|
171 |
+
mask_image[mask_image < 127] = 0
|
172 |
+
|
173 |
+
# Run inpainting
|
174 |
+
inpaint_result = model_manager(input_image, mask_image, inpaint_request)
|
175 |
+
|
176 |
+
if concat:
|
177 |
+
mask_image = cv2.cvtColor(mask_image, cv2.COLOR_GRAY2RGB)
|
178 |
+
inpaint_result = cv2.hconcat([input_image, mask_image, inpaint_result])
|
179 |
+
|
180 |
+
return inpaint_result
|
requirements.txt
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
torch>=2.0.0
|
2 |
+
opencv-python
|
3 |
+
diffusers
|
4 |
+
accelerate
|
5 |
+
peft==0.7.1
|
6 |
+
transformers==4.37.2
|
7 |
+
safetensors
|
8 |
+
controlnet-aux==0.0.3
|
9 |
+
fastapi==0.108.0
|
10 |
+
uvicorn
|
11 |
+
python-multipart
|
12 |
+
python-socketio==5.7.2
|
13 |
+
typer
|
14 |
+
pydantic>=2.5.2
|
15 |
+
rich
|
16 |
+
loguru
|
17 |
+
yacs
|
18 |
+
piexif==1.1.3
|
19 |
+
omegaconf
|
20 |
+
easydict
|
21 |
+
gradio
|
22 |
+
typer-config==1.4.0
|
23 |
+
Pillow==9.5.0
|
24 |
+
ultralytics
|
25 |
+
flask
|
26 |
+
flask_cors
|