200 lines
6.7 KiB
Python
200 lines
6.7 KiB
Python
|
|
import argparse
|
|
import os
|
|
from datetime import datetime
|
|
from typing import Any, Optional
|
|
|
|
from PIL import Image, ImageOps
|
|
|
|
import torch
|
|
import comfy.utils
|
|
import numpy as np
|
|
import folder_paths
|
|
from diffusers import FluxTransformer2DModel
|
|
from .pipeline_flux_fill_with_cfg import FluxFillCFGPipeline
|
|
|
|
def is_low_memory():
|
|
mem = torch.cuda.get_device_properties(0).total_memory / (1024 ** 3)
|
|
if mem < 30:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
class RH_OneReward_Loader:
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"required": {
|
|
"model": (['flux.1-fill-dev-OneReward-transformer', 'flux.1-fill-dev-OneRewardDynamic-transformer'], 'flux.1-fill-dev-OneReward-transformer'),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("RHOneRewardPipeline",)
|
|
RETURN_NAMES = ("OneReward Pipeline",)
|
|
FUNCTION = "load"
|
|
|
|
CATEGORY = "Runninghub/OneReward"
|
|
|
|
def load(self, **kwargs):
|
|
model = kwargs.get('model')
|
|
model_path = os.path.join(folder_paths.models_dir, 'OneReward', model)
|
|
transformer_onereward = FluxTransformer2DModel.from_pretrained(
|
|
model_path,
|
|
torch_dtype=torch.bfloat16
|
|
)
|
|
print('--- OneReward transformer loaded ---')
|
|
|
|
pipe = FluxFillCFGPipeline.from_pretrained(
|
|
os.path.join(folder_paths.models_dir, 'black-forest-labs', 'FLUX.1-Fill-dev'),
|
|
transformer=transformer_onereward,
|
|
torch_dtype=torch.bfloat16)
|
|
|
|
print('--- pipeline loaded ---')
|
|
|
|
if is_low_memory():
|
|
pipe.enable_model_cpu_offload()
|
|
from optimum.quanto import freeze, qint8, quantize, quantization_map, QuantizedDiffusersModel, requantize
|
|
quantize(pipe.transformer, qint8)
|
|
freeze(pipe.transformer)
|
|
print('--- transformer quantized ---')
|
|
else:
|
|
pipe.to('cuda')
|
|
print('--- run in 48g mode ---')
|
|
|
|
return (pipe, )
|
|
|
|
class RH_OneReward_Sampler:
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"required": {
|
|
"pipeline": ("RHOneRewardPipeline", ),
|
|
"image": ("IMAGE", ),
|
|
"mask": ("MASK", ),
|
|
"prompt": ("STRING", {"multiline": True,
|
|
'default': ''}),
|
|
"num_inference_steps": ("INT", {"default": 50}),
|
|
"guidance_scale": ("FLOAT", {"default": 1.0}),
|
|
"true_cfg": ("FLOAT", {"default": 4.0}),
|
|
"seed": ("INT", {"default": 20, "min": 0, "max": 0xffffffffffffffff,
|
|
"tooltip": "The random seed used for creating the noise."}),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("image",)
|
|
FUNCTION = "sample"
|
|
|
|
CATEGORY = "Runninghub/OneReward"
|
|
|
|
def tensor_2_pil(self, img_tensor):
|
|
if img_tensor is not None:
|
|
i = 255. * img_tensor.squeeze().cpu().numpy()
|
|
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
|
|
return img
|
|
else:
|
|
return None
|
|
|
|
def sample(self, **kwargs):
|
|
pipeline = kwargs.get('pipeline')
|
|
image = self.tensor_2_pil(kwargs.get('image'))
|
|
mask = self.tensor_2_pil(kwargs.get('mask'))
|
|
|
|
width, height = image.size[0], image.size[1]
|
|
prompt = kwargs.get('prompt')
|
|
guidance_scale = kwargs.get('guidance_scale')
|
|
num_inference_steps = kwargs.get('num_inference_steps')
|
|
seed = kwargs.get('seed') % (2 ** 32)
|
|
true_cfg = kwargs.get('true_cfg')
|
|
|
|
#kiki:hardcode hyperparameters
|
|
negative_prompt = 'nsfw'
|
|
self.pbar = comfy.utils.ProgressBar(num_inference_steps)
|
|
|
|
with torch.no_grad():
|
|
image = pipeline(
|
|
prompt=prompt,
|
|
negative_prompt=negative_prompt,
|
|
image=image,
|
|
mask_image=mask,
|
|
height=height,
|
|
width=width,
|
|
guidance_scale=guidance_scale,
|
|
true_cfg=true_cfg,
|
|
num_inference_steps=num_inference_steps,
|
|
generator=torch.Generator("cpu").manual_seed(seed),
|
|
update_func=self.update,
|
|
).images[0]
|
|
|
|
image = np.array(image).astype(np.float32) / 255.0
|
|
image = torch.from_numpy(image)[None,]
|
|
|
|
return (image, )
|
|
|
|
def update(self):
|
|
self.pbar.update(1)
|
|
|
|
class RH_OneReward_Eraser(RH_OneReward_Sampler):
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"required": {
|
|
"pipeline": ("RHOneRewardPipeline", ),
|
|
"image": ("IMAGE", ),
|
|
"mask": ("MASK", ),
|
|
"num_inference_steps": ("INT", {"default": 50}),
|
|
"guidance_scale": ("FLOAT", {"default": 1.0}),
|
|
"true_cfg": ("FLOAT", {"default": 4.0}),
|
|
"seed": ("INT", {"default": 20, "min": 0, "max": 0xffffffffffffffff,
|
|
"tooltip": "The random seed used for creating the noise."}),
|
|
},
|
|
}
|
|
|
|
def sample(self, **kwargs):
|
|
pipeline = kwargs.get('pipeline')
|
|
image = self.tensor_2_pil(kwargs.get('image'))
|
|
mask = self.tensor_2_pil(kwargs.get('mask'))
|
|
|
|
width, height = image.size[0], image.size[1]
|
|
guidance_scale = kwargs.get('guidance_scale')
|
|
num_inference_steps = kwargs.get('num_inference_steps')
|
|
seed = kwargs.get('seed') % (2 ** 32)
|
|
true_cfg = kwargs.get('true_cfg')
|
|
|
|
#kiki:hardcode hyperparameters
|
|
prompt = 'remove'
|
|
negative_prompt = 'nsfw'
|
|
self.pbar = comfy.utils.ProgressBar(num_inference_steps)
|
|
|
|
with torch.no_grad():
|
|
image = pipeline(
|
|
prompt=prompt,
|
|
negative_prompt=negative_prompt,
|
|
image=image,
|
|
mask_image=mask,
|
|
height=height,
|
|
width=width,
|
|
guidance_scale=guidance_scale,
|
|
true_cfg=true_cfg,
|
|
num_inference_steps=num_inference_steps,
|
|
generator=torch.Generator("cpu").manual_seed(seed),
|
|
update_func=self.update,
|
|
).images[0]
|
|
|
|
image = np.array(image).astype(np.float32) / 255.0
|
|
image = torch.from_numpy(image)[None,]
|
|
|
|
return (image, )
|
|
|
|
NODE_CLASS_MAPPINGS = {
|
|
"RunningHub OneReward Loader": RH_OneReward_Loader,
|
|
"RunningHub OneReward Sampler": RH_OneReward_Sampler,
|
|
"RunningHub OneReward Eraser": RH_OneReward_Eraser,
|
|
}
|
|
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"RunningHub OneReward Loader": "RunningHub OneReward Loader",
|
|
"RunningHub OneReward Sampler": "RunningHub OneReward Sampler",
|
|
"RunningHub OneReward Eraser": "RunningHub OneReward Eraser",
|
|
} |