Buckets:

hf-doc-build/doc / diffusers /main /tr /using-diffusers /write_own_pipeline.md
mishig's picture
|
download
raw
15.1 kB
# Hattaların, modellerin ve zamanlayıcıların anlaşılması
🧨 Diffusers, kullanım senaryonuza özel difüzyon sistemleri oluşturmak için kullanıcı dostu ve esnek bir araç kutusu olarak tasarlanmıştır. Araç kutusunun çekirdeğinde modeller ve zamanlayıcılar (schedulers) bulunur. [DiffusionPipeline](/docs/diffusers/main/tr/api/pipelines/overview#diffusers.DiffusionPipeline) bu bileşenleri kolaylık için bir arada paketlerken, pipeline'ı parçalayıp modelleri ve zamanlayıcıları ayrı ayrı kullanarak yeni difüzyon sistemleri oluşturabilirsiniz.
Bu eğitimde, temel bir pipeline ile başlayıp ardından Stable Diffusion pipeline'ına geçerek, çıkarım için bir difüzyon sistemi oluşturmak üzere modelleri ve zamanlayıcıları (scheduler) nasıl kullanacağınızı öğreneceksiniz.
## Temel bir hattı parçalarına ayırma
Bir pipeline, çıkarım için bir modeli çalıştırmak için hızlı ve kolay bir yoldur; bir görüntü oluşturmak için dört satırdan fazla kod gerektirmez:
```py
>>> from diffusers import DDPMPipeline
>>> ddpm = DDPMPipeline.from_pretrained("google/ddpm-cat-256", use_safetensors=True).to("cuda") # or "mps", "xpu", "cpu"
>>> image = ddpm(num_inference_steps=25).images[0]
>>> image
```
Bu çok kolaydı, ama pipeline bunu nasıl yaptı? Pipeline'ı parçalara ayıralım ve perdenin arkasında neler olduğunu inceleyelim.
Yukarıdaki örnekte, pipeline bir [UNet2DModel](/docs/diffusers/main/tr/api/models/unet2d#diffusers.UNet2DModel) modeli ve bir [DDPMScheduler](/docs/diffusers/main/tr/api/schedulers/ddpm#diffusers.DDPMScheduler) içerir. Pipeline, istenen çıktı boyutunda rastgele gürültü alarak ve bunu modeli birkaç kez kullanarak bir görüntünün gürültüsünü azaltır. Her zaman adımında, model *noise residual* değerini tahmin eder ve scheduler bunu daha az gürültülü bir görüntüyü tahmin etmek için kullanır. Pipeline, belirtilen çıkarım adım sayısının sonuna ulaşana kadar bu süreci tekrarlar.
Model ve zamanlayıcıyı ayrı ayrı kullanarak hattı yeniden oluşturmak için kendi gürültü azaltma sürecimizi yazalım.
1. Modeli ve zamanlayıcıyı yükleyin:
```py
>>> from diffusers import DDPMScheduler, UNet2DModel
>>> scheduler = DDPMScheduler.from_pretrained("google/ddpm-cat-256")
>>> model = UNet2DModel.from_pretrained("google/ddpm-cat-256", use_safetensors=True).to("cuda") # or "mps", "xpu", "cpu"
```
2. Gürültü azaltma sürecinin çalıştırılacağı zaman adımı sayısını ayarlayın:
```py
>>> scheduler.set_timesteps(50)
```
3. Zamanlayıcı adımlarını ayarlamak, bu örnekte 50 olan eşit aralıklı elemanlardan oluşan bir tensör oluşturur. Her eleman, modelin bir görüntüyü gürültüden arındırdığı bir zaman adımına karşılık gelir. Daha sonra gürültüden arındırma döngüsünü oluşturduğunuzda, bir görüntüyü gürültüden arındırmak için bu tensör üzerinde yineleme yapacaksınız:
```py
>>> scheduler.timesteps
tensor([980, 960, 940, 920, 900, 880, 860, 840, 820, 800, 780, 760, 740, 720,
700, 680, 660, 640, 620, 600, 580, 560, 540, 520, 500, 480, 460, 440,
420, 400, 380, 360, 340, 320, 300, 280, 260, 240, 220, 200, 180, 160,
140, 120, 100, 80, 60, 40, 20, 0])
```
4. İstenen çıktıyla aynı şekle sahip rastgele bir gürültü oluşturun:
```py
>>> import torch
>>> sample_size = model.config.sample_size
>>> noise = torch.randn((1, 3, sample_size, sample_size), device="cuda") # or "mps", "xpu", "cpu"
```
5. Şimdi timestep'ler üzerinde dönmek için bir döngü yazın. Her timestep'te model bir [UNet2DModel.forward()](/docs/diffusers/main/tr/api/models/unet2d#diffusers.UNet2DModel.forward) geçişi yapar ve gürültülü kalanı döndürür. Zamanlayıcının [step()](/docs/diffusers/main/tr/api/schedulers/ddpm#diffusers.DDPMScheduler.step) metodu, gürültülü kalanı, timestep'i ve girdiyi alır ve bir önceki timestep'teki görüntüyü tahmin eder. Bu çıktı, gürültü azaltma döngüsünde modele giden bir sonraki girdi olur ve `timesteps` dizisinin sonuna ulaşılana kadar tekrarlanır.
```py
>>> input = noise
>>> for t in scheduler.timesteps:
... with torch.no_grad():
... noisy_residual = model(input, t).sample
... previous_noisy_sample = scheduler.step(noisy_residual, t, input).prev_sample
... input = previous_noisy_sample
```
Bu, tüm gürültü azaltma sürecidir ve herhangi bir difüzyon sistemini yazmak için bu aynı kalıbı kullanabilirsiniz.
6. Son adım, gürültüsü azaltılmış çıktıyı bir görüntüye dönüştürmektir:
```py
>>> from PIL import Image
>>> import numpy as np
>>> image = (input / 2 + 0.5).clamp(0, 1).squeeze()
>>> image = (image.permute(1, 2, 0) * 255).round().to(torch.uint8).cpu().numpy()
>>> image = Image.fromarray(image)
>>> image
```
Bir sonraki bölümde, becerilerinizi test edeceksiniz ve daha karmaşık Stable Diffusion hattını parçalara ayırarak inceleyeceksiniz. Adımlar daha az ya da daha çok aynı. Gerekli bileşenleri başlatacak ve bir `timestep` dizisi oluşturmak için zaman adımı sayısını ayarlayacaksınız. `timestep` dizisi gürültü azaltma döngüsünde kullanılır ve bu dizideki her bir öğe için model daha az gürültülü bir görüntü tahmin eder. Gürültü azaltma döngüsü `timestep`'ler üzerinde iterasyon yapar ve her zaman adımında gürültülü bir artık (residual) üretir; zamanlayıcı (scheduler) bunu, bir önceki zaman adımında daha az gürültülü bir görüntü tahmin etmek için kullanır. Bu işlem, `timestep` dizisinin sonuna ulaşana kadar tekrarlanır.
Hadi deneyelim!
## Stable Diffusion hattını parçalarına ayırın
Stable Diffusion, metinden görüntüye *latent difüzyon* modelidir. Gerçek piksel uzayı yerine görüntünün daha düşük boyutlu bir temsilini kullandığı için latent difüzyon modeli olarak adlandırılır; bu da onu daha bellek verimli kılar. Kodlayıcı (encoder), görüntüyü daha küçük bir temsile sıkıştırır ve çözücü (decoder), sıkıştırılmış temsili tekrar bir görüntüye dönüştürür. Metinden görüntüye modeller için metin gömümleri (embeddings) üretmek üzere bir belirteç ayrıştırıcı (tokenizer) ve bir kodlayıcıya (encoder) ihtiyacınız olacaktır. Önceki örnekten, bir UNet modeline ve bir zamanlayıcıya (scheduler) ihtiyacınız olduğunu zaten biliyorsunuz.
Gördüğünüz gibi bu, yalnızca bir UNet modeli içeren DDPM hattından zaten daha karmaşık. Stable Diffusion modeli üç ayrı önceden eğitilmiş modele sahiptir.
> [!TIP]
> 💡 VAE, UNet ve metin kodlayıcı modellerin nasıl çalıştığına dair daha fazla ayrıntı için [Stable Diffusion nasıl çalışır?](https://huggingface.co/blog/stable_diffusion#how-does-stable-diffusion-work) blogunu okuyun.
Stable Diffusion hattı için nelerin gerektiğini bildiğinize göre, bu bileşenlerin tümünü [from_pretrained()](/docs/diffusers/main/tr/api/models/overview#diffusers.ModelMixin.from_pretrained) yöntemiyle yükleyin. Bunları önceden eğitilmiş [`stable-diffusion-v1-5/stable-diffusion-v1-5`](https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5) kontrol noktasında bulabilirsiniz ve her bileşen ayrı bir alt klasörde saklanır:
```py
>>> from PIL import Image
>>> import torch
>>> from transformers import CLIPTextModel, CLIPTokenizer
>>> from diffusers import AutoencoderKL, UNet2DConditionModel, PNDMScheduler
>>> vae = AutoencoderKL.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="vae", use_safetensors=True)
>>> tokenizer = CLIPTokenizer.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="tokenizer")
>>> text_encoder = CLIPTextModel.from_pretrained(
... "CompVis/stable-diffusion-v1-4", subfolder="text_encoder", use_safetensors=True
... )
>>> unet = UNet2DConditionModel.from_pretrained(
... "CompVis/stable-diffusion-v1-4", subfolder="unet", use_safetensors=True
... )
```
Varsayılan [PNDMScheduler](/docs/diffusers/main/tr/api/schedulers/pndm#diffusers.PNDMScheduler) yerine, farklı bir zamanlayıcının ne kadar kolay entegre edilebildiğini görmek için [UniPCMultistepScheduler](/docs/diffusers/main/tr/api/schedulers/unipc#diffusers.UniPCMultistepScheduler) ile değiştirin:
```py
>>> from diffusers import UniPCMultistepScheduler
>>> scheduler = UniPCMultistepScheduler.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="scheduler")
```
Çıkarımı hızlandırmak için, zamanlayıcının aksine eğitilebilir ağırlıklara sahip olduklarından modelleri bir GPU'ya taşıyın:
```py
>>> torch_device = "cuda" # or "mps", "xpu", "cpu"
>>> vae.to(torch_device)
>>> text_encoder.to(torch_device)
>>> unet.to(torch_device)
```
### Metin gömlemleri oluşturun
Bir sonraki adım, gömme (embedding) üretmek için metni belirteçlere (token) dönüştürmektir. Metin, UNet modelini koşullandırmak ve difüzyon sürecini girdi istemine benzeyen bir sonuca yönlendirmek için kullanılır.
> [!TIP]
> 💡 `guidance_scale` parametresi, bir görüntü oluşturulurken istem (prompt) ne kadar ağırlık taşımalı sorusunu belirler.
Başka bir şey üretmek isterseniz, dilediğiniz istemci seçmekte serbestsiniz!
```py
>>> prompt = ["a photograph of an astronaut riding a horse"]
>>> height = 512 # default height of Stable Diffusion
>>> width = 512 # default width of Stable Diffusion
>>> num_inference_steps = 25 # Number of denoising steps
>>> guidance_scale = 7.5 # Scale for classifier-free guidance
>>> generator = torch.manual_seed(0) # Seed generator to create the initial latent noise
>>> batch_size = len(prompt)
```
Metni belirteçlere ayırın ve istemden gömme değerlerini oluşturun:
```py
>>> text_input = tokenizer(
... prompt, padding="max_length", max_length=tokenizer.model_max_length, truncation=True, return_tensors="pt"
... )
>>> with torch.no_grad():
... text_embeddings = text_encoder(text_input.input_ids.to(torch_device))[0]
```
Ayrıca, dolgu (padding) jetonuna ait gömme değerleri olan *koşulsuz metin gömme değerlerini* de üretmeniz gerekecektir. Bunların, koşullu `text_embeddings` ile aynı şekle (`batch_size` ve `seq_length`) sahip olması gerekir:
```py
>>> max_length = text_input.input_ids.shape[-1]
>>> uncond_input = tokenizer([""] * batch_size, padding="max_length", max_length=max_length, return_tensors="pt")
>>> uncond_embeddings = text_encoder(uncond_input.input_ids.to(torch_device))[0]
```
İki ileri geçiş yapmaktan kaçınmak için koşullu ve koşulsuz gömme vektörlerini bir partiye birleştirelim:
```py
>>> text_embeddings = torch.cat([uncond_embeddings, text_embeddings])
```
### Rastgele gürültü oluşturun
Ardından, difüzyon süreci için bir başlangıç noktası olarak bazı başlangıç rastgele gürültüsü üretin. Bu, görüntünün gizli (latent) temsili olup kademeli olarak gürültüsü azaltılacaktır. Bu aşamada `latent` görüntü, nihai görüntü boyutundan küçüktür ancak bu sorun değildir çünkü model, bunu daha sonra nihai 512x512 görüntü boyutlarına dönüştürecektir.
> [!TIP]
> 💡 Yükseklik ve genişlik, `vae` modelinin 3 alt örnekleme katmanına sahip olması nedeniyle 8'e bölünür. Bunu aşağıdakini çalıştırarak kontrol edebilirsiniz:
>
> ```py
> 2 ** (len(vae.config.block_out_channels) - 1) == 8
> ```
```py
>>> latents = torch.randn(
... (batch_size, unet.config.in_channels, height // 8, width // 8),
... generator=generator,
... device=torch_device,
... )
```
### Görüntüyü gürültüden arındırın
Girişi, [UniPCMultistepScheduler](/docs/diffusers/main/tr/api/schedulers/unipc#diffusers.UniPCMultistepScheduler) gibi gelişmiş zamanlayıcılar için gerekli olan gürültü ölçeği değeri olan başlangıç gürültü dağılımı *sigma* ile ölçekleyerek başlayın:
```py
>>> latents = latents * scheduler.init_noise_sigma
```
Son adım, `latents` içindeki saf gürültüyü, promptunuzla tanımlanan bir görüntüye kademeli olarak dönüştürecek gürültü azaltma döngüsünü oluşturmaktır. Unutmayın, gürültü azaltma döngüsünün yapması gereken üç şey var:
1. Gürültü azaltma sırasında kullanılacak zaman adımlarını zamanlayıcıda ayarlayın.
2. Adımlar üzerinde yinele.
3. Her zaman adımında, gürültü artığını tahmin etmek için UNet modelini çağırın ve önceki gürültülü örneği hesaplamak için zamanlayıcıya (scheduler) iletin.
```py
>>> from tqdm.auto import tqdm
>>> scheduler.set_timesteps(num_inference_steps)
>>> for t in tqdm(scheduler.timesteps):
... # expand the latents if we are doing classifier-free guidance to avoid doing two forward passes.
... latent_model_input = torch.cat([latents] * 2)
... latent_model_input = scheduler.scale_model_input(latent_model_input, timestep=t)
... # predict the noise residual
... with torch.no_grad():
... noise_pred = unet(latent_model_input, t, encoder_hidden_states=text_embeddings).sample
... # perform guidance
... noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
... noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)
... # compute the previous noisy sample x_t -> x_t-1
... latents = scheduler.step(noise_pred, t, latents).prev_sample
```
### Görseli çözümlen
Son adım, `vae` kullanarak gizil temsilini bir görüntüye çözmek ve `sample` ile çözülmüş çıktıyı almaktır:
```py
# scale and decode the image latents with vae
latents = 1 / 0.18215 * latents
with torch.no_grad():
image = vae.decode(latents).sample
```
Son olarak, oluşturduğunuz görüntüyü görmek için görüntüyü `PIL.Image` biçimine dönüştürün!
```py
>>> image = (image / 2 + 0.5).clamp(0, 1).squeeze()
>>> image = (image.permute(1, 2, 0) * 255).to(torch.uint8).cpu().numpy()
>>> image = Image.fromarray(image)
>>> image
```
## Sonraki adımlar
Temelden karmaşığa uzanan boru hatlarında, kendi difüzyon sisteminizi yazmak için asıl ihtiyacınızın bir gürültü azaltma döngüsü olduğunu gördünüz. Döngü, zamanlayıcının zaman adımlarını ayarlamalı, bunlar üzerinde yinelemeli ve UNet modelini çağırarak gürültü artığını tahmin etmek ile zamanlayıcıya geçirerek önceki gürültülü örneği hesaplamak arasında dönüşümlü olarak işlem yapmalıdır.
Bu, 🧨 Diffusers'ın tasarlanış amacının ta kendisidir: modeller ve zamanlayıcılar kullanarak kendi difüzyon sisteminizi yazmanızı sezgisel ve kolay hale getirmek.
Sonraki adımlarınız için istediğiniz zaman:
* 🧨 Diffusers'a [bir pipeline oluşturmayı ve katkıda bulunmayı](../conceptual/contribution) nasıl yapacağınızı öğrenin. Neler yapacağınızı görmek için sabırsızlanıyoruz!
* Kütüphanedeki [mevcut pipeline'ları](../api/pipelines/overview) inceleyin ve modelleri ile zamanlayıcıları ayrı ayrı kullanarak bir pipeline'ı sıfırdan inşa edip edemeyeğinizi görün.

Xet Storage Details

Size:
15.1 kB
·
Xet hash:
c60e170bfe2e99ee336e2f564b9fd8172c23ccdf242219fa578c2097591f97d8

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.