Buckets:
| # ControlNet | |
| [ControlNet](https://huggingface.co/papers/2302.05543)은 텍스트 프롬프트를 유지하면서 구조적 제어 이미지(엣지, 깊이, 또는 포즈)로 사전 학습된 diffusion 모델을 제어합니다. 기본 모델은 동결된 채로, 잔차를 통해 denoiser를 안내하는 병렬 네트워크가 추가되므로 fine-tuning 없이 레이아웃 제어가 가능합니다. | |
| 필요한 컨트롤(예: canny)에 해당하는 ControlNet을 로드한 후, [from_pretrained()](/docs/diffusers/main/ko/api/pipelines/overview#diffusers.DiffusionPipeline.from_pretrained)에 `controlnet=`로 전달합니다. `controlnet_conditioning_scale`를 사용하여 컨트롤이 생성을 얼마나 강하게 유도하는지 설정합니다. | |
| > [!TIP] | |
| > ControlNet은 [Flux](../api/pipelines/controlnet_flux), [Hunyuan-DiT](../api/pipelines/controlnet_hunyuandit), [Stable Diffusion 3](../api/pipelines/controlnet_sd3) 등 다양한 모델에서 사용할 수 있습니다. 이 가이드의 예제는 Flux와 Stable Diffusion XL를 사용합니다. 구형 Stable Diffusion 계열 체크포인트에 대한 T2I-Adapter는 [Legacy adapters](./legacy_adapters#t2i-adapter)를 참고하세요. 새로운 제어 가능 생성 작업에는 ControlNet 사용을 권장합니다. | |
| 아래 탭에는 텍스트-이미지 생성, 이미지-이미지 변환, 인페인팅을 위한 ControlNet이 표시됩니다. | |
| [opencv-python](https://github.com/opencv/opencv-python)으로 canny 이미지를 생성합니다. | |
| ```py | |
| import cv2 | |
| import numpy as np | |
| from PIL import Image | |
| from diffusers.utils import load_image | |
| original_image = load_image( | |
| "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/non-enhanced-prompt.png" | |
| ) | |
| image = np.array(original_image) | |
| low_threshold = 100 | |
| high_threshold = 200 | |
| image = cv2.Canny(image, low_threshold, high_threshold) | |
| image = image[:, :, None] | |
| image = np.concatenate([image, image, image], axis=2) | |
| canny_image = Image.fromarray(image) | |
| ``` | |
| canny 이미지를 파이프라인에 전달합니다. `controlnet_conditioning_scale` 매개변수를 사용하여 컨트롤에 부여할 가중치를 결정합니다. | |
| ```py | |
| import torch | |
| from diffusers.utils import load_image | |
| from diffusers import FluxControlNetPipeline, FluxControlNetModel | |
| controlnet = FluxControlNetModel.from_pretrained( | |
| "InstantX/FLUX.1-dev-Controlnet-Canny", dtype=torch.bfloat16 | |
| ) | |
| pipeline = FluxControlNetPipeline.from_pretrained( | |
| "black-forest-labs/FLUX.1-dev", controlnet=controlnet, dtype=torch.bfloat16 | |
| ).to("cuda") # or "mps", "xpu", "cpu" | |
| prompt = """ | |
| A photorealistic overhead image of a cat reclining sideways in a flamingo pool floatie holding a margarita. | |
| The cat is floating leisurely in the pool and completely relaxed and happy. | |
| """ | |
| pipeline( | |
| prompt, | |
| control_image=canny_image, | |
| controlnet_conditioning_scale=0.5, | |
| num_inference_steps=50, | |
| guidance_scale=3.5, | |
| ).images[0] | |
| ``` | |
| 원본 이미지 | |
| canny 이미지 | |
| 생성된 이미지 | |
| Transformers의 깊이 추정 파이프라인을 사용하여 깊이 맵을 생성합니다. | |
| ```py | |
| import torch | |
| import numpy as np | |
| from PIL import Image | |
| from transformers import DPTImageProcessor, DPTForDepthEstimation | |
| from diffusers import ControlNetModel, StableDiffusionXLControlNetImg2ImgPipeline, AutoencoderKL | |
| from diffusers.utils import load_image | |
| device = "cuda" # or "mps", "xpu", "cpu" | |
| depth_estimator = DPTForDepthEstimation.from_pretrained("Intel/dpt-hybrid-midas").to(device) | |
| feature_extractor = DPTImageProcessor.from_pretrained("Intel/dpt-hybrid-midas") | |
| def get_depth_map(image): | |
| image = feature_extractor(images=image, return_tensors="pt").pixel_values.to(device) | |
| with torch.no_grad(), torch.autocast(device): | |
| depth_map = depth_estimator(image).predicted_depth | |
| depth_map = torch.nn.functional.interpolate( | |
| depth_map.unsqueeze(1), | |
| size=(1024, 1024), | |
| mode="bicubic", | |
| align_corners=False, | |
| ) | |
| depth_min = torch.amin(depth_map, dim=[1, 2, 3], keepdim=True) | |
| depth_max = torch.amax(depth_map, dim=[1, 2, 3], keepdim=True) | |
| depth_map = (depth_map - depth_min) / (depth_max - depth_min) | |
| image = torch.cat([depth_map] * 3, dim=1) | |
| image = image.permute(0, 2, 3, 1).cpu().numpy()[0] | |
| image = Image.fromarray((image * 255.0).clip(0, 255).astype(np.uint8)) | |
| return image | |
| image = load_image( | |
| "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/non-enhanced-prompt.png" | |
| ).resize((1024, 1024)) | |
| depth_image = get_depth_map(image) | |
| ``` | |
| 깊이 맵을 파이프라인에 전달합니다. `controlnet_conditioning_scale` 매개변수를 사용하여 컨트롤에 부여할 가중치를 결정합니다. | |
| ```py | |
| controlnet = ControlNetModel.from_pretrained( | |
| "diffusers/controlnet-depth-sdxl-1.0-small", | |
| dtype=torch.float16, | |
| ) | |
| vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", dtype=torch.float16) | |
| pipeline = StableDiffusionXLControlNetImg2ImgPipeline.from_pretrained( | |
| "stabilityai/stable-diffusion-xl-base-1.0", | |
| controlnet=controlnet, | |
| vae=vae, | |
| dtype=torch.float16, | |
| ).to(device) | |
| prompt = """ | |
| A photorealistic overhead image of a cat reclining sideways in a flamingo pool floatie holding a margarita. | |
| The cat is floating leisurely in the pool and completely relaxed and happy. | |
| """ | |
| controlnet_conditioning_scale = 0.5 | |
| pipeline( | |
| prompt, | |
| image=image, | |
| control_image=depth_image, | |
| controlnet_conditioning_scale=controlnet_conditioning_scale, | |
| strength=0.99, | |
| num_inference_steps=100, | |
| ).images[0] | |
| ``` | |
| 원본 이미지 | |
| 깊이 맵 | |
| 생성된 이미지 | |
| 바꿀 픽셀을 표시하는 마스크 이미지를 생성한 후, 컨트롤 이미지와 함께 `mask_image`로 전달합니다. | |
| ```py | |
| import cv2 | |
| import torch | |
| import numpy as np | |
| from PIL import Image | |
| from diffusers.utils import load_image | |
| from diffusers import StableDiffusionXLControlNetInpaintPipeline, ControlNetModel | |
| init_image = load_image( | |
| "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/non-enhanced-prompt.png" | |
| ) | |
| init_image = init_image.resize((1024, 1024)) | |
| mask_image = load_image( | |
| "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/cat_mask.png" | |
| ) | |
| mask_image = mask_image.resize((1024, 1024)) | |
| def make_canny_condition(image): | |
| image = np.array(image) | |
| image = cv2.Canny(image, 100, 200) | |
| image = image[:, :, None] | |
| image = np.concatenate([image, image, image], axis=2) | |
| image = Image.fromarray(image) | |
| return image | |
| control_image = make_canny_condition(init_image) | |
| ``` | |
| 마스크와 제어 이미지를 파이프라인에 전달합니다. `controlnet_conditioning_scale` 매개변수를 사용하여 제어에 부여할 가중치를 결정합니다. | |
| ```py | |
| controlnet = ControlNetModel.from_pretrained( | |
| "diffusers/controlnet-canny-sdxl-1.0", dtype=torch.float16 | |
| ) | |
| pipeline = StableDiffusionXLControlNetInpaintPipeline.from_pretrained( | |
| "stabilityai/stable-diffusion-xl-base-1.0", controlnet=controlnet, dtype=torch.float16 | |
| ).to("cuda") # or "mps", "xpu", "cpu" | |
| pipeline( | |
| "a cute and fluffy bunny rabbit", | |
| num_inference_steps=100, | |
| strength=0.99, | |
| controlnet_conditioning_scale=0.5, | |
| image=init_image, | |
| mask_image=mask_image, | |
| control_image=control_image, | |
| ).images[0] | |
| ``` | |
| 원본 이미지 | |
| 마스크 이미지 | |
| 생성된 이미지 | |
| ## Multi-ControlNet | |
| 여러 ControlNet(예: canny + depth)을 리스트로 전달하여 조합합니다. 겹치는 영역은 가급적 마스크 처리하고, 각 `controlnet_conditioning_scale`를 조정합니다. `canny_image`는 OpenCV Canny(텍스트-이미지 생성과 동일하게)로, `depth_image`는 DPT(이미지-이미지 생성과 동일하게)로 생성합니다. 파이프라인을 호출하기 전에 모든 제어 이미지를 파이프라인 크기로 리사이즈합니다. | |
| ```py | |
| import cv2 | |
| import torch | |
| import numpy as np | |
| from PIL import Image | |
| from transformers import DPTImageProcessor, DPTForDepthEstimation | |
| from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel, AutoencoderKL | |
| from diffusers.utils import load_image | |
| original_image = load_image( | |
| "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/non-enhanced-prompt.png" | |
| ) | |
| image = np.array(original_image) | |
| canny_image = Image.fromarray( | |
| np.concatenate([cv2.Canny(image, 100, 200)[:, :, None]] * 3, axis=2) | |
| ) | |
| device = "cuda" # or "mps", "xpu", "cpu" | |
| depth_estimator = DPTForDepthEstimation.from_pretrained("Intel/dpt-hybrid-midas").to(device) | |
| feature_extractor = DPTImageProcessor.from_pretrained("Intel/dpt-hybrid-midas") | |
| def get_depth_map(image): | |
| image = feature_extractor(images=image, return_tensors="pt").pixel_values.to(device) | |
| with torch.no_grad(), torch.autocast(device): | |
| depth_map = depth_estimator(image).predicted_depth | |
| depth_map = torch.nn.functional.interpolate( | |
| depth_map.unsqueeze(1), | |
| size=(1024, 1024), | |
| mode="bicubic", | |
| align_corners=False, | |
| ) | |
| depth_min = torch.amin(depth_map, dim=[1, 2, 3], keepdim=True) | |
| depth_max = torch.amax(depth_map, dim=[1, 2, 3], keepdim=True) | |
| depth_map = (depth_map - depth_min) / (depth_max - depth_min) | |
| image = torch.cat([depth_map] * 3, dim=1) | |
| image = image.permute(0, 2, 3, 1).cpu().numpy()[0] | |
| image = Image.fromarray((image * 255.0).clip(0, 255).astype(np.uint8)) | |
| return image | |
| depth_image = get_depth_map(original_image.resize((1024, 1024))) | |
| controlnets = [ | |
| ControlNetModel.from_pretrained( | |
| "diffusers/controlnet-canny-sdxl-1.0", dtype=torch.float16 | |
| ), | |
| ControlNetModel.from_pretrained( | |
| "diffusers/controlnet-depth-sdxl-1.0-small", dtype=torch.float16 | |
| ), | |
| ] | |
| vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", dtype=torch.float16) | |
| pipeline = StableDiffusionXLControlNetPipeline.from_pretrained( | |
| "stabilityai/stable-diffusion-xl-base-1.0", controlnet=controlnets, vae=vae, dtype=torch.float16 | |
| ).to(device) | |
| prompt = """ | |
| a relaxed rabbit sitting on a striped towel next to a pool with a tropical drink nearby, | |
| bright sunny day, vacation scene, 35mm photograph, film, professional, 4k, highly detailed | |
| """ | |
| negative_prompt = "lowres, bad anatomy, worst quality, low quality, deformed, ugly" | |
| images = [canny_image.resize((1024, 1024)), depth_image.resize((1024, 1024))] | |
| pipeline( | |
| prompt, | |
| negative_prompt=negative_prompt, | |
| image=images, | |
| num_inference_steps=100, | |
| controlnet_conditioning_scale=[0.5, 0.5], | |
| ).images[0] | |
| ``` | |
| canny 이미지 | |
| 깊이 맵 | |
| 생성된 이미지 | |
| ## 추측 모드 | |
| 텍스트 프롬프트가 없거나 원하지 않을 때 컨트롤만으로도 이미지를 생성하는 [Guess mode](https://github.com/lllyasviel/ControlNet/discussions/188)입니다. 이 모드는 ControlNet 잔차를 블록 깊이에 따라 스케일링하며, 초기 다운 블록에서는 약 `0.1`에서 중간 블록에서는 `1.0`까지 적용합니다. 이를 통해 초기 레이어가 과도하게 제약되지 않으면서도 더 깊은 블록이 구조를 유지할 수 있습니다. | |
| ```py | |
| import torch | |
| from diffusers.utils import load_image | |
| from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel | |
| controlnet = ControlNetModel.from_pretrained( | |
| "diffusers/controlnet-canny-sdxl-1.0", dtype=torch.float16 | |
| ) | |
| pipeline = StableDiffusionXLControlNetPipeline.from_pretrained( | |
| "stabilityai/stable-diffusion-xl-base-1.0", | |
| controlnet=controlnet, | |
| dtype=torch.float16 | |
| ).to("cuda") # or "mps", "xpu", "cpu" | |
| canny_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/canny-cat.png") | |
| pipeline( | |
| "", | |
| image=canny_image, | |
| guess_mode=True | |
| ).images[0] | |
| ``` | |
| canny 이미지 | |
| 생성된 이미지 | |
Xet Storage Details
- Size:
- 12.1 kB
- Xet hash:
- 417773c7f2442f4c6baa5e8d91e8e7652df8f5419e3a11fcc1458d9e1c455c6e
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.