# LoRA

[LoRA (Low-Rank Adaptation)](https://huggingface.co/papers/2106.09685)는 원래 가중치를 고정하고 소수의 새로운 파라미터만 학습하여 사전 학습된 모델을 새로운 작업에 맞게 조정합니다. 적응 과정이 전체 미세 조정보다 빠르고 비용이 적게 들기 때문에, 새로운 스타일로 이미지를 생성하는 작업에 실용적으로 적용할 수 있습니다.

LoRA 체크포인트는 일반적으로 몇백 MB에 불과합니다. `pipeline.load_lora_weights`로 로드하고 `weight_name`을 체크포인트 파일 이름으로 설정하세요. 공유된 매개변수는 [load_lora_weights()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.StableDiffusionLoraLoaderMixin.load_lora_weights)를 참조하세요.

```py
import torch
from diffusers import AutoPipelineForText2Image

pipeline = AutoPipelineForText2Image.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_lora_weights(
    "ostris/super-cereal-sdxl-lora",
    weight_name="cereal_box_sdxl_v1.safetensors",
    adapter_name="cereal"
)
pipeline("bears, pizza bites").images[0]
```

```py
import torch
from diffusers import LTXConditionPipeline
from diffusers.utils import export_to_video, load_image

pipeline = LTXConditionPipeline.from_pretrained(
    "Lightricks/LTX-Video-0.9.5", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

pipeline.load_lora_weights(
    "Lightricks/LTX-Video-Cakeify-LoRA",
    weight_name="ltxv_095_cakeify_lora.safetensors",
    adapter_name="cakeify"
)
pipeline.set_adapters("cakeify")

# use "CAKEIFY" to trigger the LoRA
prompt = "CAKEIFY a person using a knife to cut a cake shaped like a Pikachu plushie"
image = load_image("https://huggingface.co/Lightricks/LTX-Video-Cakeify-LoRA/resolve/main/assets/images/pikachu.png")

video = pipeline(
    prompt=prompt,
    image=image,
    width=576,
    height=576,
    num_frames=161,
    decode_timestep=0.03,
    decode_noise_scale=0.025,
    num_inference_steps=50,
).frames[0]
export_to_video(video, "output.mp4", fps=26)
```

이 페이지의 pipeline LoRA API는 모델 패밀리 전체에서 동일하게 작동합니다. 노이즈 제거 모듈은 [Stable Diffusion](../api/pipelines/stable_diffusion/overview)과 [SDXL](../api/pipelines/stable_diffusion/stable_diffusion_xl)에서는 `pipeline.unet`이고, [Flux](../api/pipelines/flux), [Stable Diffusion 3](../api/pipelines/stable_diffusion/stable_diffusion_3), [AuraFlow](../api/pipelines/aura_flow), [LTX](../api/pipelines/ltx_video)와 같은 DiT 스타일 모델에서는 `pipeline.transformer`입니다. [CogVideoX](../api/pipelines/cogvideox), [HunyuanVideo](../api/pipelines/hunyuan_video), [Wan](../api/pipelines/wan)과 같은 비디오 모델에도 동일한 패턴이 적용됩니다. 모델 수준의 PEFT 메서드는 해당 속성과 일치하는 `prefix`(`"unet"` 또는 `"transformer"`)를 사용합니다.

`pipeline.load_lora_weights`는 denoiser(UNet 또는 transformer)와 text encoders에 LoRA 가중치를 로드하는 권장 방법입니다. 공유된 파라미터에 대해서는 [load_lora_weights()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.StableDiffusionLoraLoaderMixin.load_lora_weights)를 참고하세요. 다음 경우를 처리할 수 있습니다:

- checkpoint은 denoiser와 텍스트 인코더 간에 키를 공유합니다
- checkpoint는 별도의 denoiser 및 text-encoder 키를 사용합니다

[load_lora_adapter()](/docs/diffusers/main/ko/api/loaders/peft#diffusers.loaders.PeftAdapterMixin.load_lora_adapter) 메서드는 UNet이나 transformer처럼 `PeftAdapterMixin`을 서브클래스로 상속하는 모든 Diffusers 모델에서 *모델 수준*으로 LoRA 어댑터를 로드합니다. 이 메서드는 어댑터 구성을 생성하고 준비한 후, 해당 모듈에 가중치를 로드합니다.

대상 모듈(`"unet"` 또는 `"transformer"`)의 state dict 키를 필터링하려면 `prefix`를 사용합니다. 기본값은 `"transformer"`이므로 Stable Diffusion과 SDXL은 `prefix="unet"`를 전달해야 합니다.

```py
import torch
from diffusers import AutoPipelineForText2Image

pipeline = AutoPipelineForText2Image.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.unet.load_lora_adapter(
    "jbilcke-hf/sdxl-cinematic-1",
    weight_name="pytorch_lora_weights.safetensors",
    adapter_name="cinematic",
    prefix="unet"
)
# use cnmt in the prompt to trigger the LoRA
pipeline("A cute cnmt eating a slice of pizza, stunning color scheme, masterpiece, illustration").images[0]
```

```py
import torch
from diffusers import FluxPipeline

pipeline = FluxPipeline.from_pretrained(
    "black-forest-labs/FLUX.1-dev", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.transformer.load_lora_adapter(
    "alvarobartt/ghibli-characters-flux-lora",
    adapter_name="lora",
    prefix="transformer",
)
```

## torch.compile

[torch.compile](../optimization/fp16#torchcompile)는 최적화된 커널을 사용하도록 PyTorch 모델을 컴파일하여 추론 속도를 높입니다. 컴파일하기 전에 LoRA 가중치를 베이스 모델에 병합한 뒤 언로드해야 합니다.

```py
import torch
from diffusers import DiffusionPipeline

# load base model and LoRA
pipeline = DiffusionPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_lora_weights(
    "ostris/ikea-instructions-lora-sdxl",
    weight_name="ikea_instructions_xl_v1_5.safetensors",
    adapter_name="ikea"
)

# activate LoRA and set adapter weight
pipeline.set_adapters("ikea", adapter_weights=0.7)

# fuse LoRAs and unload weights
pipeline.fuse_lora(adapter_names=["ikea"], lora_scale=1.0)
pipeline.unload_lora_weights()
```

일반적으로 파이프라인에서 가장 많은 연산이 필요한 구성 요소인 denoiser를 컴파일합니다.

```py
pipeline.unet.to(memory_format=torch.channels_last)
pipeline.unet = torch.compile(pipeline.unet, mode="reduce-overhead", fullgraph=True)

pipeline("A bowl of ramen shaped like a cute kawaii bear").images[0]
```

Flux 및 기타 DiT 파이프라인의 경우, 대신 `pipeline.transformer`를 컴파일하세요.

```py
pipeline.transformer = torch.compile(pipeline.transformer, mode="reduce-overhead", fullgraph=True)
```

컴파일된 모델과 여러 LoRA를 함께 사용할 때 재컴파일을 피하는 방법은 [hotswapping](#hotswapping) 섹션을 참고하세요.

## 가중치 스케일

[set_adapters()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.set_adapters)의 `adapter_weights` 매개변수를 사용하여 적용할 LoRA의 양을 제어합니다. 가중치가 `0`이면 기본 모델 가중치만 사용하는 것과 동일하며, `1`이면 LoRA를 완전히 사용하는 것과 동일합니다.

`adapter_weights`에 스칼라를 전달하여 [set_adapters()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.set_adapters)에서 LoRA가 적용되는 강도를 제어합니다.

```py
import torch
from diffusers import AutoPipelineForText2Image

pipeline = AutoPipelineForText2Image.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_lora_weights(
    "ostris/super-cereal-sdxl-lora",
    weight_name="cereal_box_sdxl_v1.safetensors",
    adapter_name="cereal"
)
pipeline.set_adapters("cereal", adapter_weights=1.0)
pipeline("bears, pizza bites").images[0]
```

`set_adapters`를 기본 패턴으로 사용하지만, 일부 파이프라인은 호출 시 `cross_attention_kwargs={"scale": 1.0}`을 받아서 어텐션을 스케일링하는 보조 수단으로 사용할 수 있습니다. 크로스 어텐션을 사용하지 않는 파이프라인은 일반적으로 `attention_kwargs`를 대신 노출합니다(또는 Flux와 Stable Diffusion 3의 경우 `joint_attention_kwargs`).

> [!WARNING]
> [set_adapters()](/docs/diffusers/main/ko/api/loaders/peft#diffusers.loaders.PeftAdapterMixin.set_adapters) 메서드는 어텐션 가중치만 스케일링합니다. LoRA에 ResNet 또는 다운/업 샘플러가 포함된 경우, 이러한 구성 요소의 스케일 값은 `1.0`으로 유지됩니다.

각 텍스트 인코더 또는 디노이저 블록을 스케일링하려면 딕셔너리를 전달합니다. 딕셔너리의 키는 파이프라인 모듈을 따릅니다. 아래 예시는 SDXL(`unet` 및 텍스트 인코더)입니다. Flux는 `transformer`와 `text_encoder`를 사용합니다. SD3는 `transformer`와 여러 텍스트 인코더를 사용합니다.

이 SDXL 예시에서 UNet의 `"down"` 블록은 0.9로 스케일링되며, `"up"` 아래에서 `"block_0"`과 `"block_1"`의 어텐션 블록 스케일을 추가로 지정할 수 있습니다. `"mid"`와 같은 블록이 지정되지 않은 경우 기본값 `1.0`이 사용됩니다.

```py
import torch
from diffusers import AutoPipelineForText2Image

pipeline = AutoPipelineForText2Image.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_lora_weights(
    "ostris/super-cereal-sdxl-lora",
    weight_name="cereal_box_sdxl_v1.safetensors",
    adapter_name="cereal"
)
scales = {
    "text_encoder": 0.5,
    "text_encoder_2": 0.5,
    "unet": {
        "down": 0.9,
        "up": {
            "block_0": 0.6,
            "block_1": [0.4, 0.8, 1.0],
        }
    }
}
pipeline.set_adapters("cereal", scales)
pipeline("bears, pizza bites").images[0]
```

### 스케줄링 확장

샘플링 중에 LoRA 스케일을 동적으로 조정하면, 특정 단계에서 스케일을 증가 또는 감소시키는 것이 더 유리할 수 있으므로 전체 구성과 레이아웃에 대한 제어가 더 잘 됩니다.

아래 예시의 [character LoRA](https://huggingface.co/alvarobartt/ghibli-characters-flux-lora)는 캐릭터 생성을 확립하기 위해 처음에는 더 높은 scale로 시작하여 첫 20단계 동안 점진적으로 감소합니다. 이후 단계에서는 LoRA가 학습되지 않은 이미지의 다른 부분에 LoRA 기능이 과도하게 추가되는 것을 방지하기 위해 `0.2`의 scale만 적용됩니다.

```py
import torch
from diffusers import FluxPipeline

pipeline = FluxPipeline.from_pretrained(
    "black-forest-labs/FLUX.1-dev", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

pipeline.load_lora_weights("alvarobartt/ghibli-characters-flux-lora", adapter_name="lora")

num_inference_steps = 30
lora_steps = 20
lora_scales = torch.linspace(1.5, 0.7, lora_steps).tolist()
lora_scales += [0.2] * (num_inference_steps - lora_steps + 1)

pipeline.set_adapters("lora", lora_scales[0])

def callback(pipeline: FluxPipeline, step: int, timestep: torch.LongTensor, callback_kwargs: dict):
    pipeline.set_adapters("lora", lora_scales[step + 1])
    return callback_kwargs

prompt = """
Ghibli style The Grinch, a mischievous green creature with a sly grin, peeking out from behind a snow-covered tree while plotting his antics, 
in a quaint snowy village decorated for the holidays, warm light glowing from cozy homes, with playful snowflakes dancing in the air
"""
pipeline(
    prompt=prompt,
    guidance_scale=3.0,
    num_inference_steps=num_inference_steps,
    generator=torch.Generator().manual_seed(42),
    callback_on_step_end=callback,
).images[0]
```

## Hotswapping

LoRA를 핫스왑하는 것은 `load_lora_weights`를 여러 번 호출할 때 발생하는 메모리 누적과, 모델이 컴파일된 경우 재컴파일 문제를 피하면서 여러 LoRA를 효율적으로 다루는 방법입니다. 이 워크플로우는 로드된 LoRA가 필요하며, 새로운 LoRA 가중치가 기존에 로드된 LoRA의 위치를 그대로 대체하기 때문입니다.

```py
import torch
from diffusers import DiffusionPipeline

# load base model and LoRAs
pipeline = DiffusionPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_lora_weights(
    "ostris/ikea-instructions-lora-sdxl",
    weight_name="ikea_instructions_xl_v1_5.safetensors",
    adapter_name="ikea"
)
```

> [!WARNING]
> LoRA가 텍스트 인코더를 대상으로 하는 경우 핫스왑은 지원되지 않습니다.

`load_lora_weights`에 `hotswap=True`를 설정하여 두 번째 LoRA를 교체합니다. `adapter_name` 매개변수를 사용하여 교체할 LoRA를 지정합니다. 로드할 때 `adapter_name`을 생략하면 Diffusers는 어댑터 이름을 `default_0`, `default_1` 등으로 지정합니다. 이름을 붙인 어댑터는 명시적으로 지정하기가 더 쉽습니다.

```py
pipeline.load_lora_weights(
    "lordjia/by-feng-zikai",
    hotswap=True,
    adapter_name="ikea"
)
```

### 컴파일된 모델

컴파일된 모델의 경우, LoRA를 핫스왑할 때 재컴파일을 피하려면 [enable_lora_hotswap()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.enable_lora_hotswap)를 사용하세요. 이 메서드는 첫 번째 LoRA를 로드하기 *전에* 호출해야 하며, `torch.compile`은 첫 번째 LoRA를 로드한 *후에* 호출해야 합니다.

> [!TIP]
> 두 번째 LoRA가 첫 번째 LoRA와 동일한 LoRA 랭크와 스케일을 대상으로 하는 경우 [enable_lora_hotswap()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.enable_lora_hotswap) 메서드가 항상 필요한 것은 아닙니다.

[enable_lora_hotswap()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.enable_lora_hotswap) 내에서 `target_rank`를 로드할 어댑터 중 가장 높은 랭크로 설정합니다(기본값 128).

```py
import torch
from diffusers import DiffusionPipeline

# load base model and LoRAs
pipeline = DiffusionPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
# 1. enable_lora_hotswap
pipeline.enable_lora_hotswap(target_rank=128)
pipeline.load_lora_weights(
    "ostris/ikea-instructions-lora-sdxl",
    weight_name="ikea_instructions_xl_v1_5.safetensors",
    adapter_name="ikea"
)
# 2. torch.compile
pipeline.unet = torch.compile(pipeline.unet, mode="reduce-overhead", fullgraph=True)

# 3. hotswap
pipeline.load_lora_weights(
    "lordjia/by-feng-zikai",
    hotswap=True,
    adapter_name="ikea"
)
```

> [!TIP]
> 모델이 다시 컴파일되었는지 감지하려면 코드를 `with torch._dynamo.config.patch(error_on_recompile=True)` 컨텍스트 매니저 안으로 이동하세요. 위의 모든 단계를 따랐음에도 모델이 다시 컴파일되는 경우, 재현 가능한 예시를 포함하여 [이슈](https://github.com/huggingface/diffusers/issues)를 등록해 주세요.

이 기능을 사용하여 추론 시 다양한 해상도를 예상하는 경우, 컴파일 시 `dynamic=True`를 설정해야 합니다. 자세한 내용은 [동적 형상 컴파일](../optimization/fp16#dynamic-shape-compilation)을 참고하세요.

재컴파일을 피할 수 없는 시나리오가 여전히 존재합니다. 예를 들어, 핫스왑된 LoRA가 초기 어댑터보다 더 많은 레이어를 대상으로 하는 경우입니다. 가장 많은 레이어를 대상으로 하는 LoRA를 *먼저* 로드하도록 하세요. 이 제한 사항에 대한 자세한 내용은 PEFT [hotswapping](https://huggingface.co/docs/peft/main/en/package_reference/hotswap#peft.utils.hotswap.hotswap_adapter) 문서를 참조하세요.

`target_rank`와 로드 순서가 중요한 이유

[enable_lora_hotswap()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.enable_lora_hotswap) 메서드는 LoRA 스케일링 계수를 float에서 torch.tensors로 변환하고, 가중치 데이터가 교체될 때 전체 속성을 다시 할당하는 것을 방지하기 위해 가중치의 shape를 필요한 가장 큰 shape로 패딩합니다.

`target_rank` 인수가 중요한 이유입니다. 값이 0으로 패딩되어도 결과는 변하지 않습니다. 다만 패딩 크기에 따라 계산이 느려질 수 있습니다.

새로운 LoRA 속성이 추가되지 않으므로, 이후의 각 LoRA는 첫 번째 LoRA가 대상이 되는 레이어와 동일한 레이어 또는 그 부분 집합만 대상으로 할 수 있습니다. LoRA 로드 순서를 선택하는 것이 중요한 이유는, LoRA들이 서로 겹치지 않는 레이어를 대상으로 할 경우 모든 대상 레이어의 합집합을 대상으로 하는 더미 LoRA를 생성하게 될 수 있기 때문입니다.

컴파일된 모델의 LoRA 핫스왑에 대한 자세한 내용은 [LoRA fast](https://huggingface.co/blog/lora-fast) 블로그 포스트를 참고하고, 구현 세부 사항은 [`hotswap.py`](https://github.com/huggingface/peft/blob/92d65cafa51c829484ad3d95cf71d09de57ff066/src/peft/utils/hotswap.py) 파일을 확인해 보세요.

## 병합

각 LoRA의 가중치를 병합하여 여러 기존 스타일의 블렌드를 생성할 수 있습니다. LoRA를 병합하는 방법은 여러 가지가 있으며, 각각은 가중치를 병합하는 *방법*이 서로 다릅니다(생성 품질에 영향을 미칠 수 있음).

### set_adapters[[merge]]

[set_adapters()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.set_adapters) 메서드는 가중치 행렬을 연결(concatenation)하여 LoRA를 병합합니다. [set_adapters()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.set_adapters)에 LoRA 이름을 전달하고 `adapter_weights` 매개변수를 사용하여 각 LoRA의 스케일링을 제어합니다. 예를 들어, `adapter_weights=[0.5, 0.5]`인 경우 출력은 두 LoRA의 평균이 됩니다.

> [!TIP]
> 각 병합된 LoRA를 얼마나 적용할지 제어하려면 [set_adapters()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.set_adapters)에서 `adapter_weights`를 우선 사용하세요. 자세한 내용은 [Weight scale](#weight-scale) 섹션을 참조하세요.

```py
import torch
from diffusers import DiffusionPipeline

pipeline = DiffusionPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_lora_weights(
    "ostris/ikea-instructions-lora-sdxl",
    weight_name="ikea_instructions_xl_v1_5.safetensors",
    adapter_name="ikea"
)
pipeline.load_lora_weights(
    "lordjia/by-feng-zikai",
    weight_name="fengzikai_v1.0_XL.safetensors",
    adapter_name="feng"
)
pipeline.set_adapters(["ikea", "feng"], adapter_weights=[0.7, 0.8])
# use by Feng Zikai to activate the lordjia/by-feng-zikai LoRA
pipeline("A bowl of ramen shaped like a cute kawaii bear, by Feng Zikai").images[0]
```

### add_weighted_adapter

> [!TIP]
> 이것은 실험적인 방법이며, 자세한 내용은 PEFT의 [모델 병합](https://huggingface.co/docs/peft/developer_guides/model_merging)을 참고하세요. 이 통합의 동기 및 설계에 관심이 있다면 이 [이슈](https://github.com/huggingface/diffusers/issues/6892)를 확인해 보세요.

[add_weighted_adapter](https://huggingface.co/docs/peft/main/en/package_reference/lora#peft.LoraModel.add_weighted_adapter) 메서드는 [TIES](https://huggingface.co/papers/2306.01708) 또는 [DARE](https://huggingface.co/papers/2311.03099)와 같이 더 효율적인 병합 방법을 사용할 수 있게 합니다. 이러한 병합 방법은 병합된 모델에서 중복되고 잠재적으로 간섭을 일으킬 수 있는 파라미터를 제거합니다. 병합하려면 LoRA 랭크가 동일한 랭크를 가져야 한다는 점을 유의하세요. 아래 단계별 설명에서는 SDXL의 UNet을 사용합니다.

Diffusers와 PEFT의 최신 안정 버전이 설치되어 있는지 확인하세요.

```bash
pip install -U -q diffusers peft
```

LoRA UNet에 해당하는 UNet을 로드합니다.

```py
import copy
import torch
from diffusers import AutoModel, DiffusionPipeline
from peft import get_peft_model, LoraConfig, PeftModel

unet = AutoModel.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16,
    use_safetensors=True,
    variant="fp16",
    subfolder="unet",
).to("cuda")  # or "mps", "xpu", "cpu"
```

파이프라인을 로드하고, UNet을 전달한 다음, LoRA를 로드합니다.

```py
pipeline = DiffusionPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    variant="fp16",
    dtype=torch.float16,
    unet=unet
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_lora_weights(
    "ostris/ikea-instructions-lora-sdxl",
    weight_name="ikea_instructions_xl_v1_5.safetensors",
    adapter_name="ikea"
)
```

로딩한 첫 번째 UNet과 파이프라인의 LoRA UNet을 결합하여 LoRA 체크포인트에서 [PeftModel](https://huggingface.co/docs/peft/main/en/package_reference/peft_model#peft.PeftModel)을 생성합니다.

```py
sdxl_unet = copy.deepcopy(unet)
ikea_peft_model = get_peft_model(
    sdxl_unet,
    pipeline.unet.peft_config["ikea"],
    adapter_name="ikea"
)

original_state_dict = {f"base_model.model.{k}": v for k, v in pipeline.unet.state_dict().items()}
ikea_peft_model.load_state_dict(original_state_dict, strict=True)
```

> [!TIP]
> 아래와 같이 `ikea_peft_model`을 Hub에 업로드하여 저장하고 재사용할 수 있습니다.
> ```py
> ikea_peft_model.push_to_hub("ikea_peft_model", token=TOKEN)
> ```

이 과정을 반복하여 두 번째 LoRA에 대한 [PeftModel](https://huggingface.co/docs/peft/main/en/package_reference/peft_model#peft.PeftModel)을 생성합니다.

```py
pipeline.delete_adapters("ikea")
sdxl_unet.delete_adapters("ikea")

pipeline.load_lora_weights(
    "lordjia/by-feng-zikai",
    weight_name="fengzikai_v1.0_XL.safetensors",
    adapter_name="feng"
)
pipeline.set_adapters(adapter_names="feng")

feng_peft_model = get_peft_model(
    sdxl_unet,
    pipeline.unet.peft_config["feng"],
    adapter_name="feng"
)

original_state_dict = {f"base_model.model.{k}": v for k, v in pipeline.unet.state_dict().items()}
feng_peft_model.load_state_dict(original_state_dict, strict=True)
```

기본 UNet 모델을 로드하고 어댑터를 로드합니다.

```py
base_unet = AutoModel.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16,
    use_safetensors=True,
    variant="fp16",
    subfolder="unet",
).to("cuda")  # or "mps", "xpu", "cpu"

model = PeftModel.from_pretrained(
    base_unet,
    "stevhliu/ikea_peft_model",
    use_safetensors=True,
    subfolder="ikea",
    adapter_name="ikea"
)
model.load_adapter(
    "stevhliu/feng_peft_model",
    use_safetensors=True,
    subfolder="feng",
    adapter_name="feng"
)
```

[add_weighted_adapter](https://huggingface.co/docs/peft/main/en/package_reference/lora#peft.LoraModel.add_weighted_adapter)를 사용하여 LoRA를 병합하고, `combination_type`으로 병합 방식을 지정합니다. 아래 예제는 `"dare_linear"` 메서드를 사용합니다(이러한 병합 방법에 대해 자세히 알아보려면 이 [블로그 게시물](https://huggingface.co/blog/peft_merging)을 참고하세요). 이 메서드는 일부 가중치를 무작위로 제거한 후, `weights`의 각 LoRA에 설정된 가중치에 따라 텐서의 가중 합을 수행합니다.

[set_adapters()](/docs/diffusers/main/ko/api/loaders/peft#diffusers.loaders.PeftAdapterMixin.set_adapters)로 병합된 LoRA를 활성화합니다.

```py
model.add_weighted_adapter(
    adapters=["ikea", "feng"],
    combination_type="dare_linear",
    weights=[1.0, 1.0],
    adapter_name="ikea-feng"
)
model.set_adapters("ikea-feng")

pipeline = DiffusionPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    unet=model,
    variant="fp16",
    dtype=torch.float16,
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline("A bowl of ramen shaped like a cute kawaii bear, by Feng Zikai").images[0]
```

### fuse_lora

[fuse_lora()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.fuse_lora) 메서드는 LoRA 가중치를 기반 모델의 원래 denoiser(UNet 또는 transformer) 및 text encoder 가중치에 직접 병합합니다. 이를 통해 각 LoRA마다 기반 모델을 로드하는 오버헤드가 줄어들며, 모델이 한 번만 로드되므로 메모리 사용량이 감소하고 추론 속도가 향상됩니다.

```py
import torch
from diffusers import DiffusionPipeline

pipeline = DiffusionPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_lora_weights(
    "ostris/ikea-instructions-lora-sdxl",
    weight_name="ikea_instructions_xl_v1_5.safetensors",
    adapter_name="ikea"
)
pipeline.load_lora_weights(
    "lordjia/by-feng-zikai",
    weight_name="fengzikai_v1.0_XL.safetensors",
    adapter_name="feng"
)
pipeline.set_adapters(["ikea", "feng"], adapter_weights=[0.7, 0.8])
```

[fuse_lora()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.fuse_lora)를 호출하여 이를 병합합니다. `lora_scale` 매개변수는 LoRA 가중치로 출력을 얼마나 스케일링할지를 제어합니다. 파이프라인에서 `cross_attention_kwargs`에 `scale`를 전달해도 작동하지 않으므로, 지금 이 시점에 해당 조정을 수행하는 것이 중요합니다.

```py
pipeline.fuse_lora(adapter_names=["ikea", "feng"], lora_scale=1.0)
```

이미 기본 모델에 융합된 LoRA 가중치를 언로드합니다. [save_pretrained()](/docs/diffusers/main/ko/api/pipelines/overview#diffusers.DiffusionPipeline.save_pretrained)를 사용하여 로컬에 저장하거나 `~PushToHubMixin.push_to_hub`를 사용하여 Hub에 저장하여 융합된 파이프라인을 저장합니다.

```py
pipeline.unload_lora_weights()
pipeline.save_pretrained("path/to/fused-pipeline")
```

```py
pipeline.unload_lora_weights()
pipeline.push_to_hub("fused-ikea-feng")
```

융합된 파이프라인은 이제 각 LoRA를 별도로 로드할 필요 없이 추론을 위해 빠르게 로드할 수 있습니다.

```py
pipeline = DiffusionPipeline.from_pretrained(
    "username/fused-ikea-feng", dtype=torch.float16,
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline("A bowl of ramen shaped like a cute kawaii bear, by Feng Zikai").images[0]
```

`lora_scale` 값을 변경하려는 경우와 같이 기본 모델의 가중치를 복원하려면 [unfuse_lora()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.unfuse_lora)를 사용하세요. 단일 LoRA만 융합된 경우에만 unfuse할 수 있습니다. 예를 들어, 위에서 언급한 파이프라인에는 여러 개의 융합된 LoRA가 있으므로 작동하지 않습니다. 이러한 경우 전체 모델을 다시 로드해야 합니다.

```py
pipeline.unfuse_lora()
```

## 관리

Diffusers는 LoRA를 다루는 작업을 관리하는 데 도움이 되는 여러 메서드를 제공합니다. 이러한 메서드는 여러 LoRA를 함께 사용할 때 특히 유용합니다.

### set_adapters[[manage]]

[set_adapters()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.set_adapters)는 여러 개의 활성 LoRA가 있는 경우 현재 사용할 LoRA를 활성화합니다. 이를 통해 이름을 지정하여 서로 다른 LoRA 간에 전환할 수 있습니다.

```py
import torch
from diffusers import DiffusionPipeline

pipeline = DiffusionPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.load_lora_weights(
    "ostris/ikea-instructions-lora-sdxl",
    weight_name="ikea_instructions_xl_v1_5.safetensors",
    adapter_name="ikea"
)
pipeline.load_lora_weights(
    "lordjia/by-feng-zikai",
    weight_name="fengzikai_v1.0_XL.safetensors",
    adapter_name="feng"
)
# activates the feng LoRA instead of the ikea LoRA
pipeline.set_adapters("feng")
```

### save_lora_adapter

`pipeline.unet` 또는 `pipeline.transformer`로 로드한 동일한 모듈에서 [save_lora_adapter()](/docs/diffusers/main/ko/api/loaders/peft#diffusers.loaders.PeftAdapterMixin.save_lora_adapter)를 사용하여 어댑터를 저장합니다.

```py
import torch
from diffusers import AutoPipelineForText2Image

pipeline = AutoPipelineForText2Image.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.unet.load_lora_adapter(
    "jbilcke-hf/sdxl-cinematic-1",
    weight_name="pytorch_lora_weights.safetensors",
    adapter_name="cinematic",
    prefix="unet"
)
pipeline.unet.save_lora_adapter("path/to/save", adapter_name="cinematic")
```

### unload_lora_weights

[unload_lora_weights()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.unload_lora_weights) 메서드는 파이프라인의 LoRA 가중치를 해제하여 원래 모델의 가중치를 복원합니다.

```py
pipeline.unload_lora_weights()
```

### disable_lora

[disable_lora()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.disable_lora) 메서드는 모든 LoRA를 비활성화합니다(파이프라인에는 여전히 유지됨) 그리고 파이프라인을 기본 모델 가중치로 복원합니다.

```py
pipeline.disable_lora()
```

### get_active_adapters

[get_active_adapters()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.get_active_adapters) 메서드는 파이프라인에 연결된 활성 LoRA 목록을 반환합니다.

```py
pipeline.get_active_adapters()
# ["cereal", "ikea"]
```

### get_list_adapters

[get_list_adapters()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.get_list_adapters) 메서드는 파이프라인의 각 구성 요소에 대해 로드된 모든 LoRA를 반환합니다. 사전의 키는 `unet` 또는 `transformer`와 같이 로드된 모듈 및 텍스트 인코더와 일치합니다.

```py
pipeline.get_list_adapters()
# {"unet": ["cereal", "ikea"], "text_encoder_2": ["cereal"]}
```

### delete_adapters

[delete_adapters()](/docs/diffusers/main/ko/api/loaders/lora#diffusers.loaders.lora_base.LoraBaseMixin.delete_adapters) 메서드는 모델에서 LoRA와 해당 레이어를 완전히 제거합니다.

```py
pipeline.delete_adapters("ikea")
```

## 다음 단계

- [LoRA Studio](https://lorastudio.co/models)에서 사용할 수 있는 다양한 LoRA를 탐색하거나, 아래 Space를 통해 Civitai에서 좋아하는 LoRA를 Hub에 업로드할 수 있습니다.

<iframe src="https://multimodalart-civitai-to-hf.hf.space" frameborder="0" width="850" height="450"
>

- You can find additional LoRAs in the [FLUX LoRA the Explorer](https://huggingface.co/spaces/multimodalart/flux-lora-the-explorer) and [LoRA the Explorer](https://huggingface.co/spaces/multimodalart/LoraTheExplorer) Spaces.

- FlashAttention-3와 fp8 양자화와 같은 방법으로 LoRA 추론을 최적화하는 방법을 배우려면 [Diffusers와 PEFT를 활용한 Flux용 Fast LoRA 추론](https://huggingface.co/blog/lora-fast) 블로그 게시물을 확인하세요.

