raySD 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- raySD/__init__.py +6 -0
- raySD/pipeline/Abstract_Pipeline.py +28 -0
- raySD/pipeline/Stable_Diffusion_IP_Adapter.py +115 -0
- raySD/pipeline/Super_Resolution_Pipeline.py +42 -0
- raySD/pipeline/__init__.py +2 -0
- raySD/prompt/__init__.py +1 -0
- raySD/prompt/chibi_prompt.py +56 -0
- raySD/pydantic_model/Image_Generate_Model.py +7 -0
- raySD/pydantic_model/Image_Response_Model.py +4 -0
- raySD/pydantic_model/Message_Model.py +4 -0
- raySD/pydantic_model/Stable_Diffusion_IP_Adapter_Model.py +24 -0
- raySD/pydantic_model/__init__.py +4 -0
- raySD/utils/Enable_xFormers.py +9 -0
- raySD/utils/__init__.py +1 -0
- raysd-0.1.0.dist-info/METADATA +21 -0
- raysd-0.1.0.dist-info/RECORD +18 -0
- raysd-0.1.0.dist-info/WHEEL +5 -0
- raysd-0.1.0.dist-info/top_level.txt +1 -0
raySD/__init__.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
class AbstractPipeline(ABC):
|
|
4
|
+
def __init__(self, **kwargs):
|
|
5
|
+
## Hook model
|
|
6
|
+
self.module_pre_hook = []
|
|
7
|
+
self.module_post_hook = []
|
|
8
|
+
|
|
9
|
+
def __call__(self, *args, **kwargs):
|
|
10
|
+
for hook in self.module_pre_hook:
|
|
11
|
+
x = hook(*args, **kwargs)
|
|
12
|
+
x = self.forward(*args, **kwargs)
|
|
13
|
+
for hook in self.module_post_hook:
|
|
14
|
+
x = hook(*args, **kwargs)
|
|
15
|
+
return x
|
|
16
|
+
|
|
17
|
+
def register_pre_hook(self, hook):
|
|
18
|
+
self.module_pre_hook.append(hook)
|
|
19
|
+
|
|
20
|
+
def register_post_hook(self, hook):
|
|
21
|
+
self.module_post_hook.append(hook)
|
|
22
|
+
|
|
23
|
+
def forward(self, *args, **kwargs):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def load_weights(self):
|
|
28
|
+
pass
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import torch
|
|
3
|
+
from raySD.utils.Enable_xFormers import *
|
|
4
|
+
from raySD.pipeline.Abstract_Pipeline import *
|
|
5
|
+
from raySD.prompt.chibi_prompt import *
|
|
6
|
+
from raySD.pydantic_model.Stable_Diffusion_IP_Adapter_Model import *
|
|
7
|
+
import time
|
|
8
|
+
import cv2
|
|
9
|
+
from PIL import Image
|
|
10
|
+
import importlib
|
|
11
|
+
|
|
12
|
+
class StableDiffusionIPAdapterPipeline(AbstractPipeline):
|
|
13
|
+
def __init__(self, **kwargs):
|
|
14
|
+
super().__init__()
|
|
15
|
+
## Config
|
|
16
|
+
self.config = SD_IP_Config(**kwargs)
|
|
17
|
+
|
|
18
|
+
def update_params_infer(self, **kwargs):
|
|
19
|
+
self.config.inference_steps = kwargs.get("inference_steps", 20)
|
|
20
|
+
self.config.guidance_scale = kwargs.get("guidance_scale", 7)
|
|
21
|
+
self.config.ip_adapter_scale = kwargs.get("ip_adapter_scale", 1)
|
|
22
|
+
self.config.clip_skip=kwargs.get("clip_skip", 2)
|
|
23
|
+
self.config.num_images_per_prompt=kwargs.get("num_images_per_prompt", 1)
|
|
24
|
+
|
|
25
|
+
def load_weights(self):
|
|
26
|
+
from diffusers import DPMSolverMultistepScheduler
|
|
27
|
+
from diffusers import StableDiffusionPipeline
|
|
28
|
+
|
|
29
|
+
## Device
|
|
30
|
+
self.device = "cuda" if torch.cuda.is_available() else "cpu"
|
|
31
|
+
print(f"DEVICE: {self.device}")
|
|
32
|
+
## Load Stable Diffusion model
|
|
33
|
+
pipeline = StableDiffusionPipeline.from_single_file(
|
|
34
|
+
self.config.checkpoint_path,
|
|
35
|
+
torch_dtype=torch.float16,
|
|
36
|
+
safety_checker=None
|
|
37
|
+
).to(self.device)
|
|
38
|
+
|
|
39
|
+
### Scheduler
|
|
40
|
+
pipeline.scheduler = DPMSolverMultistepScheduler.from_config(
|
|
41
|
+
pipeline.scheduler.config,
|
|
42
|
+
algorithm_type="dpmsolver++", # <-- DPM++
|
|
43
|
+
use_karras_sigmas=True, # <-- Karras
|
|
44
|
+
solver_order=2 # <-- 2M (2nd order multistep)
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
if self.config.lora_style_path:
|
|
48
|
+
print("Load LoRA done")
|
|
49
|
+
pipeline.load_lora_weights(self.config.lora_style_path)
|
|
50
|
+
|
|
51
|
+
enable_xformers_if_available(pipeline)
|
|
52
|
+
|
|
53
|
+
### Load pipeline to IPAdapter
|
|
54
|
+
if self.config.ip_adapter_plus:
|
|
55
|
+
from ip_adapter.ip_adapter_faceid import IPAdapterFaceIDPlus
|
|
56
|
+
self.ip_adapter = IPAdapterFaceIDPlus(
|
|
57
|
+
pipeline,
|
|
58
|
+
image_encoder_path=self.config.image_encoder_path,
|
|
59
|
+
ip_ckpt=self.config.ip_adapter_checkpoint_path,
|
|
60
|
+
device=self.device
|
|
61
|
+
)
|
|
62
|
+
else:
|
|
63
|
+
from ip_adapter.ip_adapter_faceid import IPAdapterFaceID
|
|
64
|
+
self.ip_adapter = IPAdapterFaceID(
|
|
65
|
+
pipeline,
|
|
66
|
+
ip_ckpt=self.config.ip_adapter_checkpoint_path,
|
|
67
|
+
device=self.device
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
module = importlib.import_module("insightface.app")
|
|
71
|
+
# Load Face Analysis
|
|
72
|
+
self.face_app = module.FaceAnalysis(name=self.config.insightface_app_name, providers=self.config.insightface_providers)
|
|
73
|
+
self.face_app.prepare(ctx_id=0, det_size=self.config.det_size_face)
|
|
74
|
+
|
|
75
|
+
module_util = importlib.import_module("insightface.utils")
|
|
76
|
+
self.face_align = getattr(module_util, "face_align")
|
|
77
|
+
|
|
78
|
+
print("LOAD SD PIPELINE DONE")
|
|
79
|
+
|
|
80
|
+
def forward(self, x: Image.Image, **kwargs)->Image.Image:
|
|
81
|
+
img = cv2.cvtColor(np.array(x), cv2.COLOR_RGB2BGR)
|
|
82
|
+
faces = self.face_app.get(img)
|
|
83
|
+
face_emb = torch.from_numpy(faces[0].normed_embedding).unsqueeze(0).to(self.device)
|
|
84
|
+
aligned_face = self.face_align.norm_crop(img, landmark=faces[0].kps, image_size=self.config.target_size)
|
|
85
|
+
|
|
86
|
+
print(face_emb.shape)
|
|
87
|
+
print(aligned_face.shape)
|
|
88
|
+
|
|
89
|
+
gender = kwargs["gender"]
|
|
90
|
+
age = kwargs["age"]
|
|
91
|
+
|
|
92
|
+
if self.config.style_name == "chibi_style":
|
|
93
|
+
chibi_prompt = ChibiPrompt2(gender=gender)
|
|
94
|
+
self.prompt, self.negative_prompt = chibi_prompt.get_prompt()
|
|
95
|
+
|
|
96
|
+
start_time = time.time()
|
|
97
|
+
image = self.ip_adapter.generate(
|
|
98
|
+
face_image=aligned_face,
|
|
99
|
+
faceid_embeds=face_emb,
|
|
100
|
+
prompt=self.prompt,
|
|
101
|
+
negative_prompt=self.negative_prompt,
|
|
102
|
+
guidance_scale=self.config.guidance_scale,
|
|
103
|
+
num_inference_steps=self.config.inference_steps,
|
|
104
|
+
scale=self.config.ip_adapter_scale,
|
|
105
|
+
num_samples=self.config.num_images_per_prompt,
|
|
106
|
+
width=self.config.width,
|
|
107
|
+
height=self.config.height,
|
|
108
|
+
)[0]
|
|
109
|
+
end_time = time.time()
|
|
110
|
+
print(f"Inference time: {end_time - start_time:.2f} seconds")
|
|
111
|
+
return image
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from raySD.pipeline.Abstract_Pipeline import *
|
|
2
|
+
from PIL import Image
|
|
3
|
+
import importlib
|
|
4
|
+
import time
|
|
5
|
+
import numpy as np
|
|
6
|
+
import cv2
|
|
7
|
+
|
|
8
|
+
class SuperResolutionPipeline(AbstractPipeline):
|
|
9
|
+
def __init__(self, model_path: str, device="CPU", output_size=(768, 768)):
|
|
10
|
+
super().__init__()
|
|
11
|
+
self.model_path = model_path
|
|
12
|
+
self.device = device
|
|
13
|
+
self.output_size = output_size
|
|
14
|
+
|
|
15
|
+
def load_weights(self):
|
|
16
|
+
module = importlib.import_module("openvino")
|
|
17
|
+
Core = getattr(module, "Core")
|
|
18
|
+
core = Core()
|
|
19
|
+
model_ov = core.read_model(self.model_path)
|
|
20
|
+
self.model = core.compile_model(model_ov, device_name=self.device)
|
|
21
|
+
print("LOAD SUPER RESOLUTION MODEL DONE")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def forward(self, x: Image.Image, **kwargs)->Image.Image:
|
|
25
|
+
st = time.time()
|
|
26
|
+
x = np.array(x)
|
|
27
|
+
x = x / 255.0
|
|
28
|
+
x = np.expand_dims(x, axis=0)
|
|
29
|
+
x = np.transpose(x, (0, 3, 1, 2))
|
|
30
|
+
y = self.model([x])
|
|
31
|
+
start_time = time.time()
|
|
32
|
+
y = y[next(iter(y))]
|
|
33
|
+
end_time = time.time()
|
|
34
|
+
print(f"Inference ESRGAN: {end_time - start_time}s")
|
|
35
|
+
y = np.transpose(y, (0, 2, 3, 1))
|
|
36
|
+
y = np.squeeze(y)
|
|
37
|
+
y = cv2.resize(y, self.output_size, interpolation=cv2.INTER_AREA)
|
|
38
|
+
y = cv2.convertScaleAbs(y*255)
|
|
39
|
+
image_out = Image.fromarray(y)
|
|
40
|
+
ed = time.time()
|
|
41
|
+
print(f"All time IF: {ed - st}s")
|
|
42
|
+
return image_out
|
raySD/prompt/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .chibi_prompt import *
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from pydantic import BaseModel, model_validator
|
|
2
|
+
from typing import List, Dict, Any, Optional
|
|
3
|
+
|
|
4
|
+
class ChibiPrompt():
|
|
5
|
+
def __init__(self, gender: int):
|
|
6
|
+
self.gender = gender
|
|
7
|
+
if gender == 1:
|
|
8
|
+
self.key1 = "boy"
|
|
9
|
+
self.key2 = "male"
|
|
10
|
+
else:
|
|
11
|
+
self.key1 = "girl"
|
|
12
|
+
self.key2 = "female"
|
|
13
|
+
|
|
14
|
+
# self.prompt = f"chibi style, solo, looking at viewer, simple background, brown hair, blue shirt, 1{self.key1}, {self.key2} focus, brown hair, warm and friendly expression, natural smile, well-aligned teeth, realistic lips, smooth facial features, expressive eyes, soft lighting, high-quality shading, professional rendering, best quality, high resolution, portrait, blue background, natural proportions, detailed face, gentle grin"
|
|
15
|
+
# self.negative_prompt = f"worst quality, low quality, normal quaworst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, bad smile, bad anatomylity, jpeg artifacts, signature, watermark, username, blurry, bad anatomy, blurry teeth, deformed teeth, extra teeth, missing teeth"
|
|
16
|
+
|
|
17
|
+
self.prompt = f"chibi style, solo, looking at viewer, simple background, brown hair, blue shirt, 1{self.key1}, {self.key2} (20-30 years old), {self.key2} focus, brown hair, warm and friendly expression, natural smile, well-aligned teeth, realistic lips, smooth facial features, expressive eyes, soft lighting, high-quality shading, professional rendering, best quality, high resolution, portrait, blue background, natural proportions, detailed face, gentle grin"
|
|
18
|
+
self.negative_prompt = f"worst quality, low quality, normal quaworst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, bad smile, bad anatomylity, jpeg artifacts, signature, watermark, username, blurry, bad anatomy, blurry teeth, deformed teeth, extra teeth, missing teeth"
|
|
19
|
+
|
|
20
|
+
def get_prompt(self):
|
|
21
|
+
return self.prompt, self.negative_prompt
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ChibiPrompt1():
|
|
25
|
+
def __init__(self, gender: int):
|
|
26
|
+
self.gender = gender
|
|
27
|
+
if gender == 1:
|
|
28
|
+
self.key1 = "boy"
|
|
29
|
+
self.key2 = "male"
|
|
30
|
+
else:
|
|
31
|
+
self.key1 = "girl"
|
|
32
|
+
self.key2 = "female"
|
|
33
|
+
|
|
34
|
+
self.prompt = f"chibi style, solo, 1{self.key1}, blue shirt, brown hair, looking at viewer, warm and friendly expression, natural smile, realistic lips, well-aligned teeth, smooth facial features, expressive eyes, soft lighting, detailed face, gentle grin, portrait, blue background, simple background, professional rendering, high-quality shading, bright face, soft glow, best quality, high resolution"
|
|
35
|
+
self.negative_prompt = f"worst quality, low quality, normal quaworst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, bad smile, bad anatomylity, jpeg artifacts, signature, watermark, username, blurry, bad anatomy, blurry teeth, deformed teeth, extra teeth, missing teeth"
|
|
36
|
+
|
|
37
|
+
def get_prompt(self):
|
|
38
|
+
return self.prompt, self.negative_prompt
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ChibiPrompt2():
|
|
42
|
+
def __init__(self, gender: int):
|
|
43
|
+
self.gender = gender
|
|
44
|
+
if gender == 1:
|
|
45
|
+
self.key1 = "boy"
|
|
46
|
+
self.key2 = "male"
|
|
47
|
+
else:
|
|
48
|
+
self.key1 = "girl"
|
|
49
|
+
self.key2 = "female"
|
|
50
|
+
|
|
51
|
+
self.prompt = f"chibi style, solo, 1{self.key1}, looking at viewer, blue shirt, friendly expression, natural smile, smooth fair skin, realistic lips, big round eyes, bright eyes, evenly lit bright face, soft glow, ambient diffuse light, high quality shading, detailed soft face, professional render, best quality, high resolution, blue background"
|
|
52
|
+
|
|
53
|
+
self.negative_prompt = f"worst quality, low quality, jpeg artifacts, signature, watermark, username, blurry, bad smile, bad anatomy, blurry teeth, deformed teeth, extra teeth, missing teeth, uneven lighting, harsh shadow, flat shading, discolored skin, dark chin, underexposed face, unnatural skin tone, narrow eyes, slit eyes, squinting eyes, closed eyes, color bleeding, blue tint on face"
|
|
54
|
+
|
|
55
|
+
def get_prompt(self):
|
|
56
|
+
return self.prompt, self.negative_prompt
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from pydantic import BaseModel, model_validator
|
|
2
|
+
from typing import List, Dict, Any, Optional
|
|
3
|
+
|
|
4
|
+
class SD_IP_Config(BaseModel):
|
|
5
|
+
pretrain_model_path: str = ""
|
|
6
|
+
checkpoint_path: str = ""
|
|
7
|
+
lora_style_path: str = ""
|
|
8
|
+
style_name: str = ""
|
|
9
|
+
height: int = 512
|
|
10
|
+
width: int = 512
|
|
11
|
+
ip_adapter_plus: bool = False
|
|
12
|
+
version: float = 1.0
|
|
13
|
+
image_encoder_path: str = ""
|
|
14
|
+
ip_adapter_checkpoint_path: str = ""
|
|
15
|
+
insightface_app_name: str = ""
|
|
16
|
+
insightface_providers: List = []
|
|
17
|
+
|
|
18
|
+
det_size_face: tuple = (640, 640)
|
|
19
|
+
target_size: int = 224
|
|
20
|
+
inference_steps: int = 20
|
|
21
|
+
guidance_scale: float = 7
|
|
22
|
+
ip_adapter_scale: float = 0.6
|
|
23
|
+
clip_skip: int = 2
|
|
24
|
+
num_images_per_prompt: int = 1
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
def enable_xformers_if_available(pipe):
|
|
2
|
+
try:
|
|
3
|
+
import xformers
|
|
4
|
+
pipe.enable_xformers_memory_efficient_attention()
|
|
5
|
+
print("xformers is available and has been enabled.")
|
|
6
|
+
except ImportError:
|
|
7
|
+
print("xformers is NOT installed. Running without xformers.")
|
|
8
|
+
except Exception as e:
|
|
9
|
+
print(f"xformers is installed but could not be enabled: {e}")
|
raySD/utils/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .Enable_xFormers import *
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: raySD
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Stable diffusion pipeline for ray
|
|
5
|
+
Author: Nguyen Hong Ky
|
|
6
|
+
Requires-Dist: numpy==1.26.4
|
|
7
|
+
Requires-Dist: opencv-python>=4.10.0.84
|
|
8
|
+
Requires-Dist: pillow>=9.5.0
|
|
9
|
+
Requires-Dist: torch==2.3.1
|
|
10
|
+
Requires-Dist: torchvision==0.18.1
|
|
11
|
+
Requires-Dist: diffusers==0.33.0
|
|
12
|
+
Requires-Dist: transformers==4.49.0
|
|
13
|
+
Requires-Dist: peft==0.15.2
|
|
14
|
+
Requires-Dist: openvino==2025.1.0
|
|
15
|
+
Requires-Dist: ip-adapterv
|
|
16
|
+
Requires-Dist: pydantic
|
|
17
|
+
Requires-Dist: onnx==1.17.0
|
|
18
|
+
Requires-Dist: onnxruntime==1.17.1
|
|
19
|
+
Dynamic: author
|
|
20
|
+
Dynamic: requires-dist
|
|
21
|
+
Dynamic: summary
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
raySD/__init__.py,sha256=4ETmeXZJi5Myr8boHVhNqejNmMNHjG8oraKokGJw1ko,124
|
|
2
|
+
raySD/pipeline/Abstract_Pipeline.py,sha256=0M0H7j0b7OrJpm-FD0ZCUqiv65DjxVn9YCd38TScbZg,768
|
|
3
|
+
raySD/pipeline/Stable_Diffusion_IP_Adapter.py,sha256=0ViMt8X64TFIX9rZQT2ARFoExxN_FOfD5wUEJvoBQcQ,4564
|
|
4
|
+
raySD/pipeline/Super_Resolution_Pipeline.py,sha256=5q2L5En7zMYdnKd-yUnkQyvQ4p3wyc1tu5laZaLAUkM,1470
|
|
5
|
+
raySD/pipeline/__init__.py,sha256=3SohaavHvlq6mt5F5rpbReoU2pggZTH8T7BNE7GPPqo,84
|
|
6
|
+
raySD/prompt/__init__.py,sha256=fVssgWdHZT0v98vMT328Cx_ayYSJh_RFmIhbts_0s8c,27
|
|
7
|
+
raySD/prompt/chibi_prompt.py,sha256=u1v-1SSkdfM1QmSso99a1FcGdKW426eH3cRaGEbb_kE,4203
|
|
8
|
+
raySD/pydantic_model/Image_Generate_Model.py,sha256=RlfMwF5GhWm6sQvxVN16HVv-nLth_B7yyrFvIvyX_WA,194
|
|
9
|
+
raySD/pydantic_model/Image_Response_Model.py,sha256=tgZo2P-klG0TX_DRaReKHrH2ZUF-g53N1vnIMZLGNsw,98
|
|
10
|
+
raySD/pydantic_model/Message_Model.py,sha256=D0DNP1F8kkwwB2X8QOTLtaLleVdf_INyIwjdypuVafM,94
|
|
11
|
+
raySD/pydantic_model/Stable_Diffusion_IP_Adapter_Model.py,sha256=vpQM1To4K-amIKrFy0dxXxeLSMr5mWuAHJWWgdKGhO4,734
|
|
12
|
+
raySD/pydantic_model/__init__.py,sha256=woiNl2YsEnyRvkFFRQuDIVLm-pMiJo27xgoRrHw0mOs,152
|
|
13
|
+
raySD/utils/Enable_xFormers.py,sha256=2gZf3Shxth4jDkAtDFZa27wDFNavZa3BRn4nizgaiyw,392
|
|
14
|
+
raySD/utils/__init__.py,sha256=KavMKUtooaiUDJOsNzdEUjOxTWxZ9sn8sUPWaJ2Mkgs,30
|
|
15
|
+
raysd-0.1.0.dist-info/METADATA,sha256=YL59OSkrZJb-UxNft9_PTddMZGKH2LkmHiQeFBEs7Kg,598
|
|
16
|
+
raysd-0.1.0.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
|
17
|
+
raysd-0.1.0.dist-info/top_level.txt,sha256=1yKh5zJFazWtmZ-WR7v930Nl7KkrjpodCSBFU76K7SU,6
|
|
18
|
+
raysd-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
raySD
|