🎯 Mục tiêu bài học
ControlNet cho phép kiểm soát chính xác output của Stable Diffusion bằng cách sử dụng các điều kiện như pose, depth map, edges.
Sau bài này, bạn sẽ:
✅ Hiểu ControlNet architecture và các loại control ✅ Sử dụng Canny, Depth, OpenPose controls ✅ Implement style transfer với IP-Adapter và Neural Style Transfer ✅ Kết hợp Multi-ControlNet cho kết quả chính xác
🔍 ControlNet Architecture
- Canny Edge: Kiểm soát theo đường viền
- Depth: Kiểm soát chiều sâu 3D
- OpenPose: Kiểm soát tư thế người
- Scribble: Vẽ phác thảo đơn giản
- Segmentation: Kiểm soát theo vùng
Checkpoint
Bạn đã hiểu các loại ControlNet và use case của từng loại chưa?
📐 Canny Edge Control
1from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel2from diffusers.utils import load_image3import cv24import numpy as np5from PIL import Image67# Load ControlNet8controlnet = ControlNetModel.from_pretrained(9 "diffusers/controlnet-canny-sdxl-1.0",10 torch_dtype=torch.float1611)1213pipe = StableDiffusionXLControlNetPipeline.from_pretrained(14 "stabilityai/stable-diffusion-xl-base-1.0",15 controlnet=controlnet,16 torch_dtype=torch.float1617).to("cuda")1819# Extract edges20image = np.array(Image.open("input.png"))21edges = cv2.Canny(image, 100, 200)22edge_image = Image.fromarray(edges)2324# Generate voi edge control25result = pipe(26 prompt="beautiful watercolor painting, vibrant colors",27 image=edge_image,28 controlnet_conditioning_scale=0.7,29 num_inference_steps=3030).images[0]Checkpoint
Bạn đã thử sử dụng Canny Edge ControlNet để kiểm soát đường viền output chưa?
📐 Depth Control
1from transformers import pipeline23# Extract depth map4depth_estimator = pipeline("depth-estimation", model="Intel/dcs-large")5depth = depth_estimator(Image.open("photo.png"))6depth_image = depth["depth"]78# Use depth for controlled generation9controlnet_depth = ControlNetModel.from_pretrained(10 "diffusers/controlnet-depth-sdxl-1.0",11 torch_dtype=torch.float1612)1314pipe_depth = StableDiffusionXLControlNetPipeline.from_pretrained(15 "stabilityai/stable-diffusion-xl-base-1.0",16 controlnet=controlnet_depth,17 torch_dtype=torch.float1618).to("cuda")1920result = pipe_depth(21 prompt="anime style room, detailed, colorful",22 image=depth_image,23 controlnet_conditioning_scale=0.824).images[0]Checkpoint
Bạn đã hiểu cách dùng depth map để giữ cấu trúc 3D khi thay đổi style chưa?
📐 OpenPose Control
1from controlnet_aux import OpenposeDetector23# Detect pose4pose_detector = OpenposeDetector.from_pretrained("lllyasviel/ControlNet")5pose_image = pose_detector(Image.open("person.png"))67# Generate voi pose control8result = pipe_pose(9 prompt="professional dancer in elegant dress, studio lighting",10 image=pose_image,11 controlnet_conditioning_scale=0.812).images[0]Checkpoint
Bạn đã hiểu cách sử dụng OpenPose để kiểm soát tư thế người trong ảnh chưa?
🎨 Style Transfer
IP-Adapter (Image Prompt)
1from diffusers import StableDiffusionXLPipeline23pipe = StableDiffusionXLPipeline.from_pretrained(4 "stabilityai/stable-diffusion-xl-base-1.0",5 torch_dtype=torch.float166).to("cuda")78# Load IP-Adapter9pipe.load_ip_adapter(10 "h94/IP-Adapter",11 subfolder="sdxl_models",12 weight_name="ip-adapter_sdxl.bin"13)1415style_image = Image.open("style_reference.png")1617result = pipe(18 prompt="a cozy cafe interior",19 ip_adapter_image=style_image,20 num_inference_steps=3021).images[0]Neural Style Transfer
1import torch2import torchvision.transforms as transforms3from torchvision.models import vgg1945# Classic neural style transfer6def style_transfer(content_img, style_img, steps=300):7 device = torch.device("cuda" if torch.cuda.is_available() else "cpu")8 9 transform = transforms.Compose([10 transforms.Resize(512),11 transforms.ToTensor()12 ])13 14 content = transform(content_img).unsqueeze(0).to(device)15 style = transform(style_img).unsqueeze(0).to(device)16 17 # Use VGG19 features18 vgg = vgg19(pretrained=True).features.to(device).eval()19 20 # Optimize target image21 target = content.clone().requires_grad_(True)22 optimizer = torch.optim.Adam([target], lr=0.01)23 24 for step in range(steps):25 # Extract features and compute style + content loss26 optimizer.zero_grad()27 loss = compute_style_content_loss(vgg, target, content, style)28 loss.backward()29 optimizer.step()30 31 return targetCheckpoint
Bạn đã hiểu sự khác biệt giữa IP-Adapter và Neural Style Transfer chưa?
📐 Multi-ControlNet
1from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel23# Combine multiple controls4controlnets = [5 ControlNetModel.from_pretrained("controlnet-canny", torch_dtype=torch.float16),6 ControlNetModel.from_pretrained("controlnet-depth", torch_dtype=torch.float16),7]89pipe = StableDiffusionXLControlNetPipeline.from_pretrained(10 "stabilityai/stable-diffusion-xl-base-1.0",11 controlnet=controlnets,12 torch_dtype=torch.float1613).to("cuda")1415result = pipe(16 prompt="detailed architectural rendering",17 image=[canny_image, depth_image],18 controlnet_conditioning_scale=[0.7, 0.5]19).images[0]Checkpoint
Bạn đã biết cách kết hợp nhiều ControlNets trong cùng một pipeline chưa?
🎯 Tổng kết
Bài tập thực hành
- Sử dụng Canny ControlNet để chuyển sketch thành realistic image
- Thử Depth control để thay đổi style giữ 3D structure
- Implement style transfer giữa 2 images
- Combine multiple ControlNets
Challenge: Build "photo to painting" pipeline với consistent style
Câu hỏi tự kiểm tra
- ControlNet sử dụng các điều kiện như Canny edge và depth map để kiểm soát output của Stable Diffusion như thế nào?
- Multi-ControlNet là gì và khi nào cần kết hợp nhiều controls trong cùng một pipeline?
- Style transfer hoạt động dựa trên nguyên tắc gì của mạng VGG19 (content loss và style loss)?
- So sánh các loại ControlNet (Canny, Depth, Pose) về ứng dụng thực tế trong từng trường hợp cụ thể?
🎉 Tuyệt vời! Bạn đã hoàn thành bài học ControlNet va Style Transfer!
Tiếp theo: Chúng ta sẽ chuyển sang Vision Models - học cách AI "nhìn" và hiểu hình ảnh với GPT-4V và Claude.
