تولید تصویر با مدلهای هوش مصنوعی زمانی کاربردی شد که توانستیم محاسبات سنگین پیکسلها را به فضای نهان فشرده منتقل کنیم. استیبل دیفیوژن (Stable Diffusion) الگوی پایهی تقریباً تمام مدلهای مدرن تولید تصویر متنباز است. با درک سازوکار داخلی اجزای پنجگانهی آن — از انکودر متنی و VAE گرفته تا U-Net و اسکژولرها — کنترل دقیقتری روی کیفیت و سرعت استنتاج پیدا میکنید.
در کار عملی، هزینهی بالای سختافزار و دشواری اجارهی GPUهای ابری خارجی برای توسعهدهندگان ایرانی ایجاب میکند که بهینهترین مسیرها را انتخاب کنید. با تکنیک دیفیوژن نهان و فاینتیونینگ کمرتبه (LoRA)، امکان شخصیسازی مدلها و تولید تصویر با کارتهای گرافیک کاربری با حافظهی 8 گیگابایت نیز فراهم میشود.
در این درس علاوه بر تشریح ریاضی و ساختار مدل، با استفاده از کتابخانهی `diffusers` شیوهی اجرای تبدیل متن به تصویر، تبدیل تصویر به تصویر، اینپینتینگ و آموزش آداپتور LoRA را برای پروژههای واقعی مرور میکنیم.
استیبل دیفیوژن (Stable Diffusion) یک مدل DDPM است که در فضای نهان (latent space) یک VAE ازپیشآموزشدیده اجرا میشود، با کراساتنشن (cross-attention) روی متن شرطیسازی شده، با یک حلکنندهی ODE قطعیِ سریع نمونهگیری میکند و با هدایت بدون طبقهبند (classifier-free guidance یا CFG) هدایت میشود.
اهداف یادگیری
- بررسی پنج بخش یک پایپلاین استیبل دیفیوژن: VAE، انکودر متن، U-Net، اسکژولر (scheduler) و فیلتر ایمنی (safety checker) — و کارکرد واقعی هر کدام
- توضیح دیفیوژن نهان (latent diffusion) و اینکه چرا آموزش در فضای نهان 4x64x64 (بهجای تصویر 3x512x512) حجم محاسبات را بدون افت کیفیت تا 48 برابر کاهش میدهد
- استفاده از
diffusersبرای تولید تصویر، اجرای تبدیل تصویر به تصویر (image-to-image)، اینپینتینگ (inpainting) و تولید تصویر هدایتشده با ControlNet - فاینتیونینگ استیبل دیفیوژن با LoRA روی یک دیتاست کوچک و اختصاصی، و لود کردن آداپتور LoRA در زمان استنتاج
صورت مسئله
آموزش مستقیم یک DDPM روی تصاویر 512x512 سهکاناله (RGB) بسیار پرهزینه است. در هر گام آموزش، پسانتشار از یک U-Net عبور میکند که 3x512x512 = 786,432 مقدار ورودی میگیرد و برای نمونهگیری هم به بیش از 50 گذر رو به جلو (forward pass) از همان U-Net نیاز است. در سطح کیفی استیبل دیفیوژن 1.5 (عرضهشده در سال 2022)، دیفیوژن در فضای پیکسل به حدود 256 ماه محاسبات GPU و 10 تا 30 ثانیه زمان بهازای هر تصویر روی یک GPU کاربری نیاز داشت.
راهکاری که تولید تصویر از روی متنِ با وزنهای باز (open-weight) را کاربردی کرد، دیفیوژن نهان بود (Rombach et al., CVPR 2022). یک VAE آموزش دهید که تصویر 3x512x512 را به یک تنسور نهان 4x64x64 و برعکس تبدیل کند، سپس فرایند دیفیوژن را در همان فضای نهان انجام دهید. حجم محاسبات به میزان (3*512*512)/(4*64*64) = 48x کاهش مییابد. زمان نمونهگیری روی همان GPU از دهها ثانیه به زیر دو ثانیه میرسد.
تقریباً تمام مدلهای مدرن تولید تصویر — مانند SDXL، SD3، FLUX، HunyuanDiT و Wan-Video — مدلهای دیفیوژن نهان هستند که تفاوتشان صرفاً در معماری اتوانکودر، بخش نویززدا (U-Net یا DiT) و شیوهی شرطیسازی روی متن است. استیبل دیفیوژن را که یاد بگیرید، الگوی پایهی همهی آنها را یاد گرفتهاید.
مبانی نظری
پایپلاین
- VAE — اتوانکودر فریزشده. انکودر تصویر را به متغیرهای نهان تبدیل میکند (مورد استفاده در img2img و آموزش). دیکودر این متغیرهای نهان را دوباره به تصویر تبدیل میکند.
- انکودر متن — انکودر متنیِ CLIP (در SD 1.x/2.x)، ترکیب CLIP-L + CLIP-G (در SDXL)، یا T5-XXL (در SD3/FLUX). خروجی آن توالیای از امبدینگهای توکن است.
- U-Net — بخش نویززدا. لایههای کراساتنشن دارد که در هر سطح رزولوشن، از متغیرهای نهان به امبدینگ متن اتنشن میزنند.
- اسکژولر — الگوریتم نمونهگیری (مانند DDIM، Euler، DPM-Solver++). مقادیر سیگما را تعیین میکند و نویز پیشبینیشده را دوباره با متغیر نهان درمیآمیزد.
- فیلتر ایمنی — فیلتر اختیاری برای حذف محتوای غیراخلاقی (NSFW) یا غیرقانونی از تصویر خروجی.
هدایت بدون طبقهبند (CFG)
در شرطیسازی متنیِ ساده، مدل مقدار epsilon_theta(x_t, t, c) را برای هر پرامپت c یاد میگیرد. در CFG، همان شبکه طوری آموزش میبیند که در 10 درصد مواقع c نادیده گرفته شود (با یک امبدینگ خالی جایگزین شود)؛ در نتیجه یک مدل واحد داریم که هم نویز شرطی و هم نویز بدون شرط را پیشبینی میکند. در زمان استنتاج:
در اینجا w مقیاس هدایت (guidance scale) است. با w=0 فرایند کاملاً بدون شرط است، با w=1 شرطیسازی ساده اعمال میشود، و مقادیر w>1 خروجی را با هزینهی کاهش تنوع، به سمتی میبرد که «بیشتر منطبق بر پرامپت» باشد. مقدار پیشفرض در SD برابر w=7.5 است.
دلیل اصلی اینکه مدلهای تبدیل متن به تصویر با کیفیت مناسب محیط پروداکشن کار میکنند همین CFG است. بدون آن، پرامپتها تأثیر ضعیفی روی خروجی دارند؛ اما با وجود آن، تسلط کامل با پرامپت است.
هندسهی فضای نهان
فضای نهان 4کانالهی VAE فقط یک تصویر فشردهشده نیست؛ بلکه خمینهای (manifold) است که محاسبات جبری در آن تقریب مناسبی از ویرایشهای معنایی است (مهندسی پرامپت و درونیابی هر دو در این فضا اتفاق میافتند) و U-Net دیفیوژن آموزش دیده تا تمام ظرفیت مدلسازی خود را صرف همین فضا کند. اگر یک متغیر نهان 4x64x64 تصادفی را دیکود کنید، تصویری با ظاهر تصادفی تحویل نمیگیرید؛ بلکه خروجی کاملاً بیمعنی و خراب خواهد بود، چون فقط زیرخمینهی خاصی از این متغیرهای نهان به تصاویر معتبر دیکود میشود.
این ساختار دو پیامد مهم دارد:
- Img2img = تصویر به متغیر نهان انکود میشود، مقداری نویز به آن اضافه میگردد، نویززدا اجرا میشود و خروجی دیکود میگردد. ساختار تصویر حفظ میشود چون انکود کردن تقریباً برگشتپذیر است؛ محتوا بر اساس پرامپت تغییر میکند.
- Inpainting = فرایندی مشابه img2img دارد، با این تفاوت که نویززدا فقط بخشهای ماسکشده را بهروزرسانی میکند؛ بخشهای ماسکنشده روی همان مقدار نهان انکودشده ثابت میمانند.
معماری U-Net
مدل U-Net در استیبل دیفیوژن نسخهی بزرگی از TinyUNet درس 10 است که سه بخش جدید به آن اضافه شده است:
- بلاکهای ترنسفورمر در تمام رزولوشنهای فضایی، شامل خوداتنشن (self-attention) + کراساتنشن روی امبدینگ متن.
- امبدینگ زمان از طریق یک MLP روی کدگذاری سینوسی.
- اتصالات میانبُر (Skip connections) میان انکودر و دیکودر در رزولوشنهای متناظر.
تعداد کل پارامترها در SD 1.5 حدود 860 میلیون، در SDXL حدود 2.6 میلیارد و در FLUX حدود 12 میلیارد است. این جهش در تعداد پارامترها عمدتاً مربوط به لایههای اتنشن است.
فاینتیونینگ با LoRA
فاینتیونینگ کامل استیبل دیفیوژن به بیش از 20 گیگابایت حافظهی گرافیکی (VRAM) نیاز دارد و تمام 860 میلیون پارامتر را بهروزرسانی میکند. روش LoRA (انطباق کمرتبه یا Low-Rank Adaptation) مدل پایه را فریز نگه میدارد و ماتریسهای کوچک تجزیهی رتبه (rank-decomposition) را به لایههای اتنشن تزریق میکند. یک آداپتور LoRA برای استیبل دیفیوژن معمولاً بین 10 تا 50 مگابایت حجم دارد، در مدت 10 تا 60 دقیقه روی یک GPU کاربری آموزش میبیند و در زمان استنتاج بهصورت یک ماژول جایگزین (drop-in) لود میشود.
Original: W_q : (d_in, d_out) frozen
LoRA: W_q + alpha * (A @ B) where A : (d_in, r), B : (r, d_out)
r is typically 4-32.
تقریباً تمام مدلهای فاینتیونشدهی جامعهی کاربری با LoRA توزیع میشوند؛ وبسایتهای CivitAI و Hugging Face میزبان میلیونها نسخه از آنها هستند.
اسکژولرهایی که با آنها روبهرو میشوید
- DDIM — قطعی، حدود 50 گام، ساده.
- Euler ancestral — تصادفی (stochastic)، بین 30 تا 50 گام، نمونههای کمی خلاقانهتر.
- DPM-Solver++ 2M Karras — قطعی، بین 20 تا 30 گام، گزینهی پیشفرض محیط پروداکشن.
- LCM / TCD / Turbo — مدلهای سازگاری (consistency models) و نسخههای تقطیرشده؛ بین 1 تا 4 گام به قیمت مقداری افت کیفیت.
تعویض اسکژولر در کتابخانهی diffusers با یک خط کد انجام میشود و گاهی اوقات بدون نیاز به هیچ آموزش دوبارهای، مشکلات نمونهگیری را حل میکند.
پیادهسازی گامبهگام
در این درس بهجای پیادهسازی صفر تا صد استیبل دیفیوژن، بهصورت سرتاسری از diffusers استفاده میکنیم. بخشهایی که برای ساخت مجدد نیاز دارید (VAE، انکودر متن، U-Net و اسکژولر) هر کدام موضوع درسهای مستقلی هستند؛ هدف در اینجا تسلط بر API محیط پروداکشن است.
مرحلهی 1: تبدیل متن به تصویر
import torch
from diffusers import StableDiffusionPipeline
pipe = StableDiffusionPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
torch_dtype=torch.float16,
).to("cuda")
image = pipe(
prompt="a dog riding a skateboard in tokyo, studio ghibli style",
guidance_scale=7.5,
num_inference_steps=25,
generator=torch.Generator("cuda").manual_seed(42),
).images[0]
image.save("dog.png")
استفاده از float16 مصرف حافظهی گرافیکی را بدون افت کیفیتِ محسوس نصف میکند. اجرای num_inference_steps=25 با اسکژولر پیشفرض DPM-Solver++ کیفیتی معادل num_inference_steps=50 با DDIM ارائه میدهد.
مرحلهی 2: تعویض اسکژولر
from diffusers import DPMSolverMultistepScheduler, EulerAncestralDiscreteScheduler
pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config)
وضعیت اسکژولر از وزنهای U-Net کاملاً مستقل است. میتوانید آموزش را با DDPM انجام دهید و نمونهگیری را با هر اسکژولر دلخواهی پیش ببرید.
مرحلهی 3: تبدیل تصویر به تصویر (Img2img)
from diffusers import StableDiffusionImg2ImgPipeline
from PIL import Image
img2img = StableDiffusionImg2ImgPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
torch_dtype=torch.float16,
).to("cuda")
init_image = Image.open("dog.png").convert("RGB").resize((512, 512))
out = img2img(
prompt="a dog riding a skateboard, oil painting",
image=init_image,
strength=0.6,
guidance_scale=7.5,
).images[0]
پارامتر strength مشخص میکند قبل از نویززدایی چقدر نویز به تصویر اضافه شود (0.0 یعنی بدون تغییر، 1.0 یعنی بازتولید کامل). بازهی 0.5 تا 0.7 محدودهی استاندارد برای انتقال سبک (style transfer) است.
مرحلهی 4: اینپینتینگ
from diffusers import StableDiffusionInpaintPipeline
inpaint = StableDiffusionInpaintPipeline.from_pretrained(
"runwayml/stable-diffusion-inpainting",
torch_dtype=torch.float16,
).to("cuda")
image = Image.open("dog.png").convert("RGB").resize((512, 512))
mask = Image.open("dog_mask.png").convert("L").resize((512, 512))
out = inpaint(
prompt="a cat",
image=image,
mask_image=mask,
guidance_scale=7.5,
).images[0]
پیکسلهای سفید در ماسک بخشهایی هستند که باید از نو تولید شوند. پیکسلهای سیاه دستنخورده باقی میمانند.
مرحلهی 5: لود کردن LoRA
pipe.load_lora_weights(
"artificialguybr/studioghibli-redmond-1-5v-studio-ghibli-lora-for-liberteredmond-sd-1-5",
weight_name="StudioGhibliRedmond-15V-LiberteRedmond-StdGBRedmAF-StudioGhibli.safetensors",
)
pipe.fuse_lora(lora_scale=0.8)
image = pipe(prompt="a village square, StdGBRedmAF, Studio Ghibli").images[0]
عبارت راهانداز (trigger phrase) که در شناسنامهی مدل (model card) آمده است (StdGBRedmAF, Studio Ghibli) سبک موردنظر را فعال میکند. پارامتر lora_scale شدت اثر را کنترل میکند؛ مقدار 0.0 بیاثر است و 1.0 نهایت اثرگذاری را دارد. متد fuse_lora برای سرعت بیشتر، آداپتور را مستقیماً در وزنهای مدل ادغام میکند اما امکان تعویض آن را میگیرد. برای لود کردن یک آداپتور دیگر، ابتدا pipe.unfuse_lora() را فراخوانی کنید.
مرحلهی 6: آموزش LoRA (طرح کلی)
فرایند واقعی آموزش LoRA با کتابخانههای peft یا diffusers.training انجام میشود. طرح کلی کار به این صورت است:
# Pseudocode
for step, batch in enumerate(dataloader):
images, prompts = batch
latents = vae.encode(images).latent_dist.sample() * 0.18215
t = torch.randint(0, num_train_timesteps, (batch_size,))
noise = torch.randn_like(latents)
noisy_latents = scheduler.add_noise(latents, noise, t)
text_emb = text_encoder(tokenizer(prompts))
pred_noise = unet(noisy_latents, t, text_emb) # LoRA weights injected here
loss = F.mse_loss(pred_noise, noise)
loss.backward()
optimizer.step()
تنها ماتریسهای LoRA گرادیان دریافت میکنند؛ مدل پایهی U-Net، VAE و انکودر متن همگی فریز هستند. با اندازهی دستهی (batch size) برابر با 1 و استفاده از چکپوینتگذاری گرادیان (gradient checkpointing)، این فرایند در 8 گیگابایت حافظهی گرافیکی جا میشود.
کاربرد در محیط واقعی
تصمیمهایی که در محیط پروداکشن واقعاً با آنها روبهرو میشوید:
- خانوادهی مدل: نسخهی SD 1.5 برای فاینتیونهای جامعهی متنباز، SDXL برای جزئیات و وضوح بالاتر، و SD3 / FLUX برای جدیدترین کیفیت روز و شرایطی که نیازمند لایسنسهای سختگیرانه است.
- اسکژولر: مدل DPM-Solver++ 2M Karras برای 20 تا 30 گام؛ و LCM-LoRA زمانی که محدودیت تأخیر زیر 1 ثانیه دارید.
- دقت (Precision): فرمت
float16روی کارتهای 4080/4090، فرمتbfloat16روی A100 و مدلهای جدیدتر، وint8(باbitsandbytes) زمانی که حافظهی گرافیکی محدود است. - شرطیسازی: متن ساده خوب جواب میدهد؛ اما برای کنترل دقیقتر، آداپتورهای ControlNet (تشخیص لبهی canny، عمق، فیگور بدن) را روی پایپلاین پایه اضافه کنید.
برای تولید دستهای تصویر، ابزارهای AUTO1111 و ComfyUI گزینههای جامعهی کاربری هستند؛ برای APIهای محیط پروداکشن، ترکیب diffusers با accelerate یا استفاده از optimum-nvidia همراه با کامپایل TensorRT به کار میرود.
تحویل پروژه
خروجیهای حاصل از این درس:
outputs/prompt-sd-pipeline-planner.md— پرامپتی که با توجه به بودجهی تأخیر زمانی، هدف کیفیت و محدودیتهای مجوزی، مدل مناسب (SD 1.5 / SDXL / SD3 / FLUX) را همراه با اسکژولر و دقت تعیین میکند.outputs/skill-lora-training-setup.md— مهارتی که فایل کامل کانفیگ آموزش LoRA را برای یک دیتاست سفارشی شامل کپشنها، رتبه، اندازهی دسته و نرخ یادگیری مینویسد.
تمرینها
- (ساده) یک پرامپت ثابت را با مقادیر مختلف
guidance_scaleدر مجموعهی[1, 3, 5, 7.5, 10, 15]اجرا کنید. تغییرات تصویر را شرح دهید. در چه مقداری از مقیاس هدایت، آرتیفکتها و ناهنجاریهای تصویری ظاهر میشوند؟ - (متوسط) یک عکس واقعی انتخاب کنید و آن را با پایپلاین
StableDiffusionImg2ImgPipelineبا مقادیرstrengthدر مجموعهی[0.2, 0.4, 0.6, 0.8, 1.0]پردازش کنید. کدام مقدار ترکیببندی تصویر را حفظ میکند و همزمان سبک آن را تغییر میدهد؟ چرا مقدار 1.0 ورودی را کاملاً نادیده میگیرد؟ - (سخت) یک آداپتور LoRA روی 10 تا 20 تصویر از یک سوژهی مشخص (حیوان خانگی، لوگو، یک شخصیت) آموزش دهید و صحنههای جدیدی با حضور آن سوژه بسازید. رتبهی LoRA و تعداد گامهای آموزشی را که توانستهاند بدون بیشبرازش روی تصاویر ورودی، ویژگیهای ظاهری سوژه را به بهترین شکل حفظ کنند، گزارش کنید.
اصطلاحات کلیدی
| اصطلاح | در گفتوگوها | معنای فنی و دقیق |
|---|---|---|
| دیفیوژن نهان (Latent diffusion) | «دیفیوژن در متغیرهای نهان» | اجرای کامل DDPM در فضای نهانِ VAE با ابعاد 4x64x64 بهجای فضای پیکسل 3x512x512؛ صرفهجویی 48 برابری در محاسبات |
| فاکتور مقیاس VAE (VAE scale factor) | «0.18215» | ضریب ثابتی که واریانس متغیرهای نهان خام VAE را تقریباً برابر با یک مقیاسبندی میکند؛ در تمام پایپلاینهای SD بهصورت هاردکد وجود دارد |
| هدایت بدون طبقهبند (CFG) | «CFG» | ترکیب پیشبینی نویز در حالت شرطی و بدون شرط؛ تأثیرگذارترین پیچ تنظیم در زمان استنتاج |
| اسکژولر (Scheduler) | «سمپلر» | الگوریتمی که نویز اولیه و پیشبینیهای مدل را به مسیری نویززداییشده از متغیر نهان تبدیل میکند |
| لورا (LoRA) | «آداپتور کمرتبه» | ماتریسهای کوچک تجزیهی رتبه که لایههای اتنشن را بدون دستکاری وزنهای پایهی مدل فاینتیون میکنند |
| کراساتنشن (Cross-attention) | «اتنشن متن به تصویر» | اتنشن از توکنهای نهان تصویر به توکنهای متن؛ تزریق اطلاعات پرامپت در تمام لایههای U-Net |
| کنترلنت (ControlNet) | «شرطیسازی ساختاری» | آداپتوری مستقل که استیبل دیفیوژن را با یک ورودی کمکی دیگر (لبههای canny، عمق، فیگور بدن، بخشبندی) هدایت میکند |
| DPM-Solver++ | «اسکژولر پیشفرض» | حلکنندهی قطعیِ ODE از مرتبهی دو؛ ارائهدهندهی بالاترین کیفیت در تعداد گامهای کم (20 تا 30) در سال 2026 |
برای مطالعهی بیشتر
- High-Resolution Image Synthesis with Latent Diffusion (Rombach et al., 2022) — مقالهی اصلی استیبل دیفیوژن؛ شامل تمام آزمایشهای تفکیکی (ablation) که انتخابهای این معماری را توجیه میکنند
- Classifier-Free Diffusion Guidance (Ho & Salimans, 2022) — مقالهی معرفی ایدهی CFG
- LoRA: Low-Rank Adaptation of Large Language Models (Hu et al., 2021) — روش LoRA ابتدا برای پردازش زبان طبیعی مطرح شد و بعداً تقریباً بدون تغییر وارد استیبل دیفیوژن شد
- diffusers documentation — مستندات مرجع برای تمام پایپلاینهای SD، SDXL، SD3 و FLUX
