PEFT documentation
어댑터 핫스왑
어댑터 핫스왑
어댑터를 핫스왑하는 개념은 다음과 같습니다. 이미 여러 어댑터, 예를 들어 LoRA 두 개를 동시에 로드할 수 있습니다. 하지만 때로는 LoRA 하나를 로드한 후, 그 가중치를 다른 어댑터의 LoRA 가중치로 제자리에서 교체하고 싶을 수 있습니다. 이제 hotswap_adapter 함수를 통해 이것이 가능합니다.
일반적으로 이는 하나의 어댑터를 삭제하고 그 자리에 다른 어댑터를 로드하는 것보다 빠릅니다. 후자의 방식은 핫스왑 없이 동일한 최종 결과를 얻기 위한 방법입니다. 핫스왑의 또 다른 장점은 PEFT 모델이 이미 torch.compile을 통해 컴파일된 경우 재컴파일을 방지할 수 있다는 점입니다. 이를 통해 상당한 시간을 절약할 수 있습니다.
torch.compile 없이 사용하는 예시
import torch
from transformers import AutoModelForCausalLM
from peft import PeftModel
from peft.utils.hotswap import hotswap_adapter
model_id = ...
inputs = ...
device = ...
model = AutoModelForCausalLM.from_pretrained(model_id).to(device)
# load lora 0
model = PeftModel.from_pretrained(model, <path-adapter-0>)
with torch.inference_mode():
output_adapter_0 = model(inputs)
# replace the "default" lora adapter with the new one
hotswap_adapter(model, <path-adapter-1>, adapter_name="default", torch_device=device)
with torch.inference_mode():
output_adapter_1 = model(inputs).logitstorch.compile를 사용한 예시
import torch
from transformers import AutoModelForCausalLM
from peft import PeftModel
from peft.utils.hotswap import hotswap_adapter, prepare_model_for_compiled_hotswap
model_id = ...
inputs = ...
device = ...
max_rank = ... # maximum rank among all LoRA adapters that will be used
model = AutoModelForCausalLM.from_pretrained(model_id).to(device)
# load lora 0
model = PeftModel.from_pretrained(model, <path-adapter-0>)
# Prepare the model to allow hotswapping even if ranks/scalings of 2nd adapter differ.
# You can skip this step if all ranks and scalings are identical.
prepare_model_for_compiled_hotswap(model, target_rank=max_rank)
model = torch.compile(model)
with torch.inference_mode():
output_adapter_0 = model(inputs)
# replace the "default" lora adapter with the new one
hotswap_adapter(model, <path-adapter-1>, adapter_name="default", torch_device=device)
with torch.inference_mode():
output_adapter_1 = model(inputs).logitstarget_parameters를 통해 추가된 가중치, 즉 nn.Parameter를 직접 대상으로 하는 가중치를 핫스왑하려는 경우 재컴파일 및/또는 그래프 브레이크를 방지할 수 없음을 유의하세요. 따라서 컴파일된 모델과 핫스왑을 함께 사용할 때 target_parameters의 사용을 피하는 것이 권장됩니다.
더미 어댑터로 시작하기
어댑터 중 다른 어댑터가 필요한 모든 레이어를 대상으로 하는 것이 없다면, helpers.create_dummy_lora_config()를 사용하여 더미 어댑터를 준비하세요. 초기 기여도가 0이므로, 학습된 어댑터 가중치를 로드하기 전에 베이스 모델의 동작을 제공할 수 있습니다. 이 헬퍼는 구성만 검사하며, 베이스 모델이나 어댑터 가중치를 로드하지 않습니다.
import torch
from transformers import AutoModelForCausalLM
from peft import PeftConfig, get_peft_model
from peft.helpers import create_dummy_lora_config
from peft.utils.hotswap import hotswap_adapter, prepare_model_for_compiled_hotswap
adapter_paths = ["path-to-adapter0", "path-to-adapter1"]
configs = [PeftConfig.from_pretrained(path) for path in adapter_paths]
dummy_config = create_dummy_lora_config(configs)
print("New combined LoraConfig:")
print(dummy_config.to_dict())
base_model = AutoModelForCausalLM.from_pretrained(model_id).to(device)
model = get_peft_model(base_model, dummy_config).eval()
# Ranks are already large enough; preparation also makes scalings safe to change after compilation.
prepare_model_for_compiled_hotswap(model)
model = torch.compile(model)
with torch.inference_mode():
base_output = model(**inputs)
for path in adapter_paths:
hotswap_adapter(model, path, adapter_name="default", torch_device=device)
with torch.inference_mode():
adapted_output = model(**inputs)더미 구성은 target_modules의 합집합과 모든 r 및 rank_pattern 값 중 최대값을 취합니다. 모든 어댑터를 커버하기 위해 exclude_modules, layers_to_transform, layers_pattern를 제거합니다. 이는 대상 레이어의 정확한 합집합보다 더 많은 어댑터 메모리를 예약할 수 있습니다. 수신되는 어댑터에 없는 모듈은 핫스왑 시 제로로 설정됩니다. 초기 추론 동안 더미 어댑터를 활성화된 상태로 유지하세요. 비활성화하면 포워드 경로가 변경되어 다시 활성화할 때 재컴파일을 트리거할 수 있습니다.
이 헬퍼는 비어 있지 않고 명시적으로 지정된 대상 모듈 목록 또는 집합을 요구합니다. 정규식 및 "all-linear"를 포함한 문자열 대상과 자동으로 추론된 대상은 지원되지 않습니다. 호환되는 hotswap 설정(일치하는 dropout, rsLoRA, alpha-pattern 설정 포함)과 함께 표준 LoRA 및 rsLoRA를 지원합니다. 변형(variants), 추가로 저장된 모듈, 학습된 bias/token, 직접 파라미터 대상, base weight를 변경하는 초기화는 거부됩니다. 모든 어댑터는 동일한 base weights를 사용해야 합니다. 구성 확인은 모델의 실제 레이어 유형을 검증할 수 없으며, 컴파일된 hotswapping의 기존 제한 사항이 여전히 적용됩니다. 그룹화 된 컨볼루션의 경우, 모델을 생성하기 전에 최대 랭크를 대상 그룹 수의 공배수로 증가시켜야 할 수 있습니다.
PEFT 체크아웃에서 다음을 사용하여 구성을 저장할 수도 있습니다:
python scripts/create-dummy-lora-for-hotswap.py path-to-adapter0 path-to-adapter1 --output-dir dummy-lora
Adapter 인수는 로컬 디렉터리 또는 Hugging Face Hub 저장소 ID를 받습니다. 기본 출력 디렉터리는 dummy-lora입니다. 이 스크립트는 어댑터 체크포인트가 아닌 adapter_config.json만 작성합니다. LoraConfig.from_pretrained("dummy-lora")로 로드한 후 get_peft_model에 전달하고, 위와 같이 모델을 준비하세요. PeftModel.from_pretrained는 어댑터 가중치가 없기 때문에 이 디렉터리를 로드할 수 없습니다. 더미 가중치도 필요하면 model.save_pretrained를 호출하세요.
주의 사항
Hotswapping은 Transformers 모델과 Diffusers 모델에서 작동합니다. 그러나 몇 가지 주의할 점이 있습니다:
- 현재 LoRA만 제대로 지원됩니다.
- 동일한 PEFT 방법에만 작동하므로, 예를 들어 LoRA와 LoHa를 서로 교체하는 것은 불가능합니다.
- 교체되는 어댑터는 이전 어댑터와 동일한 레이어 또는 해당 레이어의 부분 집합을 대상으로 해야 합니다. 새로운 레이어를 대상으로 할 수 없습니다. 따라서 가능하면 가장 많은 레이어를 대상으로 하는 어댑터부터 시작하세요.
- 가짜 LoRA 설정을 생성하려면
target_parameters가 문자열 목록이어야 하며, 정규식은 지원되지 않습니다.LoraConfig의 몇 가지 다른 파라미터도 지원되지 않으며, 이러한 파라미터가 발견되면 오류가 발생합니다.layers_to_transform와layers_pattern를 사용하여 일부 레이어 인덱스만 대상으로 할 때, 가능한 가장 작은 오버랩을 찾으려는 시도는 하지 않고 대신 가짜 LoRA가 과잉 프로비저닝됩니다.exclude_modules를 통해 제외된 모듈에 대해서도 마찬가지입니다.
API
peft.utils.hotswap.hotswap_adapter
< source >( model: torch.nn.Modulemodel_name_or_path: stradapter_name: strtorch_device: Optional[str] = None**kwargs )
매개변수
- model (~PeftModel) — 로드된 어댑터가 포함된 PEFT 모델입니다.
- model_name_or_path (
str) — 새 어댑터를 로드할 모델의 이름 또는 경로입니다. - adapter_name (
str) — 교체할 어댑터의 이름, 예:"default". 교체 후에도 이름은 동일하게 유지됩니다. - torch_device — (
str, 선택 사항, 기본값 None): 새 어댑터를 로드할 디바이스입니다. - **kwargs (
optional) — 설정과 가중치를 로드하는 데 사용되는 추가 키워드 인자입니다.
기존 어댑터 데이터를 새 어댑터 데이터로 교체하되, 나머지는 그대로 유지합니다.
현재 LoRA만 지원됩니다.
이 함수는 로드된 어댑터를 새로운 어댑터로 교체하려는 경우에 유용합니다. 어댑터 이름은 동일하게 유지되지만, 가중치 및 기타 매개변수는 교체됩니다.
어댑터가 호환되지 않는 경우, 예를 들어 서로 다른 레이어를 대상으로 하거나 alpha 값이 다른 경우, 오류가 발생합니다.
예:
>>> import torch
>>> from transformers import AutoModelForCausalLM
>>> from peft import PeftModel
>>> from peft.utils.hotswap import hotswap_adapter
>>> model_id = ...
>>> inputs = ...
>>> device = ...
>>> model = AutoModelForCausalLM.from_pretrained(model_id).to(device)
>>> # load lora 0
>>> model = PeftModel.from_pretrained(model, "path-adapter-0")
>>> model = torch.compile(model) # optionally compile the model
>>> with torch.inference_mode():
... output_adapter_0 = model(inputs)
>>> # replace the "default" lora adapter with the new one
>>> hotswap_adapter(model, "path-adapter-1", adapter_name="default", torch_device=device)
>>> with torch.inference_mode():
... output_adapter_1 = model(inputs).logitspeft.utils.hotswap.hotswap_adapter_from_state_dict
< source >( model: torch.nn.Modulestate_dict: dict[str, torch.Tensor]adapter_name: strconfig: LoraConfigparameter_prefix: str = 'lora_' )
매개변수
- model (
nn.Module) — 로드된 어댑터가 포함된 모델입니다. - state_dict (
dict[str, torch.Tensor]) — 새 어댑터의 state dict입니다. 동일한 모듈 등을 대상으로 하므로 호환되어야 합니다. - adapter_name (
str) — 핫 스왑할 어댑터의 이름입니다. 예:"default". 스왑 후에도 이름은 동일하게 유지됩니다. - config (
LoraConfig) — LoRA 어댑터의 설정입니다. 이는 어댑터의 스케일링과 랭크를 결정하는 데 사용됩니다. - parameter_prefix (
str, 선택 사항, 기본값"lora_") — state dict에서 어댑터의 키를 식별하는 데 사용되는 접두사입니다. LoRA의 경우 이는"lora_"(기본값)입니다.
Raises
RuntimeError
RuntimeError— 기존 어댑터와 새 어댑터가 호환되지 않으면 RuntimeError가 발생합니다.
state_dict의 가중치로 모델의 어댑터 가중치를 교체합니다.
현재 LoRA만 지원됩니다.
이것은 어댑터가 호환성 검사를 마쳤고 state_dict가 PEFT와 함께 작동하도록 올바르게 매핑되었다고 가정하는 저수준 함수입니다. 이 작업을 대신 수행하는 고수준 함수를 사용하려면 hotswap_adapter를 사용하세요.